This question already has answers here:
PHP - SSL certificate error: unable to get local issuer certificate
(19 answers)
Closed 1 year ago.
I am trying to download the content of a secure (uses https) webpage using php and curl libraries.
However, reading failed and I get error 60: "SSL certificate problem, verify that the CA cert is OK."
also "Details: SSL3_GET_SERVER_CERTIFICATE:certificate verify failed"
So...pretty self explanatory error msg's.
My question is: How do I send an SSL certificate (the right one?) and get this page to verify it and let me in?
Also, here is my options array in case you are wondering:
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_USERAGENT => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:x.x.x) Gecko/20041107 Firefox/x.x", // who am i
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLOPT_SSL_VERIFYHOST => 1,
);
Any suggestions would be great,
Andrew
It sounds like you might be misinterpreting the error. It looks to me like the site you're connecting to is self-signed or some other common problem. Just like the usual browser warning, you're easiest work around is to disable the checks.
You'll need to set CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST to FALSE. This should disable the two main checks. They may not both be required, but this should at least get you going.
To be clear, this disables a feature designed to protect you. Only do this if you have verified the certificate and server by some other means.
More info on the PHP site: curl_setopt()
If you want to use SSL peer verification (turning it off is not always good idea) you may use next solution on Windows globally for all applications:
Download file with root certificates from here:
http://curl.haxx.se/docs/caextract.html
Add to php.ini:
curl.cainfo=C:/path/to/cacert.pem
that's all magic, CURL can now verify certificates.
(as I know there is no such problem on Linux, at least on Ubuntu)
Even after following advice on SO.. You may still have problems with an error like:
error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error
the problem is with the SSL version. Use the following for version 3
curl_setopt($ch, CURLOPT_SSLVERSION,3)
I am assuming that u have enabled verification of peer and host as well and are pointing to an actual certificate file. Eg.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "/cacert.pem");
This is a "problem" with openssl and VeriSign.
I had a similar problem and my openssl was missing the intermediate ssl certificate used by VeriSign to sign the server certificate.
https://knowledge.verisign.com/support/ssl-certificates-support/index?page=content&id=AR657
I had to import these intermediate certificates from the VeriSign Homepage or Firefox cert-database-export into my local ca-certificates list and after this step I was able to use wget/curl to use the protected connection without any errors.
If it's a developer machine - you can also add this certificate in you system.
Something like this - https://www.globalsign.com/support/intermediate/intermediate_windows.php
It's for WinXP, but it works also on other versions of windows.
You're not SENDing the SSL cert. It appears there's a problem with the SSL cert as it is installed on the host you are contacting. Use option -k or --insecure, to get past the complaint.
Ah. See Ryan Graham's answer
This is apparently on openssl bug. Tomcat can be configured to work around this in /etc/tomcat7/server.xml by restricting the available cipher list:
<Connector protocol="HTTP/1.1" SSLEnabled="true" ... ciphers="SSL_RSA_WITH_RC4_128_SHA"/>
Related
i'm having a problem using Seller Center SDK from this site:
https://github.com/rocket-internet-berlin/SellerCenterSDK-PHP
i did exactly like what he told. and when i came to the point to test it
php ./genericGetter.php
i got error saying:
curl error 60: ssl certificate problem: unable to get local issuer certificate
i tried to turn off my firewall and added cacert.pem from this site https://curl.haxx.se/ca/cacert.pem to my php.ini and still no luck. can someone provide a solution?
You can try add it to php.ini
curl.cainfo=c:\path\to\cacert.pem
And try set opt_option if still not work.
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_USERAGENT => "spider", // who am i
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLOPT_SSL_VERIFYPEER => false // Disabled SSL Cert checks
);
curl_setopt_array( $ch, $options );
just figured it out.
inside vendor\guzzlehttp\guzzle\src\HandlerCurlFactory.php, on line 329; change;
$conf[CURLOPT_SSL_VERIFYPEER] = true;
to
$conf[CURLOPT_SSL_VERIFYPEER] = false;
so far, i don't know the side effect that might happens. but, it does work fine now.
hopefully this is useful for those who wants to work with Seller Center SDK.
If you can trust the source that you are consuming the resources from then arguably I would say that you can deactivate that option temporally as you already did but I would recommend you to check the root of the issue for a long-term solution.
It seems that the issue is with curl not having a valid certificate:
Check if your server has the latest cacert.pem file which you can download from https://curl.haxx.se/docs/caextract.html and add to the server certs directory.
if the server uses a certificate signed by a CA represented in cacert then it might be expired, or the name might not match the domain name your SDK is using.
If you still not having a solution then check the link below to see if one of the options provided can give you a solution:
curl: (60) SSL certificate : unable to get local issuer certificate
On an Ubuntu 14.04.3 this code works fine:
$url_login = "https://test.example.com/login.do";
$cert_file = '/var/www/html/test/cert.pem';
$ssl_key = '/var/www/html/test/cert_private.pem';
$post_fields = 'userAction=1&cancelReason=&cancelType=&account=&memoType=&userText=&userid=99999999&password=xxxxxxxxxxxxxxxx';
$ch = curl_init();
$options = array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_HEADER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)',
CURLOPT_VERBOSE => 0,
CURLOPT_URL => $url_login ,
CURLOPT_SSLCERT => $cert_file ,
CURLOPT_SSLCERTTYPE, 'PEM',
CURLOPT_SSLKEY => $ssl_key,
CURLOPT_COOKIESESSION => 1,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_fields
);
curl_setopt_array($ch , $options);
$output = curl_exec($ch);
The php on Ubuntu is using curl with openssl.
On a Centos 7 if fails with:
Curl Error : SSL peer was unable to negotiate an acceptable set of security parameters.
curl is here with nss.
The "cert.pem" contains only the client certificate with the cert-chain, and the "cert_private.pem" contains the private key not password protected. (-----BEGIN RSA PRIVATE KEY-----).
How can i get the above PHP code work with both? openssl and nss implementations of curl?
How about correcting:
CURLOPT_SSLCERTTYPE, 'PEM',
to
CURLOPT_SSLCERTTYPE => 'PEM',
?
I've also come across this problem using client certificate authentication with nss, while openssl works fine.
After much testing, this is what I've established with the server we're trying to contact:
curl using TLS v1.2 (default in some cases) with client certificate fails
curl using TLS v1.2 with client cert required by server, but not used by client, connects successfully. However client is not authenticated.
curl using TLS v1.0 with client certificate is successful
The above happens regardless of cipher suite, generally we're using rsa_aes_256_cbc_sha_256.
The quick workaround is to force TLS v1.0:
CURLOPT_SSLVERSION => 4,
Clearly this isn't ideal, and your server may not support it.
Another option is to compile curl with openssl or even GnuTLS (although I haven't tested the latter) instead of nss. Again, this may not be an option.
So far this points to a problem with NSS. I'll update this answer if further debugging generates any useful information.
Just for reference, this is the full error message using curl on the command line:
* NSS error -12227 (SSL_ERROR_HANDSHAKE_FAILURE_ALERT)
* SSL peer was unable to negotiate an acceptable set of security parameters.
* Closing connection 0
curl: (35) SSL peer was unable to negotiate an acceptable set of security parameters.
Update 2015-11-24: Further testing with Wireshark and ssltap shows the initial handshake is succeeding and the connection gets as far as the client sending ChangeCipherSpec, followed by its encrypted "Finished" message.
The server should then decrypt the client's "Finished" message, verify the hash and MAC and respond with its own encrypted "Finished" message. Instead, the server is responding with "handshake_failure" at this point.
This should provide a clue as to where NSS is failing.
Chrome, Openssl and Charles Proxy can all authenticate using the client certificate. Firefox (using NSS) and curl (with NSS) both fail at this point.
Update 2015-11-27: Additional information provided by the server's operations team suggests this may be an issue with a non-compliant server. The problem only arises when using TLS 1.2 under certain circumstances. This would explain why some SSL libraries, such as OpenSSL, are flexible enough to work around it.
NSS may be more strict in its compliance with RFCs. I'll update the answer if/when we hear more from the operations team managing the server.
Update 2017-01-25: The webserver software and load balancers are custom built for a specific bank's payment gateway. We've recently tried again with a new client and the server now appears to work with both Curl built with either NSS or OpenSSL and are no longer seeing the error. In summary: the workaround was to use a different SSL library and wait for the developers to fix the server software.
I'm attempting to interface with the Google PHP API client and I am having issues with the certificate provided by Google:
Google error:
SSL certificate problem, verify that the CA cert is OK.
Retrying with the CA cert bundle from google-api-php-client.
PHP cURL error:
SSL certificate problem: unable to get local issuer certificate
I had no problems whatsoever on a Linux box. These errors are occuring on a Windows box.
I've tried a couple of different solutions:
https://code.google.com/
http://richardwarrender.com/
but to no avail.
PS:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
won't be acceptable ...
Courtesy of rmckay at webaware dot com dot au:
Please everyone, stop setting CURLOPT_SSL_VERIFYPEER to false or 0. If your PHP installation doesn't have an up-to-date CA root certificate bundle, download the one at the curl website and save it on your server:
http://curl.haxx.se/docs/caextract.html
Then set a path to it in your php.ini file, e.g. on Windows:
curl.cainfo=c:\php\cacert.pem
Turning off CURLOPT_SSL_VERIFYPEER allows man in the middle (MITM) attacks, which you don't want!
\Google_Client::$io->setOptions(array(CURLOPT_SSL_VERIFYPEER => FALSE));
#sKophek is correct and I appreciate the help as I was struggling with this. For those that prefer a touch more detail, here it is: (this is true, at least, for the 0.6.x version of the google-api-php-client)
1) \google-api-php-client\src\io\Google_CurlIO.php
2)
private $curlParams = array (
...
CURLOPT_SSL_VERIFYPEER => false,
... );
I have been developing a site locally that authenticates against a centrailzed signon. One of the steps is requiring me to make a curl request to an https resource to get an access token.
Part of the curl config is:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
//curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
As you can see I commented out the CURLOPT_SSL_VERIFYHOST option. I have read on php.net and on various blogs/stackoverflow (Security consequences of disabling CURLOPT_SSL_VERIFYHOST (libcurl/openssl)) posts WHAT these options mean.
On my development machine CURLOPT_SSL_VERIFYHOST 2 has been working fine. I am just using the vanilla php install provided in ubuntu 12.04 php5 package, and php5-curl.
On production (rackspace cloudsites) the CURLOPT_SSL_VERIFYHOST 2 is not working, which is why I changed it to false to verify this was the issue. Seeing as i didn't explicitly do anything to enable this on my localhost I do not know what directives/config options controls this.
What I mean by it is "not working" is that on production the curl call is returning an http_code of 0 when the VERIFYHOST is set to 2. When I set it to FALSE it is returning a status code of 200
My question is:
How can i enable SSL_VERIFYHOST on a linux box?
Any help would be greatly appreciated. Thank you.
For '2' you have to ensure the common name in the SSL certificate matches the hostname being utilized. This is the default and should be straight-forward as long as your SSL certificate is appropriately created for the hostname (common name) you're using it on.
From the PHP curl_setopt manual:
1 to check the existence of a common name in the SSL peer certificate. 2 to check the existence of a common name and also verify that it matches the hostname provided. In production environments the value of this option should be kept at 2 (default value).
Manual Entry for curl_setopt
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 = curl_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.