Php cURL错误35:gnutls\u握手()失败

Php cURL错误35:gnutls\u握手()失败,php,curl,travis-ci,gnutls,Php,Curl,Travis Ci,Gnutls,我在使用CURL通过SSL请求URI的PHP组件中遇到以下错误: cURL error 35: gnutls_handshake() failed: A TLS packet with unexpected length was received. 此错误发生在travis-ci.org环境中,但不在我们的任何测试环境中。参见travis ci构建 我发现运行在Travis worker中的PHP版本在“Ubuntu12.04.5 LTS”上再次编译为“GnuTLS/2.12.14”,或者在“

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

cURL error 35: gnutls_handshake() failed: A TLS packet with unexpected length was received.
此错误发生在travis-ci.org环境中,但不在我们的任何测试环境中。参见travis ci构建

我发现运行在Travis worker中的PHP版本在“Ubuntu12.04.5 LTS”上再次编译为“GnuTLS/2.12.14”,或者在“Ubuntu14.04.3 LTS”上再次编译为“GnuTLS/2.12.23”

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

因此,我假设问题与“GnuTLS/2.12.14”或“GnuTLS/2.12.23”或编译它们时使用的参数有关

我曾尝试使用CURL常量curloptsslversion限制SSL版本,但这并不能解决问题

根据www.ssllabs.com,所讨论的主机api.reporting.cloud支持TLS 1.2、TLS 1.1和TLS 1.0


有人能给我一些提示或建议吗?

我从以下几点中找到了解决问题的方法:

服务器不喜欢gnutls的TLS1.2支持中的某些内容 2.12因为如果你禁用它,它似乎可以工作。同一台服务器适用于GnuTLS3.2,这是两者在客户机hello方面的唯一区别 版本是GnuTLS3.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进行此设置(在库版本出现错误的特定情况下)。

在PHP中,可以控制CURL与CURL\u SSLVERSION\u*常量一起使用的SSL协议

通过设置:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
我可以强制curl使用“tls1.1”

通过设置:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
我可以强制curl使用“TLS1.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);
if (getenv('TRAVIS')) {
    $options['curl'][CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_1;
}
我还注意到常数CURL\u SSLVERSION\u TLSv1\u 0、CURL\u SSLVERSION\u TLSv1\u 1和CURL\u SSLVERSION\u TLSv1\u 2在travis ci的PHP5.6和PHP7版本中都不可用

总而言之,我已经遍历了所有可能的CURL_SSLVERSION_*常量,没有一个允许我连接到travis ci上的api.reporting.cloud,无论我使用哪一个PHP版本


有人对我如何从travis ci连接到api.reporting.cloud有什么建议吗?

解决这个问题的方法是将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代码的情况下设置上述常量即可:

<?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);
if (getenv('TRAVIS')) {
    $options['curl'][CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_1;
}
这种解决方法的缺点是,它只适用于Ubuntu Trusty提供的特定PHP版本(PHP5.5)。考虑到PHP5.5在2016年7月10日达到使用寿命,此解决方案是不可接受的

travis ci最好更新到Ubuntu 16.04 LTS,但travis ci基础设施经理Brandon Burton于2016年2月28日表示:

鉴于此,我们目前的重点是支持12.04和14.04 主要环境。目前,我们不太可能成功 今年支持16.04作为本地环境

因此,看起来我们在Ubuntu Trusty上停留了一段时间

这个问题的根源在于,从2011年开始,在travis ci上运行的PHP版本是使用gnutls cli(gnutls)2.12.23编译的。此特定版本的gnutls cli在某些(但不是全部)TLS 1.2连接方面存在问题


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

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