1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Avoid DH_compute_key() with OpenSSL 3

Instead construct a proper EVP_PKEY for the public key and
perform a derive operation.

Unfortunately we can't use a common code path here, because
EVP_PKEY_set1_encoded_public_key() formerly known as
EVP_PKEY_set1_tls_encodedpoint() does not appear to work with
DH keys prior to OpenSSL 3.
This commit is contained in:
Nikita Popov
2021-08-05 15:58:20 +02:00
parent c6542b2a1e
commit cb48260fdd

View File

@@ -4563,16 +4563,48 @@ static zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, s
return result;
}
static zend_string *php_openssl_dh_compute_key(EVP_PKEY *pkey, char *pub_str, size_t pub_len) {
#if PHP_OPENSSL_API_VERSION >= 0x30000
EVP_PKEY *peer_key = EVP_PKEY_new();
if (!peer_key || EVP_PKEY_copy_parameters(peer_key, pkey) <= 0 ||
EVP_PKEY_set1_encoded_public_key(peer_key, (unsigned char *) pub_str, pub_len) <= 0) {
php_openssl_store_errors();
EVP_PKEY_free(peer_key);
return NULL;
}
zend_string *result = php_openssl_pkey_derive(pkey, peer_key, 0);
EVP_PKEY_free(peer_key);
return result;
#else
DH *dh = EVP_PKEY_get0_DH(pkey);
if (dh == NULL) {
return NULL;
}
BIGNUM *pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
zend_string *data = zend_string_alloc(DH_size(dh), 0);
int len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh);
BN_free(pub);
if (len < 0) {
php_openssl_store_errors();
zend_string_release_ex(data, 0);
return NULL;
}
ZSTR_LEN(data) = len;
ZSTR_VAL(data)[len] = 0;
return data;
#endif
}
/* {{{ Computes shared secret for public value of remote DH key and local DH key */
PHP_FUNCTION(openssl_dh_compute_key)
{
zval *key;
char *pub_str;
size_t pub_len;
DH *dh;
BIGNUM *pub;
zend_string *data;
int len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sO", &pub_str, &pub_len, &key, php_openssl_pkey_ce) == FAILURE) {
RETURN_THROWS();
@@ -4581,32 +4613,16 @@ PHP_FUNCTION(openssl_dh_compute_key)
PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key, 1);
EVP_PKEY *pkey = Z_OPENSSL_PKEY_P(key)->pkey;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
RETURN_FALSE;
}
dh = EVP_PKEY_get0_DH(pkey);
if (dh == NULL) {
zend_string *result = php_openssl_dh_compute_key(pkey, pub_str, pub_len);
if (result) {
RETURN_NEW_STR(result);
} else {
RETURN_FALSE;
}
pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
data = zend_string_alloc(DH_size(dh), 0);
len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh);
if (len >= 0) {
ZSTR_LEN(data) = len;
ZSTR_VAL(data)[len] = 0;
RETVAL_NEW_STR(data);
} else {
php_openssl_store_errors();
zend_string_release_ex(data, 0);
RETVAL_FALSE;
}
BN_free(pub);
}
/* }}} */