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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
39 changes: 31 additions & 8 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,39 @@ 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
const char *name = ZSTR_VAL(new_value);

if (!strcmp(name, "default")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).default_libctx;
} else if (!strcmp(name, "custom")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).custom_libctx;
} else {
int err_type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used only when stage != ZEND_INI_STAGE_DEACTIVATE?

if (stage == ZEND_INI_STAGE_RUNTIME) {
err_type = E_WARNING;
} else {
err_type = E_ERROR;
}

/* Do not output error when restoring ini options. */
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
php_error_docref(NULL, err_type, "OpenSSL libctx \"%s\" cannot be found", name);
}
return FAILURE;
}
Comment on lines +356 to +376
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use the zend_string APIs which are clearer, and can also do some pointer comparisons if the strings are interned for any reason.

Suggested change
#if PHP_OPENSSL_API_VERSION >= 0x30000
const char *name = ZSTR_VAL(new_value);
if (!strcmp(name, "default")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).default_libctx;
} else if (!strcmp(name, "custom")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).custom_libctx;
} else {
int err_type;
if (stage == ZEND_INI_STAGE_RUNTIME) {
err_type = E_WARNING;
} else {
err_type = E_ERROR;
}
/* Do not output error when restoring ini options. */
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
php_error_docref(NULL, err_type, "OpenSSL libctx \"%s\" cannot be found", name);
}
return FAILURE;
}
#if PHP_OPENSSL_API_VERSION >= 0x30000
if (zend_string_equals(new_value, "default")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).default_libctx;
} else if (zend_string_equals(new_value, "custom")) {
OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).custom_libctx;
} else {
int err_type;
if (stage == ZEND_INI_STAGE_RUNTIME) {
err_type = E_WARNING;
} else {
err_type = E_ERROR;
}
/* Do not output error when restoring ini options. */
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
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)
Expand Down Expand Up @@ -438,9 +465,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);
}
/* }}} */

Expand All @@ -453,9 +478,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);
}
/* }}} */

Expand Down
10 changes: 10 additions & 0 deletions ext/openssl/openssl_backend_v1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
47 changes: 31 additions & 16 deletions ext/openssl/openssl_backend_v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
17 changes: 13 additions & 4 deletions ext/openssl/php_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 2 additions & 4 deletions ext/openssl/php_openssl_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 8 additions & 0 deletions php.ini-development
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions php.ini-production
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading