OpenSSL
-Stig Venaas, Wez Furlong, Sascha Kettler, Scott MacVicar
+Stig Venaas, Wez Furlong, Sascha Kettler, Scott MacVicar, Eliot Lear
| Pierre-Alain Joye <pierre@php.net> |
| Marc Delling <delling@silpion.de> (PKCS12 functions) |
| Jakub Zelenka <bukka@php.net> |
+ | Eliot Lear <lear@ofcourseimright.com> |
+----------------------------------------------------------------------+
*/
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
+#include <openssl/cms.h>
/* Common */
#include <time.h>
PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
};
+/* Add some encoding rules. This is normally handled through filters
+ * in the OpenSSL code, but we will do that part as if we were one
+ * of the OpenSSL binaries along the lines of -outform {DER|CMS|PEM}
+ */
+enum php_openssl_encoding {
+ ENCODING_DER,
+ ENCODING_SMIME,
+ ENCODING_PEM,
+};
+
/* {{{ openssl_module_entry
*/
zend_module_entry openssl_module_entry = {
REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_DETACHED", CMS_DETACHED, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_TEXT", CMS_TEXT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_NOINTERN", CMS_NOINTERN, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_NOVERIFY", CMS_NOVERIFY, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_NOCERTS", CMS_NOCERTS, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_NOATTR", CMS_NOATTR, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_BINARY", CMS_BINARY, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_CMS_NOSIGS", CMS_NOSIGS, CONST_CS|CONST_PERSISTENT);
+
REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
#endif
+ /* Register encodings */
+ REGISTER_LONG_CONSTANT("OPENSSL_ENCODING_DER",ENCODING_DER,CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_ENCODING_SMIME",ENCODING_SMIME,CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("OPENSSL_ENCODING_PEM",ENCODING_PEM,CONST_CS|CONST_PERSISTENT);
+
/* Determine default SSL configuration file */
config_filename = getenv("OPENSSL_CONF");
if (config_filename == NULL) {
php_openssl_store_errors();
goto clean_exit;
}
-
if (datafilename) {
-
if (php_openssl_open_base_dir_chk(datafilename)) {
goto clean_exit;
}
-
dataout = BIO_new_file(datafilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
if (dataout == NULL) {
php_openssl_store_errors();
goto clean_exit;
}
}
-
if (p7bfilename) {
-
if (php_openssl_open_base_dir_chk(p7bfilename)) {
goto clean_exit;
}
/* }}} */
+/* {{{ CMS S/MIME functions taken from PKCS#7 functions */
+
+/* {{{ proto bool openssl_cms_verify(string filename, int flags [, string signerscerts [, array cainfo [, string extracerts [, string content [, string pk7]]]], string sigfile, int encoding])
+ Verifies that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
+PHP_FUNCTION(openssl_cms_verify)
+{
+ X509_STORE * store = NULL;
+ zval * cainfo = NULL;
+ STACK_OF(X509) *signers= NULL;
+ STACK_OF(X509) *others = NULL;
+ CMS_ContentInfo * cms = NULL;
+ BIO * in = NULL, * datain = NULL, * dataout = NULL, * p7bout = NULL;
+ BIO *certout = NULL, *sigbio = NULL;
+ zend_long flags = 0;
+ char * filename;
+ size_t filename_len;
+ char * extracerts = NULL;
+ size_t extracerts_len = 0;
+ char * signersfilename = NULL;
+ size_t signersfilename_len = 0;
+ char * datafilename = NULL;
+ size_t datafilename_len = 0;
+ char * p7bfilename = NULL;
+ size_t p7bfilename_len = 0;
+ char * sigfile = NULL;
+ size_t sigfile_len = 0;
+ zend_long encoding = ENCODING_SMIME;
+
+ RETVAL_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|p!ap!p!p!p!l", &filename, &filename_len,
+ &flags, &signersfilename, &signersfilename_len, &cainfo,
+ &extracerts, &extracerts_len, &datafilename, &datafilename_len,
+ &p7bfilename, &p7bfilename_len,
+ &sigfile, &sigfile_len, &encoding) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ if (php_openssl_open_base_dir_chk(filename)) {
+ goto clean_exit;
+ }
+ in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(flags));
+ if (in == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ if (sigfile && (flags & CMS_DETACHED)) {
+ sigbio = BIO_new_file(sigfile, PHP_OPENSSL_BIO_MODE_R(flags));
+ if (encoding == ENCODING_SMIME) {
+ php_error_docref(NULL, E_WARNING,
+ "Detached signatures not possible with S/MIME encoding");
+ goto clean_exit;
+ }
+ } else {
+ sigbio = in; /* non-detached signature */
+ }
+
+ switch (encoding) {
+ case ENCODING_PEM:
+ cms = PEM_read_bio_CMS(sigbio, NULL, 0, NULL);
+ datain = in;
+ break;
+ case ENCODING_DER:
+ cms = d2i_CMS_bio(sigbio, NULL);
+ datain = in;
+ break;
+ case ENCODING_SMIME:
+ cms = SMIME_read_CMS(sigbio, &datain);
+ break;
+ default:
+ php_error_docref(NULL, E_WARNING, "Unknown encoding");
+ goto clean_exit;
+ }
+ if (cms == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ if (encoding != ENCODING_SMIME && !(flags & CMS_DETACHED)) {
+ datain = NULL; /* when not detached, don't pass a real BIO */
+ }
+
+ if (extracerts) {
+ others = php_openssl_load_all_certs_from_file(extracerts);
+ if (others == NULL) {
+ goto clean_exit;
+ }
+ }
+
+ store = php_openssl_setup_verify(cainfo);
+
+ if (!store) {
+ goto clean_exit;
+ }
+
+ if (datafilename) {
+
+ if (php_openssl_open_base_dir_chk(datafilename)) {
+ goto clean_exit;
+ }
+
+ dataout = BIO_new_file(datafilename, PHP_OPENSSL_BIO_MODE_W(CMS_BINARY));
+ if (dataout == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+
+ if (p7bfilename) {
+
+ if (php_openssl_open_base_dir_chk(p7bfilename)) {
+ goto clean_exit;
+ }
+
+ p7bout = BIO_new_file(p7bfilename, PHP_OPENSSL_BIO_MODE_W(CMS_BINARY));
+ if (p7bout == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+#if DEBUG_SMIME
+ zend_printf("Calling CMS verify\n");
+#endif
+ if (CMS_verify(cms, others, store, datain, dataout, (unsigned int)flags)) {
+ RETVAL_TRUE;
+
+ if (signersfilename) {
+ if (php_openssl_open_base_dir_chk(signersfilename)) {
+ goto clean_exit;
+ }
+
+ certout = BIO_new_file(signersfilename, PHP_OPENSSL_BIO_MODE_W(CMS_BINARY));
+ if (certout) {
+ int i;
+ signers = CMS_get0_signers(cms);
+ if (signers != NULL) {
+
+ for (i = 0; i < sk_X509_num(signers); i++) {
+ if (!PEM_write_bio_X509(certout, sk_X509_value(signers, i))) {
+ php_openssl_store_errors();
+ RETVAL_FALSE;
+ php_error_docref(NULL, E_WARNING, "Failed to write signer %d", i);
+ }
+ }
+
+ sk_X509_free(signers);
+ } else {
+ RETVAL_FALSE;
+ php_openssl_store_errors();
+ }
+ } else {
+ php_openssl_store_errors();
+ php_error_docref(NULL, E_WARNING, "Signature OK, but cannot open %s for writing", signersfilename);
+ RETVAL_FALSE;
+ }
+
+ if (p7bout) {
+ PEM_write_bio_CMS(p7bout, cms);
+ }
+ }
+ } else {
+ php_openssl_store_errors();
+ RETVAL_FALSE;
+ }
+clean_exit:
+ BIO_free(p7bout);
+ if (store) {
+ X509_STORE_free(store);
+ }
+ if (datain != in) {
+ BIO_free(datain);
+ }
+ if (sigbio != in) {
+ BIO_free(sigbio);
+ }
+ BIO_free(in);
+ BIO_free(dataout);
+ BIO_free(certout);
+ if (cms) {
+ CMS_ContentInfo_free(cms);
+ }
+ if (others) {
+ sk_X509_pop_free(others, X509_free);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool openssl_cms_encrypt(string infile, string outfile, mixed recipcerts, array headers [, int flags [,int encoding [, int cipher]]])
+ Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
+PHP_FUNCTION(openssl_cms_encrypt)
+{
+ zval * zrecipcerts, * zheaders = NULL;
+ STACK_OF(X509) * recipcerts = NULL;
+ BIO * infile = NULL, * outfile = NULL;
+ zend_long flags = 0;
+ zend_long encoding = ENCODING_SMIME;
+ CMS_ContentInfo * cms = NULL;
+ zval * zcertval;
+ X509 * cert;
+ const EVP_CIPHER *cipher = NULL;
+ zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
+ zend_string * strindex;
+ char * infilename = NULL;
+ size_t infilename_len;
+ char * outfilename = NULL;
+ size_t outfilename_len;
+ int need_final = 0;
+
+ RETVAL_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|lll", &infilename, &infilename_len,
+ &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &encoding, &cipherid) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+
+ if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
+ return;
+ }
+
+ infile = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(flags));
+ if (infile == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ outfile = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(flags));
+ if (outfile == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ recipcerts = sk_X509_new_null();
+
+ /* get certs */
+ if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) {
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zrecipcerts), zcertval) {
+ zend_resource *certresource;
+
+ cert = php_openssl_x509_from_zval(zcertval, 0, &certresource);
+ if (cert == NULL) {
+ goto clean_exit;
+ }
+
+ if (certresource != NULL) {
+ /* we shouldn't free this particular cert, as it is a resource.
+ make a copy and push that on the stack instead */
+ cert = X509_dup(cert);
+ if (cert == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ sk_X509_push(recipcerts, cert);
+ } ZEND_HASH_FOREACH_END();
+ } else {
+ /* a single certificate */
+ zend_resource *certresource;
+
+ cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource);
+ if (cert == NULL) {
+ goto clean_exit;
+ }
+
+ if (certresource != NULL) {
+ /* we shouldn't free this particular cert, as it is a resource.
+ make a copy and push that on the stack instead */
+ cert = X509_dup(cert);
+ if (cert == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ sk_X509_push(recipcerts, cert);
+ }
+
+ /* sanity check the cipher */
+ cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
+ if (cipher == NULL) {
+ /* shouldn't happen */
+ php_error_docref(NULL, E_WARNING, "Failed to get cipher");
+ goto clean_exit;
+ }
+
+ cms = CMS_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, (unsigned int)flags);
+
+ if (cms == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ if (flags & CMS_PARTIAL && !(flags & CMS_STREAM)) {
+ need_final=1;
+ }
+
+ /* tack on extra headers */
+ if (zheaders && encoding == ENCODING_SMIME) {
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) {
+ zend_string *str = zval_try_get_string(zcertval);
+ if (UNEXPECTED(!str)) {
+ goto clean_exit;
+ }
+ if (strindex) {
+ BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str));
+ } else {
+ BIO_printf(outfile, "%s\n", ZSTR_VAL(str));
+ }
+ zend_string_release(str);
+ } ZEND_HASH_FOREACH_END();
+ }
+
+ (void)BIO_reset(infile);
+
+ switch (encoding) {
+ case ENCODING_SMIME:
+ if (!SMIME_write_CMS(outfile, cms, infile, (int)flags)) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ break;
+ case ENCODING_DER:
+ if (need_final) {
+ if (CMS_final(cms, infile, NULL, (unsigned int) flags) != 1) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ if (i2d_CMS_bio(outfile, cms) != 1) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ break;
+ case ENCODING_PEM:
+ if (need_final) {
+ if (CMS_final(cms, infile, NULL, (unsigned int) flags) != 1) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ if (flags & CMS_STREAM) {
+ if (PEM_write_bio_CMS_stream(outfile, cms, infile, flags) == 0) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ } else {
+ if (PEM_write_bio_CMS(outfile, cms) == 0) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ break;
+ default:
+ php_error_docref(NULL, E_WARNING, "Unknown OPENSSL encoding");
+ goto clean_exit;
+ }
+
+ RETVAL_TRUE;
+
+clean_exit:
+ if (cms) {
+ CMS_ContentInfo_free(cms);
+ }
+ BIO_free(infile);
+ BIO_free(outfile);
+ if (recipcerts) {
+ sk_X509_pop_free(recipcerts, X509_free);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool openssl_cms_read(string P7B, array &certs)
+ Exports the CMS file to an array of PEM certificates */
+PHP_FUNCTION(openssl_cms_read)
+{
+ zval * zout = NULL, zcert;
+ char *p7b;
+ size_t p7b_len;
+ STACK_OF(X509) *certs = NULL;
+ STACK_OF(X509_CRL) *crls = NULL;
+ BIO * bio_in = NULL, * bio_out = NULL;
+ CMS_ContentInfo * cms = NULL;
+ int i;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &p7b, &p7b_len,
+ &zout) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ RETVAL_FALSE;
+
+ PHP_OPENSSL_CHECK_SIZE_T_TO_INT(p7b_len, p7b);
+
+ bio_in = BIO_new(BIO_s_mem());
+ if (bio_in == NULL) {
+ goto clean_exit;
+ }
+
+ if (0 >= BIO_write(bio_in, p7b, (int)p7b_len)) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ cms = PEM_read_bio_CMS(bio_in, NULL, NULL, NULL);
+ if (cms == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ switch (OBJ_obj2nid(CMS_get0_type(cms))) {
+ case NID_pkcs7_signed:
+ case NID_pkcs7_signedAndEnveloped:
+ certs = CMS_get1_certs(cms);
+ crls = CMS_get1_crls(cms);
+ break;
+ default:
+ break;
+ }
+
+ zout = zend_try_array_init(zout);
+ if (!zout) {
+ goto clean_exit;
+ }
+
+ if (certs != NULL) {
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ X509* ca = sk_X509_value(certs, i);
+
+ bio_out = BIO_new(BIO_s_mem());
+ if (bio_out && PEM_write_bio_X509(bio_out, ca)) {
+ BUF_MEM *bio_buf;
+ BIO_get_mem_ptr(bio_out, &bio_buf);
+ ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
+ add_index_zval(zout, i, &zcert);
+ BIO_free(bio_out);
+ }
+ }
+ }
+
+ if (crls != NULL) {
+ for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+ X509_CRL* crl = sk_X509_CRL_value(crls, i);
+
+ bio_out = BIO_new(BIO_s_mem());
+ if (bio_out && PEM_write_bio_X509_CRL(bio_out, crl)) {
+ BUF_MEM *bio_buf;
+ BIO_get_mem_ptr(bio_out, &bio_buf);
+ ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
+ add_index_zval(zout, i, &zcert);
+ BIO_free(bio_out);
+ }
+ }
+ }
+
+ RETVAL_TRUE;
+
+clean_exit:
+ BIO_free(bio_in);
+ if (cms != NULL) {
+ CMS_ContentInfo_free(cms);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool openssl_cms_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, int flags, int encoding [, string extracertsfilename]])
+ Signs the MIME message in the file named infile with signcert/signkey and output the result to file name outfile. headers lists plain text headers to exclude from the signed portion of the message, and should include to, from and subject as a minimum */
+
+PHP_FUNCTION(openssl_cms_sign)
+{
+ zval * zcert, * zprivkey, * zheaders;
+ zval * hval;
+ X509 * cert = NULL;
+ EVP_PKEY * privkey = NULL;
+ zend_long flags = 0;
+ zend_long encoding = ENCODING_SMIME;
+ CMS_ContentInfo * cms = NULL;
+ BIO * infile = NULL, * outfile = NULL;
+ STACK_OF(X509) *others = NULL;
+ zend_resource *certresource = NULL, *keyresource = NULL;
+ zend_string * strindex;
+ char * infilename;
+ size_t infilename_len;
+ char * outfilename;
+ size_t outfilename_len;
+ char * extracertsfilename = NULL;
+ size_t extracertsfilename_len;
+ int need_final = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppzza!|llp!",
+ &infilename, &infilename_len, &outfilename, &outfilename_len,
+ &zcert, &zprivkey, &zheaders, &flags, &encoding, &extracertsfilename,
+ &extracertsfilename_len) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ RETVAL_FALSE;
+
+ if (extracertsfilename) {
+ others = php_openssl_load_all_certs_from_file(extracertsfilename);
+ if (others == NULL) {
+ goto clean_exit;
+ }
+ }
+
+ privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, 0, &keyresource);
+ if (privkey == NULL) {
+ if (!EG(exception)) {
+ php_error_docref(NULL, E_WARNING, "Error getting private key");
+ }
+ goto clean_exit;
+ }
+
+ cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
+ if (cert == NULL) {
+ php_error_docref(NULL, E_WARNING, "Error getting cert");
+ goto clean_exit;
+ }
+
+ if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
+ goto clean_exit;
+ }
+
+ if ((encoding & ENCODING_SMIME) && (flags & CMS_DETACHED)) {
+ php_error_docref(NULL,
+ E_WARNING, "Detached signatures not possible with S/MIME encoding");
+ goto clean_exit;
+ }
+
+ /* a CMS struct will not be complete if either CMS_PARTIAL or CMS_STREAM is set.
+ * However, CMS_PARTIAL requires a CMS_final call whereas CMS_STREAM requires
+ * a different write routine below. There may be a more efficient way to do this
+ * with function pointers, but the readability goes down.
+ * References: CMS_sign(3SSL), CMS_final(3SSL)
+ */
+
+ if (flags & CMS_PARTIAL && !(flags & CMS_STREAM)) {
+ need_final=1;
+ }
+
+ infile = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(flags));
+ if (infile == NULL) {
+ php_openssl_store_errors();
+ php_error_docref(NULL, E_WARNING, "Error opening input file %s!", infilename);
+ goto clean_exit;
+ }
+
+ outfile = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(CMS_BINARY));
+ if (outfile == NULL) {
+ php_openssl_store_errors();
+ php_error_docref(NULL, E_WARNING, "Error opening output file %s!", outfilename);
+ goto clean_exit;
+ }
+
+ cms = CMS_sign(cert, privkey, others, infile, (unsigned int)flags);
+ if (cms == NULL) {
+ php_openssl_store_errors();
+ php_error_docref(NULL, E_WARNING, "Error creating CMS structure!");
+ goto clean_exit;
+ }
+ if (BIO_reset(infile) != 0) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ /* tack on extra headers */
+ if (zheaders && encoding == ENCODING_SMIME) {
+ int ret;
+
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) {
+ zend_string *str = zval_try_get_string(hval);
+ if (UNEXPECTED(!str)) {
+ goto clean_exit;
+ }
+ if (strindex) {
+ ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), ZSTR_VAL(str));
+ } else {
+ ret = BIO_printf(outfile, "%s\n", ZSTR_VAL(str));
+ }
+ zend_string_release(str);
+ if (ret < 0) {
+ php_openssl_store_errors();
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+ /* writing the signed data depends on the encoding */
+ switch (encoding) {
+ case ENCODING_SMIME:
+ if (!SMIME_write_CMS(outfile, cms, infile, (int)flags)) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ break;
+ case ENCODING_DER:
+ if (need_final) {
+ if (CMS_final(cms, infile, NULL, (unsigned int) flags) != 1) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ if (i2d_CMS_bio(outfile, cms) != 1) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ break;
+ case ENCODING_PEM:
+ if (need_final) {
+ if (CMS_final(cms, infile, NULL, (unsigned int) flags) != 1) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ if (flags & CMS_STREAM) {
+ if (PEM_write_bio_CMS_stream(outfile, cms, infile, flags) == 0) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ } else {
+ if (PEM_write_bio_CMS(outfile, cms) == 0) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ }
+ break;
+ default:
+ php_error_docref(NULL, E_WARNING, "Unknown OPENSSL encoding");
+ goto clean_exit;
+ }
+ RETVAL_TRUE;
+
+clean_exit:
+ if (cms) {
+ CMS_ContentInfo_free(cms);
+ }
+ BIO_free(infile);
+ BIO_free(outfile);
+ if (others) {
+ sk_X509_pop_free(others, X509_free);
+ }
+ EVP_PKEY_free(privkey);
+ if (cert && certresource == NULL) {
+ X509_free(cert);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool openssl_cms_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey [, int encoding])
+ Decrypts the S/MIME message in the file name infilename and output the results to the file name outfilename. recipcert is a CERT for one of the recipients. recipkey specifies the private key matching recipcert, if recipcert does not include the key */
+
+PHP_FUNCTION(openssl_cms_decrypt)
+{
+ zval * recipcert, * recipkey = NULL;
+ X509 * cert = NULL;
+ EVP_PKEY * key = NULL;
+ zend_resource *certresval, *keyresval;
+ zend_long encoding = ENCODING_SMIME;
+ BIO * in = NULL, * out = NULL, * datain = NULL;
+ CMS_ContentInfo * cms = NULL;
+ char * infilename;
+ size_t infilename_len;
+ char * outfilename;
+ size_t outfilename_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppz|zl", &infilename, &infilename_len,
+ &outfilename, &outfilename_len, &recipcert,
+ &recipkey, &encoding) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ RETVAL_FALSE;
+
+ cert = php_openssl_x509_from_zval(recipcert, 0, &certresval);
+ if (cert == NULL) {
+ php_error_docref(NULL, E_WARNING, "Unable to coerce parameter 3 to x509 cert");
+ goto clean_exit;
+ }
+
+ key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, 0, &keyresval);
+ if (key == NULL) {
+ if (!EG(exception)) {
+ php_error_docref(NULL, E_WARNING, "Unable to get private key");
+ }
+ goto clean_exit;
+ }
+
+ if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
+ goto clean_exit;
+ }
+
+ in = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(CMS_BINARY));
+ if (in == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ out = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(CMS_BINARY));
+ if (out == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+
+ switch (encoding) {
+ case ENCODING_DER:
+ cms = d2i_CMS_bio(in, NULL);
+ break;
+ case ENCODING_PEM:
+ cms = PEM_read_bio_CMS(in, NULL, 0, NULL);
+ break;
+ case ENCODING_SMIME:
+ cms = SMIME_read_CMS(in, &datain);
+ break;
+ default:
+ php_error_docref(NULL, E_WARNING,
+ "Unknown OPENSSL encoding");
+ goto clean_exit;
+ }
+
+ if (cms == NULL) {
+ php_openssl_store_errors();
+ goto clean_exit;
+ }
+ if (CMS_decrypt(cms, key, cert, NULL, out, 0)) {
+ RETVAL_TRUE;
+ } else {
+ php_openssl_store_errors();
+ }
+clean_exit:
+ if (cms) {
+ CMS_ContentInfo_free(cms);
+ }
+ BIO_free(datain);
+ BIO_free(in);
+ BIO_free(out);
+ if (cert && certresval == NULL) {
+ X509_free(cert);
+ }
+ if (key && keyresval == NULL) {
+ EVP_PKEY_free(key);
+ }
+}
+/* }}} */
+
+/* }}} */
+
+
+
/* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding])
Encrypts data with private key */
PHP_FUNCTION(openssl_private_encrypt)
function openssl_pkcs7_read(string $infilename, &$certs): bool {}
+function openssl_cms_verify(string $filename, int $flags = 0, ?string $signerscerts = null, ?array $cainfo = null, ?string $extracerts = null, ?string $content = null, ?string $pk7 = null, ?string $sigfile = null, $encoding = OPENSSL_ENCODING_SMIME): bool {}
+
+/** @param resource|string|array $recipcerts */
+function openssl_cms_encrypt(string $infile, string $outfile, $recipcerts, ?array $headers, int $flags = 0, int $encoding = OPENSSL_ENCODING_SMIME, int $cipher = OPENSSL_CIPHER_RC2_40): bool {}
+
+/**
+ * @param resource|string $signcert
+ * @param resource|string|array $signkey
+ */
+function openssl_cms_sign(string $infile, string $outfile, $signcert, $signkey, ?array $headers, int $flags = 0, int $encoding = OPENSSL_ENCODING_SMIME, ?string $extracertsfilename = null): bool {}
+
+/**
+ * @param resource|string $recipcert
+ * @param resource|string|array $recipkey
+ */
+function openssl_cms_decrypt(string $infilename, string $outfilename, $recipcert, $recipkey, int $encoding = OPENSSL_ENCODING_SMIME): bool {}
+
+function openssl_cms_read(string $infilename, &$certs): bool {}
+
+
/** @param resource|string|array $key */
function openssl_private_encrypt(string $data, &$crypted, $key, int $padding = OPENSSL_PKCS1_PADDING): bool {}
ZEND_ARG_INFO(1, certs)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_cms_verify, 0, 1, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, signerscerts, IS_STRING, 1, "null")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, cainfo, IS_ARRAY, 1, "null")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, extracerts, IS_STRING, 1, "null")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, content, IS_STRING, 1, "null")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pk7, IS_STRING, 1, "null")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sigfile, IS_STRING, 1, "null")
+ ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, encoding, "OPENSSL_ENCODING_SMIME")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_cms_encrypt, 0, 4, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, infile, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, outfile, IS_STRING, 0)
+ ZEND_ARG_INFO(0, recipcerts)
+ ZEND_ARG_TYPE_INFO(0, headers, IS_ARRAY, 1)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_LONG, 0, "OPENSSL_ENCODING_SMIME")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, cipher, IS_LONG, 0, "OPENSSL_CIPHER_RC2_40")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_cms_sign, 0, 5, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, infile, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, outfile, IS_STRING, 0)
+ ZEND_ARG_INFO(0, signcert)
+ ZEND_ARG_INFO(0, signkey)
+ ZEND_ARG_TYPE_INFO(0, headers, IS_ARRAY, 1)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_LONG, 0, "OPENSSL_ENCODING_SMIME")
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, extracertsfilename, IS_STRING, 1, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_cms_decrypt, 0, 4, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, infilename, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, outfilename, IS_STRING, 0)
+ ZEND_ARG_INFO(0, recipcert)
+ ZEND_ARG_INFO(0, recipkey)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_LONG, 0, "OPENSSL_ENCODING_SMIME")
+ZEND_END_ARG_INFO()
+
+#define arginfo_openssl_cms_read arginfo_openssl_pkcs7_read
+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_private_encrypt, 0, 3, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
ZEND_ARG_INFO(1, crypted)
ZEND_FUNCTION(openssl_pkcs7_sign);
ZEND_FUNCTION(openssl_pkcs7_decrypt);
ZEND_FUNCTION(openssl_pkcs7_read);
+ZEND_FUNCTION(openssl_cms_verify);
+ZEND_FUNCTION(openssl_cms_encrypt);
+ZEND_FUNCTION(openssl_cms_sign);
+ZEND_FUNCTION(openssl_cms_decrypt);
+ZEND_FUNCTION(openssl_cms_read);
ZEND_FUNCTION(openssl_private_encrypt);
ZEND_FUNCTION(openssl_private_decrypt);
ZEND_FUNCTION(openssl_public_encrypt);
ZEND_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign)
ZEND_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
ZEND_FE(openssl_pkcs7_read, arginfo_openssl_pkcs7_read)
+ ZEND_FE(openssl_cms_verify, arginfo_openssl_cms_verify)
+ ZEND_FE(openssl_cms_encrypt, arginfo_openssl_cms_encrypt)
+ ZEND_FE(openssl_cms_sign, arginfo_openssl_cms_sign)
+ ZEND_FE(openssl_cms_decrypt, arginfo_openssl_cms_decrypt)
+ ZEND_FE(openssl_cms_read, arginfo_openssl_cms_read)
ZEND_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt)
ZEND_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt)
ZEND_FE(openssl_public_encrypt, arginfo_openssl_public_encrypt)
--- /dev/null
+--TEST--
+openssl_cms_decrypt() tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$encrypted = tempnam(sys_get_temp_dir(), "cms_dec_basic");
+if ($encrypted === false)
+ die("failed to get a temporary filename!");
+$outfile = $encrypted . ".out";
+
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$headers = array("test@test", "testing openssl_cms_encrypt()");
+$wrong = "wrong";
+$empty = "";
+
+openssl_cms_encrypt($infile, $encrypted, $single_cert, $headers);
+
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $single_cert, $privkey));
+print("\nDecrypted text:\n");
+readfile($outfile);
+var_dump(openssl_cms_decrypt($encrypted, $outfile, openssl_x509_read($single_cert), $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $single_cert, $wrong));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $wrong, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, null, $privkey));
+var_dump(openssl_cms_decrypt($wrong, $outfile, $single_cert, $privkey));
+var_dump(openssl_cms_decrypt($empty, $outfile, $single_cert, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $empty, $single_cert, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $empty, $privkey));
+var_dump(openssl_cms_decrypt($encrypted, $outfile, $single_cert, $empty));
+
+if (file_exists($encrypted)) {
+ echo "true\n";
+ unlink($encrypted);
+}
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+?>
+--EXPECTF--
+bool(true)
+
+Decrypted text:
+Now is the winter of our discontent.
+bool(true)
+
+Warning: openssl_cms_decrypt(): Unable to get private key in %s on line %d
+bool(false)
+
+Warning: openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert in %s on line %d
+bool(false)
+
+Warning: openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert in %s on line %d
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+
+Warning: openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert in %s on line %d
+bool(false)
+
+Warning: openssl_cms_decrypt(): Unable to get private key in %s on line %d
+bool(false)
+true
+true
--- /dev/null
+--TEST--
+openssl_cms_decrypt() and invalid parameters
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+
+function myErrorHandler($errno, $errstr, $errfile, $errline) {
+ var_dump($errstr);
+}
+set_error_handler("myErrorHandler");
+
+$a = 1;
+$b = 1;
+$c = new stdclass;
+$d = new stdclass;
+
+try {
+ var_dump(openssl_cms_decrypt($a, $b, $c, $d));
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+var_dump($c);
+
+var_dump(openssl_cms_decrypt($b, $b, $b, $b));
+var_dump(openssl_cms_decrypt($a, $b, "", ""));
+var_dump(openssl_cms_decrypt($a, $b, true, false));
+var_dump(openssl_cms_decrypt($a, $b, 0, 0));
+
+echo "Done\n";
+?>
+--EXPECT--
+Object of class stdClass could not be converted to string
+object(stdClass)#1 (0) {
+}
+string(64) "openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert"
+bool(false)
+string(64) "openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert"
+bool(false)
+string(64) "openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert"
+bool(false)
+string(64) "openssl_cms_decrypt(): Unable to coerce parameter 3 to x509 cert"
+bool(false)
+Done
--- /dev/null
+--TEST--
+openssl_cms_encrypt() tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$outfile = tempnam(sys_get_temp_dir(), "cms_enc_basic");
+if ($outfile === false)
+ die("failed to get a temporary filename!");
+$outfile2 = $outfile . ".out";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$wrongkey = "file://" . __DIR__ . "/private_rsa_2048.key";
+$multi_certs = array($single_cert, $single_cert);
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_encrypt()");
+$headers = array("test@test", "testing openssl_cms_encrypt()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+
+var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $headers));
+var_dump(openssl_cms_encrypt($infile, $outfile, openssl_x509_read($single_cert), $headers));
+var_dump(openssl_cms_decrypt($outfile, $outfile2, $single_cert, $privkey));
+readfile($outfile2);
+var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $assoc_headers));
+var_dump(openssl_cms_encrypt($infile, $outfile, $single_cert, $empty_headers));
+var_dump(openssl_cms_encrypt($wrong, $outfile, $single_cert, $headers));
+var_dump(openssl_cms_encrypt($empty, $outfile, $single_cert, $headers));
+var_dump(openssl_cms_encrypt($infile, $empty, $single_cert, $headers));
+var_dump(openssl_cms_encrypt($infile, $outfile, $wrong, $headers));
+var_dump(openssl_cms_encrypt($infile, $outfile, $empty, $headers));
+var_dump(openssl_cms_encrypt($infile, $outfile, $multi_certs, $headers));
+var_dump(openssl_cms_encrypt($infile, $outfile, array_map('openssl_x509_read', $multi_certs) , $headers));
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+if (file_exists($outfile2)) {
+ echo "true\n";
+ unlink($outfile2);
+}
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+Now is the winter of our discontent.
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+true
+true
--- /dev/null
+--TEST--
+openssl_cms_encrypt() der test
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip";
+?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$tname = tempnam(sys_get_temp_dir(), "ssl");
+if ($tname === false)
+ die("failed to get a temporary filename!");
+$cryptfile= $tname . ".der";
+$decryptfile = $tname . ".out";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$headers = array("test@test", "testing openssl_cms_encrypt()");
+
+var_dump(openssl_cms_encrypt($infile, $cryptfile, $single_cert, $headers, OPENSSL_CMS_BINARY, OPENSSL_ENCODING_DER));
+if (openssl_cms_decrypt($cryptfile, $decryptfile, $single_cert, $privkey, OPENSSL_ENCODING_DER) == false) {
+ print "DER decrypt error\n";
+ print "recipient:\n";
+ readfile($single_cert);
+ print "input:\n";
+ readfile($infile);
+ $der=file_get_contents($cryptfile);
+ print "outfile base64:\n" . base64_encode($der) . "\n--------\n";
+ while (( $errstr=openssl_error_string()) != false) {
+ print $errstr . "\n";
+ }
+} else {
+ readfile($decryptfile);
+}
+
+if (file_exists($cryptfile)) {
+ echo "true\n";
+ unlink($cryptfile);
+}
+if (file_exists($decryptfile)) {
+ echo "true\n";
+ unlink($decryptfile);
+}
+unlink($tname);
+?>
+--EXPECTF--
+bool(true)
+Now is the winter of our discontent.
+true
+true
+
--- /dev/null
+--TEST--
+openssl_cms_encrypt() pem test
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip";
+?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$tname = tempnam(sys_get_temp_dir(), "ssl");
+if ($tname === false)
+ die("failed to get a temporary filename!");
+$cryptfile= $tname . ".pem";
+$decryptfile = $tname . ".pemout";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$headers = array("test@test", "testing openssl_cms_encrypt()");
+
+var_dump(openssl_cms_encrypt($infile, $cryptfile, $single_cert, $headers, OPENSSL_CMS_BINARY, OPENSSL_ENCODING_PEM));
+if (openssl_cms_decrypt($cryptfile, $decryptfile, $single_cert, $privkey, OPENSSL_ENCODING_PEM) == false) {
+ print "PEM decrypt error\n";
+ print "recipient:\n";
+ readfile($single_cert);
+ print "input:\n";
+ readfile($infile);
+ print "outfile:\n";
+ readfile($cryptfile);
+ while (( $errstr=openssl_error_string()) != false) {
+ print $errstr . "\n";
+ }
+} else {
+ readfile($decryptfile);
+}
+
+if (file_exists($cryptfile)) {
+ echo "true\n";
+ unlink($cryptfile);
+}
+if (file_exists($decryptfile)) {
+ echo "true\n";
+ unlink($decryptfile);
+}
+unlink($tname);
+?>
+--EXPECTF--
+bool(true)
+Now is the winter of our discontent.
+true
+true
--- /dev/null
+--TEST--
+openssl_cms_read() tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = file_get_contents(__DIR__ . "/cert.p7b");
+$certfile = file_get_contents(__DIR__ . "/cert.crt");
+$result = [];
+
+var_dump(openssl_cms_read("", $result));
+var_dump(openssl_cms_read($certfile, $result));
+var_dump(openssl_cms_read($infile, $result));
+var_dump($result);
+?>
+--EXPECT--
+bool(false)
+bool(false)
+bool(true)
+array(1) {
+ [0]=>
+ string(1249) "-----BEGIN CERTIFICATE-----
+MIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYD
+VQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBv
+cnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJ
+KoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYzMDEwMjg0M1oXDTA4
+MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRl
+IGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1
+ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ulX4/WDAVBYfoTPRTz
+e4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4I2bkWR6/PTqrvnv+
+iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkxQ/ksqL9O/F6zk+aR
+S1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+QHK9XDWF7CkpgRLo
+Ymhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLoYmhqtz99oYGHpIGE
+MIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTAT
+BgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5n
+ZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0ggkArsVWzHI3UKIw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUnStC0TBqngr3Kx+zS
+UW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQS3X2+Y0VvIpW72LW
+PVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r8s+KhNAqI4PbClvn
+4vh8xF/9+eVEj+hM+0OflA==
+-----END CERTIFICATE-----
+"
+}
--- /dev/null
+--TEST--
+openssl_cms_sign() tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/cert.crt";
+$outfile = tempnam(sys_get_temp_dir(), "ssl");
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_sign()");
+$headers = array("test@test", "testing openssl_cms_sign()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers));
+$s = stat($outfile);
+if ($s['size'] < 500) {
+ print "size failure, not big enough.";
+}
+var_dump(openssl_cms_sign($infile, $outfile, $single_cert, $privkey, $headers));
+var_dump(openssl_cms_sign($infile, $outfile, $single_cert, $privkey, $assoc_headers));
+var_dump(openssl_cms_sign($infile, $outfile, $single_cert, $privkey, $empty_headers));
+var_dump(openssl_cms_sign($wrong, $outfile, $single_cert, $privkey, $headers));
+var_dump(openssl_cms_sign($empty, $outfile, $single_cert, $privkey, $headers));
+var_dump(openssl_cms_sign($infile, $empty, $single_cert, $privkey, $headers));
+var_dump(openssl_cms_sign($infile, $outfile, $wrong, $privkey, $headers));
+var_dump(openssl_cms_sign($infile, $outfile, $empty, $privkey, $headers));
+var_dump(openssl_cms_sign($infile, $outfile, $single_cert, $wrong, $headers));
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+
+Warning: openssl_cms_sign(): Error opening input file %s in %s on line %d
+bool(false)
+
+Warning: openssl_cms_sign(): Error opening input file %s in %s on line %d
+bool(false)
+
+Warning: openssl_cms_sign(): Error opening output file %s in %s on line %d
+bool(false)
+
+Warning: openssl_cms_sign(): Error getting cert in %s on line %d
+bool(false)
+
+Warning: openssl_cms_sign(): Error getting cert in %s on line %d
+bool(false)
+
+Warning: openssl_cms_sign(): Error getting private key in %s on line %d
+bool(false)
+true
--- /dev/null
+--TEST--
+openssl_cms_sign() der tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/cert.crt";
+$outfile = tempnam(sys_get_temp_dir(), "ssl");
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_sign()");
+$headers = array("test@test", "testing openssl_cms_sign()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $empty_headers, OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY, OPENSSL_ENCODING_DER));
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers));
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+true
--- /dev/null
+--TEST--
+openssl_cms_sign() and openssl_cms_verify() tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$outfile = tempnam(sys_get_temp_dir(), "ssl");
+$vout= $outfile . ".vout";
+
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_sign()");
+$headers = array("test@test", "testing openssl_cms_sign()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+print("Plain text:\n");
+readfile($infile);
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers));
+var_dump(openssl_cms_verify($outfile,OPENSSL_CMS_NOVERIFY, NULL, array(), NULL, $vout));
+print("\nValidated content:\n");
+readfile($vout);
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+?>
+--EXPECTF--
+Plain text:
+Now is the winter of our discontent.
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
--- /dev/null
+--TEST--
+openssl_cms_sign() and verify detached tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$outfile = tempnam(sys_get_temp_dir(), "ssl");
+$vout= $outfile . ".vout";
+
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_sign()");
+$headers = array("test@test", "testing openssl_cms_sign()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+print("S/MIME attached\nPlain text:\n");
+readfile($infile);
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers));
+var_dump(openssl_cms_verify($outfile,OPENSSL_CMS_NOVERIFY, NULL, array(), NULL, $vout));
+print("\nValidated content:\n");
+readfile($vout);
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+
+// test three forms of detached signatures:
+// PEM first
+print("\nPEM Detached:\n");
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers,
+ OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY,OPENSSL_ENCODING_PEM));
+var_dump(openssl_cms_verify($infile,OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY,
+ NULL, array(), NULL, $vout, NULL, $outfile, OPENSSL_ENCODING_PEM));
+print("\nValidated content:\n");
+readfile($vout);
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+
+// DER next
+print("\nDER Detached:\n");
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers,
+ OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY,OPENSSL_ENCODING_DER));
+var_dump(openssl_cms_verify($infile,OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_DETACHED|OPENSSL_CMS_BINARY,
+ NULL, array(), NULL, $vout, NULL, $outfile, OPENSSL_ENCODING_DER));
+print("\nValidated content:\n");
+readfile($vout);
+// extreme measures to avoid stupid temporary errors for failure to unlink a file.
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+$outfile=$outfile . "x";
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+
+// S/MIME next
+print("\nS/MIME Detached (an error):\n");
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers,
+ OPENSSL_CMS_DETACHED,OPENSSL_ENCODING_SMIME));
+var_dump(openssl_cms_verify($infile,OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_DETACHED,
+ NULL, array(), NULL, $vout, NULL, $outfile, OPENSSL_ENCODING_SMIME));
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+?>
+--EXPECTF--
+S/MIME attached
+Plain text:
+Now is the winter of our discontent.
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
+
+PEM Detached:
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
+
+DER Detached:
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
+
+S/MIME Detached (an error):
+
+Warning: openssl_cms_sign(): Detached signatures not possible with S/MIME encoding in %s on line %d
+bool(false)
+
+Warning: openssl_cms_verify(): Detached signatures not possible with S/MIME encoding in %s on line %d
+bool(false)
--- /dev/null
+--TEST--
+openssl_cms_sign() and verify with attached signatures
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$infile = __DIR__ . "/plain.txt";
+$outfile = tempnam(sys_get_temp_dir(), "ssl");
+$vout= $outfile . ".vout";
+
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$privkey = "file://" . __DIR__ . "/private_rsa_1024.key";
+$single_cert = "file://" . __DIR__ . "/cert.crt";
+$assoc_headers = array("To" => "test@test", "Subject" => "testing openssl_cms_sign()");
+$headers = array("test@test", "testing openssl_cms_sign()");
+$empty_headers = array();
+$wrong = "wrong";
+$empty = "";
+print("S/MIME attached\nPlain text:\n");
+readfile($infile);
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers));
+var_dump(openssl_cms_verify($outfile,OPENSSL_CMS_NOVERIFY, NULL, array(), NULL, $vout));
+print("\nValidated content:\n");
+readfile($vout);
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+print("\nPEM Attached:\n");
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers,
+ OPENSSL_CMS_BINARY,OPENSSL_ENCODING_PEM));
+var_dump(openssl_cms_verify($outfile,OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_BINARY,
+ NULL, array(), NULL, $vout, NULL, NULL, OPENSSL_ENCODING_PEM));
+print("\nValidated content:\n");
+readfile($vout);
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+
+// DER next
+
+print("\nDER Attached:\n");
+var_dump(openssl_cms_sign($infile, $outfile, openssl_x509_read($single_cert), $privkey, $headers,
+ OPENSSL_CMS_BINARY,OPENSSL_ENCODING_DER));
+var_dump(openssl_cms_verify($outfile,OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_BINARY,
+ NULL, array(), NULL, $vout, NULL, NULL, OPENSSL_ENCODING_DER));
+print("\nValidated content:\n");
+readfile($vout);
+// extreme measures to avoid stupid temporary errors for failure to unlink a file.
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+if (file_exists($vout)) {
+ echo "true\n";
+ unlink($vout);
+}
+
+?>
+--EXPECTF--
+S/MIME attached
+Plain text:
+Now is the winter of our discontent.
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
+
+PEM Attached:
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
+
+DER Attached:
+bool(true)
+bool(true)
+
+Validated content:
+Now is the winter of our discontent.
+true
+true
--- /dev/null
+--TEST--
+openssl_cms_verify() tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$outfile = tempnam(sys_get_temp_dir(), "cms_v_basic");
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$contentfile = $outfile . ".out";
+
+$pkcsfile = __DIR__ . "/openssl_cms_verify__pkcsfile.tmp";
+$eml = __DIR__ . "/signed.eml";
+$wrong = "wrong";
+$empty = "";
+$cainfo = array();
+
+var_dump(openssl_cms_verify($wrong, 0));
+var_dump(openssl_cms_verify($empty, 0));
+var_dump(openssl_cms_verify($eml, 0));
+var_dump(openssl_cms_verify($eml, 0, $empty));
+var_dump(openssl_cms_verify($eml, OPENSSL_CMS_NOVERIFY, $outfile));
+var_dump(openssl_cms_verify($eml, OPENSSL_CMS_NOVERIFY, $outfile, $cainfo, $outfile, $contentfile));
+var_dump(openssl_cms_verify($eml, OPENSSL_CMS_NOVERIFY, $outfile, $cainfo, $outfile, $contentfile, $pkcsfile));
+var_dump(file_get_contents($pkcsfile));
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($contentfile)) {
+ echo "true\n";
+ unlink($contentfile);
+}
+?>
+--CLEAN--
+<?php
+unlink(__DIR__ . DIRECTORY_SEPARATOR . '/openssl_cms_verify__pkcsfile.tmp');
+?>
+--EXPECTF--
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+string(2058) "-----BEGIN CMS-----
+MIIFzQYJKoZIhvcNAQcCoIIFvjCCBboCAQExDzANBglghkgBZQMEAgEFADALBgkq
+hkiG9w0BBwGgggNwMIIDbDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEB
+BQUAMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwx
+FTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4g
+QW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYz
+MDEwMjg0M1oXDTA4MDczMDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQI
+ExFSaW8gR3JhbmRlIGRvIFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYD
+VQQDExVIZW5yaXF1ZSBkbyBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5n
+ZWxvQHBocC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ul
+X4/WDAVBYfoTPRTze4SZLwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4
+I2bkWR6/PTqrvnv+iiiItHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkx
+Q/ksqL9O/F6zk+aRS1d+KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+
+QHK9XDWF7CkpgRLoYmhqtz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLo
+Ymhqtz99oYGHpIGEMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5k
+ZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlx
+dWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0
+ggkArsVWzHI3UKIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUn
+StC0TBqngr3Kx+zSUW8KutKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQ
+S3X2+Y0VvIpW72LWPVKPhYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r
+8s+KhNAqI4PbClvn4vh8xF/9+eVEj+hM+0OflDGCAiEwggIdAgEBMIGPMIGBMQsw
+CQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcT
+DFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8w
+HQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0AgkArsVWzHI3UKIwDQYJYIZI
+AWUDBAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0B
+CQUxDxcNMTcwNTIyMTAxMDU1WjAvBgkqhkiG9w0BCQQxIgQg37MSoxw91phVhwUO
+MeurwtXAXK1ADEeYYl/7Bfmz4CsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQME
+ASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG
+9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgw
+DQYJKoZIhvcNAQEBBQAEgYAw4XcsQ4BIhEuRNspG8RqPE9ODCrTWwXPSQ4B9fzks
+KUAsqcefO8AfifY+uuq3/k6Prhl23U5ILth/0fUAIGFLTcIZziaGTwbpgcmRSmNi
+jBxatHyKVaGJNGqij5KRk8vhEpy5mwOzmkUzYa0r4teXjyfnKhI/h1vUrO3kKybC
+5Q==
+-----END CMS-----
+"
+true
+true
--- /dev/null
+--TEST--
+openssl_cms_verify() der tests
+--SKIPIF--
+<?php if (!extension_loaded("openssl")) print "skip"; ?>
+--FILE--
+<?php
+$outfile = tempnam(sys_get_temp_dir(), "ssl");
+if ($outfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$contentfile = tempnam(sys_get_temp_dir(), "ssl");
+if ($contentfile === false) {
+ die("failed to get a temporary filename!");
+}
+
+$pkcsfile = __DIR__ . "/openssl_cms_verify__pkcsfile.tmp";
+$eml = __DIR__ . "/signed.eml";
+$wrong = "wrong";
+$empty = "";
+$cainfo = array();
+$plain = __DIR__ . "/plain.txt";
+$p7file = __DIR__ . "/shakespeare.p7s";
+$pemfile = __DIR__ . "/shakespeare.pem";
+var_dump(openssl_cms_verify($wrong, 0));
+var_dump(openssl_cms_verify($empty, 0));
+var_dump(openssl_cms_verify($eml, 0));
+var_dump(openssl_cms_verify($eml, 0, $empty));
+var_dump(openssl_cms_verify($eml, OPENSSL_CMS_NOVERIFY, $outfile));
+var_dump(openssl_cms_verify($eml, OPENSSL_CMS_NOVERIFY, $outfile, $cainfo, $outfile, $contentfile));
+var_dump(openssl_cms_verify($eml, OPENSSL_CMS_NOVERIFY, $outfile, $cainfo, $outfile, $contentfile, $pkcsfile));
+var_dump(openssl_cms_verify($plain, OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_BINARY|OPENSSL_CMS_DETACHED,$outfile,$cainfo,NULL,$contentfile,$pkcsfile,$p7file,OPENSSL_ENCODING_DER));
+var_dump(openssl_cms_verify($plain, OPENSSL_CMS_NOVERIFY|OPENSSL_CMS_BINARY|OPENSSL_CMS_DETACHED,$outfile,$cainfo,NULL,$contentfile,$pkcsfile,$pemfile,OPENSSL_ENCODING_PEM));
+var_dump(file_get_contents($pkcsfile));
+
+if (file_exists($outfile)) {
+ echo "true\n";
+ unlink($outfile);
+}
+
+if (file_exists($contentfile)) {
+ echo "true\n";
+ unlink($contentfile);
+}
+?>
+--CLEAN--
+<?php
+unlink(__DIR__ . DIRECTORY_SEPARATOR . '/openssl_cms_verify__pkcsfile.tmp');
+?>
+--EXPECTF--
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+string(2049) "-----BEGIN CMS-----
+MIIFyQYJKoZIhvcNAQcCoIIFujCCBbYCAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+hvcNAQcBoIIDcDCCA2wwggLVoAMCAQICCQCuxVbMcjdQojANBgkqhkiG9w0BAQUF
+ADCBgTELMAkGA1UEBhMCQlIxGjAYBgNVBAgTEVJpbyBHcmFuZGUgZG8gU3VsMRUw
+EwYDVQQHEwxQb3J0byBBbGVncmUxHjAcBgNVBAMTFUhlbnJpcXVlIGRvIE4uIEFu
+Z2VsbzEfMB0GCSqGSIb3DQEJARYQaG5hbmdlbG9AcGhwLm5ldDAeFw0wODA2MzAx
+MDI4NDNaFw0wODA3MzAxMDI4NDNaMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMR
+UmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UE
+AxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vs
+b0BwaHAubmV0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLXp6PkCtbpV+P
+1gwFQWH6Ez0U83uEmS8IGnpeI8Fk8rY/vHOZzZZaxRCw+loyc342qCDIQheMOCNm
+5Fkevz06q757/oooiLR3yryYGKiKG1IZIiplmtsC95oKrzUSKk60wuI1mbgpMUP5
+LKi/Tvxes5PmkUtXfimz2qgkeUcPpQIDAQABo4HpMIHmMB0GA1UdDgQWBBTbfkBy
+vVw1hewpKYES6GJoarc/fTCBtgYDVR0jBIGuMIGrgBTbfkByvVw1hewpKYES6GJo
+arc/faGBh6SBhDCBgTELMAkGA1UEBhMCQlIxGjAYBgNVBAgTEVJpbyBHcmFuZGUg
+ZG8gU3VsMRUwEwYDVQQHEwxQb3J0byBBbGVncmUxHjAcBgNVBAMTFUhlbnJpcXVl
+IGRvIE4uIEFuZ2VsbzEfMB0GCSqGSIb3DQEJARYQaG5hbmdlbG9AcGhwLm5ldIIJ
+AK7FVsxyN1CiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAj9RlJ0rQ
+tEwap4K9ysfs0lFvCrrSjtDkXOUfGlf8fS5Wia8z8kCYIj6buYV6IC0ikSB8UEt1
+9vmNFbyKVu9i1j1Sj4WJTbTt6Cp36CRiop9HhIV0WTI3xFv5M52PmWZjYn1dq/LP
+ioTQKiOD2wpb5+L4fMRf/fnlRI/oTPtDn5QxggIfMIICGwIBATCBjzCBgTELMAkG
+A1UEBhMCQlIxGjAYBgNVBAgTEVJpbyBHcmFuZGUgZG8gU3VsMRUwEwYDVQQHEwxQ
+b3J0byBBbGVncmUxHjAcBgNVBAMTFUhlbnJpcXVlIGRvIE4uIEFuZ2VsbzEfMB0G
+CSqGSIb3DQEJARYQaG5hbmdlbG9AcGhwLm5ldAIJAK7FVsxyN1CiMAsGCWCGSAFl
+AwQCAaCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP
+Fw0yMDAzMTMxMDMxMThaMC8GCSqGSIb3DQEJBDEiBCD7i6er2GffWfJgrK5Yi2Kh
+XfedL51/uszuPjxImv7g1jB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjAL
+BglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMC
+AgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkq
+hkiG9w0BAQEFAASBgBphoY0L/jnrzSIOpaS0b2Yzfw9CuuShcUA3oiib/tFn3mzV
+gSfYaiIdL0d4FSMRiLFkkbBrxBKD+oMZIMI7ZurpQpqKq0OGPzORflh3sfFLqSI1
+8Txoc8qJ5JKpip3W9IQwIwPpAU4HhBgWP2HPODY2/Q3bDtUQ3I9KrJIewr9Q
+-----END CMS-----
+"
+true
+true
--- /dev/null
+Now is the winter of our discontent.
--- /dev/null
+-----BEGIN CMS-----
+MIIFyQYJKoZIhvcNAQcCoIIFujCCBbYCAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+hvcNAQcBoIIDcDCCA2wwggLVoAMCAQICCQCuxVbMcjdQojANBgkqhkiG9w0BAQUF
+ADCBgTELMAkGA1UEBhMCQlIxGjAYBgNVBAgTEVJpbyBHcmFuZGUgZG8gU3VsMRUw
+EwYDVQQHEwxQb3J0byBBbGVncmUxHjAcBgNVBAMTFUhlbnJpcXVlIGRvIE4uIEFu
+Z2VsbzEfMB0GCSqGSIb3DQEJARYQaG5hbmdlbG9AcGhwLm5ldDAeFw0wODA2MzAx
+MDI4NDNaFw0wODA3MzAxMDI4NDNaMIGBMQswCQYDVQQGEwJCUjEaMBgGA1UECBMR
+UmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UE
+AxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vs
+b0BwaHAubmV0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLXp6PkCtbpV+P
+1gwFQWH6Ez0U83uEmS8IGnpeI8Fk8rY/vHOZzZZaxRCw+loyc342qCDIQheMOCNm
+5Fkevz06q757/oooiLR3yryYGKiKG1IZIiplmtsC95oKrzUSKk60wuI1mbgpMUP5
+LKi/Tvxes5PmkUtXfimz2qgkeUcPpQIDAQABo4HpMIHmMB0GA1UdDgQWBBTbfkBy
+vVw1hewpKYES6GJoarc/fTCBtgYDVR0jBIGuMIGrgBTbfkByvVw1hewpKYES6GJo
+arc/faGBh6SBhDCBgTELMAkGA1UEBhMCQlIxGjAYBgNVBAgTEVJpbyBHcmFuZGUg
+ZG8gU3VsMRUwEwYDVQQHEwxQb3J0byBBbGVncmUxHjAcBgNVBAMTFUhlbnJpcXVl
+IGRvIE4uIEFuZ2VsbzEfMB0GCSqGSIb3DQEJARYQaG5hbmdlbG9AcGhwLm5ldIIJ
+AK7FVsxyN1CiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAj9RlJ0rQ
+tEwap4K9ysfs0lFvCrrSjtDkXOUfGlf8fS5Wia8z8kCYIj6buYV6IC0ikSB8UEt1
+9vmNFbyKVu9i1j1Sj4WJTbTt6Cp36CRiop9HhIV0WTI3xFv5M52PmWZjYn1dq/LP
+ioTQKiOD2wpb5+L4fMRf/fnlRI/oTPtDn5QxggIfMIICGwIBATCBjzCBgTELMAkG
+A1UEBhMCQlIxGjAYBgNVBAgTEVJpbyBHcmFuZGUgZG8gU3VsMRUwEwYDVQQHEwxQ
+b3J0byBBbGVncmUxHjAcBgNVBAMTFUhlbnJpcXVlIGRvIE4uIEFuZ2VsbzEfMB0G
+CSqGSIb3DQEJARYQaG5hbmdlbG9AcGhwLm5ldAIJAK7FVsxyN1CiMAsGCWCGSAFl
+AwQCAaCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP
+Fw0yMDAzMTMxMDMxMThaMC8GCSqGSIb3DQEJBDEiBCD7i6er2GffWfJgrK5Yi2Kh
+XfedL51/uszuPjxImv7g1jB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjAL
+BglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMC
+AgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkq
+hkiG9w0BAQEFAASBgBphoY0L/jnrzSIOpaS0b2Yzfw9CuuShcUA3oiib/tFn3mzV
+gSfYaiIdL0d4FSMRiLFkkbBrxBKD+oMZIMI7ZurpQpqKq0OGPzORflh3sfFLqSI1
+8Txoc8qJ5JKpip3W9IQwIwPpAU4HhBgWP2HPODY2/Q3bDtUQ3I9KrJIewr9Q
+-----END CMS-----