Context for multiple connections with OpenSSL - c

I want to get multiple connections with OpenSSL.
Should I create new SSL_CTX context for every new connection or accept all connections with one context?
Should I do additional actions with memory or something with start/stop connection, except
close(_socket); //socket which accept the connection
SSL_shutdown(_ssl); //_ssl — SSL connection
SSL_free (_ssl);

Should I create new SSL_CTX context for every new connection or accept all connections with one context?
It depends on the number of server names and distinct certificates.
If you have one server name and one certificate, then use one default context.
If you have multiple server names and one certificate, then use one default context.
If you have multiple server names and multiple certificate, then see below on the SNI or servername callback and swapping in a context.
If your server listens for foo.com and bar.com with distinct certifcates, then you will need three contexts. One default context is for non-SNI clients, one context is for foo.com, and one context is for bar.com.
Effectively, the only thing that will likely change between the two sites is the certificate that's served. So you listen with the default context. If the client provided a servername via SNI, then you swap-in one of the other two contexts in the servername callback and SSL_set_SSL_CTX. Here's how it would look:
static int ServerNameCallback(SSL *ssl, int *ad, void *arg)
{
UNUSED(ad);
UNUSED(arg);
ASSERT(ssl);
if (ssl == NULL)
return SSL_TLSEXT_ERR_NOACK;
const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
ASSERT(servername && servername[0]);
if (!servername || servername[0] == '\0')
return SSL_TLSEXT_ERR_NOACK;
/* Need a certificate and context for this domain */
SSL_CTX* ctx = GetServerContext(servername);
ASSERT(ctx != NULL);
if (ctx == NULL)
return SSL_TLSEXT_ERR_NOACK;
/* We should not be peeking into the object like this... */
ASSERT(ctx != ssl->ctx);
/* Useless return value */
SSL_CTX* v = SSL_set_SSL_CTX(ssl, ctx);
return SSL_TLSEXT_ERR_OK;
}
GetServerContext just provides the context for foo.com or bar.com. It creates them once, and then reuses the same ones.
For the default context, you set the servername callback with SSL_CTX_set_tlsext_servername_callback. There's no need to set it for non-default contexts.
SSL_CTX_set_tlsext_servername_callback(ctx, ServerNameCallback);
Contexts are referenced counted, so you can reuse them.
Should I do additional actions with memory or something with
start/stop connection, except
close(_socket); //socket which accept the connection
SSL_shutdown(_ssl); //_ssl — SSL connection
SSL_free (_ssl);
Here, you should seek a treatment of the subject. For example, you should not call close before SSL_shutdown. And the first call to SSL_shutdown may fail, so you need to know what to do next.
For a treatment of the subject, see Eric Rescorla's tutorials: An Introduction to OpenSSL Programming, Part I of II and An Introduction to OpenSSL Programming, Part II of II. Or get the book: Network Security with OpenSSL.

Related

LwIP Clilent can't establish a connection

I want to connect two F746ZG boards so that they can communicate via TCP. I am using the STM implementation of LwIP with the netconn API. The IP address is supplied via DHCP, but it is always the same address. Also, the address matches the expected value. The problem I am facing is that the client seemingly can't establish a connection. I am binding the connection to port 8880. Since I ran into this issue, I have written a debug client that should just periodically send a predefined message to a server. Here is the code for the client:
static void tcpecho_client_thread(void const *arg)
{
struct netconn *xNetConn = NULL;
err_t bind_err, connect_err;
char* b_data = "OK"; // Data to be sent
uint16_t b_len = sizeof ( b_data );
IP4_ADDR(&local_ip, IP_ADDR0_CLIENT, IP_ADDR1_CLIENT, IP_ADDR2_CLIENT, IP_ADDR3_CLIENT);
IP4_ADDR(&pc_ip, IP_ADDR0_PC, IP_ADDR0_PC, IP_ADDR2_PC, IP_ADDR3_PC);
xNetConn = netconn_new ( NETCONN_TCP );
if (xNetConn != NULL){
bind_err = netconn_bind ( xNetConn, &local_ip, TCP_PORT_NETCONN );
if(bind_err == ERR_OK){
// Try to connect to server
for(;;){
connect_err = netconn_connect ( xNetConn, &pc_ip, TCP_PORT_NETCONN);
if (connect_err == ERR_OK){
// We are connected
while(1){
BSP_LED_On(LED1);
netconn_write(xNetConn, b_data, b_len, NETCONN_COPY);
vTaskDelay(1000); // To see the result easily in Comm Operator
}
}
}
}else{
// Failed to bind the connection
BSP_LED_On(LED3);
}
}else{
// Failed to allocate a new connection
BSP_LED_On(LED3);
}
}
When I debug this, netconn_connect never manages to actually connect to something. Since I am able to ping the board and get a response, I am confused, what is going wrong here. I have tried to use Hercules to set up a TCP server on my PC so that the board can connect to that, but that also doesn't work. Using Wireshark, I can see the responses to my ping command coming in, but I don't see anything that would indicate the board trying to connect to my PC.
I have tested the corresponding server on the second board, but that runs fine. I can connect to it with Hercules and send data, so I doubt there is anything fundamentally wrong with the LwIP stack.
What I could guess is that I messed up the netconn_bind, I am not 100% sure what IP you are supposed to bind the connection to. The way it currently is, is how I read the documentation. For the server, I have bound it to IP_ADDR_ANY. Besides that, my implementation mostly matches with the examples you can find online (e.g. LwIP Wiki).
I have figured out the problem. After I delete the netconn_bind call, everything works fine for me.

How to duplicate a SSL_CTX object in a TLS application?

I am having a application in. c that uses openssl for TLS v1.2 implemention.
The application shall open multiple remote connections to remote server running with the same version of TLS. I have a single set of key, certificate and CA_certificate to be used for all connections.
I need to maintain the SSL_CTX object for each client separately. But, I wish to create a single global SSL_CTX context object and configure it once for the following:
SSL_CTX_set_ecdh_auto()
SSL_CTX_use_certificate_file()
SL_CTX_use_PrivateKey_file()
SSL_CTX_set_verify()
SSL_CTX_set_options()
SSL_CTX_load_verify_locations
SSL_CTX_set_verify_depth()
And then, for each connections initiated by the application, I can duplicate (make a copy) of the above configured context ctx and call SSL_new() directly, without going through the listed steps over and over for each client.
Does Openssl provide any function to duplicate the SSL_CTX object?
If not is there any other safe way to do so? like memcpy() etc.
SSL_CTX has a counting reference. It means it will be freed when its reference counts reaches zero.
So rather than copying SSL_CTX, just increase its reference by SSL_CTX_up_ref() and use same object. As a result, your code will be something like this:
SSL_CTX *g_ssl_ctx = nullptr;
//...
//init g_ssl_ctx
//...
SSL_CTX *get_client_ctx() {
SSL_CTX_up_ref(g_ssl_ctx);
return g_ssl_ctx;
}

How to determine if a connection used encryption/SSL from apache2 httpd module?

In the context of an Apache2 module written in C, how can I determine if a request (request_rec *r) is encrypted? I've seen code that seems to do that, but I either haven't been able to figure out how to implement it or it always return 'true', even on unencrypted connections.
In PHP, $_SERVER['HTTPS'] gets set to 'on' if HTTPS is used.
In your own module, define
#include <mod_ssl.h>
static int is_https(conn_rec *c)
{
int (*is_https_conn)(conn_rec *c);
is_https_conn = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
if (is_https_conn)
return is_https_conn(c);
return 0;
}
so you can test if request request_rec *r uses an SSL/TLS connection, using
if (is_https(r->connection)) {
/* Yes, request is via an SSL/TLS-encrypted connection */
} else {
/* No, the request is not via an encrypted connection */
}
The logic is based on the fact that the SSL/TLS module uses APR_REGISTER_OPTIONAL_FN(ssl_is_https) to register the function ssl_is_https() in modules/ssl/ssl_engine_vars.c:ssl_var_register(). This function takes a connection (conn_rec *), and returns nonzero if the connection uses SSL/TLS encryption (HTTPS).
We use APR_RETRIEVE_OPTIONAL_FN(ssl_is_https) to retrieve the pointer to said function. If it is not registered, this returns NULL (and obviously no connection can then be encrypted). If it returns a non-NULL pointer, we call the function. It will return nonzero if the connection is HTTPS.

libssh2 public key authentication only requiring passphrase if key request is accepted

I'm using libssh2 to make a networking program more secure.
I'd like my program to authenticate in as similar way to the OpenSSH client ssh(1) as possible. The OpenSSH client will only ask for passphrases for keys that are actually accepted by the server.
As I understand from this link, an ssh client sends a request to use a public key, and if that is accepted, it can unlock the private key using the passphrase.
libssh2 provides a function libssh2_userauth_publickey_fromfile which takes the private and public key file names and a passphrase. Using this function is very straight forward, but it means I have to obtain the passphrase for private keys even if the public key wouldn't have been accepted by the server in the first place. This is clearly a problem for users that have a lot of different keys (my program currently iterates through key files in the ~/.ssh directory).
I have tried reading the man pages for libssh2 functions, and most of them appear too brief for me to understand without a more detailed knowledge of the ssh protocol. In fact some of them haven't even been written yet.
Can anyone tell me how to only prompt for passphrases for keys that are actually accepted by an ssh server using libssh2?
After RTFM and doing some testing, I discovered that libssh2_userauth_publickey_fromfile will return a different error code depending on whether the key wasn't accepted by the server, or the passphrase was incorrect.
So, here is a pretty inefficient solution (because it calls libssh2_userauth_publickey_fromfile and hence all the key exchange parts of the protocol at least twice).
int nAttempts = 3; // number of attempts the user gets at entering the passphrase
// Try authenticating with an empty passphrase
int err = libssh2_userauth_publickey_fromfile(session, user, pub, priv,"");
if (err == 0)
{
fprintf(stderr, "You shouldn't use keys with an empty passphrase!\n");
}
else if (err == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED)
{
// if we get here it means the public key was initially accepted
// but the private key has a non-empty passphrase
char p[BUFSIZ];
for (int i = 0; i < nAttempts; ++i)
{
get_passphrase(p); // assume this gets the passphrase
err = libssh2_userauth_publickey_fromfile(session, user, pub, priv,p);
if (err != LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) break;
}
}
if (err != 0)
{
fprintf(stderr, "Authentication using key %s failed!\n", priv);
}
For completeness, the get_passphrase function uses the solution to this question to prompt the user for a passphrase.

Openssl query about usage

I am trying to use OpenSSL in my application, and achieve a secure connection.
At first I tried:
create ssl struct
create socketbio for the tcp socket
create a sslbio
set socketbio to SSL strcut
SSL_accept(ssl)
BIO_push(ssl, socketbio)
This cause handshake to happen successfully, but application data wasn't properly decrypted.
Then I tweaked a little, and relaced 6 with
(new) BIO_ctrl(sslbio, SET_SSL, ssl)
and things worked fine.
I Wanted to know, what's wrong with previous approach, and what's causing the new apprach work?
It's hard to answer the question without knowing why you think BIO_push is all you need to do. At any rate, you shouldn't call BIO_ctrl directly. You should use the high-level wrapper BIO_set_ssl defined in bio.h:
#define BIO_set_ssl(b,ssl,c) BIO_ctrl(b,BIO_C_SET_SSL,c,(char *)ssl)
This macro sets the ssl member of the BIO object as you can see in bio_ssl.c:
case BIO_C_SET_SSL:
if (ssl != NULL)
ssl_free(b);
b->shutdown=(int)num;
ssl=(SSL *)ptr;
((BIO_SSL *)b->ptr)->ssl=ssl;
bio=SSL_get_rbio(ssl);
if (bio != NULL)
{
if (b->next_bio != NULL)
BIO_push(bio,b->next_bio);
b->next_bio=bio;
CRYPTO_add(&bio->references,1,CRYPTO_LOCK_BIO);
}
b->init=1;
break;
The important step in this function is not the BIO_push, but rather is where it sets the ssl pointer in the BIO_SSL object to your active SSL context, i.e., ((BIO_SSL *)b->ptr)->ssl=ssl;.

Resources