[Libwebsockets] Verifying client certificate

Alexander Bruines alexander.bruines at gmail.com
Thu Aug 6 18:19:01 CEST 2015

Thank you Bruce,

I had already figured out that Andy is a very busy man and that it's up to us users ;-)
That does not matter to much, I like a challenge, but I could really use some help from you / other users out there.

Until now I have been trying to get information from the client certificate on the 'public' side of libwebsockets.

The application I'm writing that uses libwebsockets is going to be used to remotely arm/disarm security control panels, so I would really like to know 'who' is doing 'what'.
Therefor, I'd gladly create a patch to implement something in libwebsockets that will make this work. That is, if I can figure it out.

To associate a peer client certificate with a particular websocket connection we need accomplish this in the function
static int OpenSSL_verify_callback() in ssl.c. This is (as far as I know) the only valid place to call SSL_get_peer_certificate() and always get the correct relsult.

The following code-snippets modify libwebsockets so that both the 'context' and the 'new_wsi' are available in OpenSSL_verify_callback().
OpenSSL_verify_callback() is then modified to store the result of X509_NAME_oneline() in a newly added variable to struct libwebsocket named 'char *peer_oneline'.

This however turns out to be the easy part...
With these modifications 'wsi->peer_oneline' is only available in the wsi of the protocol that initiates the connection (ie. not necessarily protocol 0).
(Refreshing the webpage in the browser causes wsi->peer_oneline to get lost completely.)

I have not yet figured out how to properly propagate the new 'peer_oneline' variable to all wsi's created for the connection.

(sorry no patch since it still needs a lot of work):

*** In private-libwebsockets.h add (after the definition of struct libwebsocket):

||struct lws_openssl_ex_data {||
||  struct libwebsocket_context *context;||
||  struct libwebsocket *wsi;||

*** In private-libwebsockets.h add to 'struct libwebsocket':

||  char *peer_oneline;||

*** In libwebsockets.c: libwebsocket_close_and_free_session() add near the end (just before lws_free(wsi):

||    /* Free any stored peer certificate information */||
||    if (wsi->peer_oneline) lws_free(wsi->peer_oneline);||

*** In ssl.c: lws_server_socket_service_ssl(): add to the beginning of this function:

|  struct lws_openssl_ex_data *ex_data;||

*** In ssl.c: lws_server_socket_service_ssl(): replace SSL_set_ex_data(...) with:

|  ex_data = lws_zalloc(sizeof(struct lws_openssl_ex_data));||
||  if (!ex_data) {||
||        lwsl_err("no ex_data\n");||
||        return 0;||
||  }||
||  ex_data->context = context;||
||  ex_data->wsi = new_wsi;||
||    SSL_set_ex_data(new_wsi->ssl,||
||        openssl_websocket_private_data_index, ex_data);||

*** In ssl.c: modify OpenSSL_verify_callback() to look like this:

|static int||
||OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)||
||    SSL *ssl;||
||    int n;||
||    struct lws_openssl_ex_data *ex_data;||
||    X509 * certificate;||
||    ssl = X509_STORE_CTX_get_ex_data(x509_ctx,||
||        SSL_get_ex_data_X509_STORE_CTX_idx());||
||    /*||
||     * !!! nasty openssl requires the index to come as a library-scope||
||     * static||
||     */||
||    ex_data = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);||
||    if (!ex_data) {||
||        lwsl_err("no ex_data\n");||
||        return 0;||
||    }||
||    n = ex_data->context->protocols[0].callback(ex_data->context, ex_data->wsi,||
||                           x509_ctx, ssl, preverify_ok);||
||    certificate = SSL_get_peer_certificate(ssl);||
||    if (certificate) {||
||        ex_data->wsi->peer_oneline = X509_NAME_oneline(||
||      X509_get_subject_name(certificate), NULL, 0);||
||    }||
||    else {||
||        ex_data->wsi->peer_oneline = NULL;||
||    }||
||  /* ex_data is no longer needed after authentication */||
||    SSL_set_ex_data(ssl, openssl_websocket_private_data_index, NULL);||
||    lws_free(ex_data);||
||    /* convert return code from 0 = OK to 1 = OK */||
||    return !n;||

Thanks, Alex.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://libwebsockets.org/pipermail/libwebsockets/attachments/20150806/3d490b0a/attachment-0001.html>

More information about the Libwebsockets mailing list