Skip to content

Introduce OpenSSL INI for selecting libctx #18768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
@@ -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);
}
/* }}} */

10 changes: 10 additions & 0 deletions ext/openssl/openssl_backend_v1.c
Original file line number Diff line number Diff line change
@@ -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);
47 changes: 31 additions & 16 deletions ext/openssl/openssl_backend_v3.c
Original file line number Diff line number Diff line change
@@ -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);
17 changes: 13 additions & 4 deletions ext/openssl/php_openssl.h
Original file line number Diff line number Diff line change
@@ -70,15 +70,24 @@ struct php_openssl_errors {
int bottom;
};

ZEND_BEGIN_MODULE_GLOBALS(openssl)
struct php_openssl_errors *errors;
struct php_openssl_errors *errors_mark;
struct php_openssl_libctx {
#if PHP_OPENSSL_API_VERSION >= 0x30000
OSSL_LIB_CTX *libctx;
char *propq;
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;
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)
6 changes: 2 additions & 4 deletions ext/openssl/php_openssl_backend.h
Original file line number Diff line number Diff line change
@@ -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);

8 changes: 8 additions & 0 deletions php.ini-development
Original file line number Diff line number Diff line change
@@ -1857,6 +1857,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)
8 changes: 8 additions & 0 deletions php.ini-production
Original file line number Diff line number Diff line change
@@ -1859,6 +1859,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)