Skip to content

Commit 6db2c2d

Browse files
committed
Use param API for openssl_pkey_get_details()
Now that the DSA/DH/EC keys are not created using the legacy API, we can fetch the details using the param API as well, and not run into buggy priv_key handling.
1 parent 26a51e8 commit 6db2c2d

File tree

1 file changed

+106
-17
lines changed

1 file changed

+106
-17
lines changed

ext/openssl/openssl.c

Lines changed: 106 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3765,17 +3765,17 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
37653765
}
37663766
/* }}} */
37673767

3768-
#define OPENSSL_GET_BN(_array, _bn, _name) do { \
3769-
if (_bn != NULL) { \
3770-
int len = BN_num_bytes(_bn); \
3771-
zend_string *str = zend_string_alloc(len, 0); \
3772-
BN_bn2bin(_bn, (unsigned char*)ZSTR_VAL(str)); \
3773-
ZSTR_VAL(str)[len] = 0; \
3774-
add_assoc_str(&_array, #_name, str); \
3775-
} \
3776-
} while (0);
3768+
static void php_openssl_add_bn_to_array(zval *ary, const BIGNUM *bn, const char *name) {
3769+
if (bn != NULL) {
3770+
int len = BN_num_bytes(bn);
3771+
zend_string *str = zend_string_alloc(len, 0);
3772+
BN_bn2bin(bn, (unsigned char *)ZSTR_VAL(str));
3773+
ZSTR_VAL(str)[len] = 0;
3774+
add_assoc_str(ary, name, str);
3775+
}
3776+
}
37773777

3778-
#define OPENSSL_PKEY_GET_BN(_type, _name) OPENSSL_GET_BN(_type, _name, _name)
3778+
#define OPENSSL_PKEY_GET_BN(_type, _name) php_openssl_add_bn_to_array(&_type, _name, #_name)
37793779

37803780
#define OPENSSL_PKEY_SET_BN(_data, _name) do { \
37813781
zval *bn; \
@@ -4616,12 +4616,34 @@ PHP_FUNCTION(openssl_pkey_get_private)
46164616

46174617
/* }}} */
46184618

4619+
#if PHP_OPENSSL_API_VERSION >= 0x30000
4620+
static void php_openssl_copy_bn_param(
4621+
zval *ary, EVP_PKEY *pkey, const char *param, const char *name) {
4622+
BIGNUM *bn = NULL;
4623+
if (EVP_PKEY_get_bn_param(pkey, param, &bn) > 0) {
4624+
php_openssl_add_bn_to_array(ary, bn, name);
4625+
BN_free(bn);
4626+
}
4627+
}
4628+
4629+
static zend_string *php_openssl_get_utf8_param(
4630+
EVP_PKEY *pkey, const char *param, const char *name) {
4631+
char buf[64];
4632+
size_t len;
4633+
if (EVP_PKEY_get_utf8_string_param(pkey, param, buf, sizeof(buf), &len) > 0) {
4634+
zend_string *str = zend_string_alloc(len, 0);
4635+
memcpy(ZSTR_VAL(str), buf, len);
4636+
ZSTR_VAL(str)[len] = '\0';
4637+
return str;
4638+
}
4639+
return NULL;
4640+
}
4641+
#endif
4642+
46194643
/* {{{ returns an array with the key details (bits, pkey, type)*/
46204644
PHP_FUNCTION(openssl_pkey_get_details)
46214645
{
46224646
zval *key;
4623-
EVP_PKEY *pkey;
4624-
BIO *out;
46254647
unsigned int pbio_len;
46264648
char *pbio;
46274649
zend_long ktype;
@@ -4630,9 +4652,9 @@ PHP_FUNCTION(openssl_pkey_get_details)
46304652
RETURN_THROWS();
46314653
}
46324654

4633-
pkey = Z_OPENSSL_PKEY_P(key)->pkey;
4655+
EVP_PKEY *pkey = Z_OPENSSL_PKEY_P(key)->pkey;
46344656

4635-
out = BIO_new(BIO_s_mem());
4657+
BIO *out = BIO_new(BIO_s_mem());
46364658
if (!PEM_write_bio_PUBKEY(out, pkey)) {
46374659
BIO_free(out);
46384660
php_openssl_store_errors();
@@ -4646,6 +4668,72 @@ PHP_FUNCTION(openssl_pkey_get_details)
46464668
/*TODO: Use the real values once the openssl constants are used
46474669
* See the enum at the top of this file
46484670
*/
4671+
#if PHP_OPENSSL_API_VERSION >= 0x30000
4672+
zval ary;
4673+
switch (EVP_PKEY_base_id(pkey)) {
4674+
case EVP_PKEY_RSA:
4675+
ktype = OPENSSL_KEYTYPE_RSA;
4676+
array_init(&ary);
4677+
add_assoc_zval(return_value, "rsa", &ary);
4678+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_N, "n");
4679+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_E, "e");
4680+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_D, "d");
4681+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, "p");
4682+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, "q");
4683+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, "dmp1");
4684+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, "dmq1");
4685+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, "iqmp");
4686+
break;
4687+
case EVP_PKEY_DSA:
4688+
ktype = OPENSSL_KEYTYPE_DSA;
4689+
array_init(&ary);
4690+
add_assoc_zval(return_value, "dsa", &ary);
4691+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_FFC_P, "p");
4692+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_FFC_Q, "q");
4693+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_FFC_G, "g");
4694+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_PRIV_KEY, "priv_key");
4695+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_PUB_KEY, "pub_key");
4696+
break;
4697+
case EVP_PKEY_DH:
4698+
ktype = OPENSSL_KEYTYPE_DH;
4699+
array_init(&ary);
4700+
add_assoc_zval(return_value, "dh", &ary);
4701+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_FFC_P, "p");
4702+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_FFC_G, "g");
4703+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_PRIV_KEY, "priv_key");
4704+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_PUB_KEY, "pub_key");
4705+
break;
4706+
case EVP_PKEY_EC: {
4707+
ktype = OPENSSL_KEYTYPE_EC;
4708+
array_init(&ary);
4709+
add_assoc_zval(return_value, "ec", &ary);
4710+
4711+
zend_string *curve_name = php_openssl_get_utf8_param(
4712+
pkey, OSSL_PKEY_PARAM_GROUP_NAME, "curve_name");
4713+
if (curve_name) {
4714+
add_assoc_str(&ary, "curve_name", curve_name);
4715+
4716+
int nid = OBJ_sn2nid(ZSTR_VAL(curve_name));
4717+
if (nid != NID_undef) {
4718+
ASN1_OBJECT *obj = OBJ_nid2obj(nid);
4719+
if (obj) {
4720+
// OpenSSL recommends a buffer length of 80.
4721+
char oir_buf[80];
4722+
int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
4723+
add_assoc_stringl(&ary, "curve_oid", oir_buf, oir_len);
4724+
ASN1_OBJECT_free(obj);
4725+
}
4726+
}
4727+
}
4728+
4729+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_EC_PUB_X, "x");
4730+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_EC_PUB_Y, "y");
4731+
php_openssl_copy_bn_param(&ary, pkey, OSSL_PKEY_PARAM_PRIV_KEY, "d");
4732+
break;
4733+
}
4734+
EMPTY_SWITCH_DEFAULT_CASE();
4735+
}
4736+
#else
46494737
switch (EVP_PKEY_base_id(pkey)) {
46504738
case EVP_PKEY_RSA:
46514739
case EVP_PKEY_RSA2:
@@ -4762,14 +4850,14 @@ PHP_FUNCTION(openssl_pkey_get_details)
47624850
pub = EC_KEY_get0_public_key(ec_key);
47634851

47644852
if (EC_POINT_get_affine_coordinates_GFp(ec_group, pub, x, y, NULL)) {
4765-
OPENSSL_GET_BN(ec, x, x);
4766-
OPENSSL_GET_BN(ec, y, y);
4853+
php_openssl_add_bn_to_array(&ec, x, "x");
4854+
php_openssl_add_bn_to_array(&ec, y, "y");
47674855
} else {
47684856
php_openssl_store_errors();
47694857
}
47704858

47714859
if ((d = EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(pkey))) != NULL) {
4772-
OPENSSL_GET_BN(ec, d, d);
4860+
php_openssl_add_bn_to_array(&ec, d, "d");
47734861
}
47744862

47754863
add_assoc_zval(return_value, "ec", &ec);
@@ -4783,6 +4871,7 @@ PHP_FUNCTION(openssl_pkey_get_details)
47834871
ktype = -1;
47844872
break;
47854873
}
4874+
#endif
47864875
add_assoc_long(return_value, "type", ktype);
47874876

47884877
BIO_free(out);

0 commit comments

Comments
 (0)