SSL経由でURIを要求するためにCURLを使用するPHPコンポーネントから、次のエラーが発生しています。
cURL error 35: gnutls_handshake() failed: A TLS packet with unexpected length was received.
このエラーはtravis-ci.org環境で発生しますが、テスト環境では発生しません。 travis-ci build 1446637 を参照してください。
Travisワーカーで実行中のPHPバージョンは、「Ubuntu 12.04.5 LTS」で「GnuTLS/2.12.14」、または「GnuTLS/2.12.23」でコンパイルされていることを発見しました「Ubuntu 14.04.3 LTS」。
開発環境では、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をサポートしています。
誰かが私に何かヒントや指針を持っていますか?
この問題の回避策は、標準のUbuntu Trusty php5-cliおよびphp5-curlパッケージを使用するようにtravis-ciを構成することです。標準パッケージは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が7月にサポート終了に達した2016年10月、このソリューションは受け入れられません。
Travis-ciはUbuntu 16.04 LTSに更新するのが理想的ですが、2016年2月28日のTravis-ci wrote のインフラストラクチャマネージャーであるBrandon Burtonは次のようになります。
そのため、現在、主要な環境として12.04と14.04のサポートに重点を置いています。現時点では、今年のネイティブ環境として16.04をサポートすることはほとんどありません。
したがって、しばらくの間、Ubuntu Trustyに悩まされているように見えます。
この問題の根本は、travis-ciで実行されるPHPバージョンが2011年からgnutls-cli(GnuTLS)2.12.23でコンパイルされていることです。この特定のバージョンのgnutls-cliには問題があります。一部(すべてではない)のTLS 1.2接続。
@ travis-ci:より最近のバージョンのGnuTLSに対してPHPバージョンを使用して、またはTLS 1.2をより適切にサポートするバージョンに対して)再コンパイルすることは可能でしょうか?
PHPでは、curlがCURL_SSLVERSION_ *定数で使用する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 "
ここでは、「TLSv1.0を使用したSSL接続」がバックエンドサーバーに正しく接続していることがはっきりとわかります。
ただし、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_ *定数をループしましたが、使用しているPHPバージョンに関係なく、1つの定数ではtravis-ciのapi.reporting.cloudに接続できません。
Travis-ciからapi.reporting.cloudに接続する方法について何か提案はありますか?
私はこの問題の解決策をこの メーリングリスト で見つけました:
サーバーはgnutls 2.12のTLS 1.2サポートに何かを好まない。なぜならそれを無効にすると機能するように見えるからだ。同じサーバーがgnutls 3.2で動作し、2つのバージョンのclient 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からこの設定を行うことです(ライブラリバージョンの特定の場合)。