Fix curl SSL certificate problem

Fix curl SSL certificate problem

Posted by

When using curl, from PHP, from time to time, I had to use some 3rd party API services. Today I would like to deep dive into common error when trying to connect to 3rd party services using HTTPS/SSL using curl.

When the certificate chain is not properly configured on the client app server that tries to establish a connection to 3rd party API service you will get an error. For example, in the case of a self-signed certificate is used, it can be:

SSL certificate problem: self signed certificate

Most of the developers do not try to solve this problem and force curl to establish SSL connection.

They add the following line (in bold), which is not secure:

$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

This is not the right solution as it basically discharges the essence of SSL that is establishing trust.

Solution for paranoids

If you are paranoid like me, the best solution is specifically exact certificate and make sure curl is using it. You will need to do the following:

  1. Extract public key from the 3rd party API server
  2. Save to file
  3. Configure curl to use this file

Let’s say you want to connect to https://www.google.com/ . Use the following command to extract certificates.

echo quit | openssl s_client -showcerts -servername \
  www.google.com -connect google.com:443

You will get something like this:

CONNECTED(00000005)
 depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
 verify return:1
 depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3
 verify return:1
 depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = www.google.com
 verify return:1
 Certificate chain
  0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
    i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
 -----BEGIN CERTIFICATE-----
 MIIDzzCCAregAwIBAgIQTAKF/mTTiunPDZ51KWg/EzANBgkqhkiG9w0BAQsFADBU
 XXXXXXXXXXXXXXXXX
 AWBQx3SbgohiAde4zLqtz/NJfQ==
 -----END CERTIFICATE-----
  1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
    i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
 -----BEGIN CERTIFICATE-----
 MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAw
  XXXXXXXXXXXXXXXXX
 c7o835DLAFshEWfC7TIe3g==
 -----END CERTIFICATE-----
 Server certificate
 subject=/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
 issuer=/C=US/O=Google Trust Services/CN=Google Internet Authority G3
 No client certificate CA names sent
 Server Temp Key: ECDH, X25519, 253 bits
 SSL handshake has read 2581 bytes and written 308 bytes
 New, TLSv1/SSLv3, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
 Server public key is 256 bit
 Secure Renegotiation IS supported
 XXXXXXXX
 DONE

You need to copy all lines, starting from —–BEGIN CERTIFICATE—– to —–END CERTIFICATE—– and save it to a single file that will have full certificate chain file. For example certs.pem.

For example, the file will have the following contents (it can be 1 certificate too):

 -----BEGIN CERTIFICATE-----
 MIIDzzCCAregAwIBAgIQTAKF/mTTiunPDZ51KWg/EzANBgkqhkiG9w0BAQsFADBU
 XXXXXXXXXXXXXXXXX
 AWBQx3SbgohiAde4zLqtz/NJfQ==
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
 MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAw
 XXXXXXXXXXXXXXXXX
 c7o835DLAFshEWfC7TIe3g==
 -----END CERTIFICATE-----

Now, the last thing. You need to configure PHP curl to use this certificate chain file now. You will need to add the following lines of code to your PHP program:

curl_setopt($ch, CURLOPT_CAINFO,  getcwd().'/certs.pem');

Hope this solution helps you. leave your comments.

I LOVE FEEDBACK 🙂