Skip to content

Commit de062fe

Browse files
committed
ext/openssl: Match IPv6 IPADDR SAN when connecting to bracketed URI
php_openssl_get_url_name() returns NULL for resourcenames of the form "[::1]:port" because php_url_parse_ex() cannot extract a host from a bracketed hostport when no scheme is present. With url_name unset, the SAN matcher falls back to peer_name which is also unset under default client config, so verify_peer_name silently rejects every IPv6 literal target even when the cert carries the matching IPADDR SAN entry. Handle the bare "[host]:port" form before php_url_parse_ex() and strip surrounding brackets on the parse path for callers that pass a full "ssl://[::1]:port" URL. The SAN matcher's inet_pton(AF_INET6, ...) call now sees "::1" instead of "[::1]" and the 16-byte IPADDR SAN comparison body runs.
1 parent 05afc37 commit de062fe

2 files changed

Lines changed: 76 additions & 0 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
--TEST--
2+
Peer verification matches an IPADDR SAN when connecting to a bracketed IPv6 URI
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (!function_exists("proc_open")) die("skip no proc_open");
8+
$probe = @stream_socket_server("tcp://[::1]:0", $errno, $errstr);
9+
if (!$probe) die("skip IPv6 loopback not available");
10+
fclose($probe);
11+
?>
12+
--FILE--
13+
<?php
14+
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'peer_verification_ipv6_san.pem.tmp';
15+
$cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'peer_verification_ipv6_san-ca.pem.tmp';
16+
17+
$serverCode = <<<'CODE'
18+
$serverUri = "ssl://[::1]:0";
19+
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
20+
$serverCtx = stream_context_create(['ssl' => [
21+
'local_cert' => '%s'
22+
]]);
23+
24+
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
25+
phpt_notify_server_start($server);
26+
27+
$client = @stream_socket_accept($server, 3);
28+
if ($client) {
29+
fwrite($client, "HELLO\n");
30+
}
31+
CODE;
32+
$serverCode = sprintf($serverCode, $certFile);
33+
34+
$clientCode = <<<'CODE'
35+
$serverUri = "ssl://{{ ADDR }}";
36+
$clientFlags = STREAM_CLIENT_CONNECT;
37+
$clientCtx = stream_context_create(['ssl' => [
38+
'cafile' => '%s',
39+
]]);
40+
41+
$client = @stream_socket_client($serverUri, $errno, $errstr, 3, $clientFlags, $clientCtx);
42+
if (!$client) {
43+
echo "connect failed: $errstr\n";
44+
return;
45+
}
46+
echo trim(fread($client, 16)), "\n";
47+
CODE;
48+
$clientCode = sprintf($clientCode, $cacertFile);
49+
50+
include 'CertificateGenerator.inc';
51+
$certificateGenerator = new CertificateGenerator();
52+
$certificateGenerator->saveCaCert($cacertFile);
53+
$certificateGenerator->saveNewCertAsFileWithKey('ipv6-san', $certFile, null, 'IP:::1');
54+
55+
include 'ServerClientTestCase.inc';
56+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
57+
?>
58+
--CLEAN--
59+
<?php
60+
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'peer_verification_ipv6_san.pem.tmp');
61+
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'peer_verification_ipv6_san-ca.pem.tmp');
62+
?>
63+
--EXPECT--
64+
HELLO

ext/openssl/xp_ssl.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,6 +2760,13 @@ static char *php_openssl_get_url_name(const char *resourcename,
27602760
return NULL;
27612761
}
27622762

2763+
if (resourcenamelen >= 2 && resourcename[0] == '[') {
2764+
const char *end = memchr(resourcename, ']', resourcenamelen);
2765+
if (end != NULL && end > resourcename + 1) {
2766+
return pestrndup(resourcename + 1, end - resourcename - 1, is_persistent);
2767+
}
2768+
}
2769+
27632770
url = php_url_parse_ex(resourcename, resourcenamelen);
27642771
if (!url) {
27652772
return NULL;
@@ -2775,6 +2782,11 @@ static char *php_openssl_get_url_name(const char *resourcename,
27752782
--len;
27762783
}
27772784

2785+
if (len >= 2 && host[0] == '[' && host[len-1] == ']') {
2786+
host += 1;
2787+
len -= 2;
2788+
}
2789+
27782790
if (len) {
27792791
url_name = pestrndup(host, len, is_persistent);
27802792
}

0 commit comments

Comments
 (0)