fixing SSL certificate problem: unable to get local issuer certificate for real in PHP

Viewed 456

In my PHP code, at some point I perform a cURL to an external website. Today, all of a sudden I got this error:

SSL certificate problem: unable to get local issuer certificate

This is the relevant part of my code:

//downloaded from https://curl.haxx.se/docs/caextract.html
//(latest version Wed Oct 14 03:12:15 2020 GMT)    
$cacert_pem = realpath("some/path/to/cacert.pem"); 

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($query_data));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_CAINFO, $cacert_pem);

Searching the web for this issue, I came across a lot of questions from this site but none of them really explains what is going on, they just tell to edit php.ini and point to the cacert file, or to update the file to a newer version or do something like this:

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

Which is obviously not recommended...

Then I landed here https://www.offset101.com/fix-ssl-certificate-problem/ and one of the solutions is:

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $cacert_pem);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $cacert_pem);

and the error is gone!

So, my questions are:

  1. Why is this happening in the first place? I mean, why the code was working yesterday but not today. If I understand correctly, the problem is on my side and not on the external website.
  2. Is the solution described really fixing the issue or is the same like setting the value to 0? According to the documentation https://www.php.net/manual/es/function.curl-setopt.php, the possible values for CURLOPT_SSL_VERIFYHOST are either 0, 1 or 2.
  3. And of course...how can I fix this?
1 Answers

Why is this happening in the first place? I mean, why the code was working yesterday but not today. If I understand correctly, the problem is on my side and not on the external website

If no changes where done to your code and it suddenly stopped working the problem might be with the remote site. A typical problem is that the certificate of the site got renewed and that the certificate was either improperly setup (like missing intermediate certificates) or that the certificate is now issued by a different CA.

Since it looks like your CA trust store is simply the commonly used one which also used by Firefox I expect that the problem is a misconfiguration on the server side. Since the site you are trying to reach is not known to us you have to check it yourself. For this you can use SSLLabs to analyze the site and then look out for any problems, specifically "chain issues".

Is the solution described really fixing the issue or is the same like setting the value to 0?

From my understanding this "solution" is dangerously wrong. As you correctly realized these options don't take a string as argument but only a number. Giving a string will implicitly convert this string to a number which will result in 0 unless the string starts with a number. So in most cases the "fix" shown in the post you refer to actually disables the certificate validation. No wonder that the error is then gone, but is is of course pretty dangerous.

And of course...how can I fix this?

Depends on the actual cause of the error. In case of missing intermediate certificates from the server you can try to add these missing certificates to your trust store, i.e. in addition to the ones you have already in there.

Related