"tlsv1 alert internal error" 握手期间

"tlsv1 alert internal error" during handshake

我有一个 PHP 脚本来检查 URL 的可用性(基本上,对于给定的 URL,当 URL可以在浏览器中打开,反之亦然)。我偶然发现了一个 URL:https://thepiratebay.gd/. This URL could be correctly opened in browser, but fsockopen() just fails with the SSL handshake errors. There are not many options for debugging fsockopen() in PHP, but while digging more into it, I found that I am also not able to connect to 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:

这个网站似乎可以使用网络浏览器或 curl 打开,但是,我无法找到通过 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 whosebug.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 连接到这个特定的网站吗?

这两个是一个糟糕的组合:

-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 证书颁发机构 的认证。

不同的 CA 和配置与负载平衡器后面的分布式站点通信,每个参与的 Web 服务器的配置略有不同。


除了多个网络服务器和配置之外,一些网络服务器本身配置错误。它们配置错误,因为它们不发送构建验证路径所需的链。

该链应包括(1)服务器证书; (2) 形成 "root" 链的从属 CA 或中间体。对于(2),可能有一个或多个中间体。

链应该包括根。您必须拥有 root,并且必须信任它。


This website seem to open fine using web browser or curl, however, I was not able to find a way to connect to it via openssl...

这是因为由于 Web 服务器配置错误,浏览器携带了数百个根 CA 和从属 CA 的列表:) 该列表包括 AddTrust External CA RootDigiCert High Assurance EV Root CA,和COMODO ECC Root Certificate Authority.


Can anyone advice how to connect to this particular website using openssl?

好的,对于OpenSSL命令,你应该使用-CAfile。通常,您只需使用 openssl s_client -connect ... -CAfile DigiCertHighAssuranceEVRootCA.crt 之类的东西(对于通过 DigiCert High Assurance EV Root CA 认证的服务器)。但这在这种情况下不起作用。

您必须使用所需的根 CA 和从属 CA 创建一个文件。该文件应该是构建验证服务器证书的路径所需的 PEM 格式的根 CA 和从属 CA 的串联。看起来至少需要 3 或 4 个证书。

或者,您可以放弃构建自己的文件,而使用 cacert.pem. But there is some risk in using the CA Zoo (my affectionate term for them). For some of the risks, see Is cacert.pem unique to my computer?.

以编程方式,您将在 OpenSSL 中使用 SSL_CTX_load_verify_locations。串联的 PEM 文件通过 CAfile.

传递

我不确定你会在 PHP 中使用什么。


相关,cacert.pem有155个根部和部属。其中大部分不需要认证站点 thepiratebay.gd:

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

因此,您想将 CAfile 限制为仅认证网站所需的那些。


(comment) Not sure this is the correct thread to ask, but now I wonder if there is a way to skip some of these checks programmatically to reduce number of false negatives...

我可能不会放弃支票。现在您了解了发生了什么,应该更容易使用系统而不是放弃它。

重申一下,要么:

  1. 仅使用必要的根和从属 CA

    1. 您构建它,串联 PEM 证书
    2. 创建文件piratebay-certs.pem
    3. 添加必要的 CA
  2. 使用具有预定义的可信根和从属 CA 的 CA Zoo

    1. 你下载它
    2. cacert.pem

第三个选项是让站点修复其网络服务器配置。但如果现在还没有发生,它可能不会发生。 (这可能是一个设计决定——该站点可能使用多个 CA 来确保没有一个 CA 可以对该站点进行 DoS。但这并不能解决不完整的链)。


更一般的观察:

I have a PHP script that checks URLs availability (basically, the script should return true for a given URL when the URL could be opened in browser and vice versa

远离 piratebay.gd,特别是检查随机 URL,您可能不得不使用 cacert.pem。这是因为 100 万个网站的随机样本可能会使用所有这些网站。

如果piratebay.gd仍然失败,则找出cacert.pem缺少的内容,然后:

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

出于不同的原因,我收到了相同的错误消息:很多服务器都在使用 SNI,这可能会产生此错误。

就我而言(使用 boost_asio + openssl 制作的 c++ 客户端)我使用以下代码修复了它:

 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());

另见