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
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 ));