diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 0896baf58312..2736491ee414 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -438,6 +438,9 @@ PHP_GINIT_FUNCTION(openssl) #endif openssl_globals->errors = NULL; openssl_globals->errors_mark = NULL; +#if PHP_OPENSSL_API_VERSION >= 0x30000 + php_openssl_backend_init_libctx(&openssl_globals->libctx, &openssl_globals->propq); +#endif } /* }}} */ @@ -450,6 +453,9 @@ PHP_GSHUTDOWN_FUNCTION(openssl) if (openssl_globals->errors_mark) { pefree(openssl_globals->errors_mark, 1); } +#if PHP_OPENSSL_API_VERSION >= 0x30000 + php_openssl_backend_destroy_libctx(openssl_globals->libctx, openssl_globals->propq); +#endif } /* }}} */ @@ -2036,19 +2042,19 @@ PHP_FUNCTION(openssl_pkey_new) #if PHP_OPENSSL_API_VERSION >= 0x30000 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "x25519", sizeof("x25519") - 1)) != NULL && Z_TYPE_P(data) == IS_ARRAY) { - php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_X25519, data); + php_openssl_pkey_object_curve_25519_448(return_value, "X25519", data); return; } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ed25519", sizeof("ed25519") - 1)) != NULL && Z_TYPE_P(data) == IS_ARRAY) { - php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_ED25519, data); + php_openssl_pkey_object_curve_25519_448(return_value, "ED25519", data); return; } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "x448", sizeof("x448") - 1)) != NULL && Z_TYPE_P(data) == IS_ARRAY) { - php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_X448, data); + php_openssl_pkey_object_curve_25519_448(return_value, "X448", data); return; } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ed448", sizeof("ed448") - 1)) != NULL && Z_TYPE_P(data) == IS_ARRAY) { - php_openssl_pkey_object_curve_25519_448(return_value, EVP_PKEY_ED448, data); + php_openssl_pkey_object_curve_25519_448(return_value, "ED448", data); return; #endif } diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 44cb22e18d2a..909aceea2d3e 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -1429,7 +1429,7 @@ EVP_PKEY *php_openssl_pkey_from_zval( zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, size_t key_size) { - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL); + EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_pkey(key); if (!ctx) { return NULL; } @@ -1487,6 +1487,37 @@ int php_openssl_get_evp_pkey_type(int key_type) { } } +const char *php_openssl_get_evp_pkey_name(int key_type) { + switch (key_type) { + case OPENSSL_KEYTYPE_RSA: + return "RSA"; +#if !defined(OPENSSL_NO_DSA) + case OPENSSL_KEYTYPE_DSA: + return "DSA"; +#endif +#if !defined(NO_DH) + case OPENSSL_KEYTYPE_DH: + return "DH"; +#endif +#ifdef HAVE_EVP_PKEY_EC + case OPENSSL_KEYTYPE_EC: + return "EC"; +#endif +#if PHP_OPENSSL_API_VERSION >= 0x30000 + case OPENSSL_KEYTYPE_X25519: + return "X25519"; + case OPENSSL_KEYTYPE_ED25519: + return "ED25519"; + case OPENSSL_KEYTYPE_X448: + return "X448"; + case OPENSSL_KEYTYPE_ED448: + return "ED448"; +#endif + default: + return ""; + } +} + EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) { if (req->priv_key_bits < MIN_KEY_LENGTH) { @@ -1500,6 +1531,7 @@ EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) php_error_docref(NULL, E_WARNING, "Unsupported private key type"); return NULL; } + const char *name = php_openssl_get_evp_pkey_name(req->priv_key_type); int egdsocket, seeded; char *randfile = php_openssl_conf_get_string(req->req_config, req->section_name, "RANDFILE"); @@ -1507,7 +1539,7 @@ EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) EVP_PKEY *key = NULL; EVP_PKEY *params = NULL; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(type, NULL); + EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name(name, type); if (!ctx) { php_openssl_store_errors(); goto cleanup; @@ -1569,7 +1601,7 @@ EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) } EVP_PKEY_CTX_free(ctx); - ctx = EVP_PKEY_CTX_new(params, NULL); + ctx = php_openssl_pkey_new_from_pkey(params); if (!ctx) { php_openssl_store_errors(); goto cleanup; diff --git a/ext/openssl/openssl_backend_v1.c b/ext/openssl/openssl_backend_v1.c index 59988451bbbd..eb94ee3fbe4b 100644 --- a/ext/openssl/openssl_backend_v1.c +++ b/ext/openssl/openssl_backend_v1.c @@ -44,6 +44,16 @@ void php_openssl_backend_shutdown(void) #endif } +EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id) +{ + return EVP_PKEY_CTX_new_id(id, NULL); +} + +EVP_PKEY_CTX *php_openssl_pkey_new_from_pkey(EVP_PKEY *pkey) +{ + return EVP_PKEY_CTX_new(pkey, NULL); +} + static bool php_openssl_pkey_init_rsa_data(RSA *rsa, zval *data) { BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; diff --git a/ext/openssl/openssl_backend_v3.c b/ext/openssl/openssl_backend_v3.c index 76965d66e65a..0876690aee0b 100644 --- a/ext/openssl/openssl_backend_v3.c +++ b/ext/openssl/openssl_backend_v3.c @@ -22,17 +22,47 @@ #include #include +ZEND_EXTERN_MODULE_GLOBALS(openssl) + void php_openssl_backend_shutdown(void) { (void) 0; } +void php_openssl_backend_init_libctx(OSSL_LIB_CTX **plibctx, char **ppropq) +{ + /* The return value is not checked because we cannot reasonable fail in GINIT so using NULL + * (default context) is probably better. */ + *plibctx = OSSL_LIB_CTX_new(); + *ppropq = NULL; +} + +void php_openssl_backend_destroy_libctx(OSSL_LIB_CTX *libctx, char *propq) +{ + if (libctx != NULL) { + OSSL_LIB_CTX_free(libctx); + } + if (propq != NULL) { + free(propq); + } +} + +EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id) +{ + return EVP_PKEY_CTX_new_from_name(OPENSSL_G(libctx), name, OPENSSL_G(propq)); +} + +EVP_PKEY_CTX *php_openssl_pkey_new_from_pkey(EVP_PKEY *pkey) +{ + return EVP_PKEY_CTX_new_from_pkey(OPENSSL_G(libctx), pkey, OPENSSL_G(propq)); +} + EVP_PKEY *php_openssl_pkey_init_rsa(zval *data) { BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; EVP_PKEY *pkey = NULL; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("RSA", EVP_PKEY_RSA); OSSL_PARAM *params = NULL; OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); @@ -100,7 +130,7 @@ EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private) { BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL; EVP_PKEY *param_key = NULL, *pkey = NULL; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("DSA", EVP_PKEY_DSA); OSSL_PARAM *params = NULL; OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); @@ -144,7 +174,7 @@ EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private) } else { *is_private = true; EVP_PKEY_CTX_free(ctx); - ctx = EVP_PKEY_CTX_new(param_key, NULL); + ctx = php_openssl_pkey_new_from_pkey(param_key); if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) { goto cleanup; } @@ -168,7 +198,7 @@ EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private) { BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL; EVP_PKEY *param_key = NULL, *pkey = NULL; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); + EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("DH", EVP_PKEY_DH); OSSL_PARAM *params = NULL; OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); @@ -219,7 +249,7 @@ EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private) } else { *is_private = true; EVP_PKEY_CTX_free(ctx); - ctx = EVP_PKEY_CTX_new(param_key, NULL); + ctx = php_openssl_pkey_new_from_pkey(param_key); if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) { goto cleanup; } @@ -250,7 +280,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) { unsigned char *point_q_buf = NULL; EC_GROUP *group = NULL; EVP_PKEY *param_key = NULL, *pkey = NULL; - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + EVP_PKEY_CTX *ctx = php_openssl_pkey_new_from_name("EC", EVP_PKEY_EC); BN_CTX *bctx = BN_CTX_new(); OSSL_PARAM *params = NULL; OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); @@ -269,7 +299,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) { goto cleanup; } - if (!(group = EC_GROUP_new_by_curve_name(nid))) { + if (!(group = EC_GROUP_new_by_curve_name_ex(OPENSSL_G(libctx), OPENSSL_G(propq), nid))) { goto cleanup; } @@ -438,7 +468,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) { } #endif -void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, zval *data) { +void php_openssl_pkey_object_curve_25519_448(zval *return_value, const char *name, zval *data) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; OSSL_PARAM *params = NULL; @@ -466,7 +496,7 @@ void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, z } params = OSSL_PARAM_BLD_to_param(bld); - ctx = EVP_PKEY_CTX_new_id(key_type, NULL); + ctx = php_openssl_pkey_new_from_name(name, 0); if (!params || !ctx) { goto cleanup; } diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index bc101539d1b1..67522f3d3471 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -73,6 +73,10 @@ struct php_openssl_errors { ZEND_BEGIN_MODULE_GLOBALS(openssl) struct php_openssl_errors *errors; struct php_openssl_errors *errors_mark; +#if PHP_OPENSSL_API_VERSION >= 0x30000 + OSSL_LIB_CTX *libctx; + char *propq; +#endif ZEND_END_MODULE_GLOBALS(openssl) #define OPENSSL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(openssl, v) diff --git a/ext/openssl/php_openssl_backend.h b/ext/openssl/php_openssl_backend.h index 158b4e27712f..b0013e927baa 100644 --- a/ext/openssl/php_openssl_backend.h +++ b/ext/openssl/php_openssl_backend.h @@ -225,8 +225,15 @@ EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo); const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo); void php_openssl_backend_init(void); +void php_openssl_backend_init_common(void); +void php_openssl_backend_gshutdown(void); void php_openssl_backend_shutdown(void); +#if PHP_OPENSSL_API_VERSION >= 0x30000 +void php_openssl_backend_init_libctx(OSSL_LIB_CTX **plibctx, char **ppropq); +void php_openssl_backend_destroy_libctx(OSSL_LIB_CTX *libctx, char *propq); +#endif + const char *php_openssl_get_conf_filename(void); void php_openssl_set_cert_locations(zval *return_value); @@ -296,15 +303,16 @@ void php_openssl_add_bn_to_array(zval *ary, const BIGNUM *bn, const char *name); } \ } while (0); +EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id); +EVP_PKEY_CTX *php_openssl_pkey_new_from_pkey(EVP_PKEY *pkey); EVP_PKEY *php_openssl_pkey_init_rsa(zval *data); EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private); BIGNUM *php_openssl_dh_pub_from_priv(BIGNUM *priv_key, BIGNUM *g, BIGNUM *p); EVP_PKEY *php_openssl_pkey_init_dh(zval *data, bool *is_private); EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private); -void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, zval *data); #if PHP_OPENSSL_API_VERSION >= 0x30000 -void php_openssl_pkey_object_curve_25519_448(zval *return_value, int key_type, zval *data); +void php_openssl_pkey_object_curve_25519_448(zval *return_value, const char *name, zval *data); #endif zend_long php_openssl_pkey_get_details(zval *return_value, EVP_PKEY *pkey);