Skip to content

Commit cb48260

Browse files
committed
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.
1 parent c6542b2 commit cb48260

File tree

1 file changed

+40
-24
lines changed

1 file changed

+40
-24
lines changed

ext/openssl/openssl.c

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4563,16 +4563,48 @@ static zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, s
45634563
return result;
45644564
}
45654565

4566+
static zend_string *php_openssl_dh_compute_key(EVP_PKEY *pkey, char *pub_str, size_t pub_len) {
4567+
#if PHP_OPENSSL_API_VERSION >= 0x30000
4568+
EVP_PKEY *peer_key = EVP_PKEY_new();
4569+
if (!peer_key || EVP_PKEY_copy_parameters(peer_key, pkey) <= 0 ||
4570+
EVP_PKEY_set1_encoded_public_key(peer_key, (unsigned char *) pub_str, pub_len) <= 0) {
4571+
php_openssl_store_errors();
4572+
EVP_PKEY_free(peer_key);
4573+
return NULL;
4574+
}
4575+
4576+
zend_string *result = php_openssl_pkey_derive(pkey, peer_key, 0);
4577+
EVP_PKEY_free(peer_key);
4578+
return result;
4579+
#else
4580+
DH *dh = EVP_PKEY_get0_DH(pkey);
4581+
if (dh == NULL) {
4582+
return NULL;
4583+
}
4584+
4585+
BIGNUM *pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
4586+
zend_string *data = zend_string_alloc(DH_size(dh), 0);
4587+
int len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh);
4588+
BN_free(pub);
4589+
4590+
if (len < 0) {
4591+
php_openssl_store_errors();
4592+
zend_string_release_ex(data, 0);
4593+
return NULL;
4594+
}
4595+
4596+
ZSTR_LEN(data) = len;
4597+
ZSTR_VAL(data)[len] = 0;
4598+
return data;
4599+
#endif
4600+
}
4601+
45664602
/* {{{ Computes shared secret for public value of remote DH key and local DH key */
45674603
PHP_FUNCTION(openssl_dh_compute_key)
45684604
{
45694605
zval *key;
45704606
char *pub_str;
45714607
size_t pub_len;
4572-
DH *dh;
4573-
BIGNUM *pub;
4574-
zend_string *data;
4575-
int len;
45764608

45774609
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sO", &pub_str, &pub_len, &key, php_openssl_pkey_ce) == FAILURE) {
45784610
RETURN_THROWS();
@@ -4581,32 +4613,16 @@ PHP_FUNCTION(openssl_dh_compute_key)
45814613
PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key, 1);
45824614

45834615
EVP_PKEY *pkey = Z_OPENSSL_PKEY_P(key)->pkey;
4584-
45854616
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
45864617
RETURN_FALSE;
45874618
}
45884619

4589-
dh = EVP_PKEY_get0_DH(pkey);
4590-
if (dh == NULL) {
4591-
RETURN_FALSE;
4592-
}
4593-
4594-
pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
4595-
4596-
data = zend_string_alloc(DH_size(dh), 0);
4597-
len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh);
4598-
4599-
if (len >= 0) {
4600-
ZSTR_LEN(data) = len;
4601-
ZSTR_VAL(data)[len] = 0;
4602-
RETVAL_NEW_STR(data);
4620+
zend_string *result = php_openssl_dh_compute_key(pkey, pub_str, pub_len);
4621+
if (result) {
4622+
RETURN_NEW_STR(result);
46034623
} else {
4604-
php_openssl_store_errors();
4605-
zend_string_release_ex(data, 0);
4606-
RETVAL_FALSE;
4624+
RETURN_FALSE;
46074625
}
4608-
4609-
BN_free(pub);
46104626
}
46114627
/* }}} */
46124628

0 commit comments

Comments
 (0)