PHP Curl HTTPS SSL23_GET_SERVER_HELLO:tlsv1 - php

I'm not able to access via curl to a https site and I'm stuck.
The url can be opened in the browser and is using the following secure connection:
The connection to this site is encrypted and authenticated using a
strong protocol (TLS 1.2), a strong key exchange (ECDHE_RSA with
P-256), and a strong cipher (AES_128_GCM).
Here the php cUrl script I'm using:
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$Org_Input); //$Org_Input
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3');
curl_setopt($curl, CURLOPT_AUTOREFERER, true); //updates the referrer
curl_setopt($curl, CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_SSLVERSION, 6);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0);
$response= curl_exec($curl);
if (FALSE === $response) {
echo "cUrl Error: " . curl_error($curl) . "<br><br>";
}
The script worked previously with the http url and now causes a problem if the url gets redirected to https. I believe it's linked to curl_setopt($curl, CURLOPT_SSLVERSION, 6);
I tried with the script
for($i=0;$i<=6;$i++) {
//if($i==2) continue;
$ch = curl_init($Org_Input);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSLVERSION, $i);
if(curl_exec($ch) === false)
echo $i.': ' . curl_error($ch) . "<br>";
else
echo $i.': works<br>';
echo "\n";
curl_close($ch);
}
And I get the following error messages:
0: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
1: error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version
2: Unknown SSL protocol error in connection to www.example.com:443
3: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
4: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
5: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
6: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
As the website is using "TLS 1.2" for secure connection I believe the 6 is the right value as it stands for "CURL_SSLVERSION_TLSv1_2"
But then I'm stuck with the error response: "1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version"
Somebody has any idea what could be the issue?
cUrl Version: 7.21.0
Open SSL version: OpenSSL 0.9.8q 2 Dec 2010
openssl version number: 9470239

OpenSSL 0.9.8q 2 Dec 2010
This no longer supported version of OpenSSL does not support modern protocols (TLS 1.2) and modern ciphers. Additionally it might be that the site requires the TLS SNI extension which maybe is not supported by old software.
It is unknown what exactly of these mentioned problem is really the issue since the URL of the site you reach is unknown. But I'm pretty sure that this is one of these causes and that an upgrade of OpenSSL, curl and the PHP bindings for it will solve the problem.
As the website is using "TLS 1.2" for secure connection I believe the 6 is the right value as it stands for "CURL_SSLVERSION_TLSv1_2"
Since this version of OpenSSL does not support TLS 1.2 trying to use TLS 1.2 using this setting will not solve the problem but maybe make it worse. Try to use TLS 1.0 instead since that is the most this OpenSSL version can do.

Related

PHP Curl - Received HTTP/0.9 when not allowed

I stumbled over a weird behavior when I try to send a post HTTP/2.0 request to apples push service:
$http2ch = curl_init();
curl_setopt($http2ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($http2ch, CURLOPT_URL, 'https://api.push.apple.com/3/device/megauniquedevicetokendummy');
curl_setopt($http2ch, CURLOPT_PORT, 443);
curl_setopt($http2ch, CURLOPT_HTTPHEADER, $httpHeader);
curl_setopt($http2ch, CURLOPT_POST, true);
curl_setopt($http2ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($http2ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($http2ch, CURLOPT_TIMEOUT, 30);
curl_setopt($http2ch, CURLOPT_HEADER, 1);
$result = curl_exec($http2ch);
if ($result === false) {
throw new \Exception("Curl failed: " . curl_error($http2ch) . " | " . curl_getinfo($http2ch, CURLINFO_HTTP_CODE));
}
The exception is thrown with the Message:
Curl failed: Received HTTP/0.9 when not allowed | 0
I explicitly told curl to use HTTP/2.0 on the second line of the code snipped above.
Does anyone have any idea what that error message means and why curl uses such an old HTTP version?
I am on PHP 7.2 and curl version 7.66.0.
This can also happen when the server is a grpc server. When curl is run against a grpc server or other non-HTTP server that doesn't respond with a valid HTTP status line that curl expects, curl will print the "Received HTTP/0.9 when not allowed".
It might be better if curl printed something like "unknown protocol" rather than assuming it is 0.9 because hitting something like a grpc server these days is going to be far more common than an actual HTTP 0.9 server.
I figured it out.
Make sure that curl is compiled with nghttp2.
If you are unsure, you can check it on your terminal using curl --version
If you dont find nghttp2/{version} you need to compile curl again with nghttp2.
curl --version example where nghttp2 is missing:
curl 7.66.0 (amd64-portbld-freebsd12.0) libcurl/7.66.0 OpenSSL/1.1.1d zlib/1.2.11
curl --version example where nghttp2 is available:
curl 7.64.1 (x86_64-apple-darwin19.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.39.2
I do not believe it requires you to have a version of curl compiled differently, but rather set the option to allow http 0.9 as a response from your older server. PHP has some notes on "CURLOPT_HTTP09_ALLOWED" that may have differed when you posted your question via https://www.php.net/manual/en/function.curl-setopt.php
The option that overcame the error for me was:
curl_setopt($http2ch, CURLOPT_HTTP09_ALLOWED, true);

PHP cURL: enforce low TLS version

Goal is to write PHP code testing for TLS v1.2 connectivity. Getting a successful answer isn't a problem, but I can't produce a failure by using an older TLS version in PHP. Testing failures is obviously needed to prove correctness of code (to some reasonable degree).
On the command line I could come up with this, giving a clear distinction:
$ curl -X POST https://api.paypal.com/v1/oauth2/token
{"name":"AUTHENTICATION_FAILURE", [...]
$ curl --tls-max 1.1 -X POST https://api.paypal.com/v1/oauth2/token
curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
In PHP I tried this ...
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.paypal.com/v1/oauth2/token');
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// $response: '{"name":"AUTHENTICATION_FAILURE", [...]
... which means a succcessful TLS v1.2 connection, as one can see in the CLI example above, despite TLS v1.1 being requested. It's the same result as when requesting CURL_SSLVERSION_TLSv1_2.
This is PHP 7.3.7 with cURL 7.64.0 and I hope I can get away without recompiling PHP just for disabling TLS v1.2 support.
To answer my own question, documentation at https://www.php.net/function.curl-setopt is/was outdated. cURL 7.54 changed behavior of CURL_SSLVERSION_ macros, these set now the minimum acceptable TLS version for the connection. It also introduced CURL_SSLVERSION_MAX_ macros, which set the maximum TLS version tried. Until PHP documentation is updated, see https://curl.haxx.se/libcurl/c/CURLOPT_SSLVERSION.html.
Accordingly, limiting the connection to TLS v1.1 works like this:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.paypal.com/v1/oauth2/token');
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
Little PHP/CURL test script:
<?php
echo 'PHP version: ' . phpversion() . PHP_EOL;
echo 'cURL version: ' . curl_version()['version'] . PHP_EOL;
$ch = curl_init('https://www.howsmyssl.com/a/check');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); // TLS 1.0
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); // TLS 1.1
//curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); // TLS 1.2 or 1.3
$data = curl_exec($ch);
curl_close($ch);
$json = json_decode($data);
echo ($data ? $json->tls_version : 'curl request failed') . PHP_EOL;
"TLS v1.1 being requested" is wrong given that TLS v1.1 or later (Added in 7.34.0) is pretty clear as well as "The maximum TLS version can be set by using one of the CURL_SSLVERSION_MAX_ macros"

cURL PUT Requests hangs

So here's my problem.
I'm using curl to access my CouchDB by HTTP. I recently updated my WAMP to the WAMP 3 64bit wich comes with PHP 5.6.16 and Apache 2.4.17. Therefore, since this upgrade, I discovered that I couldn't do PUT request anymore.
Env
PHP 5.6.16
Apache 2.4.17
Windows 10 64 bit
Wamp 3 64 bit
Curl --version
curl 7.49.1 (x86_64-pc-win32) libcurl/7.49.1 OpenSSL/1.0.2h nghttp2/1.11.1
Protocols: dict file ftp ftps gopher http https imap imaps ldap pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile NTLM SSL HTTP2
Code executed
So when I execute this :
<?php
$table="testname";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:5984/' . $table);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'validUser:validPass');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
I get a quick response from the server.
Then, I try to create a database :
<?php
$table = "testname";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost:5984/' . $table);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'validUser:validPass');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Problem
So, when I execute this code, the request will hang on curl_exec.
What's weird is that, after the timeout, the request will be received by CouchDB but no response will be given. It seems that my "Put" request are stacked in a buffer and they are waiting to be executed.
Verbose curl output
* Hostname in DNS cache was stale, zapped
* Trying ::1...
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 5984 (#0)
* Server auth using Basic with user 'validUser'
> PUT /customers HTTP/1.1
Host: localhost:5984
Authorization: Basic dGVzdEFkbWluOnRlc3RQYXNzd29yZA==
Content-type: application/json
Accept: */*
* Operation timed out after 10000 milliseconds with 0 bytes received
* Closing connection 0
Hints
-I try to install a SSL certificate but It didn't seem to work. Having this certificate still installed can cause problems?
-I can do PUT request with a REST client on my Atom editor without problems.
-I seems like there is a problem in my network route internally. I'm saying this because It affected the PHP-Curl aswell as the Curl CLI. Also, I'm able to do GET request but the PUT request are like "hanging" for no reason and are "Accepted" by my CouchDB when the timeout occurs. It's like if I was sending long poll request.
What have been tested
Execute the same command on the command line -> Same result
Try a REST Client on my Atom editor with success
A friend of mine try to access to my database remotly with success (So CouchDB doesn't seem the problem)
Even if I tested with my Firewall disabled, uninstalling my antivirus ( Bitdefender Total Security 2016) fixed my issue.

PHP and cURL: same code but unable to fetch content on existing server conf

I'm running into some awkward issue when trying to fetch content from a URL.
The issue is the URL returns no response and the http "request header" size is 0.
I've run into similar issue like this on the same website before and have solved it (with some help on StackOverflow).
Previously, the issue was due to their SSL certificate being misconfigured and the solution was to set both CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER to false. However, it seems that this time, even with these two cURL parameters being set to false, cURL is still having problems fetching from the URL.
other notes:
i.) The web content can be fetched with a regular web browser, even with incognito mode.
ii.) The CURLOPT_HTTPHEADER that I set below is the exact headers sent by the web browser. Whether I set this parameter or not, cURL doesn't return anything (and the "request header" is still zero).
I've later tested the code on a LEMP server with Ubuntu 14.04 (using simply a stock server image provided by a web host) and the code works. So this seems to be a server issue and not a code issue.
the following are the configurations:
CentOS 6 LEMP server with PHP 5.3.3 (doesn't work):
curl:
curl 7.19.7
SSL Version NSS/3.14.0.0
openssl:
OpenSSL Library Version OpenSSL 1.0.0-fips 29 Mar 2010
CentOS 5 LAMP server with PHP 5.4.40 (doesn't work. this configuration is from the server setup by the shared web hosting provider. I've no control over it.):
curl:
curl 7.38.0
SSL Version OpenSSL/0.9.8b
openssl:
OpenSSL Library Version OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008
Ubuntu 14.04 LEMP server with PHP 5.5.9 (works. this is from the stock server image provided by a VPS web host):
curl:
curl 7.35.0
SSL Version OpenSSL/1.0.1f
openssl:
OpenSSL 1.0.1f 6 Jan 2014
Since I need to make this code work on a shared hosting environment, I wonder if anyone can tell me what cause the difference so I can make a change or request a change if possible.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0");
curl_setopt($ch, CURLOPT_HTTPHEADER,
array(
'Host: www.example.com',
'User-Agent=Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0',
'Accept: application/json, text/javascript, */*; q=0.01',
'Accept-Language: en-US,en;q=0.5',
'DNT: 1',
'X-Requested-With: XMLHttpRequest',
'Referer: https://www.example.com/path/to/example.html',
'Connection: keep-alive',
));
$url = 'https://www.example.com/api/v1/example';
curl_setopt($ch, CURLOPT_URL, $url);
$output = curl_exec($ch);
print_r( curl_getinfo($ch) );
?>
To summarize. It does not work with SSL versions NSS/3.14.0.0 and OpenSSL/0.9.8b but works with OpenSSL/1.0.1f.
Looking at the SSLLabs report it can be seen that the host requires at least TLS 1.1, i.e. no support for TLS 1.0 or even lower. Support for TLS 1.1 was added to OpenSSL with version 1.0.1, i.e. it is not available with OpenSSL 0.9.8b. NSS 3.14.0 has support for TLS 1.1 included (just added with version 3.14) but as can be seen from this bug curl on RHEL6/CentOS6 will use TLS 1.0 only by default.

PayPal TLS Test URL - PHP curl SSL protocol error

I'm trying to test against a new PayPal test endpoint: https://tlstest.paypal.com.
See the very bottom of this page: TLS 1.2 and HTTP/1.1 Upgrade Microsite (Verify your...).
I'm using PHP (5.3.28) and curl (7.30.0 - OpenSSL/0.9.8y - libssh2/1.4.2) on Windows Server 2008 R2 and IIS 7.5:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://tlstest.paypal.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_SSLVERSION, 6); // CURL_SSLVERSION_TLSv1_2
$result = curl_exec($ch);
echo 'result = '.$result.'<br>';
echo 'errno = '.curl_errno($ch).'<br>';
echo 'error = '.curl_error($ch).'<br>';
curl_close($ch);
I'm getting this error:
35 Unknown SSL protocol error in connection to tlstest.paypal.com:443
I found this: Github - Unknown SSL protocol error in which someone says:
Openssl must be at 1.0.1 or higher for TLS 1.2.
Is this correct..?
My PHP OpenSSL is on version: OpenSSL/0.9.8y (from phpinfo()).
If you do need OpenSSL 1.0.1 or higher to use TLS 1.2 then presumably every server running PHP with a lesser OpenSSL version (I'm guessing that's a lot!) will be unable to use any PayPal API's or the PayPal IPN soon.
How do I update my PHP OpenSSL version on Windows..?
I have this working now. It seems as though at least OpenSSL/1.0.1i is required for TLS 1.2.
I upgraded my PHP version to 5.6.0, which upgraded OpenSSL to version 1.0.1.
I also needed these:
Use curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); to verify the certificate. The default is true as of cURL 7.10.
Save cacert.pem from http://curl.haxx.se/docs/caextract.html locally (in my case to c:\cert), then update the PHP ini that you're using to reference cacert.pem as shown here. Using the ini file saves you having to use curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '\cacert.pem'); in every call.

Categories