≡ Menu

How to Fix Curl TLS SSL Protocol Issue from CLI and PHP Code

Q: On one of our server, the webserver is not setup to support SSLv2 or SSLv3. Both are disabled on the server side. It supports only TLSv1. How can I get curl to work from both command line, and from inside my PHP code?

A: In most case, curl will automatically pick the correct protocol and connect to it. But, you can also specify a specific protocol to use for curl command. In this example, you have to instruct CURL to use TLSv1, as explained in this tutorial.

Specify Protocol on Curl Command Line

The following are the various protocol options supported on the command line by curl:

  • -0 (or) –http1.0 for HTTP 1.0 (H)
  • -1 (or) –tlsv1 for TLSv1 (SSL)
  • -2 (or) –sslv2 for SSLv2 (SSL)
  • -3 (or) –sslv3 for SSLv3 (SSL)

In this example, this particular server, works on regular HTTP. No issues here.

$ curl http://192.168.101.1
<html><body><h1>It works!</h1></body></html>

Refer this: 15 Practical Linux cURL Command Examples

But, if you use SSLv3, using the -3 option, it returns the “sslv3 alert handshake failure” error message.

$ curl -3 https://192.168.101.1
curl: (35) error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

If you use SSLv2, using -2 option, it returns the “Unknown SSL protocol” error message.

$ curl -2 https://192.168.101.1
curl: (35) Unknown SSL protocol error in connection to 192.168.101.1:443 

In this case, on this particular server, it supports only TLS. So, use -1 option as shown below.

$ curl -1 https://192.168.101.1
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

In this case, since we are using the ip-address, which doesn’t match the SSL certificate that is installed on the webserver. So, we are getting the above “SSL3_GET_SERVER_CERTIFICATE:certificate verify failed” error message.

Curl by default performs the SSL cert verification. If you are using a CA authority bundle, then the default bundle name is curl-ca-bundle.crt. You can specify a different bundle using the –cacert option.

But, in our case, we want to use the TLSv1 protocol, but without the SSL certificate verification. For this, use the -k option (or –insecure option), which will not perform the SSL certificate verification.

The following is a usage of the -k option.

$ curl -k https://192.168.101.1
curl: (35) Unknown SSL protocol error in connection to 192.168.101.1:443 

If you want to know more details about the error thrown by CURL command, use -v option. As you see below. Even when we didn’t pass the protocol option, from the command output, we can see it is trying to use SSLv2 for this.

$ curl -k -v https://192.168.101.1
* About to connect() to 192.168.101.1 port 443
*   Trying 192.168.101.1... connected
* Connected to 192.168.101.1 (192.168.101.1) port 443
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSLv2, Client hello (1):
Unknown SSL protocol error in connection to 192.168.101.1:443 
* Closing connection #0
curl: (35) Unknown SSL protocol error in connection to 192.168.101.1:443 

Solution From Command Line

Refer this: wget vs curl: How to Download Files Using wget and curl

So, in our case, since SSLv2 and SSLv3 are disabled on the server side, and for some reason if the curl doesn’t automatically set the right protocol, the following works when we want to use only TLSv1 protocol with curl from command line as shown below.

$ curl -k -1 https://192.168.101.1
<html><body><h1>It works!</h1></body></html>

If you want to see the details of what exactly this does, pass the -v option as shown below.

$ curl -k -1 -v https://192.168.101.1

The above can also be done using the following alternative options

$ curl --insecure --tlsv1 --verbose https://192.168.101.1

Again, in the above command:

  • -1 (or) –tlsv1 for TLSv1 (SSL)
  • -k (or) –insecure to Allow connections to SSL sites without certs (H)
  • -v (or) –verbose to Make the operation more talkative (lower case v)

Solution From PHP

From your PHP code, if you are using the cURL functions, and like to set the protocol options, you should use curl_setopt or curl_setopt_array function.

Use curl_setopt if you want to set only one option.

curl_setopt($c, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);

In the above:

  • $c is the curl variable that you got from the curl_init() function, when you created a new cURL resource from your PHP program.
  • CURLOPT_SSLVERSION is a curl option name.
  • CURL_SSLVERSION_TLSv1 is a curl value for the corresponding option in parameter#2

You can also use a numer instead of “CURL_SSLVERSION_TLSv1”. In this example, this is equivalent to 1.

curl_setopt($c, CURLOPT_SSLVERSION, 1);

The following are possible CURLOPT_SSLVERSION values you can set. You can either use the descriptive constant or the corresponding number that are shown below.

  • CURL_SSLVERSION_DEFAULT (0)
  • CURL_SSLVERSION_TLSv1 (1)
  • CURL_SSLVERSION_SSLv2 (2)
  • CURL_SSLVERSION_SSLv3 (3)
  • CURL_SSLVERSION_TLSv1_0 (4)
  • CURL_SSLVERSION_TLSv1_1 (5)
  • CURL_SSLVERSION_TLSv1_2 (6)

When you want to set multiple CURL option, use the curl_setopt_array as shown below. Here, apart from setting the CURLOPT_SSLVERSION, it also set’s few other curl options.

In this case, the 2nd parameter will be an array which will contain multiple CURL options as shown below.

curl_setopt_array($c, array
(
  CURLOPT_SSL_VERIFYHOST => 0,
  CURLOPT_SSL_VERIFYPEER => 0,
  CURLOPT_SSLVERSION => 1
));
Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

Comments on this entry are closed.

  • Anonymous April 11, 2017, 3:39 am

    hi, below is snippet of how am I using curl. its works fine on test system but not on clients system
    on Clients server i get error “Unknown SSL protocol error in connection ”
    how can i fix it ?? please advise

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_USERPWD, “$email:$password”);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_SSLVERSION, 1); // tried 6 as well but same error
    $server_output = curl_exec ($ch);
    print curl_error($ch);

  • Aniket May 19, 2017, 2:11 pm

    Hi Ramesh,

    I face the same issue related to ‘ Unknown SSL protocol error in connection to abc-test.xyz.com:443’
    Ive tried to use –tlsv1 –insecure,but nothing works.Your thoughts?

    Heres the entire command and its verbose output:

    $ /usr/share/centrifydc/bin/curl -kH –tlsv1 –insecure -v “Accept: application/xml” -H “X-Coupa-API-KEY: 6a5b933911223344555466d814c0d” https://abc-test.xyz.com/api/data_file_sources?file_file_name=Lookupvalues_04282017_054457.csv
    * Hostname was NOT found in DNS cache
    * getaddrinfo(3) failed for Accept:80
    * Couldn’t resolve host ‘Accept’
    * Closing connection 0
    curl: (6) Couldn’t resolve host ‘Accept’
    * Hostname was NOT found in DNS cache
    * Trying 54.xxx.x.100…
    * Connected to abc-test.xyz.com (54.xxx.x.100) port 443 (#1)
    * SSLv3, TLS handshake, Client hello (1):
    * Unknown SSL protocol error in connection to abc-test.xyz.com:443
    * Closing connection 1
    curl: (35) Unknown SSL protocol error in connection to abc-test.xyz.com:443