curl SSL certificate error - php

I'm trying to install Vaprobash via CURL but I get this message everytime I try to download something through CURL. I'm using a Mac.
curl -L http://bit.ly/vaprobash > Vagrantfile
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.

Append option in curl call:
-k/--insecure
The curl will be not trying to verify SSL cert.

The link is redirecting to a secure HTTP (SSL) server, and curl doesn't have access to the proper chain of trusted certificates to confirm that the site says it is who it is.
If you're sure the site is legitimate, and this is a once-off effort, you can use the --insecure option (it will ignore any certificate errors). Opening the link in a browser directs to GitHub with no issues, and curl fetches it fine on my Ubuntu 12.04 box.
It's likely a missing certificate in your SSL installation. Run with the -v option to get a detailed output if you need to confirm this.

Related

PHPmyAdmin, enable SSL in local net

I have a PHP application on Apache 2.4 server with installed mySql server and PHPmyAdmin.
To do some tests for educational purposes I need to enable SSL / TLS both on the PHP WEB application and on PHPmyAdmin.
all tests are performed on a local network between two computers, so there is the problem of generating certificates, but I followed this guide:
https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/
I generated the certificate of the certification authority that I installed on both machines of the local network (the server and the client), and the 3 files needed by Apache:
server.crt (server signed certificate)
server.csr (certificate signing request)
server.key (private key)
following the guide I then enabled TLS 1.3 on the PHP application successfully.
Now I should repeat the thing on phpMyAdmin and enable SSL. I've read that I need to add these directives to the config.inc.php file:
$cfg['Servers'][$i]['ssl'] = true
$cfg['Servers'][$i]['ssl_cert']
$cfg['Servers'][$i]['ssl_key']
$cfg['Servers'][$i]['ssl_ca']
The first must be set TRUE, while the others require the path of the certificates. Can I use the same certificates I use for the app?
I tried to do it: for the certificate of the CA, I exported it, converted it to .pem, put it in a folder in c: and entered the path in ssl_ca, for the signed certificate of the server, I simply converted it to .pem and entered the path, while the keys I left it like this and entered the path.
However, phpmyAdmin gives me an error:
mysqli::real_connect(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificat e verify failed
Happens because I don't use the csr file?
Thanks!

What exactly goes into CURLOPT_CAINFO/CAPATH?

Trying to make CURL in PHP work with a self signed certificate. I've made a copy of the cert file available to the client code, and I specify the path to the cert file both in CURLOPT_CAINFO and CURLOPT_CAPATH. Still, I'm getting error 60: SSL certificate problem: unable to get local issuer certificate.
Here are the repro steps. All on Linux (Debian Stretch in my case). Replace example.com with a relevant hostname.
First, I'd generate a private key:
openssl genrsa -out key.pem 2048
Compose a config file:
[req]
prompt=no
distinguished_name=dn
req_extensions=ext
x509_extensions=ext
[dn]
emailAddress=seva#example.com
CN=example.com
O=Seva Alekseyev
L=Chicago
ST=IL
C=US
[ext]
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=#alt
[alt]
DNS=example.com
Save as req.txt, generate a self signed cert:
openssl req -x509 -new -config req.txt -days 3650 -key key.pem -out example.cer
Install example.cer and key.pem in Apache under hostname example.com. Browse to make sure the basic setup works (modulo the scary security message).
Now, the client. Placed a copy of example.cer under $path. The PHP code goes:
$cu = curl_init("https://example.com/");
curl_setopt_array($cu, array(
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CAINFO => "$path/example.cer",
CURLOPT_CAPATH => "$path/example.cer"
));
$r = curl_exec($cu);
$c = curl_errno($cu);
$s = curl_error($cu);
curl_close($cu);
echo "$c $s";
Then the error message.
What am I missing here? Some guides suggest the value of CURLOPT_CAINFO/CAPATH should a folder instead, with serial-based symlinks pointing to cert files. Tried that too, same error. The document at https://curl.haxx.se/docs/sslcerts.html says:
Get a CA certificate that can verify the remote server and use the proper option to point out this CA cert for verification when connecting.
But there's no CA there, no cert chain. The signing cert is itself. Should I somehow transform the cert so that CURL sees it as a CA one? Should I generate a fake CA cert first, and sign the SSL cert with that one?
Command line curl, as in curl --cacert example.cer https://example.com/, pops the same message.
Related question here, but I'd rather not mess with systemwide settings.
The certificates pointed to by CURLOPT_CAINFO/CAPATH are expected to be CA certificates - at least when OpenSSL is used. This means that your self-signed certificate need also to be a CA certificate, i.e. it should not only be for serverAuth but also have basic constraints CA:true.
The keyUsage line under [ext] must include keyCertSign, like this:
keyUsage=digitalSignature,keyEncipherment,keyCertSign
Otherwise, it's not a CA cert as far as OpenSSL is concerned.
OBTW, the basicConstraints=CA:true line under [ext], suggested by Steffen, is not necessary, I've checked. At least with CURL 7.52.1 and OpenSSL 1.0.2r it's not.
In the client code, CURLOPT_CAPATH is not necessary, either. CURL supports two alternative ways of specifying the root CA cert bundle. CURLOPT_CAINFO makes CURL read and parse a single file, potentially with multiple certificates in it. CURLOPT_CAPATH makes CURL scan a directory with certificate files identified by their serial numbers - or symlinks to those, as generated by c_rehash. Since in my scenario the effective root CA cert bundle has exactly one cert, the one file approach is sufficient.
Doesn't work under Windows, at least with command line CURL 7.55.1. The Windows version of CURL uses the built-in Schannel library for its SSL implementation, and ignores the --cacert option, instead relying on Windows' built-in trusted CA store. See here.
It might be possible to rebuild CURL for Windows against a different SSL implementation, but the trouble is hardly worth it. Windows comes with its own fleet of HTTP(S) clients.

How to fix Curl error 60 without downloading cert

I'm using Rackspace API in PHP, and it just stopped working (everything worked fine 3 days ago). It uses guzzle, who uses curl. And curl just stopped working.
[Thu Jun 21 14:55:36 2018] [error] [client xxx.xx.xxx.xx] PHP Fatal error: Uncaught exception 'Guzzle\\Http\\Exception\\CurlException' with message '[curl] 60: [url] https://identity.api.rackspacecloud.com/v2.0/tokens' in
/var/www/passline.com/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php:359\nStack trace:\n#0
/var/www/passline.com/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php(292): Guzzle\\Http\\Curl\\CurlMulti->isCurlException(Object(Guzzle\\Http\\Message\\EntityEnclosingRequest), Object(Guzzle\\Http\\Curl\\CurlHandle), Array)\n#1
/var/www/passline.com/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php(257): Guzzle\\Http\\Curl\\CurlMulti->processResponse(Object(Guzzle\\Http\\Message\\EntityEnclosingRequest),
Object(Guzzle\\Http\\Curl\\CurlHandle), Array)\n#2
/var/www/passline.com/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php(240): Guzzle\\Http\\Curl\\CurlMulti->processMessages()\n#3
/var/www/passline.com/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php(224): Guzzle\\Http\\Curl\\CurlMulti->executeHandles()\n#4
/var/www/passline.com/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php(111)
The important part from the error is the following:
[curl] 60: [url] https://identity.api.rackspacecloud.com/v2.0/tokens
I get an error 60 from Curl, who means is an SSL cert error. Most answer say's the solution to this problem is: deactivate ssl or download a new cert.
curl: (60) SSL certificate : unable to get local issuer certificate
https://es.stackoverflow.com/questions/174276/curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate-url-h
I won't deactivate SSL, I can't use http instead of https and I want to avoid having to get into the machine and downloading a new cert.
If someday I have an old cert again, my site is going to stop working. What is the correct way to fix this?
This server has CenOs 6, We're using PHP 5.3.3 and curl 7.19.7
---- Edit ----
So, my problem is because of the change in the certificates of curl. From https://curl.haxx.se/docs/caextract.html
This bundle was generated at Wed Jun 20 03:12:06 2018 GMT .
There is a tool on linux called update-ca-certificates who solves this problem, also, the curl site say's you can run
curl --remote-name --time-cond cacert.pem https://curl.haxx.se/ca/cacert.pem
But, I don't know, someday I'll see the system stop working properly, I gonna get into the machine an run this command, and, that's all?, What doest the other people do?, set a cron with this command? or what?
Older versions of Guzzle made use of their own CA file that was bundled with the Guzzle library. It would use that file instead of system's (/etc/pki/tls/certs).
If you can get things working with cURL from the command line but get this error in Guzzle that is likely the culprit.
Things were changed to use the system CA bundle by default in late 2014.
https://github.com/guzzle/guzzle/issues/623
https://github.com/guzzle/guzzle/pull/800
The behaviour of newer (> 3.0 ?) versions is described here (see verify configuration flag):
Check if openssl.cafile is set in your php.ini file.
Check if curl.cainfo is set in your php.ini file.
Check if /etc/pki/tls/certs/ca-bundle.crt exists (Red Hat, CentOS, Fedora; provided by the ca-certificates package)
Check if /etc/ssl/certs/ca-certificates.crt exists (Ubuntu, Debian; provided by the ca-certificates package)
Check if /usr/local/share/certs/ca-root-nss.crt exists (FreeBSD; provided by the ca_root_nss package)
Check if /usr/local/etc/openssl/cert.pem (OS X; provided by homebrew)
Check if C:\windows\system32\curl-ca-bundle.crt exists (Windows)
Check if C:\windows\curl-ca-bundle.crt exists (Windows)
If someday I have an old cert again, my site is going to stop working. Curl should download a new cert by himself? isn't it?.
The concept of TLS is that the server sends its certificate to the client, shows a prove that it actually owns the private key belonging to the certificate and then the client checks if the certificate is considered trusted. Trusted means among others that the certificate was issued by a locally trusted CA (certificate authority).
Typically the client has a set of CA it trusts, i.e. CA like Let's Encrypt. If the certificate was issued by such an already trusted CA no changes to the client are needed whenever the certificate is changed as long as the issuer CA is still trusted and the server is configured properly to provide all intermediate CA certificates which are needed to build the trust path.
If instead you have a self-signed certificate or a certificate signed by some private CA the client has no kind of trust anchor it can use to verify the certificate. In this you need to provide the necessary trust anchor to the client. In case of a private CA it is sufficient to setup the client once with this private CA and it will accept also later certificates issued by this CA. But in case of a self-signed certificate this means that you need to update the expected certificate at the client whenever you update the certificate at the server. There is no automatic way to do it - because how should the client verify that it gets the correct new certificate without having an established trust to the party providing the new certificate?
This issue was caused by the change in the certificates of curl. From https://curl.haxx.se/docs/caextract.html
This bundle was generated at Wed Jun 20 03:12:06 2018 GMT .
There is a tool on linux called update-ca-certificates who solves this problem, also, the curl site say's you can run
curl --remote-name --time-cond cacert.pem https://curl.haxx.se/ca/cacert.pem
Just consider any of these commands may be needed to run again in the future if the certificates are renovated again.

cURL complaining on local SSL https requests

I have an Ubuntu LAMP server on Digital Ocean and have setup an SSL certificate (which works perfectly fine). The website runs via https (http requests are redirected to https). In one of my PHP scripts, I have to send a cURL request to the local server. I am basically sending a POST request with JSON data that will be used for templating a document at the other end. In short, both ends are hosted at the same site:
https://example.com/form.php
https://example.com/templates/document.php
The cURL error I get when sending data from form.php to templates/document.php is:
SSL certificate problem: unable to get local issuer certificate
I have read at least 20 articles telling me to add these lines to php.ini at their original line positions:
curl.cainfo="/etc/ssl/certs/cacert.pem"
openssl.cafile="/etc/ssl/certs/cacert.pem"
The CA certificate is located as described above, but the cURL error persists.
I am able to bypass this error by forcing CURLOPT_SSL_VERIFYPEER to false in the cURL request itself. However, I know this is not an option for a website in production mode.
Is it not possible to do such SSL cURL request to its own host? Or is it so that I can actually disable CURLOPT_SSL_VERIFYPEER for this very specific request since it's just a local request anyway?
Thank you in advance!
EDIT:
Adding a verbose option to the cURL request shows the following information:
Trying 123.456.789.01...
Connected to example.com (123.456.789.01) port 443 (#0)
ALPN, offering http/1.1
Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
successfully set certificate verify locations:
CAfile: /etc/ssl/certs/cacert.pem CApath: /etc/ssl/certs
SSL certificate problem: unable to get local issuer certificate
Closing connection 0
It doesn't seem to be of any help though.

SSL peer certificate or SSH remote key was not OK

I'm testing an API that uses curl_exec php function and a CA certificate but something is going wrong and I'm a little lost.
I have configured SSL on my apache VirtualHost and looks ok ( opening https:://[myVHost]... works ).
However the API curl call give me back this message:
SSL peer certificate or SSH remote key was not OK
I'm not very experienced with SSL so I have few ideas about the cause of that.
UPDATE:
This is the code I'm using in my cURL request, I have commented 2 lines and changes their value (look at 'TODO' line ) and in this way it is working, however this is just a work arround ...
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_CONNECTTIMEOUT] = 50;
$opts[CURLOPT_TIMEOUT] = 100;
$headers = array(
'Accept: application/json',
"User-Agent: APIXXX-PHP-Client");
$opts[CURLOPT_HTTPHEADER] = $headers;
$opts[CURLOPT_USERPWD] = $env->getApiKey() . ':';
if (certificatePresent()) {
// $opts[CURLOPT_SSL_VERIFYPEER] = true;
// $opts[CURLOPT_SSL_VERIFYHOST] = 2;
// TODO: SET IT BACK
$opts[CURLOPT_SSL_VERIFYPEER] = 0;
$opts[CURLOPT_SSL_VERIFYHOST] = 0;
$opts[CURLOPT_CAINFO] = $path
}
curl_setopt_array($curl, $opts);
$response = curl_exec($curl);
You are probably using self-signed SSL certifiacate, which will not pass when the CURLOPT_SSL_VERIFYPEER options is set.
There are two solutions:
Set up valid SSL certificate.
Disable SSL verification in Curl. (add --insecure option)
If you disable verification, you can't be sure if you are really communicating with your host.
So it depends on level of security you need.
Beside CURLOPT_SSL_VERIFYPEER there are two other settings which might be changed to false/0:
CURLOPT_SSL_VERIFYHOST
CURLOPT_SSL_VERIFYSTATUS
Beware that you should fix your SSL certificates & settings instead of disable security!
Although I am answering an old post, I think it will help the new viewers-
You can check the problem by adding
$opts[CURLOPT_VERBOSE] = 1
For self signed certificate your client may connect with the server using IP address, because the host name is not available in DNS cache. In that case the COMMON NAME(CN) of your server certificate needs to match with the Server IP (put IP address as common name when generating the server certificate). When you do it correctly, you can see this message:
common name: 192.168.0.1 (matched)
Here 192.168.0.1 is an example.
You're right to want to enable SSL_VERIFYPEER if you are worried about man-in-the-middle attacks.
Is your $path set to point to the certificate (or certificate bundle) provided by the API owner? Is that certificate readable by the web server user? If so, have you verified that the certificate(s) is the same as when you visit the https address manually in a browser and inspect the certificate?
If you can't get it to work, and the API you are connecting to has a SSL certificate that works in your normal browser without warnings, you should be able to set $path to your CA root bundle on your server.
You can build a valid SSL certificate and ensure that it is stored in the trusted folder.
Valid SSL certificate can be created by including the following command in the developer command prompt of VS2012. (This can be obtained by typing developer in the start)
The following command creates a self-signed certificate that can be used to test a web application that uses Secure Sockets Layer (SSL) on a web server whose URL is www.example.com. The OID defined by the -eku option identifies that certificate as an SSL server certificate. The certificate is stored in the my store and is available at the machine (rather than user) level. The certificate's private key is exportable, and the certificate is valid from May 10, 2010 through December 22, 2011.
Makecert -r -pe -n CN="www.example.com" -b 05/10/2010 -e 12/22/2011 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
For more on how to create the SSL certificate
Now make sure that this certificate is trusted, this can be done by typing CERTMGR in the cmd..
now the cert created is in the PERSONAL folder.. copy it and paste it to the TRUSTED PEOPLE FOLDER.
This should do the trick. Let me know if that doesn't work.
I had the same issue. I follow the instruction here: http://siteber.com/download-failed-ssl-peer-certificate-or-ssh-remote-key-was-not-ok/ and it fixed mine.
basically I went to /etc/resolv.conf
and Replace any
OpenDNS server:
208.67.222.222
208.67.220.220
With
Google’s public DNS servers:
nameserver 8.8.8.8
nameserver 8.8.4.4
This error can also occur if you update packages on a linux server that has a self-signed certificate.
Solution:
Stop your existing Apache/nginx server.
Run certbot (if you are using lets encrypt)
Restart your Apache/nginx server.
Note: If you're using Springboot, add System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,TLSv1.3"); to your application.properties file
Voila!
I spent almost all day for this error, and problem was in using ipv6, and called api server does not support ipv6.
Solution:
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_VERSION_IPV4);

Categories