SSL handshake is not working when compiled in Ubun

2019-08-07 16:55发布

问题:

This is the flow I use to setup my HTTPS server with SSL.

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.

It's not the full code once it's very big, but I can complete with more details if necessary.

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

The problem is: when I try to connect from a browser (Google Chrom), it says:

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

Other browsers say similar messages...

When I try to connect from wget, I get:

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'.

I just changed the serial of the certificate to 00000000.

So... If I finally follow the wget message and do...

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

... THEN the server works perfectly!

So, the conclusion I get is: the server itself IS working, but the handshake has some problem with the SSL certificate. The certificate is valid, used in other servers, Apache accepts it perfectly and as I told, once again, this same implementation works on Windows, OS X and Ubuntu 13. This problem is only happening on Ubuntu 14.

Things I tried to do:

  1. I tried to update the OpenSSL [compiled it by myself] but nothing
    happened.
  2. I tried to try other methods instead of SSLv23_server_method(), nothing happened
  3. I compiled in Ubuntu 13 and executed in Ubuntu 14 (AND THIS WORKED!)

Weard (item 3) is that if I compile in Ubuntu 13 and run on Ubuntu 14, it works! So maybe some Ubuntu 14 static library is with problem?

Is my SSL implementation correct? What else can be done so I can fix it for Ubuntu 14 and my server work everywhere?

--

I do openssl s_client -connect example.com:443 and get:

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
---

回答1:

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 indicates the client and server could not agree on a protocol - SSLv3, TLS 1.0, etc. I believe it corresponds to the protocol_version alert of TLS. See RFC 5246, Section 7.2.

OpenSSL has been TLS 1.2 since 1.0.1. See the OpenSSL CHANGELOG. However, Ubuntu prior to 14 disabled TLS 1.1 and TLS 1.2 for interop reasons. See Ubuntu 12.04 LTS: OpenSSL downlevel version and does not support TLS 1.2. Ubuntu 14 (and subsequent) enables TLS 1.1 and TLS 1.2. (And TLS 1.3 is around the corner: The Transport Layer Security (TLS) Protocol Version 1.3 (draft-ietf-tls-rfc5246-bis-00)).

There could be another issues if you have to go through a proxy. The problem is related to the ClientHello size. The ClientHello size increased with TLS 1.1 and TLS 1.2 because of additional cipher suites (more correctly, TLS 1.2 because TLS 1.1 did not add any cipher suites). Size should not matter except some proxies have fixed size buffer and other hard coded limits that simply break the exchange. It is an issue with some F5 and Ironport appliances.

You can test for TLS 1.2 and ClientHello size sensitivity with s_client:

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"

The above connects with TLS 1.2 and uses only 2 cipher suites (4 bytes). If it connects with 2 cipher suites, then drop the -cipher and see if it connects with the 80+ (over 160 bytes) that are builtin.

If it does not connect with TLS 1.2, then try either -tls1 or -ssl3.

EDIT: You problem is an ancient server and TLS 1.1 and TLS 1.2. See below on the steps to isolate the problem.

You have three potential fixes.

First

The first fix is to have the server upgrade to something that's not ancient. If its a proxy, then fix the proxy.

Second

If you need to modify the protocol versions, then perform the following to get SSLv3 or YLS 1.0 only:

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

Third

If you need to modify the cipher suite list:

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

EDIT: You problem is an ancient server and TLS 1.1 and TLS 1.2. You need to use (1) from above, or (2) from above. Ideally, the ancient server would be fixed so everyone can benefit.

TLS 1.2 does not work:

$ 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 does not work:

$ 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 does work:

$ 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 does work:

$ 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!

This is a different issue. wget is likely avoiding the issue by incorporating one of the fixes above. A Wirehsark trace would tell you.

Also, if you provided a real server name, we could help you identify the Root CA you should be using (to avoid Unable to locally verify the issuer's authority).

Here's what I am seeing with 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
...

So you need Go Daddy Class 2 Certification Authority. You can get that from Go Daddy Repository, SSL Certificate Information. The file is gd-class2-root.crt, and you can pass it to s_client and the result is 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)