Recently I ran into an issue where I couldn’t use PHP to retrieve an SSL site on OSX Sierra. Interestingly, the following scenarios were true:
- PHP using libCURL worked fine. HTTPS would access and decode without an issue
- file_get_contents was unable to access the URL
- SOAPClient was unable to decode SSL resources
The error produced by file_get_contents for the URL in question was:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
After a bit of digging, I found the following:
- libCURL uses the Apple SecureTransport layer to map and manage their SSL certificates. This means that they do not rely on OpenSSL certificate data to be able to verify intermediate certificates
- file_get_contents and SOAPClient still rely on libssl to be able to perform their SSL verification chain, which expects intermediate certificates to exist on the file system
Running the following command:
php -r 'print_r(openssl_get_cert_locations());'
returned a set of default files and locations that PHP’s openssl layer was expecting to find data:
Array ( [default_cert_file] => /usr/local/libressl/etc/ssl/cert.pem [default_cert_file_env] => SSL_CERT_FILE [default_cert_dir] => /usr/local/libressl/etc/ssl/certs [default_cert_dir_env] => SSL_CERT_DIR [default_private_dir] => /usr/local/libressl/etc/ssl/private [default_default_cert_area] => /usr/local/libressl/etc/ssl [ini_cafile] => [ini_capath] => )
but none of these paths existed. The solution/workaround I implemented was running the following in shell:
% sudo mkdir -p /usr/local/libressl/etc/ssl/certs % sudo curl -o /usr/local/libressl/etc/ssl/cert.pem https://curl.haxx.se/ca/cacert.pem
This creates the default_cert_file directories and imports the latest certificate store from curl.haxx.se.
Other options may include using tools such as brew to install additional resources on the system; but I prefer not to do that – or utilising tools such as Docker to contain your PHP application execution.