diff options
author | Jakub Zelenka <bukka@php.net> | 2017-04-24 17:11:36 +0100 |
---|---|---|
committer | Jakub Zelenka <bukka@php.net> | 2017-04-24 17:11:36 +0100 |
commit | 9fa347997a47d5b44515a701b695e47696cba04b (patch) | |
tree | f17d87c27475b7b27cc7f6f6dd6bca2f86fe052c /ext/openssl | |
parent | f7b8322b144122baddaf365c37dca3b8e547725e (diff) | |
download | php-git-9fa347997a47d5b44515a701b695e47696cba04b.tar.gz |
Fix bug #73833 (null character not allowed in openssl_pkey_get_private)
Diffstat (limited to 'ext/openssl')
-rw-r--r-- | ext/openssl/openssl.c | 85 | ||||
-rw-r--r-- | ext/openssl/tests/bug73833.phpt | 30 |
2 files changed, 90 insertions, 25 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 31c60b7d90..f490677931 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -784,7 +784,9 @@ struct php_x509_request { /* {{{ */ /* }}} */ static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval); -static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval); +static EVP_PKEY * php_openssl_evp_from_zval( + zval * val, int public_key, char *passphrase, size_t passphrase_len, + int makeresource, zend_resource **resourceval); static int php_openssl_is_private_key(EVP_PKEY* pkey); static X509_STORE * setup_verify(zval * calist); static STACK_OF(X509) * load_all_certs_from_file(char *certfile); @@ -1696,7 +1698,8 @@ PHP_FUNCTION(openssl_spki_new) } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, 1, &keyresource); + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(challenge_len, challenge); + pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, challenge_len, 1, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "Unable to use supplied private key"); @@ -2069,7 +2072,7 @@ PHP_FUNCTION(openssl_x509_check_private_key) if (cert == NULL) { RETURN_FALSE; } - key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource); + key = php_openssl_evp_from_zval(zkey, 0, "", 0, 1, &keyresource); if (key) { RETVAL_BOOL(X509_check_private_key(cert, key)); } @@ -2635,7 +2638,7 @@ PHP_FUNCTION(openssl_pkcs12_export_to_file) php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); return; } - priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource); + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource); if (priv_key == NULL) { php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; @@ -2716,7 +2719,7 @@ PHP_FUNCTION(openssl_pkcs12_export) php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1"); return; } - priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource); + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource); if (priv_key == NULL) { php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; @@ -3191,7 +3194,7 @@ PHP_FUNCTION(openssl_csr_sign) goto cleanup; } } - priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource); + priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource); if (priv_key == NULL) { php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3"); goto cleanup; @@ -3315,7 +3318,7 @@ PHP_FUNCTION(openssl_csr_new) if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { /* Generate or use a private key */ if (Z_TYPE_P(out_pkey) != IS_NULL) { - req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, &key_resource); + req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, 0, &key_resource); if (req.priv_key != NULL) { we_made_the_key = 0; } @@ -3452,6 +3455,27 @@ PHP_FUNCTION(openssl_csr_get_public_key) /* {{{ EVP Public/Private key functions */ +struct php_openssl_pem_password { + char *key; + int len; +}; + +/* {{{ php_openssl_pem_password_cb */ +static int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata) +{ + struct php_openssl_pem_password *password = userdata; + + if (password == NULL || password->key == NULL) { + return -1; + } + + size = (password->len > size) ? size : password->len; + memcpy(buf, password->key, size); + + return size; +} +/* }}} */ + /* {{{ php_openssl_evp_from_zval Given a zval, coerce it into a EVP_PKEY object. It can be: @@ -3465,7 +3489,9 @@ PHP_FUNCTION(openssl_csr_get_public_key) empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in the Apache error log! */ -static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval) +static EVP_PKEY * php_openssl_evp_from_zval( + zval * val, int public_key, char *passphrase, size_t passphrase_len, + int makeresource, zend_resource **resourceval) { EVP_PKEY * key = NULL; X509 * cert = NULL; @@ -3497,10 +3523,12 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * p if (Z_TYPE_P(zphrase) == IS_STRING) { passphrase = Z_STRVAL_P(zphrase); + passphrase_len = Z_STRLEN_P(zphrase); } else { ZVAL_COPY(&tmp, zphrase); convert_to_string(&tmp); passphrase = Z_STRVAL(tmp); + passphrase_len = Z_STRLEN(tmp); } /* now set val to be the key param and continue */ @@ -3599,7 +3627,14 @@ static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * p if (in == NULL) { TMP_CLEAN; } - key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase); + if (passphrase == NULL) { + key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + } else { + struct php_openssl_pem_password password; + password.key = passphrase; + password.len = passphrase_len; + key = PEM_read_bio_PrivateKey(in, NULL, php_openssl_pem_password_cb, &password); + } BIO_free(in); } } @@ -4072,8 +4107,7 @@ PHP_FUNCTION(openssl_pkey_export_to_file) RETVAL_FALSE; PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); - - key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource); + key = php_openssl_evp_from_zval(zpkey, 0, passphrase, passphrase_len, 0, &key_resource); if (key == NULL) { php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1"); @@ -4146,8 +4180,7 @@ PHP_FUNCTION(openssl_pkey_export) RETVAL_FALSE; PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); - - key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource); + key = php_openssl_evp_from_zval(zpkey, 0, passphrase, passphrase_len, 0, &key_resource); if (key == NULL) { php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1"); @@ -4215,7 +4248,7 @@ PHP_FUNCTION(openssl_pkey_get_public) if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) { return; } - pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &res); + pkey = php_openssl_evp_from_zval(cert, 1, NULL, 0, 1, &res); if (pkey == NULL) { RETURN_FALSE; } @@ -4254,7 +4287,9 @@ PHP_FUNCTION(openssl_pkey_get_private) if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) { return; } - pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &res); + + PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase); + pkey = php_openssl_evp_from_zval(cert, 0, passphrase, passphrase_len, 1, &res); if (pkey == NULL) { RETURN_FALSE; @@ -4756,7 +4791,7 @@ PHP_FUNCTION(openssl_pkcs7_sign) } } - privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource); + privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, 0, &keyresource); if (privkey == NULL) { php_error_docref(NULL, E_WARNING, "error getting private key"); goto clean_exit; @@ -4854,7 +4889,7 @@ PHP_FUNCTION(openssl_pkcs7_decrypt) goto clean_exit; } - key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval); + key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, 0, &keyresval); if (key == NULL) { php_error_docref(NULL, E_WARNING, "unable to get private key"); goto clean_exit; @@ -4916,7 +4951,7 @@ PHP_FUNCTION(openssl_private_encrypt) } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource); + pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "key param is not a valid private key"); @@ -4977,7 +5012,7 @@ PHP_FUNCTION(openssl_private_decrypt) } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource); + pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key"); RETURN_FALSE; @@ -5043,7 +5078,7 @@ PHP_FUNCTION(openssl_public_encrypt) return; RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource); + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key"); RETURN_FALSE; @@ -5104,7 +5139,7 @@ PHP_FUNCTION(openssl_public_decrypt) } RETVAL_FALSE; - pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource); + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key"); RETURN_FALSE; @@ -5193,7 +5228,7 @@ PHP_FUNCTION(openssl_sign) if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) { return; } - pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource); + pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a private key"); RETURN_FALSE; @@ -5278,7 +5313,7 @@ PHP_FUNCTION(openssl_verify) RETURN_FALSE; } - pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource); + pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a public key"); RETURN_FALSE; @@ -5357,7 +5392,7 @@ PHP_FUNCTION(openssl_seal) /* get the public keys we are using to seal this data */ i = 0; ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) { - pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i]); + pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, 0, &key_resources[i]); if (pkeys[i] == NULL) { php_error_docref(NULL, E_WARNING, "not a public key (%dth member of pubkeys)", i+1); RETVAL_FALSE; @@ -5451,7 +5486,7 @@ PHP_FUNCTION(openssl_open) return; } - pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource); + pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, 0, &keyresource); if (pkey == NULL) { php_error_docref(NULL, E_WARNING, "unable to coerce parameter 4 into a private key"); RETURN_FALSE; diff --git a/ext/openssl/tests/bug73833.phpt b/ext/openssl/tests/bug73833.phpt new file mode 100644 index 0000000000..e6a298fdcc --- /dev/null +++ b/ext/openssl/tests/bug73833.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #73833: null character not allowed in openssl_pkey_get_private +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip openssl not loaded"); +?> +--FILE-- +<?php +$passwords = ["abc\x00defghijkl", "abcdefghikjl"]; + +foreach($passwords as $password) { + $key = openssl_pkey_new(); + + if (openssl_pkey_export($key, $privatePEM, $password) === false) { + echo "Failed to encrypt.\n"; + } else { + echo "Encrypted!\n"; + } + if (openssl_pkey_get_private($privatePEM, $password) === false) { + echo "Failed to decrypt.\n"; + } else { + echo "Decrypted!\n"; + } +} +?> +--EXPECT-- +Encrypted! +Decrypted! +Encrypted! +Decrypted! |