By Josnidhin


2011-06-19 03:18:21 8 Comments

I am using XAMPP for development. Recently I upgraded my installation of xampp from an old version to 1.7.3.

Now when I curl HTTPS enabled sites I get the following exception

Fatal error: Uncaught exception 'RequestCore_Exception' with message 'cURL resource: Resource id #55; cURL error: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (60)'

Everyone suggest using some specific curl options from PHP code to fix this problem. I think this shouldn't be the way. Because I didn't have any problem with my old version of XAMPP and happened only after installing the new version.

I need help to figure out what settings change in my PHP installation, Apache etc can fix this problem.

11 comments

@Reinaldo Mendes 2014-10-09 02:43:16

I have the same error on amazon AMI linux.

I Solved by setting curl.cainfo on /etc/php.d/curl.ini

https://gist.github.com/reinaldomendes/97fb2ce8a606ec813c4b

Addition October 2018

On Amazon Linux v1 edit this file

vi /etc/php.d/20-curl.ini

To add this line

curl.cainfo="/etc/ssl/certs/ca-bundle.crt"

@Tim 2018-10-30 07:50:17

Perfect, thanks! I updated the question to add exactly what I did that solved the problem for me, rather than creating another answer.

@Spencer Williams 2017-02-28 04:42:26

For the love of all that is holy...

In my case, I had to set the openssl.cafile PHP config variable to the PEM file path.

I trust it is very true that there are many systems where setting curl.cainfo in PHP's config is exactly what is needed, but in the environment I'm working with, which is the eboraas/laravel docker container, which uses Debian 8 (jessie) and PHP 5.6, setting that variable did not do the trick.

I noticed that the output of php -i did not mention anything about that particular config setting, but it did have a few lines about openssl. There is both an openssl.capath and openssl.cafile option, but just setting the second one allowed curl via PHP to finally be okay with HTTPS URLs.

@knezmilos 2017-04-24 07:53:12

Thank you! Setting the curl.cainfo didn't work for me either, but setting openssl.cafile did! I'm on Windows 7 with XAMPP and PHP 7.1.1.

@Krys 2018-02-05 13:22:04

@knezmilos how did you go about setting the openssl.cafile? where did you download, and how do you activate it?

@knezmilos 2018-02-05 13:24:50

Well, it's been a while but I think it's something like this: curl.cainfo = "C:\xampp\cacert\cacert.pem" and openssl.cafile= "C:\xampp\cacert\cacert.pem" in php.ini, while I think I got the pem file from one of the answers here.

@TrophyGeek 2017-04-18 21:45:23

I ended up here when trying to get GuzzleHttp (php+apache on Mac) to get a page from www.googleapis.com.

Here was my final solution in case it helps anyone.

Look at the certificate chain for whatever domain is giving you this error. For me it was googleapis.com

openssl s_client -host www.googleapis.com -port 443

You'll get back something like this:

Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.googleapis.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority

Note: I captured this after I fixed the issue, to your chain output may look different.

Then you need to look at the certificates allowed in php. Run phpinfo() in a page.

<?php echo phpinfo();

Then look for the certificate file that's loaded from the page output:

openssl.cafile  /usr/local/php5/ssl/certs/cacert.pem

This is the file you'll need to fix by adding the correct certificate(s) to it.

sudo nano /usr/local/php5/ssl/certs/cacert.pem

You basically need to append the correct certificate "signatures" to the end of this file.

You can find some of them here: You may need to google/search for others in the chain if you need them.

They look like this:

example certificate image

(Note: This is an image so people will not simply copy/paste certificates from stackoverflow)

Once the right certificates are in this file, restart apache and test.

@Marc B 2011-06-19 05:23:16

curl used to include a list of accepted CAs, but no longer bundles ANY CA certs. So by default it'll reject all SSL certificates as unverifiable.

You'll have to get your CA's cert and point curl at it. More details at cURLS's Details on Server SSL Certificates.

@Josnidhin 2011-06-19 15:51:04

The curl is happening in Amazon web services php library. I didn't understand how to fix it without editing the library code.

@Marc B 2011-06-19 16:29:13

Then turn off certificate verification (CURLOPT_SSL_VERIFYPEER -> false). Your either add the CA cert of the site you're trying to do SSL with, or you disable CA verfification. Those are the only two options available.

@Till 2013-05-07 12:21:21

Just fyi — setting CURLOPT_SSL_VERIFYPEER to false defeats the purpose of using SSL.

@mrjrdnthms 2013-07-17 19:05:49

"You'll have to get your CA's cert and point curl at it" -> see Артур Курицын's answer below for details...

@Mark Fox 2014-02-23 05:38:02

@Till doesn't it defeat half the purpose of SSL? You still get privacy between you and your peer: you just don't have authenticity of your peer.

@hdgarrood 2014-08-16 06:55:13

without authenticity, what's the point in encrypting the data you're sending? If you've been MITMed then the data is compromised anyway

@AI0867 2015-05-13 16:44:21

That depends on what you're sending and the resources of your attacker. Sure, people can MITM you, but without SSL, anyone can passively snoop your plaintexts. Encryption-only SSL is still better than no SSL at all.

@Elijah Lynn 2016-03-22 18:47:34

Does anyone know what version of Curl "used to include a list of accepted CAs"?

@Артур Курицын 2013-05-11 07:54:51

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.haxx.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");

@Jonathan Nicol 2013-09-26 02:21:34

This worked for me in XAMPP on OS X. It fixed a problem where a Wordpress plugin wouldn't update due to being unable to locate a local certificate.

@http203 2014-05-02 18:43:06

For anyone else trying to solve this problem on Windows using Apache, I had to set the full path (i.e. C:\PATH_TO\cacert.pem) in my PHP code. On IIS, the relative path seemed to work ok.

@mujaffars 2014-08-11 11:43:38

If the cacert.pem is in same directory then curl_setopt($ch, CURLOPT_CAINFO, dirname(FILE) . '/cacert.pem'); will work

@Nate 2014-09-07 03:07:13

When using WampServer with 2., you must add the variable to two separate php.ini files. See stackoverflow.com/a/25706713/1101095

@qbolec 2016-03-11 18:42:52

What's puzzling/ironic is that you can download curl.haxx.se/ca/cacert.pem over HTTPS without specifing any extra options. Is the certificate for curl.haxx.se backed into curl itself?

@Kwnstantinos Natsios 2016-09-23 12:52:12

I have the cacert.pem file in /usr/local/lib/ where the php.ini file is and i have this code [PHP] curl.cainfo = "/cacert.pem" just in the beggining of the php.ini file. But i get this error Failed to save image file, with error message: error setting certificate verify locations: CAfile: /cacert.pem CApath: noneFailed to update your Event, with error message: Bad Request

@TimothyBuktu 2016-11-28 15:22:46

This worked for me on Centos. Caused some confusion because I'm running multiple versions of PHP through phpbrew and I was editing the wrong php.ini file :/ Used phpinfo to log PHP config, and once I added cacert.pem path to the right php.ini it worked like a charm

@Rashmy 2018-08-28 08:55:04

i had this issue: Exception: SSL Certificate problem: unable to get local issuer certificate and the above answer worked like a charm for me. Thank u

@LOwens1931 2014-09-30 15:27:31

When setting the curl options for CURLOPT_CAINFO please remember to use single quotes, using double quotes will only cause another error. So your option should look like:

curl_setopt ($ch, CURLOPT_CAINFO, 'c:\wamp\www\mywebfolder\cacert.pem');

Additionally, in your php.ini file setting should be written as:(notice my double quotes)

curl.cainfo = "C:\wamp\www\mywebfolder"

I put it directly below the line that says this: extension=php_curl.dll

(For organizing purposes only, you could put it anywhere within your php.ini, i just put it close to another curl reference so when I search using keyword curl I caan find both curl references in one area.)

@Solow Developer 2015-10-02 20:59:10

I hope php.ini should point to the pem file instead of its parent folder

@Nate 2014-09-07 03:04:34

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.

@Deepak Oberoi 2012-09-06 06:07:52

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.haxx.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

@Dan Herd 2012-09-20 11:11:34

It is generally considered polite to credit the source of your information and only quote certain parts relevant to the question, rather than simply copying and pasting it on here!

@Deepak Oberoi 2013-12-17 11:59:32

Sorry, I have been Away, yeah I appricate Dan for that and Updated The Post

@GTodorov 2014-12-03 21:41:09

At least Deepak made the effort to research it. @danherd So danherd, you just made the research to find that he took the code from somewhere? What was the attribution right of this code? Instead of wasting your time to find someone else' mistakes try to help someone on your own. Don't fight, share!

@Zsolt Boszormenyi 2014-01-02 18:32:37

The solution is very simple! Put this line before curl_exec:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

For me it works.

@rdlowrey 2014-03-02 01:37:35

Never, ever disable peer verification unless you don't care if the data is compromised in transit.

@braden 2014-08-08 16:56:06

Agreed. If you want a secure app you need peer verification.

@Adam F 2014-11-03 22:27:33

"Never, ever disable peer verification " UNLESS you want default browser functionality haha. Also, why is this downvoted so much? This is the only answer that is short, sweet, to the point AND effective.

@Bruno 2015-03-13 12:57:29

@AdamF FYI, browsers DO verify the peer certificate by default, they only give you the option to bypass errors manually, with a warning.

@madRai 2013-12-18 18:52:16

Sometimes if the application you try to contact has self signed certificates, the normal cacert.pem from http://curl.haxx.se/ca/cacert.pem does not solve the problem.

If you are sure about the service endpoint url, hit it through browser, save the certificate manually in "X 509 certificate with chain (PEM)" format. Point this certificate file with the

curl_setopt ($ch, CURLOPT_CAINFO, "pathto/{downloaded certificate chain file}");   

@Chris Dutrow 2012-05-12 19:59:16

Warning: this can introduce security issues that SSL is designed to protect against.

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.

@Bruno 2012-05-14 00:46:49

... and by disabling the verification of the certificates, you leave the door open to potential MITM attacks, which SSL/TLS otherwise aims to protect against. DON'T DO THIS!

@Chris Dutrow 2012-05-16 21:11:38

Yup. I should have drawn more attention to this in the answer. Only do this if you aren't working on anything important. I use it on localhost to access websites that I personally programmed.

@Ilija 2013-11-24 21:50:05

Downvote from me. This is a dirty fix to get your code working, but not a solution. Answer provided by Артур Курицын is much better.

@jww 2014-08-13 19:00:26

@Jānis - its kind of equivalent to nothing. In this incarnation, it wastes network bandwidth because the server still sends the certificate. Since CURLOPT_SSL_VERIFYPEER=false, don't send the certificate. Just use an anonymous protocol, like Anonymous Diffie-Hellman (ADH).

@Adam F 2014-11-03 22:28:22

This doesn't work, see the answer below for a proper method.

@ROR 2014-12-09 07:14:48

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); worked for me thanks

@Kenyakorn Ketsombut 2015-03-13 04:28:07

@Bruno This is the perfect solution, for helper scripts, tests, trusted applications, intranet, ..... Everyone who knows A LITTLE about SSL, knows in which cases the certificate validation can be skipped. So all the 'smart' comments on this answer and things like 'DON'T DO THIS' is just NONSENSE!!

@Bruno 2015-03-13 12:53:20

@KenyakornKetsombut Not sure, really. If you really want a good test environment, use your own test CA, that will be a more realistic test. Otherwise, you'll just have vulnerable code in your code base, which you'll have to treat separately later (which can be more costly overall). Most likely, you'll forget to remove that bad code the day before shipping. Generally, if you already are in a trusted environment, you might not need SSL, but if your helper scripts and trusted applications are on a network you might not be able to trust fully, you might as well do things right.

@Bruno 2015-03-13 12:54:26

... "Everyone who knows A LITTLE about SSL [...]"... and you'd be surprised how many people don't even bother knowing a little bit about the basics of SSL/TLS, and are just coming here to copy/paste a quick fix for their error message.

@Markon 2015-06-25 08:10:20

I completely agree with @Bruno. Further, if the OP had known this in advance, she wouldn't have asked, therefore it's good to warn, because she didn't talk about internal scripts or testing, but "HTTPS enabled websites", and this makes me think that previously the default behavior was to cURL these websites without SSL verification (in a production environment). If you know what you are doing, you don't ask on stackoverflow. My 2 cents.

@Carlos2W 2016-02-19 16:08:31

It's perfect for testing a post PHP file, and when testing is finished, you should remove this, as it is not secure.

Related Questions

Sponsored Content

31 Answered Questions

[SOLVED] Reference - What does this error mean in PHP?

28 Answered Questions

1 Answered Questions

[SOLVED] Curl command for https ( SSL )

8 Answered Questions

[SOLVED] SSL error SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

  • 2015-08-25 18:19:53
  • clarkk
  • 103161 View
  • 38 Score
  • 8 Answer
  • Tags:   php apache openssl

2 Answered Questions

1 Answered Questions

Run DocuSign sample PHP code?

0 Answered Questions

AWS EC2 PHP SDK SSL error

0 Answered Questions

SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

  • 2014-08-13 18:21:14
  • maths
  • 3396 View
  • 0 Score
  • 0 Answer
  • Tags:   php curl ssl

0 Answered Questions

1 Answered Questions

[SOLVED] Translate cURL command line into PHP cURL

  • 2012-09-17 13:02:11
  • loudislav
  • 960 View
  • 5 Score
  • 1 Answer
  • Tags:   php curl

Sponsored Content