How to set the list of trusted certificate authorities as a socket client in PHP?


Fabien Ménager

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

If I summarize my problem in this message : https://groups.google.com/d/msg/eu_connectathon/O-VGI_3cltw/ARsElA65ZkkJ

Edit : Sorry, Google Groups is not public, here is the message:

Hi Florian,

What is the exact meaning of the error message "The server requested a certificate, but the issuer list does not contain a valid certificate authority". Means the implementation of the TLS tool client has changed over the years, or am I using the wrong certificate?

This message means that the server has sent a certificate request message to the client without any value in the certificate_authorities field.

I ran into this issue last year and had a discussion with the developers of the TLS tool. He claims that if the server doesn't include this field, assuming you'll be connecting to multiple top-level affinity domains (each with its own CA), the client won't know what certificate to return.

It seems that OpenSSL can be instructed to return this value by calling SSL_CTX_set_client_CA_list, for example in DcmTLSTransportLayer::addTrustedCertificateFile. I haven't tested this with TLS tools, but I'd like this to be done before the connectathon starts.

But my implementation in PHP is different from theirs. It seems that PHP lacks the "SSL CTX set client CA list" possibility to tell the client which certificate authority should be used.

$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 "The server requested a certificate, but there is no valid certificate authority in the issuer list."

The message between client and server passes, but the test is not correct because the prompt message is "not secure enough".

Do you see the problem, are there more options for PHP that I don't see?

thank you for your help.

Edit : Following @ rdlowrey 's suggestion, I just created a bug report: https://bugs.php.net/bug.php?id=69215

Rodri

As I mentioned in my original comment:

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

This bug has been corrected upstream as described in the related bug report:

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

This change will manifest as soon as the PHP 5.6.8 binaries are released (or you can manually build PHP against current sources prior to that release).

implement

With the updated binaries, the OP's example code works as expected without modification. Simple example of encryption context used in server:

<?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 example above, PHP automatically used the name from the certificate found in the file referenced above my-ca-certs.pemwhen sending the client CA list as part of the TLS handshake .

notes

Peer name verification is not automatically enabled when peer verification is enabled in an encrypted server stream via "verify_peer" => truePHP . Unless you only want to allow a single certificate holder (with a specific known name) to access the server, this is exactly what you want. This default behavior supports the more common use case of allowing any client whose certificate is signed by a trusted CA to establish a connection to the server. However, if you wish to enforce name verification in the encrypted server, modify the above context example as follows:

<?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
]]);

Related


How to get a trusted SSL certificate?

substitute I want to secure my symfony2 application with https. I followed the instructions on how to create an SSL certificate and the SSL works fine, but Firefox says this page is not trusted. Same goes for Safari. How to get a trusted SSL certificate? Dextr

How to get a trusted SSL certificate?

substitute I want to secure my symfony2 application with https. I followed the instructions on how to create an SSL certificate and the SSL works fine, but Firefox says this page is not trusted. Same goes for Safari. How to get a trusted SSL certificate? Dextr

How to get a trusted SSL certificate?

substitute I want to secure my symfony2 application with https. I followed the instructions on how to create an SSL certificate and the SSL works fine, but Firefox says this page is not trusted. Same goes for Safari. How to get a trusted SSL certificate? Dextr

Where does Chrome get its list of certificate authorities from?

Laurent Kubasski On Fedora, I'm talking about the list that shows up when you go to Settings > Manage Certificates > Permissions tab. I've read that it should be in the NSS shared database, but this command returns an empty list: [laurent@localhost nssdb]$ cer

Where does Chrome get its list of certificate authorities from?

Laurent Kubasski On Fedora, I'm talking about the list that shows up when you go to Settings > Manage Certificates > Permissions tab. I've read that it should be in the NSS shared database, but this command returns an empty list: [laurent@localhost nssdb]$ cer

Where does Chrome get its list of certificate authorities from?

Laurent Kubasski On Fedora, I'm talking about the list that shows up when you go to Settings > Manage Certificates > Permissions tab. I've read that it should be in the NSS shared database, but this command returns an empty list: [laurent@localhost nssdb]$ cer

How to set pypi to be trusted?

light blue I am trying to use Python wheels. When I do that pip install wheel, it says there is a requirement, but I get this SSL error: (base) C:\Users\xxxx\PycharmProjects\prepay_clone>pip install wheel Requirement already satisfied: wheel in c:\programdata\

How to set pypi to be trusted?

light blue I am trying to use Python wheels. When I do that pip install wheel, it says there is a requirement, but I get this SSL error: (base) C:\Users\xxxx\PycharmProjects\prepay_clone>pip install wheel Requirement already satisfied: wheel in c:\programdata\

How to set pypi to be trusted?

light blue I am trying to use Python wheels. When I do that pip install wheel, it says there is a requirement, but I get this SSL error: (base) C:\Users\xxxx\PycharmProjects\prepay_clone>pip install wheel Requirement already satisfied: wheel in c:\programdata\

How to set pypi to be trusted?

light blue I am trying to use Python wheels. When I do that pip install wheel, it says there is a requirement, but I get this SSL error: (base) C:\Users\xxxx\PycharmProjects\prepay_clone>pip install wheel Requirement already satisfied: wheel in c:\programdata\