]> granicus.if.org Git - php/commitdiff
Add support for Cryptographic Message Syntax (CMS)
authorEliot Lear <lear@ofcourseimright.com>
Mon, 9 Mar 2020 15:01:20 +0000 (16:01 +0100)
committerJakub Zelenka <bukka@php.net>
Sun, 7 Jun 2020 15:58:34 +0000 (16:58 +0100)
It add CMS (RFC 5652) support, which is an update to PKCS7.  The functions
are analogous BUT NOT IDENTICAL to openssl_pkcs7*.  In particular, support for
different encodings (PEM, DER, SMIME) is now available.

20 files changed:
ext/openssl/CREDITS
ext/openssl/openssl.c
ext/openssl/openssl.stub.php
ext/openssl/openssl_arginfo.h
ext/openssl/tests/openssl_cms_decrypt_basic.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_decrypt_error.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_encrypt_basic.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_encrypt_der.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_encrypt_pem.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_read_basic.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_sign_basic.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_sign_der.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_sign_verify_basic.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_sign_verify_detached.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_sign_verify_nodetached_pem.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_verify_basic.phpt [new file with mode: 0644]
ext/openssl/tests/openssl_cms_verify_der.phpt [new file with mode: 0644]
ext/openssl/tests/plain.txt [new file with mode: 0644]
ext/openssl/tests/shakespeare.p7s [new file with mode: 0644]
ext/openssl/tests/shakespeare.pem [new file with mode: 0644]

index b685ce13e5cbfe9a4107fac34e558c0b41528cfb..56490621c90337c3cad14480c99360163a7e1f05 100644 (file)
@@ -1,2 +1,2 @@
 OpenSSL
-Stig Venaas, Wez Furlong, Sascha Kettler, Scott MacVicar
+Stig Venaas, Wez Furlong, Sascha Kettler, Scott MacVicar, Eliot Lear
index 227ce613db64db639b7611ca17ee2dc36fd72483..5460dc5de44cfdf37221e01ac208f49c13d9ebfd 100644 (file)
@@ -16,6 +16,7 @@
    |          Pierre-Alain Joye <pierre@php.net>                          |
    |          Marc Delling <delling@silpion.de> (PKCS12 functions)        |
    |          Jakub Zelenka <bukka@php.net>                               |
+   |          Eliot Lear <lear@ofcourseimright.com>                       |
    +----------------------------------------------------------------------+
  */
 
@@ -53,6 +54,7 @@
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
 #include <openssl/pkcs12.h>
+#include <openssl/cms.h>
 
 /* Common */
 #include <time.h>
@@ -115,6 +117,16 @@ enum php_openssl_cipher_type {
        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 = {
@@ -1075,6 +1087,15 @@ PHP_MINIT_FUNCTION(openssl)
        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);
@@ -1118,6 +1139,11 @@ PHP_MINIT_FUNCTION(openssl)
        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) {
@@ -4777,22 +4803,17 @@ PHP_FUNCTION(openssl_pkcs7_verify)
                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;
                }
@@ -5309,6 +5330,748 @@ 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)
index d6a27b4b1ca4863d352893f42c1fb4cb6187eb9e..0c6d3ea9f96eb042f0c80e3552f3284f17ae2730 100644 (file)
@@ -129,6 +129,26 @@ function openssl_pkcs7_decrypt(string $infilename, string $outfilename, $recipce
 
 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 {}
 
index 47bd49eef10053194da9280e16396341b7a4a911..77df5ca206108f686e34be5c2d84e5203715426a 100644 (file)
@@ -196,6 +196,49 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_pkcs7_read, 0, 2, _IS_BO
        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)
@@ -353,6 +396,11 @@ ZEND_FUNCTION(openssl_pkcs7_encrypt);
 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);
@@ -416,6 +464,11 @@ static const zend_function_entry ext_functions[] = {
        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)
diff --git a/ext/openssl/tests/openssl_cms_decrypt_basic.phpt b/ext/openssl/tests/openssl_cms_decrypt_basic.phpt
new file mode 100644 (file)
index 0000000..ec295be
--- /dev/null
@@ -0,0 +1,68 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_decrypt_error.phpt b/ext/openssl/tests/openssl_cms_decrypt_error.phpt
new file mode 100644 (file)
index 0000000..28812c3
--- /dev/null
@@ -0,0 +1,44 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_encrypt_basic.phpt b/ext/openssl/tests/openssl_cms_encrypt_basic.phpt
new file mode 100644 (file)
index 0000000..fd37e72
--- /dev/null
@@ -0,0 +1,60 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_encrypt_der.phpt b/ext/openssl/tests/openssl_cms_encrypt_der.phpt
new file mode 100644 (file)
index 0000000..ddbf50a
--- /dev/null
@@ -0,0 +1,49 @@
+--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
+
diff --git a/ext/openssl/tests/openssl_cms_encrypt_pem.phpt b/ext/openssl/tests/openssl_cms_encrypt_pem.phpt
new file mode 100644 (file)
index 0000000..4b99b65
--- /dev/null
@@ -0,0 +1,48 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_read_basic.phpt b/ext/openssl/tests/openssl_cms_read_basic.phpt
new file mode 100644 (file)
index 0000000..581bf4f
--- /dev/null
@@ -0,0 +1,44 @@
+--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-----
+"
+}
diff --git a/ext/openssl/tests/openssl_cms_sign_basic.phpt b/ext/openssl/tests/openssl_cms_sign_basic.phpt
new file mode 100644 (file)
index 0000000..cbeaaf3
--- /dev/null
@@ -0,0 +1,64 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_sign_der.phpt b/ext/openssl/tests/openssl_cms_sign_der.phpt
new file mode 100644 (file)
index 0000000..aa7f64d
--- /dev/null
@@ -0,0 +1,32 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_sign_verify_basic.phpt b/ext/openssl/tests/openssl_cms_sign_verify_basic.phpt
new file mode 100644 (file)
index 0000000..f2a2a79
--- /dev/null
@@ -0,0 +1,47 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_sign_verify_detached.phpt b/ext/openssl/tests/openssl_cms_sign_verify_detached.phpt
new file mode 100644 (file)
index 0000000..ab5bab4
--- /dev/null
@@ -0,0 +1,129 @@
+--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)
diff --git a/ext/openssl/tests/openssl_cms_sign_verify_nodetached_pem.phpt b/ext/openssl/tests/openssl_cms_sign_verify_nodetached_pem.phpt
new file mode 100644 (file)
index 0000000..7576e4a
--- /dev/null
@@ -0,0 +1,103 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_verify_basic.phpt b/ext/openssl/tests/openssl_cms_verify_basic.phpt
new file mode 100644 (file)
index 0000000..22dbf2a
--- /dev/null
@@ -0,0 +1,87 @@
+--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
diff --git a/ext/openssl/tests/openssl_cms_verify_der.phpt b/ext/openssl/tests/openssl_cms_verify_der.phpt
new file mode 100644 (file)
index 0000000..e00aa03
--- /dev/null
@@ -0,0 +1,95 @@
+--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
diff --git a/ext/openssl/tests/plain.txt b/ext/openssl/tests/plain.txt
new file mode 100644 (file)
index 0000000..1714e68
--- /dev/null
@@ -0,0 +1 @@
+Now is the winter of our discontent.
diff --git a/ext/openssl/tests/shakespeare.p7s b/ext/openssl/tests/shakespeare.p7s
new file mode 100644 (file)
index 0000000..6a65362
Binary files /dev/null and b/ext/openssl/tests/shakespeare.p7s differ
diff --git a/ext/openssl/tests/shakespeare.pem b/ext/openssl/tests/shakespeare.pem
new file mode 100644 (file)
index 0000000..9806ee8
--- /dev/null
@@ -0,0 +1,33 @@
+-----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-----