Introduce OpenSSL INI for selecting libctx (#18768)

Closes GH-18768

Co-authored-by: Gina Peter Banyard <girgias@php.net>
This commit is contained in:
Jakub Zelenka 2025-07-14 14:16:14 +01:00 committed by GitHub
parent 2beb44a80b
commit d0c0a9abfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 95 additions and 32 deletions

View file

@ -351,12 +351,31 @@ int php_openssl_get_ssl_stream_data_index(void)
return ssl_stream_data_index;
}
/* {{{ INI Settings */
static PHP_INI_MH(OnUpdateLibCtx)
{
#if PHP_OPENSSL_API_VERSION >= 0x30000
if (zend_string_equals_literal(new_value, "default")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).default_libctx;
} else if (zend_string_equals_literal(new_value, "custom")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).custom_libctx;
} else {
/* Do not output error when restoring ini options. */
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
int err_type = stage == ZEND_INI_STAGE_RUNTIME ? E_WARNING : E_ERROR;
php_error_docref(NULL, err_type, "OpenSSL libctx \"%s\" cannot be found", ZSTR_VAL(new_value));
}
return FAILURE;
}
#endif
return SUCCESS;
}
PHP_INI_BEGIN()
PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_PERDIR, NULL)
PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL)
PHP_INI_ENTRY("openssl.libctx", "custom", PHP_INI_PERDIR, OnUpdateLibCtx)
PHP_INI_END()
/* }}} */
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(openssl)
@ -438,9 +457,7 @@ 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
php_openssl_backend_init_libctx(&openssl_globals->ctx);
}
/* }}} */
@ -453,9 +470,7 @@ 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
php_openssl_backend_destroy_libctx(&openssl_globals->ctx);
}
/* }}} */

View file

@ -44,6 +44,16 @@ void php_openssl_backend_shutdown(void)
#endif
}
void php_openssl_backend_init_libctx(struct php_openssl_libctx *ctx)
{
// Do nothing as there is no libctx
}
void php_openssl_backend_destroy_libctx(struct php_openssl_libctx *ctx)
{
// Do nothing as there is no libctx
}
EVP_PKEY_CTX *php_openssl_pkey_new_from_name(const char *name, int id)
{
return EVP_PKEY_CTX_new_id(id, NULL);

View file

@ -29,32 +29,47 @@ void php_openssl_backend_shutdown(void)
(void) 0;
}
void php_openssl_backend_init_libctx(OSSL_LIB_CTX **plibctx, char **ppropq)
#define PHP_OPENSSL_DEFAULT_CONF_MFLAGS \
(CONF_MFLAGS_DEFAULT_SECTION | CONF_MFLAGS_IGNORE_MISSING_FILE | CONF_MFLAGS_IGNORE_RETURN_CODES)
void php_openssl_backend_init_libctx(struct php_openssl_libctx *ctx)
{
/* 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;
ctx->default_libctx = OSSL_LIB_CTX_get0_global_default();
ctx->custom_libctx = OSSL_LIB_CTX_new();
if (ctx->custom_libctx != NULL) {
/* This is not being checked because there is not much that can be done. */
CONF_modules_load_file_ex(ctx->custom_libctx, NULL, NULL,
PHP_OPENSSL_DEFAULT_CONF_MFLAGS);
#ifdef LOAD_OPENSSL_LEGACY_PROVIDER
OSSL_PROVIDER_load(ctx->custom_libctx, "legacy");
OSSL_PROVIDER_load(ctx->custom_libctx, "default");
#endif
ctx->libctx = ctx->custom_libctx;
} else {
/* If creation fails, just fallback to default */
ctx->libctx = ctx->default_libctx;
}
ctx->propq = NULL;
}
void php_openssl_backend_destroy_libctx(OSSL_LIB_CTX *libctx, char *propq)
void php_openssl_backend_destroy_libctx(struct php_openssl_libctx *ctx)
{
if (libctx != NULL) {
OSSL_LIB_CTX_free(libctx);
if (ctx->custom_libctx != NULL) {
OSSL_LIB_CTX_free(ctx->custom_libctx);
}
if (propq != NULL) {
free(propq);
if (ctx->propq != NULL) {
free(ctx->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));
return EVP_PKEY_CTX_new_from_name(PHP_OPENSSL_LIBCTX, name, PHP_OPENSSL_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));
return EVP_PKEY_CTX_new_from_pkey(PHP_OPENSSL_LIBCTX, pkey, PHP_OPENSSL_PROPQ);
}
EVP_PKEY *php_openssl_pkey_init_rsa(zval *data)
@ -299,7 +314,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
goto cleanup;
}
if (!(group = EC_GROUP_new_by_curve_name_ex(OPENSSL_G(libctx), OPENSSL_G(propq), nid))) {
if (!(group = EC_GROUP_new_by_curve_name_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ, nid))) {
goto cleanup;
}
@ -698,7 +713,7 @@ zend_string *php_openssl_dh_compute_key(EVP_PKEY *pkey, char *pub_str, size_t pu
const EVP_MD *php_openssl_get_evp_md_by_name(const char *name)
{
return EVP_MD_fetch(OPENSSL_G(libctx), name, OPENSSL_G(propq));
return EVP_MD_fetch(PHP_OPENSSL_LIBCTX, name, PHP_OPENSSL_PROPQ);
}
static const char *php_openssl_digest_names[] = {
@ -754,7 +769,7 @@ static const char *php_openssl_cipher_names[] = {
const EVP_CIPHER *php_openssl_get_evp_cipher_by_name(const char *name)
{
return EVP_CIPHER_fetch(OPENSSL_G(libctx), name, OPENSSL_G(propq));
return EVP_CIPHER_fetch(PHP_OPENSSL_LIBCTX, name, PHP_OPENSSL_PROPQ);
}
const EVP_CIPHER *php_openssl_get_evp_cipher_from_algo(zend_long algo)
@ -805,7 +820,7 @@ static int php_openssl_compare_func(Bucket *a, Bucket *b)
void php_openssl_get_cipher_methods(zval *return_value, bool aliases)
{
array_init(return_value);
EVP_CIPHER_do_all_provided(OPENSSL_G(libctx),
EVP_CIPHER_do_all_provided(PHP_OPENSSL_LIBCTX,
aliases ? php_openssl_add_cipher_or_alias : php_openssl_add_cipher,
return_value);
zend_hash_sort(Z_ARRVAL_P(return_value), php_openssl_compare_func, 1);

View file

@ -70,15 +70,24 @@ struct php_openssl_errors {
int bottom;
};
struct php_openssl_libctx {
#if PHP_OPENSSL_API_VERSION >= 0x30000
OSSL_LIB_CTX *libctx;
OSSL_LIB_CTX *default_libctx;
OSSL_LIB_CTX *custom_libctx;
#endif
char *propq;
};
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
struct php_openssl_libctx ctx;
ZEND_END_MODULE_GLOBALS(openssl)
#define PHP_OPENSSL_LIBCTX OPENSSL_G(ctx).libctx
#define PHP_OPENSSL_PROPQ OPENSSL_G(ctx).propq
#define OPENSSL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(openssl, v)
#if defined(ZTS) && defined(COMPILE_DL_OPENSSL)

View file

@ -237,10 +237,8 @@ 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
void php_openssl_backend_init_libctx(struct php_openssl_libctx *ctx);
void php_openssl_backend_destroy_libctx(struct php_openssl_libctx *ctx);
const char *php_openssl_get_conf_filename(void);

View file

@ -1863,6 +1863,14 @@ ldap.max_links = -1
; SSL stream context option.
;openssl.capath=
; The libctx is an OpenSSL library context. OpenSSL defines a default library
; context, but PHP OpenSSL also defines its own library context to avoid
; interference with other libraries using OpenSSL and to provide an independent
; context for each thread in ZTS. Possible values:
; "custom" - use a custom library context (default)
; "default" - use the default OpenSSL library context
;openssl.libctx=custom
[ffi]
; FFI API restriction. Possible values:
; "preload" - enabled in CLI scripts and preloaded files (default)

View file

@ -1865,6 +1865,14 @@ ldap.max_links = -1
; SSL stream context option.
;openssl.capath=
; The libctx is an OpenSSL library context. OpenSSL defines a default library
; context, but PHP OpenSSL also defines its own library context to avoid
; interference with other libraries using OpenSSL and to provide an independent
; context for each thread in ZTS. Possible values:
; "custom" - use a custom library context (default)
; "default" - use the default OpenSSL library context
;openssl.libctx=custom
[ffi]
; FFI API restriction. Possible values:
; "preload" - enabled in CLI scripts and preloaded files (default)