Add openssl_pkcs7_read and output P7B in openssl_pkcs7_verify

Add an optional argument to openssl_pkcs7_verify to save the P7B
structure which can contain extra CA intermediate certificates send
along with an S/MIME signed email.

Introduce a new function called openssl_pkcs7_read, which can read a
PKCS#7 structure passed as a string and returns by reference an array
with PEM certificates formatted as a string.
This commit is contained in:
Jelle van der Waa 2017-05-30 11:24:31 +02:00 committed by Jakub Zelenka
parent d09edf7b34
commit 787a18a50a
5 changed files with 255 additions and 4 deletions

View File

@ -290,6 +290,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
ZEND_ARG_INFO(0, cainfo) /* array */
ZEND_ARG_INFO(0, extracerts)
ZEND_ARG_INFO(0, content)
ZEND_ARG_INFO(0, pk7)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4)
@ -318,6 +319,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3)
ZEND_ARG_INFO(0, recipkey)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_read, 0, 0, 2)
ZEND_ARG_INFO(0, infilename)
ZEND_ARG_INFO(1, certs)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(1, crypted)
@ -519,6 +525,7 @@ const zend_function_entry openssl_functions[] = {
PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
PHP_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign)
PHP_FE(openssl_pkcs7_encrypt, arginfo_openssl_pkcs7_encrypt)
PHP_FE(openssl_pkcs7_read, arginfo_openssl_pkcs7_read)
PHP_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt)
PHP_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt)
@ -4968,7 +4975,7 @@ PHP_FUNCTION(openssl_pbkdf2)
/* {{{ PKCS7 S/MIME functions */
/* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
/* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content [, string pk7]]]]])
Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
PHP_FUNCTION(openssl_pkcs7_verify)
{
@ -4977,7 +4984,7 @@ PHP_FUNCTION(openssl_pkcs7_verify)
STACK_OF(X509) *signers= NULL;
STACK_OF(X509) *others = NULL;
PKCS7 * p7 = NULL;
BIO * in = NULL, * datain = NULL, * dataout = NULL;
BIO * in = NULL, * datain = NULL, * dataout = NULL, * p7bout = NULL;
zend_long flags = 0;
char * filename;
size_t filename_len;
@ -4987,12 +4994,14 @@ PHP_FUNCTION(openssl_pkcs7_verify)
size_t signersfilename_len = 0;
char * datafilename = NULL;
size_t datafilename_len = 0;
char * p7bfilename = NULL;
size_t p7bfilename_len = 0;
RETVAL_LONG(-1);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|papp", &filename, &filename_len,
if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|pappp", &filename, &filename_len,
&flags, &signersfilename, &signersfilename_len, &cainfo,
&extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
&extracerts, &extracerts_len, &datafilename, &datafilename_len, &p7bfilename, &p7bfilename_len) == FAILURE) {
return;
}
@ -5040,6 +5049,19 @@ PHP_FUNCTION(openssl_pkcs7_verify)
goto clean_exit;
}
}
if (p7bfilename) {
if (php_openssl_open_base_dir_chk(p7bfilename)) {
goto clean_exit;
}
p7bout = BIO_new_file(p7bfilename, "w");
if (p7bout == NULL) {
php_openssl_store_errors();
goto clean_exit;
}
}
#if DEBUG_SMIME
zend_printf("Calling PKCS7 verify\n");
#endif
@ -5081,12 +5103,19 @@ PHP_FUNCTION(openssl_pkcs7_verify)
php_error_docref(NULL, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
RETVAL_LONG(-1);
}
if (p7bout) {
PEM_write_bio_PKCS7(p7bout, p7);
}
}
} else {
php_openssl_store_errors();
RETVAL_FALSE;
}
clean_exit:
if (p7bout) {
BIO_free(p7bout);
}
X509_STORE_free(store);
BIO_free(datain);
BIO_free(in);
@ -5230,6 +5259,107 @@ clean_exit:
}
/* }}} */
/* {{{ proto bool openssl_pkcs7_read(string P7B, array &certs)
Exports the PKCS7 file to an array of PEM certificates */
PHP_FUNCTION(openssl_pkcs7_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;
PKCS7 * p7 = NULL;
int i;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/", &p7b, &p7b_len,
&zout) == FAILURE) {
return;
}
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;
}
p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
if (p7 == NULL) {
php_openssl_store_errors();
goto clean_exit;
}
switch (OBJ_obj2nid(p7->type)) {
case NID_pkcs7_signed:
if (p7->d.sign != NULL) {
certs = p7->d.sign->cert;
crls = p7->d.sign->crl;
}
break;
case NID_pkcs7_signedAndEnveloped:
if (p7->d.signed_and_enveloped != NULL) {
certs = p7->d.signed_and_enveloped->cert;
crls = p7->d.signed_and_enveloped->crl;
}
break;
default:
break;
}
zval_dtor(zout);
array_init(zout);
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:
if (bio_in != NULL) {
BIO_free(bio_in);
}
if (p7 != NULL) {
PKCS7_free(p7);
}
}
/* }}} */
/* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, 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 */

View File

@ -97,6 +97,7 @@ PHP_FUNCTION(openssl_pkcs7_verify);
PHP_FUNCTION(openssl_pkcs7_decrypt);
PHP_FUNCTION(openssl_pkcs7_sign);
PHP_FUNCTION(openssl_pkcs7_encrypt);
PHP_FUNCTION(openssl_pkcs7_read);
PHP_FUNCTION(openssl_error_string);

View File

@ -0,0 +1,22 @@
-----BEGIN PKCS7-----
MIIDnQYJKoZIhvcNAQcCoIIDjjCCA4oCAQExADALBgkqhkiG9w0BBwGgggNwMIID
bDCCAtWgAwIBAgIJAK7FVsxyN1CiMA0GCSqGSIb3DQEBBQUAMIGBMQswCQYDVQQG
EwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNVBAcTDFBvcnRv
IEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxvMR8wHQYJKoZI
hvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0MB4XDTA4MDYzMDEwMjg0M1oXDTA4MDcz
MDEwMjg0M1owgYExCzAJBgNVBAYTAkJSMRowGAYDVQQIExFSaW8gR3JhbmRlIGRv
IFN1bDEVMBMGA1UEBxMMUG9ydG8gQWxlZ3JlMR4wHAYDVQQDExVIZW5yaXF1ZSBk
byBOLiBBbmdlbG8xHzAdBgkqhkiG9w0BCQEWEGhuYW5nZWxvQHBocC5uZXQwgZ8w
DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMteno+QK1ulX4/WDAVBYfoTPRTze4SZ
Lwgael4jwWTytj+8c5nNllrFELD6WjJzfjaoIMhCF4w4I2bkWR6/PTqrvnv+iiiI
tHfKvJgYqIobUhkiKmWa2wL3mgqvNRIqTrTC4jWZuCkxQ/ksqL9O/F6zk+aRS1d+
KbPaqCR5Rw+lAgMBAAGjgekwgeYwHQYDVR0OBBYEFNt+QHK9XDWF7CkpgRLoYmhq
tz99MIG2BgNVHSMEga4wgauAFNt+QHK9XDWF7CkpgRLoYmhqtz99oYGHpIGEMIGB
MQswCQYDVQQGEwJCUjEaMBgGA1UECBMRUmlvIEdyYW5kZSBkbyBTdWwxFTATBgNV
BAcTDFBvcnRvIEFsZWdyZTEeMBwGA1UEAxMVSGVucmlxdWUgZG8gTi4gQW5nZWxv
MR8wHQYJKoZIhvcNAQkBFhBobmFuZ2Vsb0BwaHAubmV0ggkArsVWzHI3UKIwDAYD
VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCP1GUnStC0TBqngr3Kx+zSUW8K
utKO0ORc5R8aV/x9LlaJrzPyQJgiPpu5hXogLSKRIHxQS3X2+Y0VvIpW72LWPVKP
hYlNtO3oKnfoJGKin0eEhXRZMjfEW/kznY+ZZmNifV2r8s+KhNAqI4PbClvn4vh8
xF/9+eVEj+hM+0OflKEAMQA=
-----END PKCS7-----

View File

@ -0,0 +1,52 @@
--TEST--
openssl_pkcs7_read() tests
--SKIPIF--
<?php if (!extension_loaded("openssl")) print "skip"; ?>
--FILE--
<?php
$infile = file_get_contents(dirname(__FILE__) . "/cert.p7b");
$certfile = file_get_contents(dirname(__FILE__) . "/cert.crt");
$result = [];
var_dump(openssl_pkcs7_read());
var_dump(openssl_pkcs7_read(""));
var_dump(openssl_pkcs7_read("", $result));
var_dump(openssl_pkcs7_read($certfile, $result));
var_dump(openssl_pkcs7_read($infile, $result));
var_dump($result);
?>
--EXPECTF--
Warning: openssl_pkcs7_read() expects exactly 2 parameters, 0 given in %s on line %d
NULL
Warning: openssl_pkcs7_read() expects exactly 2 parameters, 1 given in %s on line %d
NULL
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-----
"
}

View File

@ -14,6 +14,8 @@ if ($contentfile === false) {
die("failed to get a temporary filename!");
}
$pkcsfile = dirname(__FILE__) . "/openssl_pkcs7_verify__pkcsfile.tmp";
$infile = dirname(__FILE__) . "/cert.crt";
$eml = dirname(__FILE__) . "/signed.eml";
$wrong = "wrong";
@ -26,6 +28,8 @@ var_dump(openssl_pkcs7_verify($eml, 0));
var_dump(openssl_pkcs7_verify($eml, 0, $empty));
var_dump(openssl_pkcs7_verify($eml, PKCS7_NOVERIFY, $outfile));
var_dump(openssl_pkcs7_verify($eml, PKCS7_NOVERIFY, $outfile, $cainfo, $outfile, $contentfile));
var_dump(openssl_pkcs7_verify($eml, PKCS7_NOVERIFY, $outfile, $cainfo, $outfile, $contentfile, $pkcsfile));
var_dump(file_get_contents($pkcsfile));
if (file_exists($outfile)) {
echo "true\n";
@ -37,6 +41,12 @@ if (file_exists($contentfile)) {
unlink($contentfile);
}
?>
--CLEAN--
<?php
if (file_exists($pkcsfile)) {
unlink($pkcsfile);
}
?>
--EXPECTF--
int(-1)
int(-1)
@ -44,5 +54,41 @@ bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
string(2062) "-----BEGIN PKCS7-----
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 PKCS7-----
"
true
true