45

I'm working with cUrl and PHP to make a request to a server (for paypal access)

Paypal developer website does never mention that an SSL certificate is required to use PayPal access API, however the code that I use to request the token is the following:

$options = array(
                CURLOPT_URL => $url,
                CURLOPT_POST => 1,
                CURLOPT_VERBOSE => 1,
                CURLOPT_POSTFIELDS => $postvals,
                CURLOPT_RETURNTRANSFER => 1,
                CURLOPT_SSLVERSION => 3
);

curl_setopt_array($ch, $options);

$response = curl_exec($ch); 
echo curl_error($ch);

This echo outputs the following error:

SSL certificate problem: unable to get local issuer certificate

My questions are:

1) do I need SSL to use paypal access if I need only to get the user email?

2) if I do not need SSL why this error occours?

PS: the endpoint is the following: https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/tokenservice

Luca Pennisi
  • 631
  • 2
  • 10
  • 14

4 Answers4

124

The correct solution is to fix your PHP setup.. setting CURLOPT_SSL_VERIFYPEER to false is a quick hack, but it's wrong as you disable the certificate validation by it's certificate authority. This exposes you to a man-in-the-middle attack.

It's easy to fix (php 5.3.7 or higher) - Download a list file with an up-to-date certificate authorities, and add this setting to your php.ini
curl.cainfo=<path-to>cacert.pem

Restart your web server, and it'll work !

oori
  • 5,533
  • 1
  • 30
  • 37
  • I already had a similar file located at /etc/ssl/certs/ca-certificates.crt (Gentoo Linux distribution). – Martin M. Nov 12 '13 at 22:37
  • 3
    Worked for me on my WAMP server setup. Thank you. – Robin Hood Nov 27 '13 at 15:13
  • 13
    Alternatively, you can specify the certificate at runtime: `curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem')`. Now you have no excuse for disabling verification! – Gras Double May 05 '14 at 14:45
  • Worked on a windows server with xampp. Thanks – agmezr May 20 '14 at 14:40
  • OMG. i was looking for this all week! – mydoglixu Oct 17 '14 at 20:35
  • In order to access https://login.salesforce.com I had to use a cert file included in my cygwin install. The cert file from haxx.se didn't include the cert they use. Copy this file to your cacert.pem: `C:\cygwin\etc\pki\ca-trust\extracted\openssl\ca-bundle.trust.crt` – Dave Lancea Nov 24 '14 at 18:14
  • This just happened 3-24-15 on Micah's PayPal .crt file. A quick update using oori's "Download" link above to the .crt file did the trick – iconMatrix Mar 27 '15 at 15:00
  • great have same issue on dailymotion api and solved it too – vimuth Jul 03 '16 at 15:08
  • 1
    I downloaded the caert.pem file and save it in ```C:\wamp\bin\php\php5.5.12```, with the proper extension. Also I have modified and uncomment the line with the ```curl.cainfo``` path, but I still get the same error :/ – JCarlosR Aug 27 '16 at 22:55
  • Using wampserver we have to modify ```C:\wamp\bin\apache\apache2.4.9\bin\``` instead of the path mentioned above. – JCarlosR Aug 27 '16 at 23:05
  • It worked for me , Just make sure you restart xampp after making changes – geekbro Feb 18 '17 at 05:26
  • I followed the above steps and still got the same error message. In my case, I was getting the error when connecting to one of my own API endpoints. I ran the SSL diagnostic tool at https://cryptoreport.rapidssl.com/checker/views/certCheck.jsp and discovered that I had the wrong intermediate cert installed on the API web server. I installed the correct intermediate cert and things started working. It seems to me that the Curl error message is misleading. – Derrick Miller Mar 16 '17 at 18:43
  • Thanks for the solution, for localhost development you have to follow above solution – Bhagwan Parge Jul 03 '19 at 09:15
12

You may disable SSL verification (which is enabled by default as of cURL 7.10), by adding this:

CURLOPT_SSL_VERIFYPEER, false

to your $options, however the proper way is to keep validation enabled.

SECURITY NOTICE

If remote site uses certificate issued by known CA but validation still fails, then most likely certificate is incorrectly set up on the remote server (lack of intermediate certificates etc.). Alternatively your system got no idea about used Certificate Authority that signed target's certificate. In such case yo should use php.ini's curl.cainfo (documentation) to point to valid PEM file with all supported CAs - that would make your setup properly validate issuer chain.

Please be aware that by setting CURLOPT_SSL_VERIFYPEER to false you are NOT solving the issue! You are working it around. This is all about security so it's fine to do that for a while, but deploying that on production is not wise, politely speaking, as you will become open to Man In The Middle Attack. You have been warned.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
5

I had the same exact problem

Can't connect to PayPal to validate IPN message: SSL certificate: unable to get local issuer certificate

I used the code samples generated on paypal's github found here (I used PHP): https://github.com/paypal/ipn-code-samples

I downloaded both certs and tried testing both from curl: http://curl.haxx.se/docs/caextract.html

After about 2 hours of testing (using paypal's ipn simulator) and googling, found that paypal ipn cannot be tested on localhost, so i pushed the code live and tried testing, but still got the same error (even with permissions set to 777).

When I set CURLOPT_SSL_VERIFYPEER, false, it worked but this would defeat the purpose of having an ssl certificate.

After snooping around on my server's files, I found a curl-ca-bundle.crt file in my PHP folder. I decided to hardcode the CURLOPT_CAINFO in my paypal ipn script to that path. It finally worked!

I noticed this older .crt file included some certificates that weren't on the latest .crt file from the curl website. It was a bunch of certificates from verisign class 1, verisign class 2, verisign class 3 and verisign class 4.

Here's the complete list of the certificate names I added to curl's .crt file:

  • Verisign Class 1 Public Primary Certification Authority
  • Verisign Class 1 Public Primary Certification Authority - G2
  • Verisign Class 1 Public Primary Certification Authority - G3
  • Verisign Class 2 Public Primary Certification Authority - G2
  • Verisign Class 2 Public Primary Certification Authority - G3
  • Verisign Class 3 Public Primary Certification Authority
  • Verisign Class 4 Public Primary Certification Authority - G2

This may have something to do with what @Andomar was saying - paypal's verisign certificate is not included in the default (by default I mean curl's default) list of safe certificates.

I didn't have the time to debug and figure out exactly which certificate is needed so I just included all of them.

For anyone who experiences this problem in the future, I would suggest to get the latest certs from curl and add one by one the certificates in the list above until the error is gone.

Here's a link for some of those verisign certificates (you may need to google for the others not listed): www.symantec.com/page.jsp?id=roots

Note*: To view paypal's current certificates you can run this command in terminal:

openssl s_client -connect paypal.com:443 -showcerts

If anyone has further insight to this issue, please comment as I spent hours to figure all of the above out.

TrieuNomad
  • 1,651
  • 1
  • 21
  • 24
  • 1
    I was able to fix the problem by adding Verisign Class 3 Public Primary CA from http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem - so apparently that's the missing one. – DiMono Dec 23 '14 at 16:56
2

SSL certificate problem: unable to get local issuer certificate

Means that cUrl doesn't trust Verisign, the certificate authority that vouches for PayPal. As Marc B comments, cUrl no longer ships with trust for any certificate authority.

You can bypass the certificate chain validation with the option:

CURLOPT_SSL_VERIFYPEER => 0

To read how to configure cUrl so that it trusts Verisign, read the cUrl documentation.

Andomar
  • 232,371
  • 49
  • 380
  • 404
  • 2
    not really strange. curl doesn't ship with any CA certs built into it anymore, so by default it doesn't trust ANYONE. – Marc B Jul 04 '13 at 21:39
  • @MarcB: Interesting, I was assuming that it used the OS certificate store. – Andomar Jul 04 '13 at 21:45
  • 3
    that'd be nice, but given how many places that store is kept, probably for the best for curl to just go paranoid and think everyone's out to get it. – Marc B Jul 04 '13 at 21:45
  • 5
    I would highly discourage anyone from turning off host/peer verification. Rather, download the cURL CA certs file (http://curl.haxx.se/ca/cacert.pem) and include it. Just as quick to resolve, and protects you a whole lot better in the long run. – Robert Aug 04 '13 at 12:54
  • ^^ why should we trust these certificates. no offense, just sayin' – mydoglixu Oct 17 '14 at 17:59
  • I am using wamp, where i can paste this line? – Gem May 17 '18 at 12:34