HTTPS and SSL3_GET_SERVER_CERTIFICATE:certificate verify failed, CA is OK

It's a pretty common problem in Windows. You need just to set cacert.pem to curl.cainfo.

Since PHP 5.3.7 you could do:

  1. download https://curl.se/ca/cacert.pem and save it somewhere.
  2. update php.ini -- add curl.cainfo = "PATH_TO/cacert.pem"

Otherwise you will need to do the following for every cURL resource:

curl_setopt ($ch, CURLOPT_CAINFO, "PATH_TO/cacert.pem");

curl used to include a list of accepted certificate authorities (CAs) but no longer bundles ANY CA certs since 7.18.1 and onwards. So by default it'll reject all TLS/SSL certificates as unverifiable.

You'll have to get your CA's root certificate and point curl at it. More details at curl's details on TLS/SSL certificates verification.


Warning: this can introduce security issues that SSL is designed to protect against, rendering your entire codebase insecure. It goes against every recommended practice.

But a really simple fix that worked for me was to call:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

before calling:

curl_exec():

in the php file.

I believe that this disables all verification of SSL certificates.


Source: http://ademar.name/blog/2006/04/curl-ssl-certificate-problem-v.html

#Curl: SSL certificate problem, verify that the CA cert is OK# ###07 April 2006###

When opening a secure url with Curl you may get the following error:

SSL certificate problem, verify that the CA cert is OK

I will explain why the error and what you should do about it.

The easiest way of getting rid of the error would be adding the following two lines to your script . This solution poses a security risk tho.

//WARNING: this would prevent curl from detecting a 'man in the middle' attack
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); 

Let see what this two parameters do. Quoting the manual.

CURLOPT_SSL_VERIFYHOST: 1 to check the existence of a common name in the SSL peer certificate. 2 to check the existence of a common name and also verify that it matches the hostname provided.

CURLOPT_SSL_VERIFYPEER: FALSE to stop CURL from verifying the peer's certificate. Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option. CURLOPT_SSL_VERIFYHOST may also need to be TRUE or FALSE if CURLOPT_SSL_VERIFYPEER is disabled (it defaults to 2). Setting CURLOPT_SSL_VERIFYHOST to 2 (This is the default value) will garantee that the certificate being presented to you have a 'common name' matching the URN you are using to access the remote resource. This is a healthy check but it doesn't guarantee your program is not being decieved.

###Enter the 'man in the middle'###

Your program could be misleaded into talking to another server instead. This can be achieved through several mechanisms, like dns or arp poisoning ( This is a story for another day). The intruder can also self-sign a certificate with the same 'comon name' your program is expecting. The communication would still be encrypted but you would be giving away your secrets to an impostor. This kind of attack is called 'man in the middle'

###Defeating the 'man in the middle'###

Well, we need to to verify the certificate being presented to us is good for real. We do this by comparing it against a certificate we reasonable* trust.

If the remote resource is protected by a certificate issued by one of the main CA's like Verisign, GeoTrust et al, you can safely compare against Mozilla's CA certificate bundle which you can get from http://curl.se/docs/caextract.html

Save the file cacert.pem somewhere in your server and set the following options in your script.

curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, TRUE); 
curl_setopt ($ch, CURLOPT_CAINFO, "pathto/cacert.pem");

for All above Info Credit Goes to : http://ademar.name/blog/2006/04/curl-ssl-certificate-problem-v.html


The above solutions are great, but if you're using WampServer you might find setting the curl.cainfo variable in php.ini doesn't work.

I eventually found WampServer has two php.ini files:

C:\wamp\bin\apache\Apachex.x.x\bin
C:\wamp\bin\php\phpx.x.xx

The first is apparently used for when PHP files are invoked through a web browser, while the second is used when a command is invoked through the command line or shell_exec().

TL;DR

If using WampServer, you must add the curl.cainfo line to both php.ini files.