简体   繁体   English

如何在PHP中将受信任的证书颁发机构列表设置为socket客户端?

[英]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. 在IHE Con​​nectathon的上下文中,我想创建一个响应ATNA配置文件的原始套接字服务器,它需要具有两端证书的TLS套接字。

My issue if summed up in this message : https://groups.google.com/d/msg/eu_connectathon/O-VGI_3cltw/ARsElA65ZkkJ 如果在此消息中总结我的问题: https//groups.google.com/d/msg/eu_connectathon/O-VGI_3cltw/ARsElA65ZkkJ

Edit : Sorry, the Google Groups isn't public, here is the message : 编辑 :对不起,Google网上论坛不公开,以下是留言:

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? 是指并且在过去几年中TLS工具客户端的实施发生了变化,还是我使用了错误的证书?

The message means that the server has sent the CertificateRequest message to the clienmt with no values in the certificate_authorities field. 该消息表示服务器已将CertificateRequest消息发送到clienmt,而certificate_authorities字段中没有值。

I ran into this problem last year and discussed this with a developer of the TLS Tools. 我去年遇到了这个问题,并与TLS工具的开发人员讨论过这个问题。 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. 他声称,如果服务器不包含此字段,客户端将无法确定要返回哪种类型的证书,假设您将连接顶部多个关联域,每个域都有自己的CA.

It appears that you can instruct OpenSSL to return this value by calling SSL_CTX_set_client_CA_list, eg in DcmTLSTransportLayer::addTrustedCertificateFile. 您似乎可以通过调用SSL_CTX_set_client_CA_list来指示OpenSSL返回此值,例如在DcmTLSTransportLayer :: addTrustedCertificateFile中。 I haven't tested this with the TLS tools yet, but I hope to accomplish that before the connectathon starts. 我还没有使用TLS工具测试过这个,但我希望在connectathon启动之前完成它。

But my implementation, in PHP, is not the same as their's. 但是我在PHP中的实现与它们的实现并不相同。 It looks like PHP is missing the "SSL CTX set client CA list" possibility, to tell the client which certificate authority it should use. 看起来PHP缺少“SSL CTX设置客户端CA列表”的可能性,告诉客户端它应该使用哪个证书颁发机构。

$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." IHE Gazelle TLS客户端告诉我“服务器要求提供证书,但发布者列表不包含有效的证书颁发机构。”

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 ? 你看到了一个问题吗?PHP有没有我没看到的更多选项?

Thanks for your help. 谢谢你的帮助。

Edit : As @rdlowrey suggested me, I just created a bug report : https://bugs.php.net/bug.php?id=69215 编辑 :正如@rdlowrey建议我,我刚刚创建了一个错误报告: 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. PHP的流服务器实现从未实际使用SSL_CTX_set_client_CA_list()来加密流。

This has been corrected upstream as referenced in the associated bug report: 这已在相关错误报告中引用的上游更正:

https://bugs.php.net/bug.php?id=69215 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). 一旦发布了PHP 5.6.8二进制文件(或者您可以在该版本之前针对当前源手动构建PHP),将反映此更改。

Implementation 履行

Using an updated binary the OP's example code will work as expected without modification. 使用更新的二进制文件,OP的示例代码将按预期工作而无需修改。 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. 在上面的示例中,当作为TLS握手的一部分发送客户端CA列表时,PHP会自动使用my-ca-certs.pemmy-ca-certs.pem文件中的证书名称。

Notes 笔记

When enabling peer verification in encrypted server streams via "verify_peer" => true PHP will not automatically enable peer name verification. 通过"verify_peer" => true启用加密服务器流中的对等验证时,PHP将不会自动启用对等名称验证。 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. 此默认行为支持更常见的用例,即允许其证书由可信CA签名的任何客户端建立与服务器的连接。 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
]]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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