Рукопожатие SSL не работает при компиляции в Ubuntu 14

Это процесс, который я использую для настройки своего HTTPS-сервера с SSL.

Он отлично работает в 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), он говорит:

Не удалось установить безопасное соединение с сервером. Это может быть проблема с сервером или может потребоваться сертификат проверки подлинности клиента, которого у вас нет. Код ошибки: 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 (И ЭТО РАБОТАЛО!)

Износ (пункт 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
---

person Wagner Patriota    schedule 01.05.2014    source источник
comment
Чтобы разобраться, связано ли это с ОС или компилятором, вы можете получить ту же версию компилятора, что и Ubuntu 14, и использовать ее в Ubuntu 13 или что-то в этом роде...   -  person Mats Petersson    schedule 02.05.2014
comment
Ах да, забыл упомянуть. Я скомпилировал в 13, запустил в 14, и это сработало... Я обновлю вопрос!   -  person Wagner Patriota    schedule 02.05.2014
comment
Так что это похоже на проблему, связанную с компилятором/инструментами. Я бы все же попытался собрать либо со старым компилятором на новой платформе, либо с новым компилятором на старой платформе, чтобы убедиться, что у вас нет какого-то внешнего компонента (например, какой-то библиотеки), который является перерывом.   -  person Mats Petersson    schedule 02.05.2014
comment
Что такое URL для рассматриваемого сервера? mydomain.com — дисконтный регистратор, и я сомневаюсь, что это ваш домен (хотя могу ошибаться). Вы должны использовать example.com, потому что он зарезервирован IANA для этой цели.   -  person jww    schedule 02.05.2014
comment
О, это сервер (не клиент). Используйте 1_. Это включает TLS 1.0 и выше. Нет необходимости в SSL в 2014 году.   -  person jww    schedule 02.05.2014


Ответы (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 указывает, что клиент и сервер не смогли согласовать протокол — SSLv3, TLS 1.0 и т. д. Я полагаю, что это соответствует предупреждению protocol_version TLS. См. RFC 5246, раздел 7.2.

OpenSSL был TLS 1.2 с версии 1.0.1. См. ЖУРНАЛ ИЗМЕНЕНИЙ OpenSSL. Однако Ubuntu до 14 отключил TLS 1.1 и TLS 1.2 по причинам взаимодействия. См. Ubuntu 12.04 LTS: версия OpenSSL нижнего уровня и не поддерживает TLS 1.2. Ubuntu 14 (и последующие) включает TLS 1.1 и TLS 1.2. (И TLS 1.3 не за горами: Безопасность транспортного уровня (TLS ) Версия протокола 1.3 (draft-ietf-tls-rfc5246-bis-00)).

Могут быть другие проблемы, если вам нужно использовать прокси. Проблема связана с размером ClientHello. Размер ClientHello увеличился с TLS 1.1 и TLS 1.2 из-за дополнительных наборов шифров (точнее, TLS 1.2, потому что TLS 1.1 не добавлял никаких наборов шифров). Размер не должен иметь значения, за исключением того, что некоторые прокси имеют фиксированный размер буфера и другие жестко запрограммированные ограничения, которые просто прерывают обмен. Это проблема с некоторыми устройствами F5 и Ironport.

Вы можете проверить чувствительность TLS 1.2 и ClientHello к размеру с помощью 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"

Приведенное выше соединяется с TLS 1.2 и использует только 2 набора шифров (4 байта). Если он соединяется с двумя наборами шифров, отбросьте -cipher и посмотрите, соединяется ли он с 80+ (более 160 байтов), которые встроены.

Если он не подключается к TLS 1.2, попробуйте либо -tls1, либо -ssl3.

РЕДАКТИРОВАТЬ: ваша проблема связана с древним сервером и TLS 1.1 и TLS 1.2. Ниже приведены инструкции по локализации проблемы.

У вас есть три потенциальных исправления.

Первый

Первое исправление состоит в том, чтобы обновить сервер до чего-то, что не является древним. Если это прокси, то исправьте прокси.

Второй

Если вам нужно изменить версии протокола, выполните следующие действия, чтобы получить только 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 подскажет вам.

Кроме того, если бы вы указали реальное имя сервера, мы могли бы помочь вам определить корневой ЦС, который вы должны использовать (чтобы избежать Unable to locally verify the issuer's authority).

Вот что я вижу с 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 класса 2. Вы можете получить это в репозиторий Go Daddy, информация о SSL-сертификате. Файл 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)
person jww    schedule 02.05.2014
comment
Я попробовал оба решения 2 и 3... ничего не произошло :-( - person Wagner Patriota; 02.05.2014
comment
SSL_CTX_set_cipher_list() предназначен для sslChildSocket, исправьте это в ответе... Я пробовал, но исправил неправильно... - person Wagner Patriota; 02.05.2014
comment
@WagnerPatriota - проблема в древнем сервере. Вам нужно использовать метод (1) или (2). В идеале будет использоваться метод (1) (зафиксировать сервер). - person jww; 02.05.2014
comment
Извините, этот сервер, который вы тестировали, работает нормально. Это апач. Тот, который не работает, — это внутренний пользовательский HTTPS-сервер, созданный с нуля. Я не могу дать вам доступ к нему. Извини :-( - person Wagner Patriota; 02.05.2014
comment
SSL_CTX_set_cipher_list - о, мой плохой. Я изменил его, чтобы установить его на SSL_CTX, чтобы он применялся ко всем производным сеансам. - person jww; 02.05.2014
comment
Я сделал с SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3... тоже не сработало! - person Wagner Patriota; 02.05.2014
comment
@WagnerPatriota - извините, больше ничем помочь не могу. Это одна из радостей внутренних машин и тестирования... - person jww; 02.05.2014
comment
хорошо, спасибо за вашу помощь. Я думаю, что с тем, что вы написали до сих пор, я могу копнуть немного больше и выяснить. Я дам вам обратную связь! Большое спасибо! - person Wagner Patriota; 02.05.2014
comment
ваше решение РАБОТАЕТ! Извините, что было очень поздно, и я делал глупости. Другая часть моего веб-сервера действует как брандмауэр. Брандмауэр блокировал соединение. Большое спасибо! Теперь это работает! - person Wagner Patriota; 02.05.2014