Trying to make a secure handshake between server and client with OpenSSL - c++

I'm trying to make a basic Client-Server program that can exchange messages using the OpenSSL library. I'm very new to OpenSSL and cryptography and I'm trying to understand exactly how to make sure that the connection between my client and server is secure. Currently I'm using self signed certificates for both client and server but the certificate verification fails when the client tries to connect to the server with this error:
140336190395008:error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed:../ssl/statem/statem_srvr.c:3711:
In the main method of my server program, I first set verify for the CTX and use the following flags:
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
Then when setting up the servlet I call the following method to show certificates:
void ShowCerts(SSL* ssl) /*show the ceritficates to client and match them*/ {
X509 *cert;
long int verify;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
verify = SSL_get_verify_result(ssl);
if (verify == X509_V_OK) {
printf("Yay it worked\n");
}
if ( cert != NULL ) {
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Server: %s\n", line); /*server certifcates*/
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("client: %s\n", line); /*client certificates*/
free(line);
X509_free(cert);
} else {
printf("No certificates.\n");
}
}
As I said I'm very new to this so I might be missing something basic here. Also apologies in advance if I missed any important info, this is my first time asking a question here.

Related

SSL_connect fails with SSL_ERROR_SSL - How can I investigate what is going wrong?

Simple socket program which is trying to connect to a valid https server (can browse with FireFox/Chrome etc etc).
Code is:
// Register the error strings for libcrypto & libssl
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// load all algos
OpenSSL_add_all_algorithms();
// create context (new context for each connection)
ssl_ctx_ = SSL_CTX_new(SSLv23_client_method());
if(!ssl_ctx_) {
throw std::runtime_error("Can't initialize ssl context");
}
// create handle
ssl_h_ = SSL_new(ssl_ctx_);
if(!ssl_h_) {
SSL_CTX_free(ssl_ctx_);
throw std::runtime_error("Can't initialize new ssl handle");
}
// sd_ is a valid socket connected to a host on port 443,
// i.e. www.repubblica.it:443
// bind socket
if (!SSL_set_fd(ssl_h_, sd_)) {
SSL_free(ssl_h_);
SSL_CTX_free(ssl_ctx_);
throw std::runtime_error("Can't set sd to ssl handle");
}
// set blocking
// this api makes the socket blocking
fd_block(sd_);
// perform handshake
const int r = SSL_connect(ssl_h_);
// r is now -1
if(1 != r) {
// find out the error
const int err = SSL_get_error(ssl_h_, r);
SSL_free(ssl_h_);
SSL_CTX_free(ssl_ctx_);
throw std::runtime_error(std::string("Can't perform ssl handshake, err code: ") + ssl_err_human(err));
}
And I get the following error: Exception: Can't perform ssl handshake, err code: SSL_ERROR_SSL which is not really insightful.
What can I do next to understand what I'm doing wrong and then fix it?
Thanks!
Ps. running on Ubuntu 22.04 with default libssl-dev package

How can I validate hostnames with OpenSSL 1.1.0?

I'm trying to implement a sample hostname validation with OpenSSL.
The sample C/C++ code I have put together is:
// please note I'm connecting to https://openssl.org itself
// enable SNI
if(!SSL_set_tlsext_host_name(ssl, "www.openssl.org")) throw;
if(!SSL_connect(ssl)) throw;
// connection is fine, I can get the homepage via HTTP
X509 *cert = SSL_get_peer_certificate(ssl);
if(cert) {
if(!X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), "google.com", 0)) throw;
SSL_set_verify(ssl, SSL_VERIFY_PEER, 0);
const long cert_res = SSL_get_verify_result(ssl);
if(cert_res == X509_V_OK) {
printf("Certificate verified!\n");
}
X509_free(cert);
}
As per code above I'm successfully connecting to the openssl.org domain; then I'm setting the name to verify as google.com to test failures, but the code still succeeds.
What am I doing wrong?
How can I implement a thorough verification of hostnames using OpenSSL APIs? I wouldn't want to re-implement (most likely with bugs/wrongly) what is already implemented in the library...
I'm using Ubuntu 16.04 and this libssl version: /lib/x86_64-linux-gnu/libssl.so.1.0.0.
As suggested by jww, one simply needs to set (at least)
if(!X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), "google.com", 0)) throw;
before performing the connection itself:
if(!SSL_connect(ssl)) throw;
In this case, one case ensure OpenSSL to implement the check automatically at connection time by adding following code:
SSL_set_verify(ssl, SSL_VERIFY_PEER, 0);
before calling SSL_connect, or follow the same path as before and have return X509_V_ERR_HOSTNAME_MISMATCH by SSL_get_verify_result if one wants to handle things in more details:
// please note I'm connecting to https://openssl.org itself
// enable SNI
if(!SSL_set_tlsext_host_name(ssl, "www.openssl.org")) throw;
// enable name/domain verification
if(!X509_VERIFY_PARAM_set1_host(SSL_get0_param(ssl), "google.com", 0)) throw;
if(!SSL_connect(ssl)) throw;
// get certificate
X509 *cert = SSL_get_peer_certificate(ssl);
if(cert) {
const long cert_res = SSL_get_verify_result(ssl);
// in case of name/domain mismatch cert_res will
// be set as 62 --> X509_V_ERR_HOSTNAME_MISMATCH
if(cert_res != X509_V_OK) throw; // certificate has been tampered with
X509_free(cert);
} else throw; // we couldn't get certificate

openssl SSL_get_verify_result returns error 20

I am writing a C++ program that connects using SSL. The certificate chain checks out using:
openssl verify -CAfile test.pem private.pem
where test.pem contains the intermediate and root certificate. My test program does not verify the certificate chain.
if ( !SSL_CTX_load_verify_locations( ctx, "c:/Certs/test.pem", NULL ) ) {
// Failure message and cleanup goes here.
}
SSL* ssl;
BIO* bio = BIO_new_ssl_connect( ctx );
BIO_get_ssl( bio, &ssl );
SSL_set_mode( ssl, SSL_MODE_AUTO_RETRY );
BIO_set_conn_hostname( bio, "url.com:https" );
if ( BIO_do_connect( bio ) <= 0 ) {
// Failure message and cleanup goes here.
}
if ( SSL_get_verify_result( ssl ) != X509_V_OK ){
// Here is where I get the error 20...
// Free all resources and exit.
}
OpenSSL documentation describes error 20 as:
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate.
The issuer certificate could not be found: this occurs if the issuer certificate of an
untrusted certificate cannot be found.
I need help identifying the problem and how to solve it. I am certain the certificates I have are correct.
It seems the certificate or certificate chain is not trusted.
You can load your own from a pem file before trying to connect by using:
int rc = SSL_CTX_load_verify_locations(ssl_context, file_name, NULL);
if (rc != 1) { // verify authentication result
g_warning("Load of certificates failed!: %s", X509_verify_cert_error_string(ERR_get_error()));
return FALSE;
}
Additionally you can load from memory directly.
With something like this:
char *chain_certs = "------- BEGIN CERTIFICAT...."; /// <<< YOUR CERTIFICATE CHAIN
// Load chain of certs
X509 *cacert=NULL;
BIO *mem = BIO_new_mem_buf(chain_certs,strlen(chain_certs));
X509_STORE *cert_store = SSL_CTX_get_cert_store(ssl_context);
if(cert_store!=NULL){
int index = 0;
while ((cacert = PEM_read_bio_X509(mem, NULL, 0, NULL))!=NULL) {
if(cacert) {
g_debug("Our certificate name is %s", cacert->name);
X509_STORE_add_cert(cert_store, cacert);
X509_free(cacert);
cacert=NULL;
} /* Free immediately */
index++;
}
}
BIO_free(mem);

gSOAP - How to use SSL and self-signed certificate

I need to connect my cross-platform program to a SOAP web service. I have compiled the gSOAP tools wsdl2h and soapcpp2 and with these tools I have generated the source code files from from the .wsdl file. I have putted in the stdsoap2.h the define "#define WITH_OPENSSL" and in this way SSL are used. The problem is that when i call the service the call return ERROR 30 that means SSL ERROR but i don't know what is really the problem. I know the server send a self-signed certificate because this is a testing environment. Indeed an error message related this is printed. The output is:
Creating SOAP objects ...
Calling SOAP httpAccessService:
SSL verify error or warning with certificate at depth 0: self signed certificate
certificate issuer /C=IT/ST=Milan/L=Milan/O=Company/OU=Company/CN=company.it
certificate subject /C=IT/ST=Milan/L=Milan/O=Company/OU=Company/CN=company.it
SOAP ERROR 30
The function i use to call the service is this:
void gSOAPTesting::runTest()
{
int result = 0;
size_t requestSize;
size_t responseSize;
char endpoint[1024];
char buffer[8192];
string SoapAction;
struct soap *soap_container;
ApplicationConfigurationServiceSoapBindingProxy Proxy1;
_ns1__httpAccessService *httpAccessService;
_ns1__httpAccessServiceResponse *httpAccessServiceResponse;
printf("Creating SOAP objects ...\n");
soap_container = soap_new();
//soap_container->mode
httpAccessService = (_ns1__httpAccessService *) soap_instantiate(soap_container , SOAP_TYPE___ns1__httpAccessService , "" , "" , &requestSize);
httpAccessServiceResponse = (_ns1__httpAccessServiceResponse *) soap_instantiate(soap_container , SOAP_TYPE___ns1__httpAccessService , "" , "" , &responseSize);
soap_ssl_init(); /* init OpenSSL (just once) */
if(soap_ssl_client_context(soap_container ,
SOAP_SSL_DEFAULT ,
NULL,
NULL,
NULL,
NULL,
NULL
) != SOAP_OK)
{
printf("SOAP SSL Initialization Failure\n");
soap_print_fault(soap_container , stderr);
return ;
}
printf("Calling SOAP httpAccessService:\n");
SoapAction.clear();
SoapAction.append(SOAP_NAMESPACE_OF_ns1);
SoapAction.append("/");
SoapAction.append("httpAccessService");
result = Proxy1.httpAccessService("https://XXX.XXX.XXX.XXX:XXXX" , NULL , httpAccessService , httpAccessServiceResponse);
if(result == SOAP_OK)
{
printf("SOAP OK\n");
}
else
{
printf("SOAP ERROR %d\n" , result);
if(soap_check_state(soap_container) ) printf("Error: request soap struct not initialized\n");
if(httpAccessService->soap == NULL)
{
printf("Error: NULL request SOAP struct\n");
return;
}
if(httpAccessService->soap->endpoint == NULL) printf("Error: Empty request endpoint\n");
soap_stream_fault(soap_container , std::cout);
}
}
Any help is appreciated.
The problem is related the certificate that is not trusted because is self-signed. If I comment these lines in stdsoap2.cpp...
if (!ok)
{ soap_set_sender_error(soap, "SSL/TLS error", "SSL/TLS certificate host name mismatch in tcp_connect()", SOAP_SSL_ERROR);
soap->fclosesocket(soap, sk);
return SOAP_INVALID_SOCKET;
}
...the certificate is accepted even if the it is issued by an unknown authority.
if (soap_ssl_client_context(&soap,
SOAP_SSL_NO_AUTHENTICATION,
NULL , NULL,
NULL, /* ````````````````````````````````*/
NULL,NULL )!= SOAP_OK)
{
If you are ok ignoring the host you can do something like above instead of commneting stuff in generated files

Failing to validate server certificate with OpenSSL

I have written a SOAP client using OpenSSL (written in C++ on Ubuntu 12.04) but it currently works without checking the server security certificate. This is the function I am using to set up the connection and checking the certificate
bool bInitialiseSSL(SSL_CTX* &ctx, SSL* &ssl, BIO* &bio)
{
ctx = SSL_CTX_new(SSLv23_client_method());
bio = BIO_new_ssl_connect(ctx);
if (bio == NULL) {
ERR_print_errors_fp(stderr);
SSL_CTX_free(ctx);
return false;
}
BIO_get_ssl(bio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
char target[] = "api.betfair.com:https";
BIO_set_conn_hostname(bio, target);
BIO_set_nbio(bio,1);
while (1) {
if (BIO_do_connect(bio) <= 0) {
if (!BIO_should_retry(bio)) {
cout << "Connect failed." << endl;
BIO_free_all(bio);
SSL_CTX_free(ctx);
return false;
}
} else {
break;
}
}
if (BIO_do_handshake(bio) <= 0) {
BIO_free_all(bio);
SSL_CTX_free(ctx);
return false;
}
X509 *cert;
bool bValid = false;
cert = SSL_get_peer_certificate(ssl);
if ( cert != NULL ) {
long res = SSL_get_verify_result(ssl);
if (res == X509_V_OK) {
bValid = true;
} else {
cout << "Error in security validation: " << res << endl;
}
X509_free(cert);
}
return bValid;
}
This works fine but the return value of SSL_get_verify_result is 20 which corresponds to
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local
issuer certificate
I have read some of the OpenSSL documentation for their functions but it is not particularly user friendly. I have looked at a number of web tutorials and I cannot see what I am doing wrong. My software worked perfectly before I tried to implement the certificate checking but I cannot see what I need to do. Do I need to configure settings on my machine? The server is betfair which is supposedly very secure and I find it hard to believe that they do not have valid SSL certificates. If anyone can tell me what I am doing wrong I would be very grateful.
It depends on the certificates of the server.
If it is a public valid certificate, you can include the CA certs file into SSL_CTX.
code:
ctx = SSL_CTX_new(SSLv23_client_method());
// You can load CA certs into SSL_CTX
SSL_CTX_load_verify_locations(ctx, cafile, NULL); // cafile: CA PEM certs file
You can download the public CA certs file from cURL website CA Certs from mozilla.org
If it is a private certs, and you have the certificate file, you can use SSL_CTX_use_certificate_file instead of SSL_CTX_load_verify_locations.