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!

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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 (curl.haxx.se/docs/sslcerts.html) it works.
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?
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.
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.

7 Comments

Thanks, it works with this bundle:curl.haxx.se/docs/caextract.html. But how I should extract correct cert just for my target site?
I've tried to strip down that ca file just to certs I have in chain and it doesn't work :(
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.
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?
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.
|
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.

2 Comments

Hint: when exporting the certificate, choose Base-64 encoded X.509 (.CER) format, or you cannot copy it into a .pem file
thanks this worked for me on windows server 2019 iis php7.4

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.