cURL错误35:gnutls_handshake()失败

15

我从使用CURL通过SSL请求URI的PHP组件中遇到了以下错误:

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

这个错误发生在travis-ci.org环境中,但不会在我们的任何测试环境中发生。请参见travis-ci构建 144663700

我发现Travis工作程序中运行的PHP版本是针对"Ubuntu 12.04.5 LTS"上编译的"GnuTLS/2.12.14",或者采用"Ubuntu 14.04.3 LTS"上的"GnuTLS/2.12.23"编译的。

在我们的开发环境中,我们使用针对Debian(各种版本)上的“OpenSSL/1.0.1t”编译的标准软件包。

因此,我认为问题与“GnuTLS/2.12.14”或“GnuTLS/2.12.23”,或以它们编译的参数有关。

我尝试通过CURL常量CURLOPT_SSLVERSION限制SSL版本,但这并不能解决问题。

根据www.ssllabs.com所述,涉及主机-api.reporting.cloud支持TLS 1.2、TLS 1.1和TLS 1.0。

是否有人能给我一些提示或指针?

3个回答

8
这个问题的解决方法是配置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源码中,如果travis-ci执行PHP代码,则只需设置前面提到的常量即可。
if (getenv('TRAVIS')) {
    $options['curl'][CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_1;
}

这种解决方法的缺点在于它只适用于Ubuntu Trusty所提供的特定PHP版本(PHP 5.5)。考虑到PHP 5.5已于2016年7月10日终止生命周期,这个解决方案是不可接受的。
travis-ci最好更新到Ubuntu 16.04 LTS,但是travis-ci的基础设施经理Brandon Burton在2016年2月28日wrote
“鉴于我们目前专注于支持12.04和14.04作为我们的主要环境。目前来看,我们不太可能在今年支持16.04作为本机环境。”
因此,似乎我们还要使用Ubuntu Trusty一段时间。
这个问题的根源在于运行在travis-ci上的PHP版本是使用gnutls-cli(GnuTLS)2.12.23从2011年编译的。这个特定版本的gnutls-cli与某些(但不是所有)TLS 1.2连接存在问题。

@travis-ci: 能否重新编译您使用的PHP版本,针对更现代的GnuTLS版本 - 或者至少是更好地支持TLS 1.2的版本?


不幸的是,Ubuntu 16.04也受到了这个问题的困扰。 - RAM

4
在PHP中,可以使用CURL_SSLVERSION_*常量控制curl使用的SSL协议。
通过设置:
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 intact


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


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


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


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


Trying 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."

我注意到travis-ci的PHP 5.6版本和PHP 7版本都不支持常量CURL_SSLVERSION_TLSv1_0、CURL_SSLVERSION_TLSv1_1和CURL_SSLVERSION_TLSv1_2。
总结一下,我已经遍历了所有可能的CURL_SSLVERSION_*常量,但无论我使用哪个PHP版本都不能连接到api.reporting.cloud。
请问有人有什么建议可以帮助我在travis-ci上连接到api.reporting.cloud吗?

2
我在这个邮件列表中找到了解决问题的方法:mailing list
引用: 服务器不喜欢gnutls 2.12中TLS 1.2支持中的某些内容,因为如果你禁用它,它似乎可以工作。相同的服务器可以使用gnutls 3.2工作,而两个版本的客户端hello唯一的区别是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

下一步是通过CURL从PHP中进行此设置(在特定情况下的错误库版本)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接