Bug #80770 [Com]: It is not possible to get client peer certificate with stream_socket_server
| From: | mcmic@php.net | Date: | Thu, 18 Feb 2021 16:32:21 +0000 |
| Subject: | Bug #80770 [Com]: It is not possible to get client peer certificate with stream_socket_server | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-232261@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=80770&edit=1
ID: 80770
Comment by: mcmic@php.net
Reported by: mcmic@php.net
Summary: It is not possible to get client peer certificate
with stream_socket_server
Status: Open
Type: Bug
Package: OpenSSL related
PHP Version: 7.3.27
Block user comment: N
Private report: N
New Comment:
@daverandom:
The test you linked to is about getting the server certificate from the client, I want the other way
around, get the client certificate from the server.
And without making the client certificate mandatory, I still need to accept certificate-less
requests.
Previous Comments:
------------------------------------------------------------------------
[2021-02-18 16:26:58] daverandom@php.net
Ah no I think I see the problem, you need to pass $context instead of $conn to
stream_context_get_options()
------------------------------------------------------------------------
[2021-02-18 16:26:04] daverandom@php.net
Note that there is a test for this behaviour which is not marked as XFAIL, so I believe this
functionality should work - although I cannot immediately see an issue with your sample code
https://heap.space/xref/php-src/ext/openssl/tests/capture_peer_cert_001.phpt?r=1fab01be#38
------------------------------------------------------------------------
[2021-02-18 16:11:25] mcmic@php.net
Description:
------------
It is not possible to get the client certificate when accepting TLS connections, without forcing the
client to provide a (valid) certificate.
This forbids writing a fully compliant Gemini server in PHP, because it is not possible to accept
client certificates without forcing them on all pages.
See https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
Test script:
---------------
$context = stream_context_create(
[
'ssl' => [
'allow_self_signed' => true,
'SNI_enabled' => true,
'SNI_server_certs' => ['example.com' =>
'/path/to/cert.pem'],
'capture_peer_cert' => true,
]
]
);
$socket = stream_socket_server(
'tcp://[::]:' . $port,
$errno,
$errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
$context,
);
if ($socket === false) {
throw new \Exception($errstr, $errno);
} else {
while ($conn = stream_socket_accept($socket, -1, $peername)) {
$tlsSuccess = stream_socket_enable_crypto(
$conn,
true,
STREAM_CRYPTO_METHOD_TLS_SERVER
);
if ($tlsSuccess !== true) {
fclose($conn);
continue;
}
var_dump(stream_context_get_options($conn));
}
}
Expected result:
----------------
Have the client certificate in 'peer_certificate' key of $conn, if the client sends one.
Actual result:
--------------
No 'peer_certificate' option.
If I set 'verify_peer' to true, it works, but then it is not possible for a client to
connect without a certificate.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=80770&edit=1