OpenSSL Ignore Self-signed certificate error - c++

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;
}
}

Related

OpenSSL verify domain certificate

I'm trying to verify certificate from a CA file and it's working pretty good:
SL_CTX_load_verify_locations(ctx, trusted_ca.c_str(), nullptr)
...
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_callback);
In such a situation, it checks that the signature does indeed match the CA but it does not verify the domain.
How verify_callback should look? How do I check within the function verify_callback what is the domain?

How to enabled TLS in IXWebSocket for simple client/server application

I'm attempting to build a simple client/server application in C++ using the IXWebsocket library, using the example code as an example, as shown on this page - https://machinezone.github.io/IXWebSocket/usage/
The code works fine when using an unsecured connection (as denoted by a ws:// url), but I can't get it working at all when using a secured connection (as denoted by a wss:// url).
The website states under the "TLS Support and configuration" section that
Then, secure sockets are automatically used when connecting to a wss://* url.
Additional TLS options can be configured by passing a ix::SocketTLSOptions instance to the setTLSOptions on ix::WebSocket (or ix::WebSocketServer or ix::HttpServer)
This implies to me that simply changing the ws:// url to a wss:// url is enough to instruct the application to secure the connection, however this does not work.
When I attempt to connect using a wss:// url, the server returns the following
WebSocketServer::handleConnection() HTTP status: 400 error: Error reading HTTP request line
The website goes on to say that
Additional TLS options can be configured by passing a ix::SocketTLSOptions instance to the setTLSOptions on ix::WebSocket (or ix::WebSocketServer or ix::HttpServer)
and...
Specifying certFile and keyFile configures the certificate that will be used to communicate with TLS peers. On a client, this is only necessary for connecting to servers that require a client certificate. On a server, this is necessary for TLS support.
This implies to me that for the server to support TLS, I must provide a cert file, and a key file.
The github repo includes the script generate_certs.sh which produces a series of certificates in pem format, which should be enough to get things working. Included among them are selfsigned-client-crt.pem and selfsigned-client-key.pem, which seem like obvious candidates, however they specifically state client in the names, which suggests that they should not be used in the server application, rather they belong in the client.
The website also includes the example snippet:
webSocket.setTLSOptions({
.certFile = "path/to/cert/file.pem",
.keyFile = "path/to/key/file.pem",
.caFile = "path/to/trust/bundle/file.pem", // as a file, or in memory buffer in PEM format
.tls = true // required in server mode
});
I have attempted to populate the certFile and keyFile properties, and specified "NONE" for the caFile property as explained in the example, however this results in the server application printing SocketServer::run() tls accept failed: error in handshake : SSL - The connection indicated an EOF to the console.
What's more, the example snippet listed above states "path/to/cert/file.pem" and "path/to/key/file.pem" but doesn't explicitly state whether those should be client, or server usage.
The example doesn't come with a complete runnable implementation, and doesn't explain clearly what is needed to make TLS work in this particular form, and I'm at a bit of a loss now.
There is an example application in the github repo, however it includes a number of different variations, all of which are far more complicated than this trivial example, and it is this trivial example that I need to get working so I can understand how to implement this further.
In my server application, I have implemented the following for the TLS options:
int port = 8443;
ix::WebSocketServer server(port);
ix::SocketTLSOptions tlsOptions;
tlsOptions.certFile = "certs/selfsigned-client-crt.pem";
tlsOptions.keyFile = "certs/selfsigned-client-key.pem";
tlsOptions.caFile = "NONE";
tlsOptions.tls = true; //Required for TLS
server.setTLSOptions(tlsOptions);
I am pretty sure that the issue in in how I've set up the key and cert files. I have used the client files here, but I also tried generating and signing a server cert and key, which also did not work.
I have even tried using the trusted key and cert for both the client and server applications, and still did not get a working TLS connection (the following files were generated by the generate_cert.sh script -
selfsigned-client-crt.pem, selfsigned-client-key.pem, trusted-ca-crt.pem, trusted-ca-key.pem, trusted-client-crt.pem, trusted-client-key.pem, trusted-server-crt.pem, trusted-server-key.pem, untrusted-ca-crt.pem, untrusted-ca-key.pem, untrusted-client-crt.pem, untrusted-client-key.pem
... none of which is a self signed server cert.
What I can gather from the example page is that I need to do the following to get this working.
Generate a server cert and key
Self sign the cert
Specify the cert and key file in the tlsOptions on the server
Set the tls property in tlsOptions to true on the server
Set the caFile property in tlsOptions on the server to "NONE"
Set the url in the client to a wss:// url
But this did not work when I tried it, so there's clearly something I've missed.
All I'm aiming to do for the moment is to use self signed certs so that I can test my client and server, both running on localhost.
If anybody can steer me in the right direction, I'd be immensely grateful. I've been on this for 4 days now and I'm really lost.
Many thanks
Check this file https://github.com/machinezone/IXWebSocket/blob/master/ws/test_ws.sh / it does a full client + server encrypted exchange.
Note that on macOS there are limitations, but on windows or linux, using mbedtls and openssl everything should work fine.
ps: You will need to supply the same set of certs on the client and on the server.
https://machinezone.github.io/IXWebSocket/build/
-DUSE_TLS=1 will enable TLS support
so I do the following :
mkdir build
cd build
cmake -DUSE_TLS=1 -DUSE_WS=1 ..
works for me

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.

c++ libCurl : how to accept expired certificate using libCurl

I am working on Linux embedded application which acts as client and receives data from https server using libCurl. My application's requirement is to accept expired certificate and continue to connection establishment.
I could not find any such option that can be set using curl_easy_setopt as we can ignore -
- verification of the certificate's name against host => setting CURLOPT_SSL_VERIFYHOST to 0
- verification of the authenticity of the peer's certificate => setting CURLOPT_SSL_VERIFYPEER to FALSE
Any there any other way out I can try to make it work.
You can set a callback using CURLOPT_SSL_CTX_FUNCTION (see example at https://curl.haxx.se/libcurl/c/cacertinmem.html) where you can manipulate the SSL context, clear errors, etc.
This will probably not be enough, you can experiment with setting some options of openssl itself, see https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html.
I'm not sure if it is enough to set SSL_VERIFY_NONE or if you actually have to supply a validation callback function that says yes to everything.
I haven't tested this and I'm not sure it will actually work, but you can certainly try.

QSslError: The certificate is self-signed, and untrusted

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