c++ - 在 Ubuntu 14 中编译时 SSL 握手不起作用

标签 c++ ubuntu openssl handshake ubuntu-14.04

这是我使用 SSL 设置 HTTPS 服务器的流程。

它在 Windows、OS X 和 Ubuntu 13 上完美运行。但它无法在 Ubuntu 14 上运行,我不知道为什么。

一旦它很大,它就不是完整的代码,但如果需要,我可以补充更多细节。

SSL_library_init();

m_sslContext = SSL_CTX_new( SSLv23_server_method() );

SSL_CTX_use_certificate_chain_file( m_sslContext, "path/to/certificate.crt" );
SSL_CTX_use_PrivateKey_file( m_sslContext, "path/to/privatekey.pem", SSL_FILETYPE_PEM );

m_mainSocket = ::socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ) );

...

::listen( m_mainSocket, SOMAXCONN );

...

SOCKET childSocketHandle;

while ( ( childSocketHandle = ::accept( m_mainSocket, ... ) ) > 0 )
{
    sslChildSocket = SSL_new( m_sslContext );
    SSL_set_fd( sslChildSocket, childSocketHandle );
    SSL_set_accept_state( sslChildSocket );
    ...
    SSL_read( sslChildSocket, bufferIn, sizeof( bufferIn ) );
    ...
    SSL_write( sslChildSocket, bufferOut, sizeof( bufferOut ) ) );
}

问题是:当我尝试从浏览器 (Google Chrom) 连接时,它显示:

Unable to make a secure connection to the server. This may be a problem with the server, or it may be requiring a client authentication certificate that you don't have. Error code: ERR_SSL_PROTOCOL_ERROR

其他浏览器说类似的信息...

当我尝试从 wget 连接时,我得到:

wget https://example.com:443/
--2014-05-01 17:01:33--  https://example.com:443/
Resolving example.com (example.com)... 127.0.1.1
Connecting to example.com (example.com)|127.0.1.1|:443... connected.
ERROR: cannot verify example.com's certificate, issued by ‘/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=00000000’:
  Unable to locally verify the issuer's authority.
To connect to example.com insecurely, use `--no-check-certificate'.

我刚刚将证书的序列号更改为 00000000。

所以...如果我最终遵循 wget 消息并执行...

wget https://example.com:443/ --no-check-certificate

... 那么服务器就可以正常工作了!

因此,我得到的结论是:服务器本身可以正常工作,但握手过程中的 SSL 证书存在一些问题。该证书有效,在其他服务器中使用,Apache 完全接受它,正如我所说的,同样的实现在 Windows、OS X 和 Ubuntu 13 上工作。这个问题只发生在 Ubuntu 14 上。

我尝试做的事情:

  1. 我尝试更新 OpenSSL [自己编译的] 但什么也没有
    发生了。
  2. 我尝试尝试其他方法而不是 SSLv23_server_method(),没有任何反应
  3. 我在 Ubuntu 13 中编译并在 Ubuntu 14 中执行(并且成功了!)

Weard(第 3 项)是,如果我在 Ubuntu 13 中编译并在 Ubuntu 14 上运行,它就可以工作!那么也许某些 Ubuntu 14 静态库有问题?

我的 SSL 实现是否正确?还有什么可以做的,这样我就可以为 Ubuntu 14 修复它并且我的服务器可以在任何地方工作?

--

我执行 openssl s_client -connect example.com:443 并得到:

CONNECTED(00000003)
140735262471008:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 322 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

最佳答案

It works perfectly on Windows, OS X and Ubuntu 13. But it's failing to work on Ubuntu 14 only and I don't know why.
...
ERR_SSL_PROTOCOL_ERROR

ERR_SSL_PROTOCOL_ERROR 表示客户端和服务器无法就协议(protocol)达成一致 - SSLv3、TLS 1.0 等。我相信它对应于 TLS 的 protocol_version 警报。参见 RFC 5246, Section 7.2 .

OpenSSL 从 1.0.1 开始就是 TLS 1.2。查看OpenSSL CHANGELOG .但是,出于互操作原因,14 之前的 Ubuntu 禁用了 TLS 1.1 和 TLS 1.2。参见 Ubuntu 12.04 LTS: OpenSSL downlevel version and does not support TLS 1.2 . Ubuntu 14(及后续版本)启用 TLS 1.1 和 TLS 1.2。 (TLS 1.3 即将到来:The Transport Layer Security (TLS) Protocol Version 1.3(draft-ietf-tls-rfc5246-bis-00))。

如果您必须通过代理,可能还有其他问题。该问题与 ClientHello 大小有关。 ClientHello 的大小随着 TLS 1.1 和 TLS 1.2 的增加而增加,因为增加了密码套件(更准确地说,TLS 1.2 是因为 TLS 1.1 没有添加任何密码套件)。大小应该无关紧要,除非一些代理有固定大小的缓冲区和其他硬编码限制,这些限制只会破坏交换。这是一些 F5 和 Ironport 设备的问题。

您可以使用 s_client 测试 TLS 1.2 和 ClientHello 大小敏感性:

openssl s_client -tls1_2 -connect <server>:<port> -servername <server> \
    -cipher "SSL_RSA_WITH_3DES_EDE_CBC_SHA:TLS_RSA_WITH_3DES_EDE_CBC_SHA"

以上内容与 TLS 1.2 连接,仅使用 2 个密码套件(4 个字节)。如果它与 2 个密码套件连接,则删除 -cipher 并查看它是否与内置的 80+(超过 160 字节)连接。

如果它与 TLS 1.2 连接,则尝试 -tls1-ssl3

编辑:您的问题是一个古老的服务器以及 TLS 1.1 和 TLS 1.2。请参阅下面的步骤来隔离问题。

您有三个潜在的修复方法。

首先

第一个解决办法是让服务器升级到一个不古老的东西。如果是代理,则修复代理。

第二

如果您需要修改协议(protocol)版本,则执行以下操作以仅获取 SSLv3 或 YLS 1.0:

m_sslContext = SSL_CTX_new( SSLv23_server_method() );
const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
SSL_CTX_set_options(m_sslContext, flags);

第三

如果需要修改密码套件列表:

m_sslContext = SSL_CTX_new( SSLv23_server_method() );
const char* const PREFERRED_CIPHERS = "kEECDH:kEDH:kRSA:AESGCM:AES256:AES128:3DES:"
    "SHA256:SHA84:SHA1:!aNULL:!eNULL:HIGH:!RC4:!MD5:!SRP:!PSK:!ADH:!AECDH";
res = SSL_CTX_set_cipher_list(m_sslContext, PREFERRED_CIPHERS);

编辑:您的问题是一个古老的服务器以及 TLS 1.1 和 TLS 1.2。您需要使用上面的 (1),或上面的 (2)。理想情况下,旧服务器将得到修复,以便每个人都能受益。

TLS 1.2 不工作:

$ openssl s_client -tls1_2 -connect www.example.com:443 -CAfile gd-class2-root.crt 
CONNECTED(00000003)
140735211598300:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:s3_pkt.c:337:
...

TLS 1.1 不工作:

$ openssl s_client -tls1_1 -connect www.example.com:443 -CAfile gd-class2-root.crt 
CONNECTED(00000003)
140735211598300:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:s3_pkt.c:337:
...

TLS 1.0 确实有效:

$ openssl s_client -tls1 -connect www.example.com:443 -CAfile gd-class2-root.crt 
CONNECTED(00000003)
depth=2 C = US, O = "The Go Daddy Group, Inc.", OU = Go Daddy Class 2 Certification Authority
verify return:1
...

SSL v3 确实有效:

$ openssl s_client -ssl3 -connect www.example.com:443 -CAfile gd-class2-root.crt 
CONNECTED(00000003)
depth=2 C = US, O = "The Go Daddy Group, Inc.", OU = Go Daddy Class 2 Certification Authority
verify return:1
...

When I try to connect from wget, I get:
...
Unable to locally verify the issuer's authority.
...
So... If I finally follow the wget message and do...

wget https://mydomain.com:443/ --no-check-certificate

... THEN the server works perfectly!

这是一个不同的问题。 wget 可能通过合并上述修复程序之一来避免该问题。 Wirehsark 踪迹会告诉您。

此外,如果您提供了真实的服务器名称,我们可以帮助您识别您应该使用的根 CA(以避免无法在本地验证颁发者的权限)。

这是我在 s_client 上看到的:

$ openssl s_client -connect www.example.com:443
CONNECTED(00000003)
depth=1 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certificates.godaddy.com/repository, CN = Go Daddy Secure Certification Authority, serialNumber = 07969287
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/OU=Domain Control Validated/CN=*.example.com
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
...

因此您需要 Go Daddy Class 2 证书颁发机构。你可以从 Go Daddy Repository, SSL Certificate Information 得到它.文件是gd-class2-root.crt,你可以把它传给s_client 结果是Verify return code: 0 (ok):

$ openssl s_client -connect www.example.com:443 -CAfile gd-class2-root.crt 
CONNECTED(00000003)
depth=2 C = US, O = "The Go Daddy Group, Inc.", OU = Go Daddy Class 2 Certification Authority
verify return:1
depth=1 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certificates.godaddy.com/repository, CN = Go Daddy Secure Certification Authority, serialNumber = 07969287
verify return:1
depth=0 OU = Domain Control Validated, CN = *.example.com
verify return:1
---
Certificate chain
 0 s:/OU=Domain Control Validated/CN=*.example.com
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFRTCCBC2gAwIBAgIHKyKXfFXVZjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
ODcwHhcNMTQwMzIxMTYyMjU2WhcNMTUwMzIxMTYyMjU2WjA8MSEwHwYDVQQLExhE
b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxFzAVBgNVBAMMDiouc3RheWZpbG0uY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyRsNuqBROD+6RsmkJk7S
KtTpFO5ke92AfWnEnZuKCbbRo/WjmtCPNLQC7fAQxPJb6i/cCt9cusQqlpFjHTg/
lD5Dqoqn/GXMe4hfKbV8VV3NAjWr8f0M/M1ftaL+zo5UtRjdAEIC9ysfbKqqBOxP
hqGPiL0QpkKQ5YZMiz3S4UZzwQ1Unjj43xH4IZFffsdwY5uJqfeoOl/6qBNAQIyg
1Hk00er/+1UlO2hpMe/qjiCZvGSRUat/O51AgyCPFGDmhSEi6rjyeLvEgpILzgR7
K1/BsCe2Kxi+SRIt8UK2jFjXSRnCQyjtgOitbk/sM0afhUUIb7ns95RWAiXt5CpD
0QIDAQABo4IBuzCCAbcwDwYDVR0TAQH/BAUwAwEBADAdBgNVHSUEFjAUBggrBgEF
BQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQDAgWgMDQGA1UdHwQtMCswKaAnoCWG
I2h0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2RzMS0xMDYuY3JsMFMGA1UdIARMMEow
SAYLYIZIAYb9bQEHFwEwOTA3BggrBgEFBQcCARYraHR0cDovL2NlcnRpZmljYXRl
cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzCBgAYIKwYBBQUHAQEEdDByMCQGCCsG
AQUFBzABhhhodHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wSgYIKwYBBQUHMAKGPmh0
dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9nZF9pbnRl
cm1lZGlhdGUuY3J0MB8GA1UdIwQYMBaAFP2sYTKTbEXW4u6FX5q653aZaMznMCcG
A1UdEQQgMB6CDiouc3RheWZpbG0uY29tggxzdGF5ZmlsbS5jb20wHQYDVR0OBBYE
FOZLbPozya++C27Grhs5pPUut4WFMA0GCSqGSIb3DQEBBQUAA4IBAQBPv85UBt3g
1XGHwZ9ARxpG9InoHRQledSbRckchU35awnIXuXd6pE+kZ7RctR6BywiPRrQnmYm
0D7wHP+BVoN2cZIkTHHgx/hILGTYk47CKyVcL9+WyDd5UXkJYyfdMzfia6dnG4wZ
ucsdR8Ete2do35yZmCZHU5L9KwXarQRuNexbiOqb4kBjUaIhN79NZs1h812QWLLB
+uRhvHOfQuSleEx1ggou/rwaYKNGYrIJl4/kpCquDXbqebkR1B+ad49GD+yBMyOm
/AOfGSU6YTUfZRGjzS2yAozs+QZFUrZTDHyt6Z93OLD+4O07SSAfTD3AlQlG/V1M
KwHuBUl22QD4
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/CN=*.example.com
issuer=/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
---
No client certificate CA names sent
---
SSL handshake has read 2765 bytes and written 843 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES128-SHA
    Session-ID: 990D00002F519EEFC297CD4CB157B2F7...
    Session-ID-ctx: 
    Master-Key: A4B16EA84F4CD1E8D56A0B601A678AEE...
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1399002932
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

关于c++ - 在 Ubuntu 14 中编译时 SSL 握手不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23417562/

相关文章:

c++ - 如何避免不必要的数据复制?

C++ 集 - 并集、差集、交集 - 导致 vector 删除迭代器错误(超出范围)

git - 你可以为 git 提交启用 2FA 吗?

python - SimpleITK.Show() 在 Linux 上的 ImageJ 中生成错误

python - PRAW/Tweepy 过滤关键字

c++ - openssl 和 linux bash 计算之间的 MD5 不匹配

c++ - 每次调用一个新的随机 vector

C++ - ‘_itoa’ 未在此范围内声明

python - 如何验证 python 是否使用 Open SSL Libraries 编译

openssl - 将 RFC 名称映射到 OpenSSL