php 握手期间出现“tlsv1 警报内部错误”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30538542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"tlsv1 alert internal error" during handshake
提问by Alex Rudakov
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). There is an URL I stumbled upon: 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/using console openssl client:
我有一个检查 URL 可用性的 PHP 脚本(基本上,当 URL 可以在浏览器中打开时,脚本应该为给定的 URL 返回 true,反之亦然)。我偶然发现了一个 URL:https: //thepiratebay.gd/。这个 URL 可以在浏览器中正确打开,但 fsockopen() 只是失败并出现 SSL 握手错误。在 PHP 中调试 fsockopen() 的选项并不多,但是在深入研究它的同时,我发现我也无法使用控制台 openssl 客户端连接到https://thepiratebay.gd/:
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:
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. Apparently, the server uses TLS 1.2 with ECDHE-ECDSA-AES128-GCM-SHA256 cipher, but even when I force those for openssl, it still fails:
该网站似乎可以使用 Web 浏览器或 curl 正常打开,但是,我无法找到通过 openssl 连接到它的方法。显然,服务器使用带有 ECDHE-ECDSA-AES128-GCM-SHA256 密码的 TLS 1.2,但即使我为 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)
---
I've tried various openssl versions: 0.9.8y, 1.0.1g, and the most recent 0.9.8zf and 1.0.2a. I've also tried to run this on at least 5 servers (CentOS, Debian, OSX) with no luck.
我尝试过各种 openssl 版本:0.9.8y、1.0.1g,以及最新的 0.9.8zf 和 1.0.2a。我还尝试在至少 5 台服务器(CentOS、Debian、OSX)上运行它,但没有成功。
Every other website seem to be handled fine, here is an example of a successful handshake output:
每个其他网站似乎都处理得很好,这是一个成功的握手输出示例:
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)
It is hard to believe that all these openssl versions have the same bug, so I'm thinking that I'm doing something wrong.
很难相信所有这些 openssl 版本都有相同的错误,所以我认为我做错了什么。
Can anyone advice how to connect to this particular website using openssl?
谁能建议如何使用 openssl 连接到这个特定的网站?
采纳答案by jww
These two are a bad combination:
这两个是一个糟糕的组合:
-cipher ECDHE-ECDSA-AES128-GCM-SHA256
-cipher ECDHE-ECDSA-AES128-GCM-SHA256
And:
和:
error:/SourceCache/OpenSSL098/OpenSSL098-50/src/ssl/s23_clnt.c
error:/SourceCache/OpenSSL098/OpenSSL098-50/src/ssl/s23_clnt.c
OpenSSL 0.9.8 does not have full EC support. And it does not support TLS 1.1 or 1.2. To get the AEAD cipher suites, you need to use TLS 1.2. That means you need OpenSSL 1.0.0 or above (IIRC).
OpenSSL 0.9.8 没有完整的 EC 支持。并且它不支持 TLS 1.1 或 1.2。要获得 AEAD 密码套件,您需要使用 TLS 1.2。这意味着您需要 OpenSSL 1.0.0 或更高版本 (IIRC)。
OpenSSL 1.0.1 and 1.0.2 have them, so its probably better to use those versions.
OpenSSL 1.0.1 和 1.0.2 有它们,所以使用这些版本可能更好。
openssl s_client -connect thepiratebay.gd:443 ...
openssl s_client -connect thepiratebay.gd:443 ...
The command you are looking for is: openssl s_client -connect thepiratebay.gd:443 -tls1_2 -servername thepiratebay.gd -CAfile XXX
. -servername
enlists SNI.
您正在寻找的命令是:openssl s_client -connect thepiratebay.gd:443 -tls1_2 -servername thepiratebay.gd -CAfile XXX
。-servername
招募 SNI。
When I hit the site, the server was certified by AddTrust External CA Root. When you hit the site, it was certified by DigiCert High Assurance EV Root CA. And when you hit the site again, it was certified by COMODO ECC Certification Authority.
当我访问该站点时,服务器已通过AddTrust External CA Root认证。当您访问该站点时,它已通过DigiCert High Assurance EV Root CA 的认证。当您再次访问该站点时,它已获得COMODO ECC 认证机构的认证。
The different CAs and configurations speak to a distributed site behind a load balancer, with each participating web server in a slightly different configuration.
不同的 CA 和配置与负载均衡器后面的分布式站点通信,每个参与的 Web 服务器的配置略有不同。
In addition to multiple web servers and configurations, some of the web servers themselves are misconfigured. They are misconfigured because they do not send the chain required to build a path for validation.
除了多个 Web 服务器和配置之外,一些 Web 服务器本身也配置错误。它们配置错误,因为它们没有发送构建验证路径所需的链。
The chain should include (1) the server certificate; (2) Subordinate CAs or intermediates that form the chain to the "root". For (2), there may be one or more intermediates.
该链应包括(1)服务器证书;(2) 形成“根”链的从属 CA 或中间体。对于(2),可能有一种或多种中间体。
The chain should notinclude the root. You have to have the root, and it must be trusted.
链应该不包括根。您必须拥有根,并且必须信任它。
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 浏览器或 curl 正常打开,但是,我无法找到通过 openssl 连接到它的方法...
This is because the browsers carry around a list of hundreds of Root CAs and Subordinate CAs due to web server misconfigurations :) The list includes AddTrust External CA Root, DigiCert High Assurance EV Root CA, and COMODO ECC Root Certificate Authority.
这是因为由于 Web 服务器配置错误,浏览器携带了数百个根 CA 和从属 CA 的列表:) 该列表包括AddTrust External CA Root、DigiCert High Assurance EV Root CA和COMODO ECC Root Certificate Authority。
Can anyone advice how to connect to this particular website using openssl?
谁能建议如何使用 openssl 连接到这个特定的网站?
OK, for the OpenSSL command, you should use -CAfile
. Usually, you just use something like openssl s_client -connect ... -CAfile DigiCertHighAssuranceEVRootCA.crt
(for the server certified with DigiCert High Assurance EV Root CA). But that won't work in this case.
好的,对于 OpenSSL 命令,您应该使用-CAfile
. 通常,您只需使用类似的东西openssl s_client -connect ... -CAfile DigiCertHighAssuranceEVRootCA.crt
(对于通过DigiCert High Assurance EV Root CA认证的服务器)。但这在这种情况下不起作用。
You have to create a single file with the required Root and Subordinate CAs. The file should be a concatenation of the Root CAs and Subordinate CAs in PEM format required to build a path to validate the server certificate. It looks like it will need at least 3 or 4 certificates.
您必须使用所需的根 CA 和从属 CA 创建单个文件。该文件应该是构建验证服务器证书的路径所需的 PEM 格式的根 CA 和从属 CA 的串联。看起来它至少需要 3 或 4 个证书。
Or, you could forgo building you own file, and use something like 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?.
或者,您可以放弃构建自己的文件,而使用类似cacert.pem
. 但是使用 CA Zoo(我对它们的亲切称呼)存在一些风险。对于一些风险,请参阅cacert.pem 是我的计算机独有的吗?.
Programmatically, you would use SSL_CTX_load_verify_locations
in OpenSSL. The concatenated PEM file is passed though CAfile
.
以编程方式,您将SSL_CTX_load_verify_locations
在 OpenSSL 中使用。虽然传递了连接的 PEM 文件CAfile
。
I'm not sure what you would use in PHP.
我不确定你会在 PHP 中使用什么。
Related, cacert.pem
has 155 roots and subordinates. Most of them are not needed to certify the site thepiratebay.gd
:
相关,cacert.pem
有155个根和下属。他们中的大多数不需要认证网站thepiratebay.gd
:
$ cat cacert.pem | grep BEGIN | wc -l
155
Hence the reason you want to restrict your CAfile
to only those necessary to certify the site.
因此,您希望将您的内容限制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...
(评论)不确定这是要问的正确线程,但现在我想知道是否有办法以编程方式跳过其中一些检查以减少误报的数量......
I would probably notforgo the checks. Now that you understand what's going on, it should be easier to work with the system rather than abandoning it.
我可能不会放弃检查。现在您了解了发生了什么,应该更容易使用该系统而不是放弃它。
To reiterate, either:
重申,要么:
Use only necessary Root and Subordinate CAs
- You build it, concatenation of PEM certificates
- Create file
piratebay-certs.pem
- Add necessary CAs
Use a CA Zoo with predifined trusted Root and Subordinate CAs
- You download it
cacert.pem
仅使用必要的根和从属 CA
- 您构建它,连接 PEM 证书
- 创建文件
piratebay-certs.pem
- 添加必要的 CA
使用带有预定义可信根和从属 CA 的 CA Zoo
- 你下载
cacert.pem
The third option is to get the site to fix its web server configurations. But if it has not happened by now, it probably won't happen. (And it could be a design decision - the site may be using multiple CAs to ensure no one CA can DoS the site. But that does not address the incomplete chain).
第三种选择是让站点修复其 Web 服务器配置。但如果它现在没有发生,它可能不会发生。(这可能是一个设计决策——该站点可能使用多个 CA 来确保没有一个 CA 可以对该站点进行 DoS。但这并不能解决不完整的链)。
And the more general observation:
以及更一般的观察:
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
我有一个检查 URL 可用性的 PHP 脚本(基本上,当 URL 可以在浏览器中打开时,脚本应该为给定的 URL 返回 true,反之亦然
Moving away from piratebay.gd
in particular to checking random URLs, you will probably have to use cacert.pem
. That's because a random sample of 1 million sites will likely use all of them.
从piratebay.gd
特别是检查随机 URL 开始,您可能必须使用cacert.pem
. 这是因为 100 万个站点的随机样本可能会使用所有这些站点。
If piratebay.gd
still fails, then find out what is missing from cacert.pem
, and then:
如果piratebay.gd
仍然失败,则找出 中缺少的内容cacert.pem
,然后:
cat cacert.pem > my-expanded-cacert.pem
cat missing-cert.pem >> my-expanded-cacert.pem
回答by Malick
I had the same error message for a different reason: a lot of servers are using SNIand this may produce this error.
由于不同的原因,我收到了相同的错误消息:许多服务器都在使用SNI,这可能会产生此错误。
In my case (a c++ client made with boost_asio + openssl) I fixed it using the following code :
在我的情况下(使用 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());
see also this SO answer.
另请参阅此 SO 答案。