Init OpenSSL libctx and use it for pkey (#18282)

This commit is contained in:
Jakub Zelenka 2025-05-06 19:14:55 +01:00 committed by GitHub
parent 905bba637a
commit cb4bafa4c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 111 additions and 25 deletions

View file

@ -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
}

View file

@ -1244,9 +1244,7 @@ EVP_PKEY *php_openssl_extract_public_key(EVP_PKEY *priv_key)
return pub_key;
}
/* {{{ php_openssl_pem_password_cb */
int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata)
static int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata)
{
struct php_openssl_pem_password *password = userdata;
@ -1429,7 +1427,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;
}
@ -1456,7 +1454,7 @@ zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, size_t k
return result;
}
int php_openssl_get_evp_pkey_type(int key_type) {
static int php_openssl_get_evp_pkey_type(int key_type) {
switch (key_type) {
case OPENSSL_KEYTYPE_RSA:
return EVP_PKEY_RSA;
@ -1487,6 +1485,37 @@ int php_openssl_get_evp_pkey_type(int key_type) {
}
}
static 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 +1529,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 +1537,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 +1599,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;

View file

@ -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;

View file

@ -22,17 +22,47 @@
#include <openssl/param_build.h>
#include <openssl/provider.h>
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 @@ cleanup:
}
#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;
}

View file

@ -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)

View file

@ -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);
@ -273,10 +280,8 @@ struct php_openssl_pem_password {
int len;
};
int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata);
EVP_PKEY *php_openssl_pkey_from_zval(
zval *val, int public_key, char *passphrase, size_t passphrase_len, uint32_t arg_num);
int php_openssl_get_evp_pkey_type(int key_type);
EVP_PKEY *php_openssl_generate_private_key(struct php_x509_request * req);
void php_openssl_add_bn_to_array(zval *ary, const BIGNUM *bn, const char *name);
@ -296,15 +301,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);