Skip to content

Commit 8c4f806

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Fix phpGH-20802: undefined behavior with invalid SNI_server_certs options.
2 parents e49be5f + b6a3852 commit 8c4f806

File tree

2 files changed

+75
-11
lines changed

2 files changed

+75
-11
lines changed

ext/openssl/tests/gh20802.phpt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
GH-20802: undefined behavior with invalid SNI_server_certs option values
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (!function_exists("proc_open")) die("skip no proc_open");
8+
?>
9+
--FILE--
10+
<?php
11+
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'gh20802.pem.tmp';
12+
$serverCode = <<<'CODE'
13+
class A {};
14+
$localhost = new A();
15+
ini_set('log_errors', 'On');
16+
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
17+
$ctx = stream_context_create([
18+
'ssl' => [
19+
'local_cert' => '%s',
20+
'allow_self_signed' => true,
21+
'verify_peer_name' => false,
22+
'verify_peer' => false,
23+
'SNI_enabled' => true,
24+
'SNI_server_certs' => [
25+
'localhost' => &$localhost,
26+
]
27+
]
28+
]);
29+
$server = stream_socket_server('tls://127.0.0.1:12443', $errno, $errstr, $flags, $ctx);
30+
phpt_notify_server_start($server);
31+
stream_socket_accept($server, 3);
32+
CODE;
33+
$serverCode = sprintf($serverCode, $certFile);
34+
35+
$clientCode = <<<'CODE'
36+
$flags = STREAM_CLIENT_CONNECT;
37+
38+
$ctx = stream_context_create([
39+
'ssl' => [
40+
'SNI_enabled' => true,
41+
'verify_peer_name' => false,
42+
'verify_peer' => false
43+
]
44+
]);
45+
@stream_socket_client("tls://127.0.0.1:12443", $errno, $errstr, 1, $flags, $ctx);
46+
CODE;
47+
48+
include 'CertificateGenerator.inc';
49+
$certificateGenerator = new CertificateGenerator();
50+
$certificateGenerator->saveNewCertAsFileWithKey('gh20802-snioptions', $certFile);
51+
52+
include 'ServerClientTestCase.inc';
53+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
54+
?>
55+
--CLEAN--
56+
<?php
57+
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'gh20802.pem.tmp');
58+
?>
59+
--EXPECTF--
60+
%a
61+
PHP Warning: stream_socket_accept(): Failed to enable crypto in %s(%d) : eval()'d code on line %d
62+
PHP Warning: stream_socket_accept(): Accept failed: Cannot enable crypto in %s(%d) : eval()'d code on line %d

ext/openssl/xp_ssl.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,7 +1335,7 @@ static zend_result php_openssl_enable_server_sni(
13351335
zend_ulong key_index;
13361336
int i = 0;
13371337
char resolved_path_buff[MAXPATHLEN];
1338-
SSL_CTX *ctx;
1338+
SSL_CTX *ctx = NULL;
13391339

13401340
/* If the stream ctx disables SNI we're finished here */
13411341
if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) {
@@ -1377,6 +1377,8 @@ static zend_result php_openssl_enable_server_sni(
13771377
return FAILURE;
13781378
}
13791379

1380+
ZVAL_DEREF(current);
1381+
13801382
if (Z_TYPE_P(current) == IS_ARRAY) {
13811383
zval *local_pk, *local_cert;
13821384
zend_string *local_pk_str, *local_cert_str;
@@ -1431,17 +1433,17 @@ static zend_result php_openssl_enable_server_sni(
14311433
zend_string_release(local_pk_str);
14321434

14331435
ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff);
1434-
1435-
} else if (php_openssl_check_path_str_ex(
1436-
Z_STR_P(current), resolved_path_buff, 0, false, false,
1437-
"SNI_server_certs in ssl stream context")) {
1438-
ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff);
1436+
} else if (Z_TYPE_P(current) == IS_STRING) {
1437+
if (php_openssl_check_path_str_ex(Z_STR_P(current), resolved_path_buff, 0, false, false, "SNI_server_certs in ssl stream context")) {
1438+
ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff);
1439+
} else {
1440+
php_error_docref(NULL, E_WARNING,
1441+
"Failed setting local cert chain file `%s'; file not found",
1442+
Z_STRVAL_P(current)
1443+
);
1444+
}
14391445
} else {
1440-
php_error_docref(NULL, E_WARNING,
1441-
"Failed setting local cert chain file `%s'; file not found",
1442-
Z_STRVAL_P(current)
1443-
);
1444-
return FAILURE;
1446+
php_error_docref(NULL, E_WARNING, "SNI_server_certs options values must be of type array|string");
14451447
}
14461448

14471449
if (ctx == NULL) {

0 commit comments

Comments
 (0)