How can I validate hostnames with OpenSSL 1.1.0? - c++

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

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

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

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.

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

gSoap + SSL : CRL & certificate name check

I'm developing a webservice using gSOAP with SSL support. It works fine as long as I COPY (that's it!) the code provided as gSOAP documentation. Trying to add some feature I collide with a lot of difficulties! I don't have a good knowledge of OpenSSL libraries, so I'm here to ask your help.
I should add a CRL list to check the certificate sent by the client. How can I do it? Moreover, I changed the function pointed by soap.fsslverify with this one:
int servlet_fsslverify(int ok, X509_STORE_CTX *store)
{
ok = 1;
char buf[1024];
X509 *cert = X509_STORE_CTX_get_current_cert(store);
fprintf(stderr, "SSL verify error or warning with certificate at depth %d: %s\n",
X509_STORE_CTX_get_error_depth(store),
X509_verify_cert_error_string(X509_STORE_CTX_get_error(store)));
X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
fprintf(stderr, "certificate issuer %s\n", buf);
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
fprintf(stderr, "certificate subject %s\n", buf);
/* Note: return 1 to continue, but unsafe progress will be terminated by OpenSSL */
return ok;
}
It is called everytime a client tries to authenticate. As you can see, I'm able to check the fields in client's certificate, but I really don't know how to check if the particular certificate is present or not in a CRL.
That's all, thanks a lot to everyone would be so nice to answer.
I found the solution on the internet! Sorry I don't remember where, but I'll try to find it back and I'll edit this post - credits to the solver.
Code to be inserted right after server-context creation.
X509_STORE *store;
store = SSL_CTX_get_cert_store(ServicePtr->ctx);
if (store)
{
X509_LOOKUP *lookup;
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
if (lookup)
{
if ( X509_load_crl_file(lookup, globals.pki_crl, X509_FILETYPE_ASN1) < 1 )
{
std::cerr << "CRL not found or invalid" << std::endl;
}
}
else
{
std::cerr << "Unable to create a valid lookup" << std::endl;
}
}
else
{
std::cerr << "Unable to get X509_STORE" << std::endl;
}