Как читать веб-сокеты сертификатов TLS с помощью PHP? - PullRequest
0 голосов
/ 11 мая 2018

Я пытаюсь подключиться к защищенной веб-розетке, созданной 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 шифрования.Потому что мы получили полный доступ к этому серверу.Однако из генератора сертификатов я получил только те два упомянутых файла.Для веб-сервера это работает отлично.Но как сделать то же самое для веб-сокета в php?

Теперь, с помощью этого кода, после отправки некоторых сообщений клиенту серверный скрипт сообщает мне, что он не смог получить одноранговый узел из сертификатов.Я не знаю, что означает это сообщение и как это исправить.Я также уже пытался обменяться local_cert и local_pk друг с другом, но это все равно не помогло.

Edit: После исследования, оказывается, что phpСбой при каждой комбинации с другой ошибкой.

Мои сгенерированные файлы сертификатов выглядят так:

Файл / opt / psa / var / сертификаты / 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 / сертификаты / 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

Edit 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 / сертификаты / cert-0x8zHR 'в ... on line ...

Предупреждение: stream_socket_accept (): не удалось включить шифрование в... on line ...

Предупреждение: stream_socket_accept (): принять не удалось: Успех в ... on line ...

Предупреждение: socket_read () ожидает, что параметр 1 будет ресурсом, логическое значение указано в ... on line ...

Примечание: неопределенное смещение: 1 in ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсомлогическое значение указано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение указано в ... on line ...

предупреждение: socket_write() ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение указывается в ... on line ...

Предупреждение: socket_write ()ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... on line ...

Предупреждение: socket_close () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... 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 / сертификаты / cert-Du9H8N 'в ...on line ...

Предупреждение: stream_socket_accept (): не удалось включить шифрование в ... on line ...

Внимание: stream_socket_accept (): accept fail: Success in ...on line ...

Предупреждение: socket_read () ожидает, что параметр 1 будет ресурсом, логическое значение указано в ... on line ...

Примечание: неопределенное смещение: 1 in ...on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсным, логическое значениезадано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... on line ...

Предупреждение: socket_write ()ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение указано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ...on line ...

Предупреждение: socket_close () ожидает, что параметр 1 будет ресурсом, логическое значение указано в ... on line ...

И с (просто конкатенацией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 будет ресурсом, логическое значение указано в ... on line ...

Примечание: неопределенное смещение: 1 in ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение указано в ... on line ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение указано в... ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом,логическое значение задано в ... ...

Предупреждение: socket_write () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... ...

предупреждение: socket_write () ожидает параметр 1быть ресурсом, логическое значение задано в ... ...

Предупреждение: socket_close () ожидает, что параметр 1 будет ресурсом, логическое значение задано в ... 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, пожалуйста, дайте мне знать.Онлайн конвертация невозможна.

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Попробуйте это:

stream_context_set_option($cont, 'ssl', 'local_cert', '/opt/psa/var/certificates/cert-0x8zHR');
stream_context_set_option($cont, 'ssl', 'ca_file', '/opt/psa/var/certificates/cert-Du9H8N');

Если это не сработает, попробуйте закомментировать вторую строку (ca_flie) и установите verify_peer на false

Что такое сообщения об ошибках в обоих случаях?

Обновление: кстати, ваши сертификаты уже в формате .pem (в кодировке ASCII-base64).

0 голосов
/ 26 мая 2018

Вы сказали:

Мои сгенерированные файлы сертификатов выглядят так:

Файл / opt / psa / var / сертификаты / cert-0x8zHR:

----- НАЧАТЬ ЗАПРОС СЕРТИФИКАТА ----- несколько букв ----- КОНЕЦ ЗАПРОСА СЕРТИФИКАТА -----

----- НАЧАТЬ ЧАСТНЫЙ КЛЮЧ ----- несколько букв ----- КОНЕЦ ЧАСТНОГО КЛЮЧА -----

----- НАЧАТЬ СЕРТИФИКАТ ----- несколько букв ----- КОНЕЦ СЕРТИФИКАТА -----

----- НАЧАТЬ СЕРТИФИКАТ ----- несколько букв ----- КОНЕЦ СЕРТИФИКАТА -----

Это неправильно на многих уровнях.

Во-первых, часть «ЗАПРОС СЕРТИФИКАТА» становится абсолютно бесполезной, как только вы получаете сертификат. Вы можете просто проигнорировать эту часть.

Теперь скопируйте часть "PRIVATE KEY" с заголовками в одном файле. Это ваш закрытый ключ, который вы можете использовать везде, где у вас есть опции "local_pk" или программное обеспечение, запрашивающее ключ.

Тогда у вас есть два сертификата. И еще один в другом файле. Вам нужно будет все это отсортировать. Если бы вы предоставили настоящий контент сертификатов (который является общедоступным), люди могли бы помочь вам лучше. Здесь только с «некоторыми буквами» мы можем только догадываться.

В приведенном выше файле два сертификата могут быть CA и промежуточным. Вы должны скопировать их оба в другой файл, и это будет соответствовать опции «ca_cert».

Полагаю, что второй файл - это ваш пробный сертификат (снова только предположение, без ваших данных). Используйте его везде, где у вас есть "local_cert" или вы запрашиваете сертификат. Этот сертификат должен соответствовать файлу закрытого ключа (вы не можете проверить это вручную, вам нужны инструменты).

После того, как вы создали все правильные файлы, первый больше не должен использоваться. Я бы рекомендовал использовать лучшую семантику для имени файла, потому что cert-X и cert-Y будет довольно сложно. Вместо этого используйте имя веб-сайта, чтобы у вас были такие файлы, как www.example.com.cert, www.example.com-ca.cert и www.example.com.key, чтобы сразу было понятно, что к чему. Или с каталогом с именем www.example.com/, а затем cert.pem, ca.pem и key.pem внутри каталога. Сами по себе эти расширения не используются программным обеспечением и, независимо от содержимого, только вы сами можете определить, что имеет смысл.

Итак, сначала разберитесь со всем этим, чтобы ваш вопрос прояснился. Прямо сейчас кажется, что вы пытаетесь делать что-то вслепую, пока не придете к тому, что работает, что не является идеальной ситуацией в сфере безопасности и TLS.

Если возможно, я бы посоветовал вам попробовать использовать библиотеку абстракций более высокого уровня для обработки TLS, поскольку она явно слишком мала, так что вы можете потерять так много опций.

0 голосов
/ 25 мая 2018

Похоже, что OpenSSL не нравится ваш ключ.

Вы можете попробовать позвонить http://php.net/manual/en/function.openssl-error-string.php, чтобы узнать, есть ли дополнительная информация о причинах?

Или попробовать другойкомбинации файлов ключей в соответствии с этими, возможно, связанными вопросами, которые содержат одну и ту же ошибку:

GL

...