websocket 在PHP中使用stream_socket_client时出现SSL/TLS握手错误“bad certificate”

um6iljoc  于 2023-08-05  发布在  PHP
关注(0)|答案(1)|浏览(150)

我遇到了一个SSL/TLS握手错误,消息是“坏证书”,同时试图在PHP中使用stream_socket_client建立安全连接。目标是将我们的PHP应用程序与需要SSL/TLS加密的外部服务集成。
下面是相关的代码片段:

private function createSocketConnection($host, $port)
    {
        // Path to the client certificate and private key
        // $localCertificateFile = '/var/www/sslcert/suezpublic.crt';
        // $privateKeyFile = '/var/www/sslcert/privatekesy.pem';

        // Create a secure SSL/TLS context with client certificates
        $contextOptions = [
            'ssl' => [
                'local_cert' => '/var/www/sslcert/suezcombined.pem',
                // 'local_pk' => '/var/www/sslcert/privatekesy.pem',
                'cafile' => '/var/www/sslcert/bizswitch.pem', // GoDaddy Intermediate certificate or your CA certificate
                'verify_peer' => true, // Enable peer certificate verification
                'verify_peer_name' => true, // Check that the common name exists and matches the host name
                'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, // Use TLSv1.2
                // 'crypto_timeout' => 30, // Increase the handshake timeout to 30 seconds
                'CN_match' => 'www.suezelectric.com', // Ensure the common name matches the server's hostname
                'ciphers' => 'HIGH:!SSLv2:!SSLv3', // Specify allowed ciphers for security
                'disable_compression' => true, // Disable SSL/TLS compression for security
                'capture_peer_cert' => true,
                'capture_peer_chain' => true,
                // 'allow_self_signed' => true,
                'debug' => true, // Enable SSL debugging
            ],
        ];
        $context = stream_context_create($contextOptions);

        // Create a TCP/IP socket connection
        $socket = stream_socket_client("tls://$host:$port", $errno, $errstr, 30);

        if ($socket === false) {
            throw new Exception("Failed to create socket: [$errno] $errstr");
        }

        // Enable SSL/TLS on the stream
        $secured = stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);

        if ($secured === false) {
            throw new Exception("Failed to enable SSL/TLS on the socket");
        }

        return $socket;

        // Now you can use the $socket to send/receive data with the server using SSL/TLS
        // For example, you can use fwrite($socket, $data) to send data to the server.
    }

字符串
本人已验证以下内容:

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

有趣的是,当服务器管理员在服务器端禁用身份验证时,SSL/TLS握手成功完成。但是,当启用身份验证时,会发生“坏证书”错误,并且还注意到服务器正在接收空证书链。
我已经尝试使用error_log进行调试,并验证证书文件的路径是否正确。
在PHP中使用stream_socket_client时,我的SSL/TLS配置中是否缺少了什么,或者是否有任何潜在的陷阱可能导致此错误?
对此问题的任何指导或见解将不胜感激。谢谢你,谢谢

kse8i1jr

kse8i1jr1#

感谢@miken32为我指出资源https://www.php.net/manual/en/context.ssl.php,我已经能够解决我的问题。因此,我想我应该把它作为一个答案

private function createSocketConnection($host, $port)
{
    // Create a secure SSL/TLS context with client certificates
    $contextOptions = [
        'ssl' => [
            'local_cert' => '/filepath/public_cert.pem',
            'cafile' => '/filepath/server_cert.pem',
            'verify_peer' => true,
            'verify_peer_name' => true,
            'allow_self_signed' => true,
        ],
    ];
    $context = stream_context_create($contextOptions);

    // Create a TCP/IP socket connection
    $socket = stream_socket_client("tcp://$host:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);

    if ($socket === false) {
        throw new Exception("Failed to create socket: [$errno] $errstr");
    }

    return $socket;
}

字符串
这样,我就成功地建立了到服务器的SSL连接。同样值得注意的是,当使用stream_socket_client()连接到socket时,旧方法如socket_writesocket_readsocket_close将不再起作用。我将它们分别更改为fwritefreadfclose

相关问题