SSL/TLS 握手错误,使用 PHP 中的 stream_socket_client 时出现“证书无效”。

huangapple go评论147阅读模式
英文:

SSL/TLS Handshake Error "bad certificate" when using stream_socket_client in PHP

问题

我在尝试使用PHP中的stream_socket_client建立安全连接时遇到了SSL/TLS握手错误,错误消息是"bad certificate"。目标是将我们的PHP应用程序与要求SSL/TLS加密的外部服务集成。

以下是相关的代码片段:

  1. private function createSocketConnection($host, $port)
  2. {
  3. // 客户端证书和私钥的路径
  4. // $localCertificateFile = '/var/www/sslcert/suezpublic.crt';
  5. // $privateKeyFile = '/var/www/sslcert/privatekesy.pem';
  6. // 使用客户端证书创建安全的SSL/TLS上下文
  7. $contextOptions = [
  8. 'ssl' => [
  9. 'local_cert' => '/var/www/sslcert/suezcombined.pem',
  10. // 'local_pk' => '/var/www/sslcert/privatekesy.pem',
  11. 'cafile' => '/var/www/sslcert/bizswitch.pem', // GoDaddy Intermediate证书或您的CA证书
  12. 'verify_peer' => true, // 启用对等证书验证
  13. 'verify_peer_name' => true, // 检查通用名称是否存在且与主机名匹配
  14. 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, // 使用TLSv1.2
  15. // 'crypto_timeout' => 30, // 将握手超时增加到30秒
  16. 'CN_match' => 'www.suezelectric.com', // 确保通用名称与服务器的主机名匹配
  17. 'ciphers' => 'HIGH:!SSLv2:!SSLv3', // 指定允许的密码套件以确保安全性
  18. 'disable_compression' => true, // 为了安全性禁用SSL/TLS压缩
  19. 'capture_peer_cert' => true,
  20. 'capture_peer_chain' => true,
  21. // 'allow_self_signed' => true,
  22. 'debug' => true, // 启用SSL调试
  23. ],
  24. ];
  25. $context = stream_context_create($contextOptions);
  26. // 创建TCP/IP套接字连接
  27. $socket = stream_socket_client("tls://$host:$port", $errno, $errstr, 30);
  28. if ($socket === false) {
  29. throw new Exception("Failed to create socket: [$errno] $errstr");
  30. }
  31. // 在流上启用SSL/TLS
  32. $secured = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
  33. if ($secured === false) {
  34. throw an Exception("Failed to enable SSL/TLS on the socket");
  35. }
  36. return $socket;
  37. // 现在您可以使用$socket与服务器使用SSL/TLS发送/接收数据
  38. // 例如,您可以使用fwrite($socket, $data)将数据发送到服务器。
  39. }

我已经验证了以下内容:

  • 客户端证书(public_cert.crt)和私钥(private_key.pem)是有效的,并正确匹配。
  • CA证书(server_cert.pem)已提供,并包含必要的中间证书。
  • STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT和'ciphers'设置与服务器的配置兼容。

有趣的是,当服务器管理员在服务器端禁用身份验证时,SSL/TLS握手成功完成。但是,当启用身份验证时,会出现"bad certificate"错误,并且还注意到服务器收到了空的证书链。

我已经尝试使用error_log进行调试,并验证了证书文件的路径是正确的。

在我的SSL/TLS配置中是否有任何遗漏或在使用PHP中的stream_socket_client时可能导致此错误的潜在陷阱?对于这个问题的任何指导或见解将不胜感激。谢谢!

英文:

I am encountering an SSL/TLS handshake error with the message "bad certificate" while attempting to establish a secure connection using stream_socket_client in PHP. The goal is to integrate our PHP application with an external service that requires SSL/TLS encryption.

Here is the relevant code snippet:

  1. private function createSocketConnection($host, $port)
  2. {
  3. // Path to the client certificate and private key
  4. // $localCertificateFile = '/var/www/sslcert/suezpublic.crt';
  5. // $privateKeyFile = '/var/www/sslcert/privatekesy.pem';
  6. // Create a secure SSL/TLS context with client certificates
  7. $contextOptions = [
  8. 'ssl' => [
  9. 'local_cert' => '/var/www/sslcert/suezcombined.pem',
  10. // 'local_pk' => '/var/www/sslcert/privatekesy.pem',
  11. 'cafile' => '/var/www/sslcert/bizswitch.pem', // GoDaddy Intermediate certificate or your CA certificate
  12. 'verify_peer' => true, // Enable peer certificate verification
  13. 'verify_peer_name' => true, // Check that the common name exists and matches the host name
  14. 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, // Use TLSv1.2
  15. // 'crypto_timeout' => 30, // Increase the handshake timeout to 30 seconds
  16. 'CN_match' => 'www.suezelectric.com', // Ensure the common name matches the server's hostname
  17. 'ciphers' => 'HIGH:!SSLv2:!SSLv3', // Specify allowed ciphers for security
  18. 'disable_compression' => true, // Disable SSL/TLS compression for security
  19. 'capture_peer_cert' => true,
  20. 'capture_peer_chain' => true,
  21. // 'allow_self_signed' => true,
  22. 'debug' => true, // Enable SSL debugging
  23. ],
  24. ];
  25. $context = stream_context_create($contextOptions);
  26. // Create a TCP/IP socket connection
  27. $socket = stream_socket_client("tls://$host:$port", $errno, $errstr, 30);
  28. if ($socket === false) {
  29. throw new Exception("Failed to create socket: [$errno] $errstr");
  30. }
  31. // Enable SSL/TLS on the stream
  32. $secured = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
  33. if ($secured === false) {
  34. throw new Exception("Failed to enable SSL/TLS on the socket");
  35. }
  36. return $socket;
  37. // Now you can use the $socket to send/receive data with the server using SSL/TLS
  38. // For example, you can use fwrite($socket, $data) to send data to the server.
  39. }

I have verified the following:

  • The client certificate (public_cert.crt) and private key (private_key.pem) are valid and correctly matched.
  • The CA certificate (server_cert.pem) is provided and contains the necessary intermediate certificates.
  • The STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT and 'ciphers' settings are compatible with the server's configuration.

Interestingly, when the server admintrators disable authentication on the server-side, the SSL/TLS handshake completes successfully. However, when authentication is enabled, the "bad certificate" error occurs, and it has also been noticed that the server is receiving an empty certificate chain.

I have already tried debugging with error_log and verified that the certificate files' paths are correct.

Is there anything I am missing in my SSL/TLS configuration or any potential pitfalls when using stream_socket_client in PHP that could be causing this error?

Any guidance or insights into this issue would be greatly appreciated. Thank you!

答案1

得分: 2

感谢 @miken32 指向了 https://www.php.net/manual/en/context.ssl.php 资源,我已成功解决了我的问题。因此,我认为我应该将它作为答案发布。

  1. private function createSocketConnection($host, $port)
  2. {
  3. // 创建带有客户端证书的安全 SSL/TLS 上下文
  4. $contextOptions = [
  5. 'ssl' => [
  6. 'local_cert' => '/filepath/public_cert.pem',
  7. 'cafile' => '/filepath/server_cert.pem',
  8. 'verify_peer' => true,
  9. 'verify_peer_name' => true,
  10. 'allow_self_signed' => true,
  11. ],
  12. ];
  13. $context = stream_context_create($contextOptions);
  14. // 创建一个 TCP/IP 套接字连接
  15. $socket = stream_socket_client("tcp://$host:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
  16. if ($socket === false) {
  17. throw new Exception("Failed to create socket: [$errno] $errstr");
  18. }
  19. return $socket;
  20. }

通过这种方式,我已成功建立了与服务器的 SSL 连接。还值得注意的是,当使用 stream_socket_client() 连接套接字时,旧的方法如 socket_writesocket_readsocket_close 将不再起作用。我将它们分别更改为 fwritefreadfclose

英文:

Thank you @miken32 for pointing me to the resource https://www.php.net/manual/en/context.ssl.php I have been able to resolve my issue. Hence, I thought I should post it as an answer

  1. private function createSocketConnection($host, $port)
  2. {
  3. // Create a secure SSL/TLS context with client certificates
  4. $contextOptions = [
  5. 'ssl' => [
  6. 'local_cert' => '/filepath/public_cert.pem',
  7. 'cafile' => '/filepath/server_cert.pem',
  8. 'verify_peer' => true,
  9. 'verify_peer_name' => true,
  10. 'allow_self_signed' => true,
  11. ],
  12. ];
  13. $context = stream_context_create($contextOptions);
  14. // Create a TCP/IP socket connection
  15. $socket = stream_socket_client("tcp://$host:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
  16. if ($socket === false) {
  17. throw new Exception("Failed to create socket: [$errno] $errstr");
  18. }
  19. return $socket;
  20. }

With this, I have successfully established an SSL connection to the server. It is also good to note that when using stream_socket_client() to connect to the socket, old methods like socket_write, socket_read, and socket_close will no longer work. I changed them to fwrite, fread and fclose respectively

huangapple
  • 本文由 发表于 2023年8月4日 23:47:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837449.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定