22
votes

I've been having problems on my development server where cURL, while working perfectly with anything HTTP, does not function properly with anything HTTPS—even the exact same resource with different protocols (for testing I've been requesting google.com using both HTTP and HTTPS).

The cURL error returned is 35:

A problem occurred somewhere in the SSL/TLS handshake.

I have combed the web and SO for solutions, and all of them have been to either set CURLOPT_SSL_VERIFYPEER to false, which changes nothing, or to download the certificate file and set CURLOPT_CAINFO to its path, which also changes nothing.

When setting a certificate, I followed the instructions of this tutorial and this tutorial, trying to both download the certificate for the resource I'm requesting, and downloading a cert bundle.

I've also tried explicitly setting CURLOP_PORT to 443. For thoroughness of my question, other options I set are CURLOPT_VERBOSE=true, CURLOPT_RETURNTRANSFER=true, and CURLOPT_SSL_VERIFYHOST=2 (I've tried every combination of 1, and 2 with VERIFYPEER both true and false). I also have made sure in phpinfo() that I have OpenSSL and it is enabled.

I'm using a lot of old code that worked perfectly on my last production server, so this code has worked before. But that hosting was shared hosting and I don't know most of the configuration there.

4
Are you accessing the same URL? You've hit most of the same research that I did when I ran into this issue.Jason
I used both http:// www.google.com, which worked; and https:// www.google.com, which didn't.spezied
@Spezied, if the supplied answer answers your question, could you please choose it as your answer so the question can be closed? Thx.Joseph Lust
It doesn't answer the question since I clearly stated in the question that that was exactly the unsatisfactory answer I've found elsewhere in SO and on the Internet. I've since concluded that it must not be fixable in PHP; there's something wrong with PHP or my extensions or something. Though I still don't know quite how to fix that. I'll poke around and see. Thank you anyway.spezied

4 Answers

25
votes

Curl doesn't have built-in root certificates (like most modern browser do). You need to explicitly point it to a cacert.pem file:

  curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cert/file/cacert.pem');

Without this, curl cannot verify the certificate sent back via ssl. This same root certificate file can be used every time you use SSL in curl.

You can get the cacert.pem file here: http://curl.haxx.se/docs/caextract.html

12
votes

How about this. It fetches what might be the HTTPS Google homepage. (Since I've disabled certificate verification, I have no way to actually know that it's the real Google homepage.) It should do the trick for you.

<?PHP

// connect via SSL, but don't check cert
$handle=curl_init('https://www.google.com');
curl_setopt($handle, CURLOPT_VERBOSE, true);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
$content = curl_exec($handle);

echo $content; // show target page
?>
6
votes

Find if your OS includes a directory of certificates. If so then the required CA certs will often already be included. On Ubuntu, for example, it's usually /etc/ssl/certs. If this directory exists, set the CA path parameter:

curl_setopt($ch, CURLOPT_CAPATH, '/etc/ssl/certs');

Alternatively you can reference a single CA certificate file. Include a cacert.pem file in your project or install it on your server. Download from a trusted source, e.g. cacert.org. For a single file do not set the CAPATH and instead only set CAINFO:

curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem');

Turning off peer and host verification is a quick but insecure workaround to the real problem. These features exist for good reason: so you can trust, via 3rd party, that the system you're connecting to is the one you expect.

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
0
votes
var_dump( curl_error($ch) );

will tell you the error. It might be different cause.