"tlsv1 предупреждает внутреннюю ошибку" во время рукопожатия

У меня есть PHP script, который проверяет наличие URL-адресов (в основном, script должен возвращать true для заданного URL-адреса, когда URL-адрес может быть открыт в браузере и наоборот). Я наткнулся на URL: https://thepiratebay.gd/. Этот URL-адрес можно было бы правильно открыть в браузере, но fsockopen() просто терпит неудачу с ошибками квитирования SSL. Вариантов отладки fsockopen() в PHP не так много, но, копаясь в нем, я обнаружил, что я также не могу подключиться к https://thepiratebay.gd/ с помощью консоли Клиент openssl:

openssl s_client -connect thepiratebay.gd:443 
CONNECTED(00000003)
39613:error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error:/SourceCache/OpenSSL098/OpenSSL098-50/src/ssl/s23_clnt.c:602:

Этот веб-сайт, похоже, отлично работает с помощью веб-браузера или завитка, однако я не смог найти способ подключения к нему через openssl. По-видимому, сервер использует TLS 1.2 с шифрованием ECDHE-ECDSA-AES128-GCM-SHA256, но даже когда я заставляю их для openssl, он все равно терпит неудачу:

openssl s_client -cipher ECDHE-ECDSA-AES128-GCM-SHA256 -connect thepiratebay.gd:443 -tls1_2
CONNECTED(00000003)
140735195829088:error:14094438:SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error:s3_pkt.c:1256:SSL alert number 80
140735195829088:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:596:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: 
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1432931347
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

Я пробовал различные версии openssl: 0.9.8y, 1.0.1g и самые последние 0.9.8zf и 1.0.2a. Я также пытался запустить это, по крайней мере, на 5 серверах (CentOS, Debian, OSX) без везения.

Кажется, что все остальные веб-сайты обрабатываются отлично, вот пример успешного вывода рукопожатия:

openssl s_client -connect stackoverflow.com:443  -tls1
CONNECTED(00000003)
depth=1 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=NY/L=New York/O=Stack Exchange, Inc./CN=*.stackexchange.com
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGajCCBVKgAwIBAgIQCn1PE//Ffo4Be8tPBlsAZDANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xMzEwMjIxMjAwMDFaFw0xNjA3MDYxMjAwMDBa
MGoxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJOWTERMA8GA1UEBxMITmV3IFlvcmsx
<---skipped few lines--->
qOHCjaUIx7vKszN4cqbvyry/NdxYkPCC7S8Eks8NjSyppzRL79tU0Yr1MUhVEd6h
GjB2qDwvAGqyWmLz1Q/l82lZbXyBF26DVTJ3RFRUzzieyzKucaVgohI7HC2yyJ9Y
AsE7wvVK4odQI3fRjOsLRaXjFtpiaor0rERUxM4mg7jj05leRBkSazNjv2xvCL5/
Qqm5PN666tREQwvgvXZgg+ZlKWkFyOq6X3THstM6CC8DTGED0cb94WPQA4YTp9OQ
rS3+OedQN+Nlu80Sk8Y=
-----END CERTIFICATE-----
subject=/C=US/ST=NY/L=New York/O=Stack Exchange, Inc./CN=*.stackexchange.com
issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
---
No client certificate CA names sent
---
SSL handshake has read 3956 bytes and written 426 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES128-SHA
    Session-ID: 2E38670F2CABEF3D65FAC67DB6D2E00DBACA4519E50B463D57FCFF8410640BF5
    Session-ID-ctx: 
    Master-Key: 4C63E5502FF7DD36853048E775435A76CB1FDEB37104D6714B1C37D89482D8111B93574D2B3D7F38A1EEFF85D69F9F54
    Key-Arg   : None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 39 a8 c2 5f c5 15 04 b3-20 34 af fe 20 8e 4d 6c   9.._.... 4.. .Ml
    0010 - 6e 63 f1 e3 45 fd 2a 2c-d9 3c 0d ac 11 ab c0 c9   nc..E.*,.<......
    0020 - ce 51 19 89 13 49 53 a0-af 87 89 b0 5d e2 c5 92   .Q...IS.....]...
    0030 - af e5 84 28 03 4e 1e 98-4c a7 03 d5 5f fc 15 69   ...(.N..L..._..i
    0040 - 7c 83 d2 98 7d 42 50 31-30 00 d7 a8 3c 85 88 a7   |...}BP10...<...
    0050 - cd c0 bb 45 c8 12 b1 c8-4b 76 3c 41 5e 47 04 b5   ...E....Kv<A^G..
    0060 - 60 67 22 76 60 bb 44 f3-4b 3d 3d 99 af 0e dd 0d   `g"v`.D.K==.....
    0070 - 13 95 db 94 90 c2 0f 47-26 04 65 6b 71 b2 f8 1c   .......G&.ekq...
    0080 - 31 95 82 8b 00 38 59 08-1e 84 80 dc da 04 5c f0   1....8Y.......\.
    0090 - ae cc 2b ac 55 0f 39 59-0b 39 7d c7 16 b9 60 ef   ..+.U.9Y.9}...`.

    Start Time: 1432930782
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)

Трудно поверить, что все эти версии openssl имеют одинаковую ошибку, поэтому я думаю, что я делаю что-то неправильно.

Может ли кто-нибудь советовать, как подключиться к этому конкретному сайту с помощью openssl?

Ответ 1

Эти два являются плохой комбинацией:

-cipher ECDHE-ECDSA-AES128-GCM-SHA256

и

error:/SourceCache/OpenSSL098/OpenSSL098-50/src/ssl/s23_clnt.c

OpenSSL 0.9.8 не имеет полной поддержки EC. И он не поддерживает TLS 1.1 или 1.2. Чтобы получить комплекты шифрования AEAD, вам необходимо использовать TLS 1.2. Это означает, что вам нужно OpenSSL 1.0.0 или выше (IIRC).

OpenSSL 1.0.1 и 1.0.2 имеют их, поэтому, вероятно, лучше использовать эти версии.


 openssl s_client -connect thepiratebay.gd:443 ...

Команда, которую вы ищете, это: openssl s_client -connect thepiratebay.gd:443 -tls1_2 -servername thepiratebay.gd -CAfile XXX. -servername завершает SNI.

Когда я попал на сайт, сервер был сертифицирован AddTrust External CA Root. Когда вы попали на сайт, он был сертифицирован DigiCert High Assurance EV Root CA. И когда вы снова попали на сайт, он был сертифицирован сертификационным центром COMODO ECC.

Различные ЦС и конфигурации говорят с распределенным сайтом за балансировщиком нагрузки, причем каждый участвующий веб-сервер имеет несколько другую конфигурацию.


В дополнение к нескольким веб-серверам и конфигурациям некоторые из самих веб-серверов неправильно сконфигурированы. Они неправильно сконфигурированы, потому что они не отправляют цепочку, необходимую для создания пути для проверки.

Цепочка должна включать (1) сертификат сервера; (2) Подчиненные ЦС или промежуточные звенья, которые образуют цепочку к "корню". Для (2) может быть один или несколько промежуточных продуктов.

Цепочка не должна включать корень. У вас должен быть корень, и ему нужно доверять.


Этот веб-сайт, похоже, отлично работает с помощью веб-браузера или завитка, однако мне не удалось найти способ подключения к нему через openssl...

Это связано с тем, что браузеры переносят список сотен корневых ЦС и подчиненных ЦС из-за неправильных конфигураций веб-сервера:) В список входят AddTrust External CA Root, DigiCert High Assurance EV Root CA и корневой центр сертификации COMODO ECC.


Может ли кто-нибудь советовать, как подключиться к этому конкретному сайту с помощью openssl?

ОК, для команды OpenSSL вы должны использовать -CAfile. Обычно вы просто используете что-то вроде openssl s_client -connect ... -CAfile DigiCertHighAssuranceEVRootCA.crt (для сервера, сертифицированного с помощью DigiCert High Assurance EV Root CA). Но в этом случае это не сработает.

Вам необходимо создать один файл с необходимыми корневыми и подчиненными центрами сертификации. Файл должен быть конкатенацией корневых ЦС и подчиненных ЦС в формате PEM, необходимых для создания пути для проверки сертификата сервера. Похоже, что для этого потребуется не менее 3 или 4 сертификатов.

Или вы можете отказаться от создания собственного файла и использовать что-то вроде cacert.pem. Но есть некоторый риск использования CA Zoo (мой ласковый термин для них). Для некоторых рисков см. Является ли cacert.pem уникальным для моего компьютера?.

Программно, вы бы использовали SSL_CTX_load_verify_locations в OpenSSL. Конкатенированный файл PEM передается, хотя CAfile.

Я не уверен, что вы будете использовать в PHP.


Связано, cacert.pem имеет 155 корней и подчиненных. Большинство из них не требуется для сертификации сайта thepiratebay.gd:

$ cat cacert.pem | grep BEGIN | wc -l
     155

Следовательно, причина, по которой вы хотите ограничить свой CAfile только теми, которые необходимы для сертификации сайта.


(комментарий) Не уверен, что это правильный вопрос, но теперь я задаюсь вопросом, есть ли способ пропустить некоторые из этих проверок программным путем, чтобы уменьшить количество ложных негативов...

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

Повторить:

  • Используйте только необходимые корневые и подчиненные ЦС

    • Вы создаете его, конкатенация сертификатов PEM.
    • Создать файл piratebay-certs.pem
    • Добавить необходимые центры сертификации
  • Используйте CA Zoo с предопределенными доверенными корневыми и подчиненными центрами сертификации

    • Вы загрузили его
    • cacert.pem

Третий вариант - заставить сайт исправить свои настройки веб-сервера. Но если этого не произошло, то, вероятно, этого не произойдет. (И это может быть дизайнерское решение - сайт может использовать несколько центров сертификации, чтобы гарантировать, что ни один CA не сможет выполнить DoS-сайт, но это не касается неполной цепочки).


И более общее наблюдение:

У меня есть PHP script, который проверяет наличие URL-адресов (в основном, script должен возвращать true для данного URL-адреса, когда URL-адрес может быть открыт в браузере и наоборот

Отклоняясь от piratebay.gd, в частности, для проверки случайных URL-адресов, вам, вероятно, придется использовать cacert.pem. Это потому, что случайная выборка из 1 миллиона сайтов, вероятно, будет использовать их все.

Если piratebay.gd все еще не удается, узнайте, что отсутствует в cacert.pem, а затем:

cat cacert.pem > my-expanded-cacert.pem
cat missing-cert.pem >> my-expanded-cacert.pem

Ответ 2

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

В моем случае (клиент С++, сделанный с boost_asio + openssl), я исправил его, используя следующий код:

 char port[] =  "https";
 string host =  "www.server.com"
 boost::asio::ip::tcp::resolver::query query(host, port);
 ...
 boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12);
 ...
 ...
 //the following line fix the issue
 SSL_set_tlsext_host_name(socket_.native_handle(), host_.c_str());

см. также этот ответ SO.