Я пытаюсь подключиться к защищенному websocket, созданному PHP, но по какой-то причине он не работает. Файлы сертификатов читаются для 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);
Клиентская сторона:
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);
}
У меня нет файла *.pem. Просто два файла, которые используются на веб-сервере Apache. При необходимости можно было бы преобразовать эти файлы в файл pem. Но я думаю, что он также должен работать в php с этими обоими файлами, не так ли?
Для лучшего тестирования мы используем изолированный субдомен с сертификатом let encrypt. Потому что мы получили полный доступ к этому серверу. Однако из генератора certifacte я получил только эти два упомянутых файла. Для веб-сервера он работает отлично. Но как сделать то же самое для websocket в php?
Теперь, с помощью этого кода, после отправки некоторых сообщений клиенту серверный скрипт говорит мне, что он не смог получить партнера из сертификатов. Я не знаю, что это означает, и как это исправить. Я также пытался обменять local_cert
и local_pk
друг на друга, но это все равно не помогло.
Edit: после некоторого исследования выясняется, что 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-----
Файл /opt/psa/var/certificates/cert-Du9H8N:
-----BEGIN CERTIFICATE-----
some letters
-----END CERTIFICATE-----
Все строки из строк сертификата из обоих из них заканчиваются в позиции символа 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');
Предупреждение: stream_socket_accept(): невозможно установить файл закрытого ключа '/opt/psa/var/certificates/cert-0x8zHR' в... on line...
Предупреждение: stream_socket_accept(): Не удалось включить криптографию... в строке...
Предупреждение: stream_socket_accept(): accept failed: Success in... on line...
Предупреждение: socket_read() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Примечание: Неопределенное смещение: 1 в... на линии...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_close() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
И с
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');
Предупреждение: stream_socket_accept(): невозможно установить файл закрытого ключа '/opt/psa/var/certificates/cert-Du9H8N' в... on line...
Предупреждение: stream_socket_accept(): Не удалось включить криптографию... в строке...
Предупреждение: stream_socket_accept(): accept failed: Success in... on line...
Предупреждение: socket_read() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Примечание: Неопределенное смещение: 1 в... на линии...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_close() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
И с (просто конкатенация cert-0x8zHR с сертификатом-Du9H8N)
$file = dirname(__FILE__, 3) . \DIRECTORY_SEPARATOR . 'fullchain.pem';
stream_context_set_option($cont, 'ssl', 'local_cert', $file);
Предупреждение: stream_socket_accept(): не удалось получить сертификат одноранговой сети...
Предупреждение: stream_socket_accept(): Не удалось включить криптографию в......
Предупреждение: stream_socket_accept(): accept failed: Успех в......
Предупреждение: socket_read() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Примечание: Неопределенное смещение: 1 в... на линии...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в......
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в......
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в......
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в......
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, boolean задан в......
Предупреждение: socket_close() ожидает, что параметр 1 будет ресурсом, boolean задан в... on line...
Редактировать 3: Да, действительно, есть ошибка openssl. После третьего предупреждения socket_stream_accept
теперь я получаю эту ошибку, просто используя код из примера php doc:
error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
Я искал эту ошибку в Интернете. Говорят, если эта ошибка появляется, я выбрал неверный файл сертификата.
Кроме того, если я играю эту команду:
openssl x509 -noout -in cert-0x8zHR -modulus
Я получил две разные строки для модуля. Но я не знаю, почему, и как это исправить. Эти оба файла используются в конфигурации vhost для веб-сервера Apache и отлично работают:
SSLEngine on
SSLVerifyClient none
SSLCertificateFile /opt/psa/var/certificates/cert-0x8zHR
SSLCACertificateFile /opt/psa/var/certificates/cert-Du9H8N
PS: Если вы знаете какой-либо инструмент для локального преобразования в файл pem, пожалуйста, дайте мне знать. Онлайн-конвертация невозможна.