From 1a3bb102967c011f058782f38a107597ff0180be Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 25 Jul 2025 14:54:34 +0200 Subject: [PATCH] Integrate OpenSSL libctx to pwhash This allows using OpenSSL Argon2 password hashing on ZTS. Closes GH-19236 --- ext/openssl/config0.m4 | 3 --- ext/openssl/openssl.c | 8 +++++++ ext/openssl/openssl_pwhash.c | 13 ++++++----- .../tests/openssl_libctx_with_zts_argon.phpt | 22 +++++++++++++++++++ .../openssl_libctx_without_zts_argon.phpt | 18 +++++++++++++++ 5 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 ext/openssl/tests/openssl_libctx_with_zts_argon.phpt create mode 100644 ext/openssl/tests/openssl_libctx_without_zts_argon.phpt diff --git a/ext/openssl/config0.m4 b/ext/openssl/config0.m4 index 774213336b6ee..15d1feb96eeab 100644 --- a/ext/openssl/config0.m4 +++ b/ext/openssl/config0.m4 @@ -49,9 +49,6 @@ if test "$PHP_OPENSSL" != "no"; then the default provider.])]) AS_VAR_IF([PHP_OPENSSL_ARGON2], [no],, [ - AS_VAR_IF([PHP_THREAD_SAFETY], [yes], - [AC_MSG_ERROR([Not supported in ZTS mode for now])]) - PHP_CHECK_LIBRARY([crypto], [OSSL_set_max_threads], [AC_DEFINE([HAVE_OPENSSL_ARGON2], [1], [Define to 1 to enable OpenSSL argon2 password hashing.])], diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 04879d1a51635..2f9e160b57e58 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -355,7 +355,15 @@ static PHP_INI_MH(OnUpdateLibCtx) { #if PHP_OPENSSL_API_VERSION >= 0x30000 if (zend_string_equals_literal(new_value, "default")) { +#if defined(ZTS) && defined(HAVE_OPENSSL_ARGON2) + 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 \"default\" cannot be used in this configuration"); + } + return FAILURE; +#else OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).default_libctx; +#endif } else if (zend_string_equals_literal(new_value, "custom")) { OPENSSL_G(ctx).libctx = OPENSSL_G(ctx).custom_libctx; } else { diff --git a/ext/openssl/openssl_pwhash.c b/ext/openssl/openssl_pwhash.c index 5fe5bb5cf1bba..dc125e3b516db 100644 --- a/ext/openssl/openssl_pwhash.c +++ b/ext/openssl/openssl_pwhash.c @@ -22,7 +22,7 @@ #include "ext/standard/php_password.h" #include "php_openssl.h" -#if defined(HAVE_OPENSSL_ARGON2) +#ifdef HAVE_OPENSSL_ARGON2 #include "Zend/zend_attributes.h" #include "openssl_pwhash_arginfo.h" #include @@ -46,6 +46,8 @@ #define PHP_OPENSSL_HASH_SIZE 32 #define PHP_OPENSSL_DIGEST_SIZE 128 +ZEND_EXTERN_MODULE_GLOBALS(openssl) + static inline zend_result get_options(zend_array *options, uint32_t *memlimit, uint32_t *iterlimit, uint32_t *threads) { zval *opt; @@ -98,8 +100,8 @@ static bool php_openssl_argon2_compute_hash( uint32_t oldthreads; bool ret = false; - oldthreads = OSSL_get_max_threads(NULL); - if (OSSL_set_max_threads(NULL, threads) != 1) { + oldthreads = OSSL_get_max_threads(PHP_OPENSSL_LIBCTX); + if (OSSL_set_max_threads(PHP_OPENSSL_LIBCTX, threads) != 1) { goto fail; } p = params; @@ -111,7 +113,7 @@ static bool php_openssl_argon2_compute_hash( *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, (void *)pass, pass_len); *p++ = OSSL_PARAM_construct_end(); - if ((kdf = EVP_KDF_fetch(NULL, algo, NULL)) == NULL) { + if ((kdf = EVP_KDF_fetch(PHP_OPENSSL_LIBCTX, algo, PHP_OPENSSL_PROPQ)) == NULL) { goto fail; } if ((kctx = EVP_KDF_CTX_new(kdf)) == NULL) { @@ -127,7 +129,7 @@ static bool php_openssl_argon2_compute_hash( fail: EVP_KDF_free(kdf); EVP_KDF_CTX_free(kctx); - OSSL_set_max_threads(NULL, oldthreads); + OSSL_set_max_threads(PHP_OPENSSL_LIBCTX, oldthreads); return ret; } @@ -385,4 +387,5 @@ PHP_MINIT_FUNCTION(openssl_pwhash) return SUCCESS; } + #endif /* HAVE_OPENSSL_ARGON2 */ diff --git a/ext/openssl/tests/openssl_libctx_with_zts_argon.phpt b/ext/openssl/tests/openssl_libctx_with_zts_argon.phpt new file mode 100644 index 0000000000000..13efcaa26b60b --- /dev/null +++ b/ext/openssl/tests/openssl_libctx_with_zts_argon.phpt @@ -0,0 +1,22 @@ +--TEST-- +openssl.libctx INI setting when Argon2 enabled and ZTS used +--EXTENSIONS-- +openssl +--INI-- +openssl.libctx = default +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Fatal error: PHP Startup: OpenSSL libctx "default" cannot be used in this configuration in Unknown on line 0 +string(6) "custom" diff --git a/ext/openssl/tests/openssl_libctx_without_zts_argon.phpt b/ext/openssl/tests/openssl_libctx_without_zts_argon.phpt new file mode 100644 index 0000000000000..f2fd64b7469d2 --- /dev/null +++ b/ext/openssl/tests/openssl_libctx_without_zts_argon.phpt @@ -0,0 +1,18 @@ +--TEST-- +openssl.libctx INI setting when Argon2 disable or ZTS not used +--EXTENSIONS-- +openssl +--INI-- +openssl.libctx = default +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(7) "default"