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.
Related
I'm busy with a curl php library which needs to connect to an FTPS server.
I have this semi working... If I connect to ftp://domain.com then it does work. If I watch the comms on the server with tcpflow I see it logging in with AUTH TLS and and all the comms is encrypted. The file is uploaded so all's good..
What I'm unsure of is if its valid to try connecting instead to ftps://domain.com?
The reason I'm asking is because if I change the protocol from ftp to ftps in curl then the login fails and the server (watching tcpflow comms) says that the login has failed:
191.101.002.204.00021-088.099.012.154.51630: 530 Please login with USER and PASS.
Also, when I watch the comms when trying to connect to ftps:// I don't see the client issuing the AUTH TLS command as it does with plain ftp://
The problem I have is that it seems that my client's FTP server we have to ultimately connect to doesn't seem to allow connections without the ftps:// protocol.
If I connect using lftp I can do so using ftps:// but then I have to disable ssl:
set ftp://ssl-allow no
If I try the lftp connection using ftp:// it just hangs on the login command...
I'm not really that experienced with FTP or TLS / SSL so I don't know if its maybe because the client's server doesn't have the certificates set up correctly..
Here is a portion of my curl code which works with ftp:// but not ftps://
// Works
$url = "ftp://proxy.plettretreat.co.za/";
// Does not work
$url = "ftps://proxy.plettretreat.co.za/";
$port = 990;
$username = "ftpuser";
$password = "pass";
$filename = "/test.php";
$file = dirname(__FILE__)."/test.php";
$c = curl_init();
// check for successful connection
if ( ! $c)
throw new Exception( 'Could not initialize cURL.' );
$options = array(
CURLOPT_USERPWD => $username.':'.$password,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_BINARYTRANSFER => 1,
CURLOPT_FTP_SSL => CURLFTPSSL_ALL, // require SSL For both control and data connections
CURLOPT_FTPSSLAUTH => CURLFTPAUTH_TLS, // let cURL choose the FTP authentication method (either SSL or TLS)
CURLOPT_UPLOAD => true,
CURLOPT_PORT => $port,
CURLOPT_TIMEOUT => 30,
);
Another thing I'm unsure of is that my client has given me an IP address to connect to.. Can an IP address be used in ftps? I would have thought that certificates are mostly certifying a domain name?
tl;dr
1) Can I use ftps://domain.com to connect using CURL PHP?
2) If I can use ftps:// in curl, then how do I get curl to log in (issue auth tls command)?
3) Can an FTP server use SSL / TLS with only an IP address?
Thanks...
John
Many many hours of struggling led me to an eventual answer.
Part of the answer was that the client server and the FTP server had "overly" strict firewall rules blocking the passive ports.
I was getting the following error:
Error no: 35; Error: SSL connect error.
Error 35 was because of the firewall rules. Once those were relaxed that error went away, but as a note, you will also see this error if the client machine is NAT'ed. If it is you need to set the curl option:
curl_setopt($c, CURLOPT_FTPPORT, '1.2.4.5' ); // change to your actual IP.
This tells the FTP server where to open up its data channel (instead of trying to open it to the client server's internal address).
Anyway, once the firewall and FTPPORT options were set I got:
Error no: 30; Error: bind(port=0) failed: Cannot assign requested address
This one baffled me for quite a while as everything looked correct.
I eventually stumbled upon a few thread here and elsewhere which talk about an issue with older versions of Curl using NSS for its encryption. I checked and I was using libcurl version 7.19.7 (about 8 years old) and sure enough it uses NSS...
I updated my Curl using this guide: https://www.digitalocean.com/community/questions/how-to-upgrade-curl-in-centos6.
That updated me to libcurl 7.52.1 which uses OpenSSL and lo and behold, my app started working...
So, if you're having issues connecting curl-ftp to a FTPS server, check the FTPPORT (passive IP) if you're NAT'ed, check your firewall, but most importantly, check your curl:
<?php
print print_r(curl_version());
?>
I hope this helps someone..
The bellow is my curl config of PPHttpConfig.php for paypal adaptive payment SDK,
public static $DEFAULT_CURL_OPTS = array(
CURLOPT_SSLVERSION => 4,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_TIMEOUT => 60, // maximum number of seconds to allow cURL functions to execute
CURLOPT_USERAGENT => 'PayPal-PHP-SDK',
CURLOPT_HTTPHEADER => array(),
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_SSL_CIPHER_LIST => 'TLSv1',
);
But,getting error
Type PayPal\Exception\PPConnectionException
Message error:14077410:SSL
routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
OpenSSL error messages tend towards cryptic and generic.
The most common causes for this error are that
the server certificate has expired
the server cerificate is invalid
the client and server can not negotiate a protocol level or cipher acceptable to both parties.
Your version of OpenSSL is relatively recent (but still out of date / containing serious vulnerabilities). I'd like to think that PayPal wouldn't let their certificates expire.
Less common reasons for seeing this error are
your database is CA certs is out of date
CACert database can't be found (is your PHP running in a chroot?)
you've got some silly entries in your openssl.cnf or it can't be found
you are sitting behind a MITM proxy you didn't know about
You didn't say where the PHP is running, what its running on, nor what acces you have to the machine. If it's a Linux box and you have shell access, you might want to see what happens when you probe the server from the command line.
I'm trying to send an Ajax request using cURL PHP but it gives the error
Unknown SSL protocol error in connection
while I'm able to login to same server.
I've tried this
curl_setopt( $ch, CURLOPT_SSLVERSION, 1 );
and Ajax request is something like that
$header = array('Accept' => '*/*',
"X-Requested-With" => "XMLHttpRequest",
"Content-Type" => "application/x-www-form-urlencoded");
$data = array('ClientNumber=999999&OrderClass=ContractOrders&ShowAll=ContractOrders&ShowPerPage=500');
echo $page = Spider::spider($header, 'https://wfs.nursefinders.com/MasterConsole/displayorders.cfm?ShowAll=ContractOrders', 'https://wfs.nursefinders.com/MasterConsole/BuildOrderDisplaySection.cfm', FALSE, $data[0]);
Note in spider function, first argument is header, second is referrer third is url to access, fourth doesn't matter it's for cookie file and fifth is data o post
I'm using UBUNTU 14.10 and cURL Version is curl 7.37.1 according to this command /usr/bin/curl -V
and same as printing by php phpinfo()
Please help
I believe the reason for your problem is that the server you are communicating with does not support your SSL protocol.
There is a page here with information on that: http://blog.techstacks.com/2010/03/3-common-causes-of-unknown-ssl-protocol-errors-with-curl.html
For more direct information, try looking into the API Documentation for the required connection protocol for their server. They may have provided a sample that will connect.
This server is terrible broken. It does not support the most compatible SSLv23 handshake and will just hang if one tries it. It only supports explicit SSL 3.0 or TLS 1.0 handshakes. From looking at the source code of cURL it seems to me, that all variations of enforcing TLS1.0+ will do a SSLv23 handshake, which the server can not do:
-- curl-7.41.0/lib/vtls/openssl.c
1719 default:
1720 case CURL_SSLVERSION_DEFAULT:
1721 case CURL_SSLVERSION_TLSv1:
1722 case CURL_SSLVERSION_TLSv1_0:
1723 case CURL_SSLVERSION_TLSv1_1:
1724 case CURL_SSLVERSION_TLSv1_2:
1725 /* it will be handled later with the context options */
1726 req_method = SSLv23_client_method();
This leaves only the option of using the insecure SSL 3.0, that is
curl_setopt( $ch, CURLOPT_SSLVERSION, 3 );
While I have no PHP to test with, a short test with curl -1 vs. curl -3 on the command line confirms that CURLOPT_SSLVERSION of 1 will not work while 3 should work.
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,
... );
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"/>