Hi, in course of building up a dataset of mappings of User-Agents and their common SSL ClientHello messages[1] I started to implement a small patch to nginx 1.13.0 mainline to implement a small transcript of the handshake process similar to the one enabled in openssl s_client -msg.
The format of this new variable is a series of semicolon-delimited blocks starting with a direction (C: -> sent by client, S: -> sent by server) and followed by colon-delimited hexdumps of processed blocks of data. The string C:00:01;S:0203:0405:0607;C:08090A; denotes 2 blocks of 1 byte each sent by the client, followed by 3 blocks 2 byte each from the server and finally 1 block of 3 bytes from the client. Blocks usually conform to how OpenSSL tries to process the data. I'd appreciate a short review of the patch with comments for possible improvements, code style and other related things. One yet open aspect is configurable behaviour to only enable collection on-demand. Also ideas for migrating this code into a separate module are welcome. NB: Due to size of transcribed information it is commonly not feasible to pass this variable to other backend servers via HTTP headers. Trying to do so will most likely result in the backend responding 400 Bad Request, sometimes also remarking about the overlong header. I'm still looking at ways how this can be done in a sane way (abusing memcached for transporting could be an option) - but this is outside the scope of this patch. Plainly logging the information of this header to some custom log will do just fine. Kind regards, BenBE. [1] Original paper on this approach at [2] [2] https://jhalderm.com/pub/papers/interception-ndss17.pdf
From 5cf530602b0d73e388cecf5cf4b26d1c124ae847 Mon Sep 17 00:00:00 2001 From: Benny Baumann <be...@geshi.org> Date: Mon, 1 May 2017 18:32:00 +0200 Subject: [PATCH] add: Transcript of SSL Handshake similar to openssl s_client -msg --- src/event/ngx_event_openssl.c | 110 +++++++++++++++++++++++++++++++++ src/event/ngx_event_openssl.h | 5 ++ src/http/modules/ngx_http_ssl_module.c | 3 + 3 files changed, 118 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index fdbd0c9..0ad1b34 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1171,6 +1171,9 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) return NGX_ERROR; } + sc->handshake_transcript = NULL; + sc->handshake_transcript_next = &sc->handshake_transcript; + sc->buffer = ((flags & NGX_SSL_BUFFER) != 0); sc->buffer_size = ssl->buffer_size; @@ -1219,6 +1222,55 @@ ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session) return NGX_OK; } +static void +ngx_ssl_handshake_transcribe(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg) { + ngx_connection_t* c = (ngx_connection_t*) arg; + if ( !c ) { + return; + } + + ngx_ssl_connection_t* sc = c->ssl; + if ( !sc ) { + return; + } + + // Sanity check: + if ( ssl != sc->connection ) { + return; + } + + ngx_pool_t* p = c->pool; + + ngx_chain_t* cl = ngx_alloc_chain_link( p ); + if ( !cl ) { + return; + } + + ngx_buf_t* b = ngx_calloc_buf( p ); + if ( !b ) { + return; + } + + b->temporary = 1; + b->start = ngx_pcalloc( p, len ); + if ( !b->start ) { + return; + } + + b->pos = b->start; + b->end = b->start + len; + + b->last = ngx_cpymem( b->pos, buf, len ); + + b->tag = (ngx_buf_tag_t)(uintptr_t)!!write_p; + + cl->buf = b; + cl->next = NULL; + + *sc->handshake_transcript_next = cl; + sc->handshake_transcript_next = &cl->next; +} ngx_int_t ngx_ssl_handshake(ngx_connection_t *c) @@ -1228,8 +1280,14 @@ ngx_ssl_handshake(ngx_connection_t *c) ngx_ssl_clear_error(c->log); + SSL_set_msg_callback(c->ssl->connection, ngx_ssl_handshake_transcribe); + SSL_set_msg_callback_arg(c->ssl->connection, c); + n = SSL_do_handshake(c->ssl->connection); + SSL_set_msg_callback(c->ssl->connection, NULL); + SSL_set_msg_callback_arg(c->ssl->connection, NULL); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); if (n == 1) { @@ -4088,6 +4146,58 @@ ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) return NGX_OK; } +ngx_int_t ngx_ssl_get_raw_handshake(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s) { + + if(!s) { + return NGX_ERROR; + } + + ngx_ssl_connection_t* sc = c->ssl; + if(!sc) { + return NGX_ERROR; + } + + ngx_chain_t* hsp = sc->handshake_transcript; + if(!hsp) { + ngx_str_null(s); + return NGX_OK; + } + + size_t hs_len = 0; + + for(ngx_chain_t* cp = hsp; cp; cp = cp->next) { + hs_len += 2; //Client/Server designation + hs_len += 2 * (cp->buf->last - cp->buf->pos); //Paket dump + hs_len += 1; //Delimiter + } + + s->len = hs_len; + s->data = ngx_pnalloc( pool, s->len ); + if ( s->data == NULL ) { + return NGX_ERROR; + } + + u_char* p = s->data; + + ngx_buf_tag_t prev = (ngx_buf_tag_t)(uintptr_t)!hsp->buf->tag; + + for(ngx_chain_t* cp = hsp; cp; prev = cp->buf->tag, cp = cp->next) { + if(cp->buf->tag != prev) { + p = ngx_cpystrn(p, (u_char *)(cp->buf->tag ? "S:" : "C:"), 3); + } else { + *(p-1) = ':'; + } + + p = ngx_hex_dump( p, cp->buf->pos, cp->buf->last - cp->buf->pos ); + + *p++ = ';'; + } + + s->len = p - s->data; + + return NGX_OK; +} static time_t ngx_ssl_parse_time( diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 2a14980..b4f8f1f 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -79,6 +79,9 @@ struct ngx_ssl_connection_s { ngx_event_handler_pt saved_read_handler; ngx_event_handler_pt saved_write_handler; + ngx_chain_t* handshake_transcript; + ngx_chain_t** handshake_transcript_next; + unsigned handshaked:1; unsigned renegotiation:1; unsigned buffer:1; @@ -232,6 +235,8 @@ ngx_int_t ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_raw_handshake(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index b466e5d..8de97fa 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -329,6 +329,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_raw_handshake"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_raw_handshake, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; -- 2.12.0.rc0
signature.asc
Description: OpenPGP digital signature
_______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel