如何使用PHP读取TLS证书websockets?

alp*_*am8 16 php ssl serversocket websocket phpwebsocket

我试图连接到由PHP创建的安全websocket,但由于某种原因它不起作用.证书文件对于PHP是可读的.

到目前为止,这是我的代码(PHP方面;为简单起见,剥离代码):

$context = stream_context_create();
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', 'example.com');
stream_context_set_option($context,  'ssl', 'CN_match', 'example.com');
stream_context_set_option($context,  'ssl', 'SNI_enabled', true);
stream_context_set_option($context, 'ssl', 'local_cert',  '/path/to/ssl/cert/example.com');
stream_context_set_option($context, 'ssl', 'local_pk', '/path/to/ssl/private/example.com');

$serverSocket = stream_socket_server(
        'tls://example.com:8090',
        $errNo,
        $errStr,
        \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN,
        $context
);
$client = stream_socket_accept($serverSocket);

// send initial websocket connection stuff
$request = socket_read($client, 5000);
preg_match('#Sec-WebSocket-Key: (.*)\r\n#', $request, $matches);
$key = base64_encode(pack(
    'H*',
    sha1($matches[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
));
$headers = "HTTP/1.1 101 Switching Protocols\r\n";
$headers .= "Upgrade: websocket\r\n";
$headers .= "Connection: Upgrade\r\n";
$headers .= 'Sec-WebSocket-Version: 13' . "\r\n";
$headers .= 'Sec-WebSocket-Accept: ' . $key . "\r\n\r\n";
socket_write($client, $headers, \mb_strlen($headers));

// do something here...

socket_close($client);
socket_close($serverSocket);
Run Code Online (Sandbox Code Playgroud)

客户方:

var con = new WebSocket('wss://' + host + ':' + port);
var $chat = $('#chat');

con.onmessage = function(e) {
    $chat.append('<p>' + e.data + '</p>');
};

con.onopen = function(e) {
    con.send('Hello Me!');
};

con.onclose = function (e) {
    console.log('connection closed.', arguments);
}
Run Code Online (Sandbox Code Playgroud)

我没有任何*.pem文件.只是apache web服务器中使用的两个文件.如果需要,可以将该文件转换为pem文件.但我认为它应该在php中使用这两个文件,不应该吗?

为了更好的测试,我们使用带有let的加密证书的隔离子域.因为我们可以完全访问此服务器.但是,从certifacte生成器我只得到了那两个提到的文件.对于Web服务器,它可以很好地工作.但是如何为php中的websocket做同样的事情呢?

现在,使用此代码,在向客户端发送一些消息后,服务器脚本告诉我,它无法从证书中获取对等方.我不知道这条消息的含义以及如何解决这个问题.我也试过alreay交换local_certlocal_pk互相,但它并没有帮助反正.

编辑:经过一段时间的研究,事实证明,PHP失败了每一个组合与另一个错误.

我生成的证书文件如下所示:

文件/ opt/psa/var/certificates/cert-0x8zHR:

-----BEGIN CERTIFICATE REQUEST-----
some letters
-----END CERTIFICATE REQUEST-----

-----BEGIN PRIVATE KEY-----
some letters
-----END PRIVATE KEY-----

-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)

文件/ opt/psa/var/certificates/cert-Du9H8N:

-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)

来自两个证书字符串的所有行都在字符位置65处结束.

正如你可以在php文档中看到的那样,php希望得到一个PEM格式的文​​件:http://php.net/manual/en/context.ssl.php#context.ssl.local-cert

我发现本教程将我的两个文件转换为一个PEM文件,但我的证书看起来与网站上提到的不同,而且我不知道究竟要包含在PEM文件中,PHP需要:https:// www. digicert.com/ssl-support/pem-ssl-creation.htm

编辑2:如下所述,这里是我得到的确切错误:

stream_context_set_option($cont, 'ssl',  'local_pk', '/opt/psa/var/certificates/cert-0x8zHR');
stream_context_set_option($cont, 'ssl', 'local_cert', '/opt/psa/var/certificates/cert-Du9H8N');
Run Code Online (Sandbox Code Playgroud)

警告:stream_socket_accept():无法在...中设置私钥文件`/ opt/psa/var/certificates/cert-0x8zHR'...

警告:stream_socket_accept():无法在...中启用加密...

警告:stream_socket_accept():接受失败:成功...在线......

警告:socket_read()期望参数1是资源,boolean在...中给出...

注意:未定义的偏移量:1 ...在线...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_close()期望参数1是资源,在线...给出的布尔值...

stream_context_set_option($cont, 'ssl',  'local_cert', '/opt/psa/var/certificates/cert-0x8zHR');
stream_context_set_option($cont, 'ssl', 'local_pk', '/opt/psa/var/certificates/cert-Du9H8N');
Run Code Online (Sandbox Code Playgroud)

警告:stream_socket_accept():无法在...中设置私钥文件`/ opt/psa/var/certificates/cert-Du9H8N'...

警告:stream_socket_accept():无法在...中启用加密...

警告:stream_socket_accept():接受失败:成功...在线......

警告:socket_read()期望参数1是资源,boolean在...中给出...

注意:未定义的偏移量:1 ...在线...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_close()期望参数1是资源,在线...给出的布尔值...

并且(只是cert-0x8zHR与cert-Du9H8N的串联)

$file = dirname(__FILE__, 3) . \DIRECTORY_SEPARATOR . 'fullchain.pem';
stream_context_set_option($cont, 'ssl', 'local_cert', $file);
Run Code Online (Sandbox Code Playgroud)

警告:stream_socket_accept():无法获得对等证书......

警告:stream_socket_accept():无法启用加密......

警告:stream_socket_accept():接受失败:成功......

警告:socket_read()期望参数1是资源,boolean在...中给出...

注意:未定义的偏移量:1 ...在线...

警告:socket_write()期望参数1是资源,在线...给出的布尔值...

警告:socket_write()期望参数1是资源,boolean在...中给出

警告:socket_write()期望参数1是资源,boolean在...中给出

警告:socket_write()期望参数1是资源,boolean在...中给出

警告:socket_write()期望参数1是资源,boolean在...中给出

警告:socket_write()期望参数1是资源,boolean在...中给出

警告:socket_close()期望参数1是资源,在线...给出的布尔值...

编辑3:是的,的确有一个openssl错误.在第三次socket_stream_accept警告后,我现在通过使用php doc示例中的代码得到此错误:

error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
Run Code Online (Sandbox Code Playgroud)

我在互联网上搜索了这个错误.他们说,如果出现此错误,我选择了错误的证书文件.

另外,如果我播放此命令:

openssl x509 -noout -in cert-0x8zHR -modulus
Run Code Online (Sandbox Code Playgroud)

模数有两个不同的字符串.但我不知道为什么,也不知道如何解决这个问题.这两个文件都在apache web server vhost config中使用,它可以正常工作:

SSLEngine on
SSLVerifyClient none
SSLCertificateFile /opt/psa/var/certificates/cert-0x8zHR
SSLCACertificateFile /opt/psa/var/certificates/cert-Du9H8N
Run Code Online (Sandbox Code Playgroud)

PS:如果你知道任何本地转换为pem文件的工具,请告诉我.在线转换是不可能的.

Ric*_*ich 0

OpenSSL 似乎不喜欢您的密钥。

您可以尝试致电http://php.net/manual/en/function.openssl-error-string.php看看是否有更多关于原因的信息?

或者尝试不同的关键文件组合,根据这些可能相关的问题,这些问题具有相同的错误:

GL