Я пытаюсь подключиться к защищенному веб-сокету, созданному 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’s Encrypt. Потому что мы получили полный доступ к этому серверу. Однако из генератора сертификатов я получил только эти два упомянутых файла. Для веб-сервера работает отлично. Но как сделать то же самое для веб-сокета в php?
Теперь, с этим кодом, после отправки нескольких сообщений клиенту серверный скрипт сообщает мне, что ему не удалось получить одноранговый узел из сертификатов. Я не знаю, что означает это сообщение и как это исправить. Я также уже пытался поменять местами local_cert
и local_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-----
Файл /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' в ... в строке ...
Предупреждение: stream_socket_accept(): не удалось включить криптографию в... в сети...
Предупреждение: stream_socket_accept(): принять не удалось: успех в... в строке...
Предупреждение: socket_read() ожидает, что параметр 1 будет ресурсом, логическим значением, указанным в ... в строке ...
Примечание: Неопределенное смещение: 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');
Предупреждение: stream_socket_accept(): невозможно установить файл закрытого ключа `/opt/psa/var/certificates/cert-Du9H8N' в ... в строке ...
Предупреждение: stream_socket_accept(): не удалось включить криптографию в... в сети...
Предупреждение: stream_socket_accept(): принять не удалось: успех в... в строке...
Предупреждение: socket_read() ожидает, что параметр 1 будет ресурсом, логическим значением, указанным в ... в строке ...
Примечание: Неопределенное смещение: 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);
Предупреждение: stream_socket_accept(): не удалось получить одноранговый сертификат в ... ...
Предупреждение: stream_socket_accept(): не удалось включить криптографию в ... ...
Предупреждение: stream_socket_accept(): принять не удалось: Успех в ... ...
Предупреждение: socket_read() ожидает, что параметр 1 будет ресурсом, логическим значением, указанным в ... в строке ...
Примечание: Неопределенное смещение: 1 дюйм ... на линии ...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическим значением, указанным в ... в строке ...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическим значением, заданным в ... ...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическим значением, заданным в ... ...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическим значением, заданным в ... ...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическим значением, заданным в ... ...
Предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическим значением, заданным в ... ...
Предупреждение: socket_close() ожидает, что параметр 1 будет ресурсом, логическим значением, заданным в ... в строке ...
Редактировать 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, сообщите мне об этом. Онлайн-конверсия невозможна.
local_pk
вы передаете ему файл с именемcert-something
, поэтому, если это действительно сертификат, предоставление его в качестве ключа никогда не будет работать. Обязательно предоставьтеlocal_pk
связанный закрытый ключ вашего сертификата. - person Patrick Mevzek   schedule 25.05.2018