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:
- Extract public key from the 3rd party API server
- Save to file
- 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 🙂