Search code examples
phpsslstripe-paymentstls1.2

How to fix Stripe Error: Network error [errno 77]: error setting certificate verify locations


I am attempting to use Stripe on my site but am getting the following error:

Fatal error:
    Uncaught Stripe\Error\ApiConnection: Unexpected error communicating with Stripe. If this problem persists, let us know at [email protected].
    (Network error [errno 77]: error setting certificate verify locations: CAfile: CApath: /etc/ssl/certs) in /var/www/html/assets/vendor/stripe/lib/HttpClient/CurlClient.php:284
Stack trace:
    #0 /var/www/html/assets/vendor/stripe/lib/HttpClient/CurlClient.php(241): Stripe\HttpClient\CurlClient->handleCurlError('https://api.str...', 77, 'error setting c...', 0) 
    #1 /var/www/html/assets/vendor/stripe/lib/HttpClient/CurlClient.php(203): Stripe\HttpClient\CurlClient->executeRequestWithRetries(Array, 'https://api.str...') 
    #2 /var/www/html/assets/vendor/stripe/lib/ApiRequestor.php(364): Stripe\HttpClient\CurlClient->request('post', 'https://api.str...', Array, Array, false) 
    #3 /var/www/html/assets/vendor/stripe/lib/ApiRequestor.php(96): Stripe\ApiRequestor->_requestRaw('post', '/v1/charges', Array, Array)
    #4 /var/www/html/assets/vendor/stripe/lib/ApiOperations/Request.php(5 in /var/www/html/assets/vendor/stripe/lib/HttpClient/CurlClient.php on line 284

I recently created a new VM on Google Compute Engine using the one-click LAMP deployment. I also used Lets Encrypt to allow for https. Further, I have downloaded the latest cacert.pem file and placed it in the /etc/ssl/certs folder.

The certs folder has the following permissions:

drwxr-xr-x 2 root root     20480 Apr  5 14:31 certs

The file has the following permissions:

-rw-r--r-- 1 root root 219596 Apr  5 14:29 cacert.pem

I also edited the php.ini file to point the curl.cainfo and openssl.cafile to the pem file and restarted Apache.

In looking at Stripe's site, it mentioned that TLS 1.2 is now required. I have confirmed that my site is using it. But some sample test code on Stripe's site seems to indicate that it's not seeing TLS 1.2.

According to ssllabs.com, my site is recognized as having the TLS 1.2 protocol.

The Stripe sample code that I added to my site to validate is:

\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    try {
        \Stripe\Charge::all();
        echo "TLS 1.2 supported, no action required.";
    } catch (\Stripe\Error\ApiConnection $e) {
        echo "TLS 1.2 is not supported. You will need to upgrade your integration.";
    }

I also added the following for additional version information:

echo 'PHP version: ' . phpversion() . PHP_EOL . '<br/>';
    echo 'cURL version: ' . curl_version()['version'] . PHP_EOL . '<br/>';

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://www.howsmyssl.com/a/check");
    curl_setopt($ch, CURLOPT_SSLVERSION, 6);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);

    echo 'TLS version: ' . json_decode($response)->tls_version . PHP_EOL;

The result when I run it is:

============= Stripe Suggested Test Code ============
TLS 1.2 is not supported. You will need to upgrade your integration.
================================================
==================== Version Code ===================
PHP version: 7.0.33-0+deb9u3 
cURL version: 7.52.1 
TLS version: TLS 1.2 
================================================

At this point, I'm running out of ideas. For full disclosure, I do most of my learning through Google searches and this site so any help at a hobby coder level would be appreciated.


Solution

  • So, looking at the code I see this:

    class CurlClient implements ClientInterface
    {
        public function request($method, $absUrl, $headers, $params, $hasFile)
        {
            ...
            $opts[CURLOPT_CAINFO] = Stripe::getCABundlePath();
            ...
        }
    }
    

    Which in turn, leads me to this code:

    class Stripe
    {
        // @var string Path to the CA bundle used to verify SSL certificates
        public static $caBundlePath = null;
    
        /**
         * @return string
         */
        private static function getDefaultCABundlePath()
        {
            return realpath(dirname(__FILE__) . '/../data/ca-certificates.crt');
        }
        /**
         * @return string
         */
        public static function getCABundlePath()
        {
            return self::$caBundlePath ?: self::getDefaultCABundlePath();
        }
        /**
         * @param string $caBundlePath
         */
        public static function setCABundlePath($caBundlePath)
        {
            self::$caBundlePath = $caBundlePath;
        }
    }
    

    Which makes it look like Stripe doesn't want to use the system CA path for some reason. So you can:

    • use Stripe::setCABundlePath() to point to the system CA bundle

    or

    • ensure the CA bundle at data/ca-certificates.crt (which is shipped with Stripe) is present and has appropriate permissions.