简体   繁体   中英

How to set trusted certificate authorities list to socket client in PHP?

In the context of the IHE Connectathon, I want to make a raw socket server responsing to the ATNA profile, which requires TLS sockets with both ends certificates.

My issue if summed up in this message : https://groups.google.com/d/msg/eu_connectathon/O-VGI_3cltw/ARsElA65ZkkJ

Edit : Sorry, the Google Groups isn't public, here is the message :

Hi Florian,

What exactly does the error message "Server asked for a certificate, but list of issuers doesn't contain valid certificate authority." mean and did the implementation of the TLS Tools Client change during the last years, or am I using the wrong certificates?

The message means that the server has sent the CertificateRequest message to the clienmt with no values in the certificate_authorities field.

I ran into this problem last year and discussed this with a developer of the TLS Tools. He claimed that if a server didn't include this field, the client wouldn't have a clue what kind of certificate to return, assuming a scenario where you would connect top multiple affinity domains, each with their own CA.

It appears that you can instruct OpenSSL to return this value by calling SSL_CTX_set_client_CA_list, eg in DcmTLSTransportLayer::addTrustedCertificateFile. I haven't tested this with the TLS tools yet, but I hope to accomplish that before the connectathon starts.

But my implementation, in PHP, is not the same as their's. It looks like PHP is missing the "SSL CTX set client CA list" possibility, to tell the client which certificate authority it should use.

$context = stream_context_create();

if ($certificate) {
  // Server certificate + private key
  stream_context_set_option($context, 'ssl', 'local_cert', "/path/to/server.pem"); 
  stream_context_set_option($context, 'ssl', 'passphrase', $passphrase); 

  // Client public certificates
  stream_context_set_option($context, 'ssl', 'cafile', "/path/to/ca.pem");

  stream_context_set_option($context, 'ssl', 'allow_self_signed', false);
  stream_context_set_option($context, 'ssl', 'verify_peer', true);
  stream_context_set_option($context, 'ssl', 'peer_name', "TlsTools2");
  stream_context_set_option($context, 'ssl', 'capture_peer_cert', true);
  stream_context_set_option($context, 'ssl', 'capture_peer_cert_chain', true);
}

$this->__socket = @stream_socket_server("tcp://$address:$port", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);

The IHE Gazelle TLS client tells me "Server asked for a certificate, but list of issuers doesn't contain valid certificate authority."

The messages between client and server pass, but the test is not OK, as "not enough secure", as tells the message.

Do you see a problem, and does PHP have more options I didn't see ?

Thanks for your help.

Edit : As @rdlowrey suggested me, I just created a bug report : https://bugs.php.net/bug.php?id=69215

As I mentioned in the initial comment:

PHP's stream server implementation has never actually used SSL_CTX_set_client_CA_list() for encrypted streams.

This has been corrected upstream as referenced in the associated bug report:

https://bugs.php.net/bug.php?id=69215

This change will be reflected once the PHP 5.6.8 binary is released (or you can build PHP manually against the current source prior to that release).

Implementation

Using an updated binary the OP's example code will work as expected without modification. A simple example of a crypto context to use in servers:

<?php
$serverCtx = stream_context_create(['ssl' => [
    'local_cert' => '/path/to/my-server-cert.pem',
    'passphrase' => 'elephpant',
    'cafile' => '/path/to/my-ca-certs.pem',
    'verify_peer' => true
]]);

In the above example PHP automatically uses the names from certs found in the my-ca-certs.pem file referenced above when sending the client CA list as part of the TLS handshake.

Notes

When enabling peer verification in encrypted server streams via "verify_peer" => true PHP will not automatically enable peer name verification. Unless you only wish to allow a single certificate holder (with a specific known name) access to your server this is exactly what you want. This default behavior supports the more common use-case of allowing any client whose certificate was signed by a trusted CA to establish connections to your server. However, if you wish to enforce name verification in an encrypted server modify the above context example as shown here:

<?php
$serverCtx = stream_context_create(['ssl' => [
    'local_cert' => '/path/to/my-server-cert.pem',
    'passphrase' => 'elephpant',
    'cafile' => '/path/to/my-ca-certs.pem',
    'verify_peer' => true,
    'verify_peer_name' => true, // verify the name on the cert
    'peer_name' => 'zanzibar' // ensure the cert's name matches this
]]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM