Skip to content

Commit cb4bafa

Browse files
authored
Init OpenSSL libctx and use it for pkey (#18282)
1 parent 905bba6 commit cb4bafa

6 files changed

+111
-25
lines changed

ext/openssl/openssl.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@ PHP_GINIT_FUNCTION(openssl)
438438
#endif
439439
openssl_globals->errors = NULL;
440440
openssl_globals->errors_mark = NULL;
441+
#if PHP_OPENSSL_API_VERSION >= 0x30000
442+
php_openssl_backend_init_libctx(&openssl_globals->libctx, &openssl_globals->propq);
443+
#endif
441444
}
442445
/* }}} */
443446

@@ -450,6 +453,9 @@ PHP_GSHUTDOWN_FUNCTION(openssl)
450453
if (openssl_globals->errors_mark) {
451454
pefree(openssl_globals->errors_mark, 1);
452455
}
456+
#if PHP_OPENSSL_API_VERSION >= 0x30000
457+
php_openssl_backend_destroy_libctx(openssl_globals->libctx, openssl_globals->propq);
458+
#endif
453459
}
454460
/* }}} */
455461

@@ -2036,19 +2042,19 @@ PHP_FUNCTION(openssl_pkey_new)
20362042
#if PHP_OPENSSL_API_VERSION >= 0x30000
20372043
} else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "x25519", sizeof("x25519") - 1)) != NULL &&
20382044
Z_TYPE_P(data) == IS_ARRAY) {
2039-
php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_X25519, data);
2045+
php_openssl_pkey_object_curve_25519_448(return_value, "X25519", data);
20402046
return;
20412047
} else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ed25519", sizeof("ed25519") - 1)) != NULL &&
20422048
Z_TYPE_P(data) == IS_ARRAY) {
2043-
php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_ED25519, data);
2049+
php_openssl_pkey_object_curve_25519_448(return_value, "ED25519", data);
20442050
return;
20452051
} else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "x448", sizeof("x448") - 1)) != NULL &&
20462052
Z_TYPE_P(data) == IS_ARRAY) {
2047-
php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_X448, data);
2053+
php_openssl_pkey_object_curve_25519_448(return_value, "X448", data);
20482054
return;
20492055
} else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ed448", sizeof("ed448") - 1)) != NULL &&
20502056
Z_TYPE_P(data) == IS_ARRAY) {
2051-
php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_ED448, data);
2057+
php_openssl_pkey_object_curve_25519_448(return_value, "ED448", data);
20522058
return;
20532059
#endif
20542060
}

ext/openssl/openssl_backend_common.c

+38-8
Original file line numberDiff line numberDiff line change
@@ -1244,9 +1244,7 @@ EVP_PKEY *php_openssl_extract_public_key(EVP_PKEY *priv_key)
12441244
return pub_key;
12451245
}
12461246

1247-
1248-
/* {{{ php_openssl_pem_password_cb */
1249-
int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata)
1247+
static int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata)
12501248
{
12511249
struct php_openssl_pem_password *password = userdata;
12521250

@@ -1429,7 +1427,7 @@ EVP_PKEY *php_openssl_pkey_from_zval(
14291427

14301428
zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, size_t key_size)
14311429
{
1432-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL);
1430+
EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_pkey(key);
14331431
if (!ctx) {
14341432
return NULL;
14351433
}
@@ -1456,7 +1454,7 @@ zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, size_t k
14561454
return result;
14571455
}
14581456

1459-
int php_openssl_get_evp_pkey_type(int key_type) {
1457+
static int php_openssl_get_evp_pkey_type(int key_type) {
14601458
switch (key_type) {
14611459
case OPENSSL_KEYTYPE_RSA:
14621460
return EVP_PKEY_RSA;
@@ -1487,7 +1485,38 @@ int php_openssl_get_evp_pkey_type(int key_type) {
14871485
}
14881486
}
14891487

1490-
EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req)
1488+
static const char *php_openssl_get_evp_pkey_name(int key_type) {
1489+
switch (key_type) {
1490+
case OPENSSL_KEYTYPE_RSA:
1491+
return "RSA";
1492+
#if !defined(OPENSSL_NO_DSA)
1493+
case OPENSSL_KEYTYPE_DSA:
1494+
return "DSA";
1495+
#endif
1496+
#if !defined(NO_DH)
1497+
case OPENSSL_KEYTYPE_DH:
1498+
return "DH";
1499+
#endif
1500+
#ifdef HAVE_EVP_PKEY_EC
1501+
case OPENSSL_KEYTYPE_EC:
1502+
return "EC";
1503+
#endif
1504+
#if PHP_OPENSSL_API_VERSION >= 0x30000
1505+
case OPENSSL_KEYTYPE_X25519:
1506+
return "X25519";
1507+
case OPENSSL_KEYTYPE_ED25519:
1508+
return "ED25519";
1509+
case OPENSSL_KEYTYPE_X448:
1510+
return "X448";
1511+
case OPENSSL_KEYTYPE_ED448:
1512+
return "ED448";
1513+
#endif
1514+
default:
1515+
return "";
1516+
}
1517+
}
1518+
1519+
EVP_PKEY *php_openssl_generate_private_key(struct php_x509_request * req)
14911520
{
14921521
if (req->priv_key_bits < MIN_KEY_LENGTH) {
14931522
php_error_docref(NULL, E_WARNING, "Private key length must be at least %d bits, configured to %d",
@@ -1500,14 +1529,15 @@ EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req)
15001529
php_error_docref(NULL, E_WARNING, "Unsupported private key type");
15011530
return NULL;
15021531
}
1532+
const char *name = php_openssl_get_evp_pkey_name(req->priv_key_type);
15031533

15041534
int egdsocket, seeded;
15051535
char *randfile = php_openssl_conf_get_string(req->req_config, req->section_name, "RANDFILE");
15061536
php_openssl_load_rand_file(randfile, &egdsocket, &seeded);
15071537

15081538
EVP_PKEY *key = NULL;
15091539
EVP_PKEY *params = NULL;
1510-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(type, NULL);
1540+
EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name(name, type);
15111541
if (!ctx) {
15121542
php_openssl_store_errors();
15131543
goto cleanup;
@@ -1569,7 +1599,7 @@ EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req)
15691599
}
15701600

15711601
EVP_PKEY_CTX_free(ctx);
1572-
ctx = EVP_PKEY_CTX_new(params, NULL);
1602+
ctx = php_openssl_pkey_new_from_pkey(params);
15731603
if (!ctx) {
15741604
php_openssl_store_errors();
15751605
goto cleanup;

ext/openssl/openssl_backend_v1.c

+10
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ void php_openssl_backend_shutdown(void)
4444
#endif
4545
}
4646

47+
EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id)
48+
{
49+
return EVP_PKEY_CTX_new_id(id, NULL);
50+
}
51+
52+
EVP_PKEY_CTX *php_openssl_pkey_new_from_pkey(EVP_PKEY *pkey)
53+
{
54+
return EVP_PKEY_CTX_new(pkey, NULL);
55+
}
56+
4757
static bool php_openssl_pkey_init_rsa_data(RSA *rsa, zval *data)
4858
{
4959
BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;

ext/openssl/openssl_backend_v3.c

+39-9
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,47 @@
2222
#include <openssl/param_build.h>
2323
#include <openssl/provider.h>
2424

25+
ZEND_EXTERN_MODULE_GLOBALS(openssl)
26+
2527
void php_openssl_backend_shutdown(void)
2628
{
2729
(void) 0;
2830
}
2931

32+
void php_openssl_backend_init_libctx(OSSL_LIB_CTX **plibctx, char **ppropq)
33+
{
34+
/* The return value is not checked because we cannot reasonable fail in GINIT so using NULL
35+
* (default context) is probably better. */
36+
*plibctx = OSSL_LIB_CTX_new();
37+
*ppropq = NULL;
38+
}
39+
40+
void php_openssl_backend_destroy_libctx(OSSL_LIB_CTX *libctx, char *propq)
41+
{
42+
if (libctx != NULL) {
43+
OSSL_LIB_CTX_free(libctx);
44+
}
45+
if (propq != NULL) {
46+
free(propq);
47+
}
48+
}
49+
50+
EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id)
51+
{
52+
return EVP_PKEY_CTX_new_from_name(OPENSSL_G(libctx), name, OPENSSL_G(propq));
53+
}
54+
55+
EVP_PKEY_CTX *php_openssl_pkey_new_from_pkey(EVP_PKEY *pkey)
56+
{
57+
return EVP_PKEY_CTX_new_from_pkey(OPENSSL_G(libctx), pkey, OPENSSL_G(propq));
58+
}
59+
3060
EVP_PKEY *php_openssl_pkey_init_rsa(zval *data)
3161
{
3262
BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL;
3363
BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
3464
EVP_PKEY *pkey = NULL;
35-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
65+
EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("RSA", EVP_PKEY_RSA);
3666
OSSL_PARAM *params = NULL;
3767
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
3868

@@ -100,7 +130,7 @@ EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private)
100130
{
101131
BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL;
102132
EVP_PKEY *param_key = NULL, *pkey = NULL;
103-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
133+
EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("DSA", EVP_PKEY_DSA);
104134
OSSL_PARAM *params = NULL;
105135
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
106136

@@ -144,7 +174,7 @@ EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private)
144174
} else {
145175
*is_private = true;
146176
EVP_PKEY_CTX_free(ctx);
147-
ctx = EVP_PKEY_CTX_new(param_key, NULL);
177+
ctx = php_openssl_pkey_new_from_pkey(param_key);
148178
if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) {
149179
goto cleanup;
150180
}
@@ -168,7 +198,7 @@ EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private)
168198
{
169199
BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL;
170200
EVP_PKEY *param_key = NULL, *pkey = NULL;
171-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL);
201+
EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("DH", EVP_PKEY_DH);
172202
OSSL_PARAM *params = NULL;
173203
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
174204

@@ -219,7 +249,7 @@ EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private)
219249
} else {
220250
*is_private = true;
221251
EVP_PKEY_CTX_free(ctx);
222-
ctx = EVP_PKEY_CTX_new(param_key, NULL);
252+
ctx = php_openssl_pkey_new_from_pkey(param_key);
223253
if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) {
224254
goto cleanup;
225255
}
@@ -250,7 +280,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
250280
unsigned char *point_q_buf = NULL;
251281
EC_GROUP *group = NULL;
252282
EVP_PKEY *param_key = NULL, *pkey = NULL;
253-
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
283+
EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("EC", EVP_PKEY_EC);
254284
BN_CTX *bctx = BN_CTX_new();
255285
OSSL_PARAM *params = NULL;
256286
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
@@ -269,7 +299,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
269299
goto cleanup;
270300
}
271301

272-
if (!(group = EC_GROUP_new_by_curve_name(nid))) {
302+
if (!(group = EC_GROUP_new_by_curve_name_ex(OPENSSL_G(libctx), OPENSSL_G(propq), nid))) {
273303
goto cleanup;
274304
}
275305

@@ -438,7 +468,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
438468
}
439469
#endif
440470

441-
void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, zval *data) {
471+
void php_openssl_pkey_object_curve_25519_448(zval *return_value, const char *name, zval *data) {
442472
EVP_PKEY *pkey = NULL;
443473
EVP_PKEY_CTX *ctx = NULL;
444474
OSSL_PARAM *params = NULL;
@@ -466,7 +496,7 @@ void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, z
466496
}
467497

468498
params = OSSL_PARAM_BLD_to_param(bld);
469-
ctx = EVP_PKEY_CTX_new_id(key_type, NULL);
499+
ctx = php_openssl_pkey_new_from_name(name, 0);
470500
if (!params || !ctx) {
471501
goto cleanup;
472502
}

ext/openssl/php_openssl.h

+4
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ struct php_openssl_errors {
7373
ZEND_BEGIN_MODULE_GLOBALS(openssl)
7474
struct php_openssl_errors *errors;
7575
struct php_openssl_errors *errors_mark;
76+
#if PHP_OPENSSL_API_VERSION >= 0x30000
77+
OSSL_LIB_CTX *libctx;
78+
char *propq;
79+
#endif
7680
ZEND_END_MODULE_GLOBALS(openssl)
7781

7882
#define OPENSSL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(openssl, v)

ext/openssl/php_openssl_backend.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,15 @@ EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo);
225225
const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo);
226226

227227
void php_openssl_backend_init(void);
228+
void php_openssl_backend_init_common(void);
229+
void php_openssl_backend_gshutdown(void);
228230
void php_openssl_backend_shutdown(void);
229231

232+
#if PHP_OPENSSL_API_VERSION >= 0x30000
233+
void php_openssl_backend_init_libctx(OSSL_LIB_CTX **plibctx, char **ppropq);
234+
void php_openssl_backend_destroy_libctx(OSSL_LIB_CTX *libctx, char *propq);
235+
#endif
236+
230237
const char *php_openssl_get_conf_filename(void);
231238

232239
void php_openssl_set_cert_locations(zval *return_value);
@@ -273,10 +280,8 @@ struct php_openssl_pem_password {
273280
int len;
274281
};
275282

276-
int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata);
277283
EVP_PKEY *php_openssl_pkey_from_zval(
278284
zval *val, int public_key, char *passphrase, size_t passphrase_len, uint32_t arg_num);
279-
int php_openssl_get_evp_pkey_type(int key_type);
280285
EVP_PKEY *php_openssl_generate_private_key(struct php_x509_request * req);
281286
void php_openssl_add_bn_to_array(zval *ary, const BIGNUM *bn, const char *name);
282287

@@ -296,15 +301,16 @@ void php_openssl_add_bn_to_array(zval *ary, const BIGNUM *bn, const char *name);
296301
} \
297302
} while (0);
298303

304+
EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id);
305+
EVP_PKEY_CTX *php_openssl_pkey_new_from_pkey(EVP_PKEY *pkey);
299306

300307
EVP_PKEY *php_openssl_pkey_init_rsa(zval *data);
301308
EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private);
302309
BIGNUM *php_openssl_dh_pub_from_priv(BIGNUM *priv_key, BIGNUM *g, BIGNUM *p);
303310
EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private);
304311
EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private);
305-
void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, zval *data);
306312
#if PHP_OPENSSL_API_VERSION >= 0x30000
307-
void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, zval *data);
313+
void php_openssl_pkey_object_curve_25519_448(zval *return_value, const char *name, zval *data);
308314
#endif
309315
zend_long php_openssl_pkey_get_details(zval *return_value, EVP_PKEY *pkey);
310316

0 commit comments

Comments
 (0)