OpenSSL Verify Peer (Client) Certificate in C++ - c++

I have a working application that establishes an SSL connection to a server. The server uses a self-signed certificate and the client loads a certificate authority chain to tell it that the server is OK to trust. I did that with code like this on the client:
SSL_METHOD* method = TLSv1_client_method();
_ctx = SSL_CTX_new(method);
if ( SSL_CTX_load_verify_locations(_ctx, "ca-all.crt", NULL) != 1 )
{
return false;
}
_ssl = SSL_new(_ctx);
int val = SSL_set_fd(_ssl, _socket->GetFD());
if ( val != SSL_SUCCESS )
{
int err = SSL_get_error(_ssl, val);
return false;
}
val = SSL_connect(_ssl);
And on the server:
if ( SSL_CTX_use_certificate_chain_file( g_ctx, "ca-chain1.crt" ) <= 0 ) {
return 1;
}
ppem_file = getenv( "PEM_FILE" );
if ( ppem_file == NULL ) {
ppem_file = pem_file;
}
if ( SSL_CTX_use_certificate_file( g_ctx, ppem_file,
SSL_FILETYPE_PEM ) <= 0 ) {
return 1;
}
if ( SSL_CTX_use_PrivateKey_file( g_ctx, ppem_file,
SSL_FILETYPE_PEM ) <= 0 ) {
return 2;
}
I'm trying to modify this code so that the server also verifies the client's peer certificate (self-signed, using same issuer as the server) and having a bit of trouble. I haven't found good "conceptual overview" documentation anywhere, and that seems to be a typical hurdle with the OpenSSL libraries.
On the client I added this after the SSL_CTX_load_verify_locations() call:
if ( SSL_CTX_use_certificate_file(_ctx, "generic_client.pem", SSL_FILETYPE_PEM ) != 1 )
{
return false;
}
On the server I added this after the SSL_CTX_use_PrivateKey_file() call:
STACK_OF(X509_NAME) *list;
list = SSL_load_client_CA_file( "ca_chain2.crt" );
if( list == NULL ) {
return 4;
}
SSL_CTX_set_client_CA_list( g_ctx, list );
SSL_CTX_set_verify( g_ctx, SSL_VERIFY_PEER, NULL );
The connection fails because the certificate doesn't validate. The client seems to load the certificate fine and if I comment out the SSL_CTX_set_verify line, the client connects without trouble (because its certificate is never verified).
It seems that the server doesn't think that the client's certificate authority chain is good. What am I missing here?
From the commandline I can run:
openssl verify -CAfile ca-chain2.crt generic_client.pem
And it passes, so I have the right certificate data available, I must just be using it wrong somehow.

On the server, you must also call SSL_CTX_load_verify_locations(). This function tells the server what certificates to use for certificate verification; the SSL_CTX_set_client_CA_list() function sets the list of allowed CAs that are sent to the client in the handshake. Both are required.
(You also need a SSL_CTX_use_PrivateKey_file() call on the client, after the use_certificate_file call, but I guess you're doing that and just left it out).

SSL_CTX_set_client_CA_list sets the CA list. A CA certificate, by definition, is distinct from a user certificate (e.g. it has the CA bit set). So I recommend you create a proper CA (whose CA certificate is self-signed), and use that to sign both the client and the server certificate. I assume that OpenSSL isn't expecting that the client will actually use the CA certificate for communication also.

Related

libwebsocket server with openSSL not accepting connection

I have written web socket server with the help of (libwebsocket library )which accepts web socket client connection for non SSL.
Now I wanted it to accept SSL connection so I have generated the self signed certificate and key, while creating web socket context I have given the key and certificate path and option LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT as well.
But while making https connection using wss://ip:7681 from I am getting connection request callback i.e LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED and after that LWS_CALLBACK_WSI_DESTROY and in browser getting console error about not able to connect.
Firefox can’t establish a connection to the server at wss://192.168.4.254:7681/.
Please check the following server side code used for creating openSSL based web socket server.
struct lws_protocols WebSocketCommon::protocols[ 2 ] = { {"wss", WebSocketCommon::callback, 0, 0 },{ NULL, NULL, 0, 0 } };
int callback ( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len ) {
switch ( reason ) {
case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
{
//code
break;
}
case LWS_CALLBACK_WSI_DESTROY:
{
//code
break;
}
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: {
Log::d( m_r_logger, TAG, "LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS\n");
SSL_CTX_load_verify_locations( (SSL_CTX*) user, NULL, getenv(SSL_CERT_FILE_PATH) );
break;
}
default: {
break;
}
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
}
void createContext (bool useSSL) {
struct lws_context_creation_info info;
memset( &info, 0, sizeof(struct lws_context_creation_info) );
info.port = 7681;
info.uid = -1;
info.gid = -1;
info.protocols = protocols;
info.mounts = &mount;
info.extensions = exts;
info.timeout_secs = 5;
info.ip_limit_ah = 24; /* for testing */
info.ip_limit_wsi = 400; /* for testing */
// Following options for openSSL certificate
if(useSSL){
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT | LWS_SERVER_OPTION_DISABLE_IPV6 | LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED | LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
info.ssl_cert_filepath = SSL_CERT_FILE_PATH;
info.ssl_private_key_filepath = SSL_PRIVATE_KEY_PATH;
}
fContext = lws_create_context( &info );
}
I am getting following logs while creating web socket context and accepting wss connection.
WebSocket.cpp:638...... :createContext ( ) - begin
WebSocket.cpp:640...... : createContext - fReferenceCount = 0
WebSocket.cpp:324...... : Creating Vhost 'default' port 7681, 1 protocols, IPv6 off
WebSocket.cpp:324...... : Using SSL mode
WebSocket.cpp:324...... : SSL ECDH curve 'prime256v1'
WebSocket.cpp:612...... : LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS
WebSocket.cpp:324...... : lws_tls_client_create_vhost_context: doing cert filepath /etc/nginx /ssl/mycert.crt
WebSocket.cpp:324...... : Loaded client cert /etc/nginx/ssl/mycert.crt
WebSocket.cpp:324...... : lws_tls_client_create_vhost_context: doing private key filepath
WebSocket.cpp:324...... : Loaded client cert private key /etc/nginx/ssl/mykey.key
WebSocket.cpp:324...... : created client ssl context for default
WebSocket.cpp:684...... : lws_create_context SUCCEEDED
WebSocket.cpp:759...... : start Starting Service Thread.
WebSocket.cpp:705...... : createContext - fReferenceCount = 1
WebSocket.cpp:706...... : createContext - end
Following is library versions I am using.
libwebsocket.so 13
OpenSSL 1.0.2o 27 Mar 2018
Please let me know what is going wrong ?
The problem is possibly not related to libwebsockets, but rather to do with Firefox being fussy about allowing connections to WSS that have a self signed certificate. Try to connect to your server from some other program, e.g., a simple python program.
related:
What is the problem with Websocket and Self-Signed SSL certificate
Firefox disconnects websockets connection for a self signed certificate

Client returns -1 on BIO_do_connect

I'm trying to create a basic server and client using OpenSSL and its BIOs but BIO_do_connect returns -1. ERR_get_error returns 0 after that.
I've tried to minimize the code below by just writing // check [condition]. In my real code I'm doing the same thing with an if check and then I print out the error returned by ERR_get_error. (so if condition is true I'm printing an error msg)
This is my code for the server:
// init OpenSSL
SSL_load_error_strings();
ERR_load_BIO_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_default_passwd_cb(ctx, &myPasswordCallback);
int certState = SSL_CTX_use_certificate_file(ctx, "../certs/cert.pem", SSL_FILETYPE_PEM);
// check certState < 0
int keyState = SSL_CTX_use_PrivateKey_file(ctx, "../certs/key.pem", SSL_FILETYPE_PEM);
// check keyState < 0
BIO *serverBio = BIO_new_ssl(ctx, 0);
// check serverBio == nullptr
SSL *serverSsl = nullptr;
BIO_get_ssl(serverBio, &serverSsl);
// check serverSsl == nullptr
SSL_set_mode(serverSsl, SSL_MODE_AUTO_RETRY);
BIO *acceptBio = BIO_new_accept("6672");
// check acceptBio == nullptr
int setupAcceptResult = BIO_do_accept(acceptBio);
// check setupAcceptResult <= 0
int acceptResult = BIO_do_accept(acceptBio);
// check acceptResult <= 0
BIO *clientBio = BIO_pop(acceptBio);
// check clientBio == nullptr
BIO_free_all(clientBio);
BIO_free_all(acceptBio);
BIO_free_all(serverBio);
// cleanup OpenSSL
SSL_CTX_free(ctx);
EVP_cleanup();
ERR_free_strings();
This server runs fine but my client fails to connect to it:
// init OpenSSL
SSL_load_error_strings();
ERR_load_BIO_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_default_passwd_cb(ctx, &myPasswordCallback);
int certState = SSL_CTX_use_certificate_file(ctx, "../certs/cert.pem", SSL_FILETYPE_PEM);
// check certState < 0
int keyState = SSL_CTX_use_PrivateKey_file(ctx, "../certs/key.pem", SSL_FILETYPE_PEM);
// check keyState < 0
BIO *clientBio = BIO_new_ssl_connect(ctx);
SSL *clientSsl = nullptr;
BIO_get_ssl(clientBio, &clientSsl);
// check clientSsl == nullptr
SSL_set_mode(clientSsl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(clientBio, "localhost:6672");
long connectionState = BIO_do_connect(clientBio);
// check connectionState <= 0
// here it fails; connectionState is -1
long sslState = SSL_get_verify_result(clientSsl);
// check sslState != X509_V_OK
BIO_free_all(clientBio);
SSL_CTX_free(ctx);
EVP_cleanup();
ERR_free_strings();
I'm sorry for posting so much code. I didn't really find a complete example of OpenSSL server/client using BIOs.
You server code is essentially this:
setup serverBio as SSL
create a new BIO acceptBio without SSL
accept the connection connection -> clientBio
free everything
The server is not doing any SSL handshake here since the serverBio gets not used for the newly created TCP connection clientBio.
Apart from that I recommend that you test your server and client first against known good client and server so that you can faster figure out where the problem is. openssl s_client and openssl s_server provide such test client and server. Also packet capturing (wireshark) helps to find out what happens between server and client.

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.