2

Good day!

I've REST API which is accessible via SSL (https://). I'd like to put correct cert (or cert chain) along with my scripts written PHP and CURL to make request.

Here are how certs from my target (http://api.vkontakte.ru) look like in Firefox:

http://speedcap.net/img/bc687485819715c65d6fe1e4ca1fdc40/1a2be.png

Here is a snippet from saved "cert chain X.509 in PEM format" from Firefox (described here: http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/):

-----BEGIN CERTIFICATE-----
MIIFVzCCBD+gAwIBAgIHKx5Ov2FOejANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
[..skip...]
0npsf5fkvT8E13NgVY0PK6V/baMTlTgWXKQZ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx
[..skip...]
qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV
U+4=
-----END CERTIFICATE-----

Here is code example of CURL init:

$this->ch = curl_init();
    curl_setopt_array($this->ch, array(

        CURLOPT_TIMEOUT => 30,
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_AUTOREFERER => TRUE,
        CURLOPT_FOLLOWLOCATION => TRUE,

        CURLOPT_SSL_VERIFYPEER => TRUE,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_CAINFO => <path to my cert>,        
    )); 

I've got CURL error 60 (CURLE_SSL_CACERT) complaining about wron cert.

What I've tried:

  • I've verified that my cert file is used, because when I specify wrong path it complains that it can't find cert (error 70)

  • I've checked with Facebook SDK and their cert chain that my CURL works with such setup

  • I've tried to export different chains (including or excluding) last cert in chain

  • Tried CURLOPT_SSL_VERIFYHOST => 1.

Any ideas are welcome!

artvolk
  • 9,448
  • 11
  • 56
  • 85

3 Answers3

5

Vkontakte moved from vkontakte.ru domain to vk.com few years ago. And they change their api handler url too. This is my solution:

  1. Open https://vk.com/ in firefox
  2. Export cert chain as X.509 for this site
  3. Change target url from http://api.vkontakte.ru to https://api.vk.com/

This is my code with curl options:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, getcwd() ."/ffchainvk.crt"); //  ok

Where ffchainvk.crt is file with exported cert chain.

msangel
  • 9,895
  • 3
  • 50
  • 69
  • Thanks for the following up, but at the time question was asked, domain vkontakte.ru was still used. I later discovered that problem was in incomplete cert chain. When cert chain was created by hand from firefox bundle (http://curl.haxx.se/docs/sslcerts.html) it works. – artvolk Feb 26 '13 at 09:23
  • yesterday i was unable to built correct chain for "vkontakte.ru" too, but with the bundle from firefox it works as expected. another problem is that bundle from firefox is pretty big(~300kb). do you know which cert is missing in chain? – msangel Feb 26 '13 at 11:40
  • Can't found this file right now, but it was one of the root certs, I just removed certs from firefox bundle until it stop working. – artvolk Feb 26 '13 at 14:02
3

These are the steps that appear to work:

  1. Visit the https url in firefox
  2. Click the green bar, click the arrow, then "more information"
  3. Click "View Certificate" then click "details" tab at the top
  4. Then click each level and export every certificate:

    Root CA

    Server CA and

    example-website.invalid.

    You should save all three files to your computer. Copy all three files into a single file, e.g. custom_name_cert.pem

Copy that pem file into a directory that is accessible with PHP, ideally the file has permissions 644. You might even go for 444 to prevent tampering, and change it to 644 when you need to update it.

Then update the path in your code, for example:

CURLOPT_CAINFO => '/var/www/certs/custom_name_cert.pem'

WARNING: When the website updates their SSL certificates, the above file may become out of date, and the HTTPS cURL calls may fail, breaking your application. Hopefully someone will answer here with a good way to automate updates to this file.

Frank Forte
  • 2,031
  • 20
  • 19
3

Curl uses CA certificates in a separate location on the server than what the rest of the system, like a desktop would. I have had to install CA certificates into the filesystem before. PHP libcurl will use the libraries that the command line utility uses as well. Please see http://curl.haxx.se/docs/sslcerts.html.

memnoch_proxy
  • 1,944
  • 15
  • 20
  • Thanks, it works with this bundle:http://curl.haxx.se/docs/caextract.html. But how I should extract correct cert just for my target site? – artvolk Aug 20 '11 at 07:03
  • I've tried to strip down that ca file just to certs I have in chain and it doesn't work :( – artvolk Aug 20 '11 at 07:05
  • that winnowing process is not something I've tried before. Does it fail as soon as you take out just one cert from the bundle? If so, it might be a formatting issue. Otherwise, you might need to keep experimenting. – memnoch_proxy Aug 20 '11 at 07:19
  • When I remove one it works, when I remove all except certs I've it chain in doesn't. Maybe I interpret the chain of certs in the wrong way? – artvolk Aug 20 '11 at 07:28
  • You should only need to add the CA cert to your list of trusted CA certs. The CA cert is the top-level cert, the one with CN `Go Daddy Class 2 CA`. – President James K. Polk Aug 20 '11 at 11:02
  • I've tried this, still no luck :( But the original file works, very strange :( – artvolk Aug 20 '11 at 19:56
  • In my case, curl is using openssl, which was installed with a no longer existing certificate directory. There seems to be no way to fix this other than reinstalling openssl. – David Spector Jul 22 '22 at 16:39