From 70c441966190774af550416c91a2b515a042b13f Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 30 Dec 2025 07:22:44 +0000 Subject: [PATCH 1/3] Fix GH-20802: undefined behavior with invalid SNI_server_certs options. --- ext/openssl/tests/gh20802.phpt | 63 ++++++++++++++++++++++++++++++++++ ext/openssl/xp_ssl.c | 21 +++++++----- 2 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 ext/openssl/tests/gh20802.phpt diff --git a/ext/openssl/tests/gh20802.phpt b/ext/openssl/tests/gh20802.phpt new file mode 100644 index 0000000000000..0a9fd68366e43 --- /dev/null +++ b/ext/openssl/tests/gh20802.phpt @@ -0,0 +1,63 @@ +--TEST-- +GH-20802: undefined behavior with invalid SNI_server_certs option values +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- + [ + 'local_cert' => '%s', + 'allow_self_signed' => true, + 'verify_peer_name' => false, + 'verify_peer' => false, + 'SNI_enabled' => true, + 'SNI_server_certs' => [ + 'localhost' => &$localhost, + ] + ] + ]); + $server = stream_socket_server('tls://127.0.0.1:12443', $errno, $errstr, $flags, $ctx); + phpt_notify_server_start($server); + stream_socket_accept($server, 3); +CODE; +$serverCode = sprintf($serverCode, $certFile); + +$clientCode = <<<'CODE' + $flags = STREAM_CLIENT_CONNECT; + +$ctx = stream_context_create([ + 'ssl' => [ + 'SNI_enabled' => true, + 'verify_peer_name' => false, + 'verify_peer' => false + ] + ]); + @stream_socket_client("tls://127.0.0.1:12443", $errno, $errstr, 1, $flags, $ctx); +CODE; + +include 'CertificateGenerator.inc'; +$certificateGenerator = new CertificateGenerator(); +$certificateGenerator->saveNewCertAsFileWithKey('gh20802-snioptions', $certFile); + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--CLEAN-- + +--EXPECTF-- +%a +PHP Warning: stream_socket_accept(): Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer in %s(%d) : eval()'d code on line %d +PHP Warning: stream_socket_accept(): Failed to enable crypto in %s(%d) : eval()'d code on line %d +PHP Warning: stream_socket_accept(): Accept failed: Cannot enable crypto in %s(%d) : eval()'d code on line %d diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index b576204b7d005..1cd4de907f9f6 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -1490,6 +1490,8 @@ static zend_result php_openssl_enable_server_sni( return FAILURE; } + ZVAL_DEREF(current); + if (Z_TYPE_P(current) == IS_ARRAY) { zval *local_pk, *local_cert; zend_string *local_pk_str, *local_cert_str; @@ -1544,16 +1546,17 @@ static zend_result php_openssl_enable_server_sni( zend_string_release(local_pk_str); ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff); - - } else if (php_openssl_check_path_str_ex( - Z_STR_P(current), resolved_path_buff, 0, false, false, - "SNI_server_certs in ssl stream context")) { - ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff); + } else if (Z_TYPE_P(current) == IS_STRING) { + if (php_openssl_check_path_str_ex(Z_STR_P(current), resolved_path_buff, 0, false, false, "SNI_server_certs in ssl stream context")) { + ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff); + } else { + php_error_docref(NULL, E_WARNING, + "Failed setting local cert chain file `%s'; file not found", + Z_STRVAL_P(current) + ); + } } else { - php_error_docref(NULL, E_WARNING, - "Failed setting local cert chain file `%s'; file not found", - Z_STRVAL_P(current) - ); + php_error_docref(NULL, E_WARNING, "SNI_server_certs options values must be of type array|string"); return FAILURE; } From 6cf63de1be4a5b8892fc8c545c015272023b09e8 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 30 Dec 2025 07:34:39 +0000 Subject: [PATCH 2/3] fix build --- ext/openssl/xp_ssl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 1cd4de907f9f6..60477094a1b63 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -1448,7 +1448,7 @@ static zend_result php_openssl_enable_server_sni( zend_ulong key_index; int i = 0; char resolved_path_buff[MAXPATHLEN]; - SSL_CTX *ctx; + SSL_CTX *ctx = NULL; /* If the stream ctx disables SNI we're finished here */ if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) { @@ -1557,7 +1557,6 @@ static zend_result php_openssl_enable_server_sni( } } else { php_error_docref(NULL, E_WARNING, "SNI_server_certs options values must be of type array|string"); - return FAILURE; } if (ctx == NULL) { From df087cdc0e0eca6936c3701469f724fb4b77b0b1 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 30 Dec 2025 07:49:51 +0000 Subject: [PATCH 3/3] old test local message --- ext/openssl/tests/gh20802.phpt | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/openssl/tests/gh20802.phpt b/ext/openssl/tests/gh20802.phpt index 0a9fd68366e43..786679c41c6a5 100644 --- a/ext/openssl/tests/gh20802.phpt +++ b/ext/openssl/tests/gh20802.phpt @@ -58,6 +58,5 @@ ServerClientTestCase::getInstance()->run($clientCode, $serverCode); ?> --EXPECTF-- %a -PHP Warning: stream_socket_accept(): Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer in %s(%d) : eval()'d code on line %d PHP Warning: stream_socket_accept(): Failed to enable crypto in %s(%d) : eval()'d code on line %d PHP Warning: stream_socket_accept(): Accept failed: Cannot enable crypto in %s(%d) : eval()'d code on line %d