QSslError: The certificate is self-signed, and untrusted - c++

I'm trying send a rest request to a webservice where the certificate is selfsigned. At the moment I'm creating a request, setting the url and the auth. key as headers. Then I tell the reply to ignore this ssl error:
QSslError error(QSslError::SelfSignedCertificate);
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error);
QNetworkReply *reply = _accessManager.put(request, ""); // no requestbody
reply->ignoreSslErrors(expectedSslErrors);
When I run it I get the following ssl error:
9 - The certificate is self-signed, and untrusted
followed by network error nr 6:
Request failed with message: SSL handshake failed
At the moment I'm ignoring ALL errors since it seems to be the only thing that works. Feel dirty.
Would be really grateful if anyone know what I'm doing wrong!
EDIT:
Changed to:
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(QSslError::SelfSignedCertificate);
expectedSslErrors.append(QSslError::CertificateUntrusted);
reply->ignoreSslErrors(expectedSslErrors);
But still getting the same error...

The certificate is self-signed, and untrusted
The problem is the "untrusted" part.
You have to provide the self signed certificate, as second parameter of QSslError.
Edit: Based on the source code, the comparison between the actually received SSL errors and the errors passed to ignoreSslErrors is done by comparing both the error code, and the certificate.
So if the error returned by OpenSSL would contain a certificate, like with QSslError::SelfSignedCertificate, you must always pass a certificate to QSslError constructor, or the comparison would fail.
But you can also ignore the error manually by connecting the signal sslError() to a slot where you check that the error list contains only a self signed certificate error, and then call ignoreSslErrors() (without any parameter).

Read the documentation, what you need to do is call ignoreSslErrors on a slot that responds to the QNetworkReply::sslErrors signal

Related

Error "INCORRECT_PASSWORD" in postman console on sending request with Client Certificate

I am consuming PCC API, There are two way by using different URLs:
https://connect.pointclickcare.com/auth/token
https://connect2.pointclickcare.com/auth/token
Both using same haeder and bodey excpet onre thinh that is 2nd URLs need two SSL Authentication.
I am able to consume with 1st URL.
Now I added client certificate to try to consume 2nd URL, however I am facing error and also two less value are being sent in header(Same Request
parameter is being used I only change URL for both request.)
Error: INCORRECT_PASSWORD
Screenshot is attached.
I finally found the problem, Passphrase was not added for Client Certificate being sent with http request. so I added with passphrase and now it worked fine.

Ignore common name when verifiying certificate in openssl

We are writing a new server/client app and need to Verify self-signed certificates in OpenSSL 1.1.0 where CN field isn't important.
I tried to do the following but it doesn't seem to have an effect:
X509_VERIFY_PARAM *param = NULL;
param = SSL_get0_param(sslo.ssl);
X509_VERIFY_PARAM_set1_host(param, nullptr, 0);
How can I effectivly ignore all verification of this field?
Update after Shane's answer:
I tried setting verify_callback with SSL_CTX_set_verify .
In the callback I called X509_STORE_CTX_get_error_depth . The resulting error code was X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, which according to documentation means "the passed certificate is self signed and the same certificate cannot be found in the list of trusted certificates."
This error is very generic and not related specifically to CN, if I only change the CN field in the cert to appropriate value it doesn't happen.
Use the SSL_CTX_set_verify call to specify your own verification callback function where you can OK anything you wish about the certificate.
Read that page carefully and it should tell you everything you need to know, the page also includes a example you can base your handler on if you wish.

CERTIFICATE_VERIFY_FAILED requests.session() get request

I am trying to get the contents of a page where only https urls work and it does not have a valid certificate.
import requests
session_requests = requests.session()
result = session_requests.get("some https url")
I am getting the following error:
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)
However if i use this:
requests.get('https://url.retail.publishedprices.co.il/login', verify=False)
It works, but i need to do the same kind of thing with the requests.session() since i am logging in.
If you look at the SSLLabs report for this site you will find out that there are several things wrong:
The name in the certificate does not match the name given in the URL. If you try to access this site with a browser you get an error message too.
The trust chain is incomplete and thus cannot be validated. Some browsers might try to download the missing intermediate certificate but others will simply fail here too.
Instead of trying to working around this broken setup I recommend to contact the ones who setup the site so that these serious issues gets fixed. After the fixes no workarounds in your script are needed.
Also, I don't consider disabling the validation as an acceptable workaround in this situation. This is a public accessible site which asks for sensitive data (at least username and password). And this site is explicitly enforcing https.

HTTPS request with Boost.Asio and OpenSSL

I'm trying to read the ticker symbol at https://mtgox.com/api/0/data/ticker.php from my C++ application.
I use Boost.Asio and OpenSSL because the service requires HTTPS.
Boost version: 1.47.0
OpenSSL: 1.0.0d [8 Feb 2011] Win32
For the application; I took the example from http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/ssl/client.cpp
to get started and modified it as follows:
This is where I want to connect to:
boost::asio::ip::tcp::resolver::query query("mtgox.com", "443");
I set verification to none because the handshake fails otherwise. I'm not sure if this is a problem with mtgox or that this implementation is really strict because when I print the certificate to the screen it looks legit (and chrome has no problem with it when visiting the ticker page).
socket_.set_verify_mode(boost::asio::ssl::context::verify_none);
This is the request I send:
std::stringstream request_;
request_ << "GET /api/0/data/ticker.php HTTP/1.1\r\n";
request_ << "Host: mtgox.com\r\n";
request_ << "Accept-Encoding: *\r\n";
request_ << "\r\n";
boost::asio::async_write(socket_, boost::asio::buffer(request_.str()), boost::bind(&client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
(full code: http://pastebin.com/zRTTqZVe)
I run into the following error:
Connection OK!
Verifying:
/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
Sending request:
GET /api/0/data/ticker.php HTTP 1.1
Host: mtgox.com
Accept-Encoding: *
Sending request OK!
Read failed: An existing connection was forcibly closed by the remote host
Am I going in the right direction with this? The error message isn't really descriptive of the problem and I don't know which step I did wrong.
Update:
I used cURL to see what went wrong:
curl --trace-ascii out.txt https://mtgox.com/api/0/data/ticker.php
(full output: http://pastebin.com/Rzp0RnAK)
It fails during verification.
When I connect with the "unsafe" parameter
curl --trace-ascii out.txt -k https://mtgox.com/api/0/data/ticker.php
(full output: http://pastebin.com/JR43A7ux)
everything works fine.
Fix:
I fixed the typo in the HTTP headers
I added a root certificate and
turned SSL verification back on.
In short:
You send "HTTP 1.1" instead of "HTTP/1.1". That's surely enough to make the server refuse your request. There are other differences between your request and cURL's, you might need to change those params as well - even if they seem valid to me.
Maybe OpenSSL does not have the root certificate used by the server, unlike Chrome, and that's why verification is failing.
Details:
Given a working and non-working tool, you should always compare what's happening. Here you have cURL's output and your request - comparing them showed a number of differences; usually, even with an encrypted connection, you can use a powerful packet sniffer like Wireshark, which decodes as much information from the packets as possible. Here it would allow to see that the server is actually sending less packets (I expect); another possibility would have been that your client was not getting the data sent by the server (say because the client had some bug).
If I understand correctly, curl showed only why you needed to disable verification, right? The certificate looks valid for me on chrome as well, but the root certification authority is quite unknown; curl mentions the "CA cert", i.e. the certificate of the certification authority. The root certificate is trusted because it is already present in a certificate DB on the client - I think that Chrome might have a more complete DB than OpenSSL (which is used by both cURL and your program).

OpenSSL Ignore Self-signed certificate error

I'm writing a small program with the OpenSSL library that is suppose to establish a connection with an SSLv3 server. This server dispenses a self-signed certificate, which causes the handshake to fail with this message: "sslv3 alert handshake failure, self signed certificate in certificate chain."
Is there a way I can force the connection to proceed? I've tried calling SSL_CTX_set_verify like so:
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
But it does not seem to change anything.
Any suggestions?
By default OpenSSL walks the certificate chain and tries to verify on each step, SSL_set_verify() does not change that, see tha man page. Quoting it:
The actual verification procedure is performed either using the
built-in verification procedure or using another application provided
verification function set with SSL_CTX_set_cert_verify_callback(3).
So the solution is to create a simple callback and set that one, so that you override all certificate-chain walking:
static int always_true_callback(X509_STORE_CTX *ctx, void *arg)
{
return 1;
}
SSL_CTX_set_cert_verify_callback(CTX, always_true_callback);
Have you tried giving your app the server's CA certificate so that your app can verify the certificate chain?
Check these OpenSSL Examples: http://www.rtfm.com/openssl-examples/
The wclient.c connects to any https page, for example:
wclient -h www.yahoo.com -p 443
If you run that with the default installation, you'll get a certificate error (you can use the -i flag to bypass the certificate check though).
To verify the certificate, you'll need to download the CA certificates (Verisign, Thawte, Equifax, etc), so google this file cacert.pem, download and rename it to root.pem and you'll be able to connect to a web server and validate its certificate.
Have you tried setting SSL_set_verify?
SSL_set_verify(s, SSL_VERIFY_NONE, NULL);
You could try passing your own callback to SSL_set_verify() and then doing your own verification. It's less than ideal as I think you then need to do all of the verification and then allow the self signed error to be ignored, but you should be able to work out what the standard verify code does from the OpenSSL source and then simply pull it into your own verification callback and allow the specific error code...
My sample client code (link) works fine with self signed server cert. I have the below code after SSL_connect and have full control over self signed certificates acceptability in my client
SSL_CTX* ctx = SSL_CTX_new(SSLv3_method());
// TCP connection and SSL handshake ...
/* Check the certificate */
rc = SSL_get_verify_result(ssl);
if(rc != X509_V_OK) {
if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || rc == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
fprintf(stderr, "self signed certificate\n");
}
else {
fprintf(stderr, "Certificate verification error: %ld\n", SSL_get_verify_result(ssl));
SSL_CTX_free(ctx);
return 0;
}
}