ошибка 35 cURL: сбой gnutls_handshake ()

Я сталкиваюсь с следующей ошибкой из компонента PHP, который использует CURL для запроса URI через SSL:

cURL error 35: gnutls_handshake() failed: A TLS packet with unexpected length was received.

Эта ошибка возникает в среде travis-ci.org, но не в любой из наших тестовых сред. Смотри сборку travis-ci 144663700.

Я обнаружил, что версия PHP, работающая на рабочем месте Travis, снова компилируется «GnuTLS / 2.12.14» в «Ubuntu 12.04.5 LTS» или с «GnuTLS / 2.12.23» в «Ubuntu 14.04.3 LTS».

В наших средах разработки мы используем стандартные пакеты, скомпилированные с «OpenSSL / 1.0.1t» в Debian (различные версии).

Поэтому я предполагаю, что проблема связана с «GnuTLS / 2.12.14» или «GnuTLS / 2.12.23» или с параметрами, с которыми они были скомпилированы.

Я пытался ограничить версии SSL константой CURL CURLOPT_SSLVERSION, но это не решает проблему.

Согласно www.ssllabs.com рассматриваемый хост — api.reporting.cloud — поддерживает TLS 1.2, TLS 1.1 и TLS 1.0.

У кого-нибудь есть какие-нибудь подсказки или указатели для меня?

13

Решение

Обойти эту проблему можно, настроив travis-ci для использования стандартных пакетов Ubuntu Trusty php5-cli и php5-curl. Стандартные пакеты предлагают константу CURL_SSLVERSION_TLSv1_1.

Файл .travis.yml выглядит так:

sudo: required

dist: trusty

language: php

before_install:
- sudo apt-get -y install git zip php5-cli php5-curl

before_script:
- php -r "printf('PHP %s', phpversion());"- composer self-update
- composer install --no-interaction

script:
- mkdir -p ./build/logs
- ./vendor/bin/phpunit

В исходном коде PHP это просто вопрос установки вышеупомянутой константы в случае выполнения кода PHP travis-ci:

if (getenv('TRAVIS')) {
$options['curl'][CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_1;
}

Этот обходной путь имеет недостаток, заключающийся в том, что он работает только на той версии PHP, которую предлагает Ubuntu Trusty (PHP 5.5). Учитывая, что PHP 5.5 достиг конца срока службы 10 июля 2016 года, это решение неприемлемо.

Для travis-ci было бы идеально обновиться до Ubuntu 16.04 LTS, но Брэндон Бертон, менеджер по инфраструктуре в travis-ci писал 28 февраля 2016 г .:

Учитывая это, мы в настоящее время сосредоточены на поддержке 12.04 и 14.04, так как наши
основные среды. На данный момент вряд ли мы будем
поддержка 16.04 в качестве родной среды в этом году.

Поэтому кажется, что мы застряли на Ubuntu Trusty на некоторое время.

Корень этой проблемы в том, что версия PHP, которая работает на travis-ci, была скомпилирована с помощью gnutls-cli (GnuTLS) 2.12.23, начиная с 2011 года. Эта конкретная версия gnutls-cli имеет проблемы с некоторыми (но не со всеми) TLS 1.2 соединения.

@ travis-ci: Можно ли будет перекомпилировать версии PHP, которые вы используете, для более современной версии GnuTLS — или хотя бы для той, которая лучше поддерживает TLS 1.2?

7

Другие решения

В PHP можно управлять протоколом SSL, который используется curl, с помощью констант CURL_SSLVERSION_ *.

Установив:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);

Я могу заставить curl использовать «TLS 1.1».

Установив:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);

Я могу заставить curl использовать «TLS 1.0».

Чтобы проверить все возможные протоколы SSL, я создал следующий скрипт, который затем выполняется travis-ci:

<?php

$sslVersions = [
CURL_SSLVERSION_DEFAULT,
CURL_SSLVERSION_TLSv1,
CURL_SSLVERSION_TLSv1_0,
CURL_SSLVERSION_TLSv1_1,
CURL_SSLVERSION_TLSv1_2,
CURL_SSLVERSION_SSLv2,
CURL_SSLVERSION_SSLv3,
];

var_dump(curl_version());

foreach ($sslVersions as $sslVersion) {

$uri = "https://api.reporting.cloud";

printf("Trying %d", $sslVersion);
echo PHP_EOL;

$ch = curl_init($uri);

curl_setopt($ch, CURLOPT_VERBOSE        , true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT , 0);
curl_setopt($ch, CURLOPT_TIMEOUT        , 2);
curl_setopt($ch, CURLOPT_SSLVERSION     , $sslVersion);

if (curl_exec($ch) === false) {
var_dump(curl_error($ch));
} else {
curl_close($ch);
}

echo PHP_EOL;
echo PHP_EOL;

}

exit(1);

Вывод этого скрипта в моей среде разработки:

array(9) {
["version_number"]=>
int(468480)
["age"]=>
int(3)
["features"]=>
int(182173)
["ssl_version_number"]=>
int(0)
["version"]=>
string(6) "7.38.0"["host"]=>
string(19) "x86_64-pc-linux-gnu"["ssl_version"]=>
string(14) "OpenSSL/1.0.1t"["libz_version"]=>
string(5) "1.2.8"["protocols"]=>
array(21) {
[0]=>
string(4) "dict"[1]=>
string(4) "file"[2]=>
string(3) "ftp"[3]=>
string(4) "ftps"[4]=>
string(6) "gopher"[5]=>
string(4) "http"[6]=>
string(5) "https"[7]=>
string(4) "imap"[8]=>
string(5) "imaps"[9]=>
string(4) "ldap"[10]=>
string(5) "ldaps"[11]=>
string(4) "pop3"[12]=>
string(5) "pop3s"[13]=>
string(4) "rtmp"[14]=>
string(4) "rtsp"[15]=>
string(3) "scp"[16]=>
string(4) "sftp"[17]=>
string(4) "smtp"[18]=>
string(5) "smtps"[19]=>
string(6) "telnet"[20]=>
string(4) "tftp"}
}
Trying 0
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was NOT found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA384
* Server certificate:
*    subject: serialNumber=HRB 25927; 1.3.6.1.4.1.311.60.2.1.3=DE; businessCategory=Private Organization; C=DE; postalCode=28215; ST=Bremen; L=Bremen; street=Admiralstr. 54; O=Text Control GmbH; OU=ReportingCloud; OU=COMODO EV SSL; CN=api.reporting.cloud
*    start date: 2016-06-17 00:00:00 GMT
*    expire date: 2017-06-17 23:59:59 GMT
*    subjectAltName: api.reporting.cloud matched
*    issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Extended Validation Secure Server CA
*    SSL certificate verify ok.
> GET / HTTP/1.1
Host: api.reporting.cloud
Accept: */*

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
* Server Microsoft-IIS/8.5 is not blacklisted
< Server: Microsoft-IIS/8.5
< X-AspNetMvc-Version: 5.2
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Fri, 15 Jul 2016 14:22:40 GMT
< Content-Length: 952
<
* Connection #0 to host api.reporting.cloud left intactTrying 1
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA384
* Server certificate:
*    subject: serialNumber=HRB 25927; 1.3.6.1.4.1.311.60.2.1.3=DE; businessCategory=Private Organization; C=DE; postalCode=28215; ST=Bremen; L=Bremen; street=Admiralstr. 54; O=Text Control GmbH; OU=ReportingCloud; OU=COMODO EV SSL; CN=api.reporting.cloud
*    start date: 2016-06-17 00:00:00 GMT
*    expire date: 2017-06-17 23:59:59 GMT
*    subjectAltName: api.reporting.cloud matched
*    issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Extended Validation Secure Server CA
*    SSL certificate verify ok.
> GET / HTTP/1.1
Host: api.reporting.cloud
Accept: */*

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
* Server Microsoft-IIS/8.5 is not blacklisted
< Server: Microsoft-IIS/8.5
< X-AspNetMvc-Version: 5.2
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Fri, 15 Jul 2016 14:22:40 GMT
< Content-Length: 952
<
* Connection #0 to host api.reporting.cloud left intactTrying 4
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
CApath: /etc/ssl/certs
* SSL connection using TLSv1.0 / ECDHE-RSA-AES256-SHA
* Server certificate:
*    subject: serialNumber=HRB 25927; 1.3.6.1.4.1.311.60.2.1.3=DE; businessCategory=Private Organization; C=DE; postalCode=28215; ST=Bremen; L=Bremen; street=Admiralstr. 54; O=Text Control GmbH; OU=ReportingCloud; OU=COMODO EV SSL; CN=api.reporting.cloud
*    start date: 2016-06-17 00:00:00 GMT
*    expire date: 2017-06-17 23:59:59 GMT
*    subjectAltName: api.reporting.cloud matched
*    issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Extended Validation Secure Server CA
*    SSL certificate verify ok.
> GET / HTTP/1.1
Host: api.reporting.cloud
Accept: */*

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
* Server Microsoft-IIS/8.5 is not blacklisted
< Server: Microsoft-IIS/8.5
< X-AspNetMvc-Version: 5.2
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Fri, 15 Jul 2016 14:22:40 GMT
< Content-Length: 952
<
* Connection #0 to host api.reporting.cloud left intactTrying 5
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
CApath: /etc/ssl/certs
* SSL connection using TLSv1.1 / ECDHE-RSA-AES256-SHA
* Server certificate:
*    subject: serialNumber=HRB 25927; 1.3.6.1.4.1.311.60.2.1.3=DE; businessCategory=Private Organization; C=DE; postalCode=28215; ST=Bremen; L=Bremen; street=Admiralstr. 54; O=Text Control GmbH; OU=ReportingCloud; OU=COMODO EV SSL; CN=api.reporting.cloud
*    start date: 2016-06-17 00:00:00 GMT
*    expire date: 2017-06-17 23:59:59 GMT
*    subjectAltName: api.reporting.cloud matched
*    issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Extended Validation Secure Server CA
*    SSL certificate verify ok.
> GET / HTTP/1.1
Host: api.reporting.cloud
Accept: */*

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
* Server Microsoft-IIS/8.5 is not blacklisted
< Server: Microsoft-IIS/8.5
< X-AspNetMvc-Version: 5.2
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Fri, 15 Jul 2016 14:22:41 GMT
< Content-Length: 952
<
* Connection #0 to host api.reporting.cloud left intactTrying 6
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA384
* Server certificate:
*    subject: serialNumber=HRB 25927; 1.3.6.1.4.1.311.60.2.1.3=DE; businessCategory=Private Organization; C=DE; postalCode=28215; ST=Bremen; L=Bremen; street=Admiralstr. 54; O=Text Control GmbH; OU=ReportingCloud; OU=COMODO EV SSL; CN=api.reporting.cloud
*    start date: 2016-06-17 00:00:00 GMT
*    expire date: 2017-06-17 23:59:59 GMT
*    subjectAltName: api.reporting.cloud matched
*    issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Extended Validation Secure Server CA
*    SSL certificate verify ok.
> GET / HTTP/1.1
Host: api.reporting.cloud
Accept: */*

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: text/html; charset=utf-8
* Server Microsoft-IIS/8.5 is not blacklisted
< Server: Microsoft-IIS/8.5
< X-AspNetMvc-Version: 5.2
< X-AspNet-Version: 4.0.30319
< X-Powered-By: ASP.NET
< Date: Fri, 15 Jul 2016 14:22:41 GMT
< Content-Length: 952
<
* Connection #0 to host api.reporting.cloud left intactTrying 2
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* OpenSSL was built without SSLv2 support
* Closing connection 0
string(39) "OpenSSL was built without SSLv2 support"

Trying 3
* Rebuilt URL to: https://api.reporting.cloud/
* Hostname was found in DNS cache
*   Trying 40.76.93.116...
* Connected to api.reporting.cloud (40.76.93.116) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
CApath: /etc/ssl/certs
* Unknown SSL protocol error in connection to api.reporting.cloud:443
* Closing connection 0
string(68) "Unknown SSL protocol error in connection to api.reporting.cloud:443 "

Здесь мы ясно видим, что «SSL-соединение с использованием TLSv1.0» правильно подключается к внутреннему серверу.

Однако выполнение того же сценария на travi-ci приводит к следующему:

PHP Notice:  Use of undefined constant CURL_SSLVERSION_TLSv1_0 - assumed 'CURL_SSLVERSION_TLSv1_0' in /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php on line 7
PHP Stack trace:
PHP   1. {main}() /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php:0

Notice: Use of undefined constant CURL_SSLVERSION_TLSv1_0 - assumed 'CURL_SSLVERSION_TLSv1_0' in /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php on line 7

Call Stack:
0.0002     241400   1. {main}() /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php:0

PHP Notice:  Use of undefined constant CURL_SSLVERSION_TLSv1_1 - assumed 'CURL_SSLVERSION_TLSv1_1' in /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php on line 8
PHP Stack trace:
PHP   1. {main}() /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php:0

Notice: Use of undefined constant CURL_SSLVERSION_TLSv1_1 - assumed 'CURL_SSLVERSION_TLSv1_1' in /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php on line 8

Call Stack:
0.0002     241400   1. {main}() /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php:0

PHP Notice:  Use of undefined constant CURL_SSLVERSION_TLSv1_2 - assumed 'CURL_SSLVERSION_TLSv1_2' in /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php on line 9
PHP Stack trace:
PHP   1. {main}() /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php:0

Notice: Use of undefined constant CURL_SSLVERSION_TLSv1_2 - assumed 'CURL_SSLVERSION_TLSv1_2' in /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php on line 9

Call Stack:
0.0002     241400   1. {main}() /home/travis/build/TextControl/txtextcontrol-reportingcloud-php/demo/ssl-issue.php:0

array(9) {
'version_number' =>
int(464384)
'age' =>
int(3)
'features' =>
int(50749)
'ssl_version_number' =>
int(0)
'version' =>
string(6) "7.22.0"'host' =>
string(19) "x86_64-pc-linux-gnu"'ssl_version' =>
string(14) "GnuTLS/2.12.14"'libz_version' =>
string(7) "1.2.3.4"'protocols' =>
array(18) {
[0] =>
string(4) "dict"[1] =>
string(4) "file"[2] =>
string(3) "ftp"[3] =>
string(4) "ftps"[4] =>
string(6) "gopher"[5] =>
string(4) "http"[6] =>
string(5) "https"[7] =>
string(4) "imap"[8] =>
string(5) "imaps"[9] =>
string(4) "ldap"[10] =>
string(4) "pop3"[11] =>
string(5) "pop3s"[12] =>
string(4) "rtmp"[13] =>
string(4) "rtsp"[14] =>
string(4) "smtp"[15] =>
string(5) "smtps"[16] =>
string(6) "telnet"[17] =>
string(4) "tftp"}
}
Trying 0
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* gnutls_handshake() failed: A TLS packet with unexpected length was received.
* Closing connection #0
string(76) "gnutls_handshake() failed: A TLS packet with unexpected length was received."

Trying 1
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* gnutls_handshake() failed: A TLS packet with unexpected length was received.
* Closing connection #0
string(76) "gnutls_handshake() failed: A TLS packet with unexpected length was received."

Trying 0
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* gnutls_handshake() failed: A TLS packet with unexpected length was received.
* Closing connection #0
string(76) "gnutls_handshake() failed: A TLS packet with unexpected length was received."

Trying 0
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* gnutls_handshake() failed: A TLS packet with unexpected length was received.
* Closing connection #0
string(76) "gnutls_handshake() failed: A TLS packet with unexpected length was received."

Trying 0
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* gnutls_handshake() failed: A TLS packet with unexpected length was received.
* Closing connection #0
string(76) "gnutls_handshake() failed: A TLS packet with unexpected length was received."

Trying 2
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* GnuTLS does not support SSLv2
* Closing connection #0
string(29) "GnuTLS does not support SSLv2"

Trying 3
* About to connect() to api.reporting.cloud port 443 (#0)
*   Trying 40.76.93.116... * connected
* found 164 certificates in /etc/ssl/certs/ca-certificates.crt
* gnutls_handshake() failed: A TLS packet with unexpected length was received.
* Closing connection #0
string(76) "gnutls_handshake() failed: A TLS packet with unexpected length was received."

Я также заметил, что константы CURL_SSLVERSION_TLSv1_0, CURL_SSLVERSION_TLSv1_1 и CURL_SSLVERSION_TLSv1_2 недоступны в версиях travis-ci PHP 5.6 и PHP 7.

Подводя итог, я перебрал все возможные константы CURL_SSLVERSION_ *, и ни одна из них не позволяет мне подключаться к api.reporting.cloud на travis-ci, независимо от того, какую версию PHP я использую.

Кто-нибудь есть какие-либо предложения о том, как я могу подключиться к api.reporting.cloud от travis-ci?

4

Я нашел решение проблемы в этом список рассылки:

Серверу не нравится что-то в TLS 1.2 с поддержкой gnutls
2.12, так как, если вы отключите его, кажется, работает. Тот же сервер работает с gnutls 3.2, и единственная разница в клиенте привет двух
В версиях gnutls 3.2 включены дополнительные функции.

Я использую (необходимо использовать) «gnutls-cli (GnuTLS) 2.12.23».

Следующее возвращает вышеупомянутую ошибку:

gnutls-cli --priority "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2" api.reporting.cloud

Тем не менее, форсирование «TLS 1.1» или «TLS 1.0» возвращает, как и ожидалось:

gnutls-cli --priority "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.1" api.reporting.cloud
gnutls-cli --priority "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0" api.reporting.cloud

Следующим шагом является установка этого параметра из PHP через CURL (в конкретном случае неисправной версии библиотеки).

1
По вопросам рекламы [email protected]