PHP CURL and SSL certificate (or cert chain)
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 = cu开发者_Python百科rl_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!
Vkontakte moved from vkontakte.ru domain to vk.com few years ago. And they change their api handler url too. This is my solution:
- Open https://vk.com/ in firefox
- Export cert chain as X.509 for this site
- 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.
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.
These are the steps that appear to work:
- Visit the https url in firefox
- Click the green bar, click the arrow, then "more information"
- Click "View Certificate" then click "details" tab at the top
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.
精彩评论