[PHP-CVS] [php-src] master: openssl: Check return value of SSL_CTX_set_alpn_protos() (#22996)
[email protected] (Nora Dossche via GitHub) Mon, 3 Aug 2026 20:53:55 +0000
| Newsgroups | php.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Nora Dossche (ndossche)
Committer: GitHub (web-flow)
Pusher: ndossche
Date: 2026-08-03T22:53:52+02:00
Commit: https://github.com/php/php-src/commit/8fb6827df784cdc054a7f39484536e3df60cd479
Raw diff: https://github.com/php/php-src/commit/8fb6827df784cdc054a7f39484536e3df60cd479.diff
openssl: Check return value of SSL_CTX_set_alpn_protos() (#22996)
Discovered by ESSS.
Changed paths:
A ext/openssl/tests/alpn_protocols_invalid.phpt
M ext/openssl/xp_ssl.c
Diff:
diff --git a/ext/openssl/tests/alpn_protocols_invalid.phpt b/ext/openssl/tests/alpn_protocols_invalid.phpt
new file mode 100644
index 000000000000..b440af9ad74b
--- /dev/null
+++ b/ext/openssl/tests/alpn_protocols_invalid.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Setting an invalid TLS ALPN protocol list on a client stream fails
+--EXTENSIONS--
+openssl
+--SKIPIF--
+<?php
+if (OPENSSL_VERSION_NUMBER < 0x30000000) die('skip For OpenSSL >= 3.0');
+?>
+--FILE--
+<?php
+$server = stream_socket_server('tcp://127.0.0.1:0', $errno, $errstr);
+$address = stream_socket_get_name($server, false);
+
+function try_alpn($protocols, $streamOptions): void {
+ global $address;
+
+ $context = stream_context_create([
+ 'ssl' => ['alpn_protocols' => $protocols, 'verify_peer' => false],
+ 'stream' => $streamOptions,
+ ]);
+ $client = stream_socket_client("tcp://$address", $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $context);
+ var_dump(stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_CLIENT));
+ fclose($client);
+}
+
+foreach (['', ',', 'h2,', ',h2', 'h2,,http/1.1'] as $protocols) {
+ try_alpn($protocols, []);
+}
+
+try_alpn('', [
+ 'error_mode' => StreamErrorMode::Silent,
+ 'error_store' => StreamErrorStore::All,
+]);
+foreach (stream_last_errors() as $error) {
+ var_dump($error->code, $error->message);
+}
+?>
+--EXPECTF--
+Warning: stream_socket_enable_crypto(): Failed setting TLS ALPN protocols, protocol names must not be empty in %s on line %d
+bool(false)
+
+Warning: stream_socket_enable_crypto(): Failed setting TLS ALPN protocols, protocol names must not be empty in %s on line %d
+bool(false)
+
+Warning: stream_socket_enable_crypto(): Failed setting TLS ALPN protocols, protocol names must not be empty in %s on line %d
+bool(false)
+
+Warning: stream_socket_enable_crypto(): Failed setting TLS ALPN protocols, protocol names must not be empty in %s on line %d
+bool(false)
+
+Warning: stream_socket_enable_crypto(): Failed setting TLS ALPN protocols, protocol names must not be empty in %s on line %d
+bool(false)
+bool(false)
+enum(StreamErrorCode::DecodingFailed)
+string(67) "Failed setting TLS ALPN protocols, protocol names must not be empty"
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index a8105a15c43b..130d3717ccc9 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -2654,7 +2654,13 @@ static zend_result php_openssl_create_server_ctx(php_stream *stream,
return FAILURE;
}
if (sslsock->is_client) {
- SSL_CTX_set_alpn_protos(sslsock->ctx, alpn, alpn_len);
+ if (SSL_CTX_set_alpn_protos(sslsock->ctx, alpn, alpn_len)) {
+ php_stream_warn(stream, DecodingFailed, "Failed setting TLS ALPN protocols, protocol names must not be empty");
+ efree(alpn);
+ SSL_CTX_free(sslsock->ctx);
+ sslsock->ctx = NULL;
+ return FAILURE;
+ }
} else {
sslsock->alpn_ctx.data = (unsigned char *) pestrndup((const char*)alpn, alpn_len, php_stream_is_persistent(stream));
sslsock->alpn_ctx.len = alpn_len;