[PATCH] Expose additional SSL variables

Garret Reece garret at trailofbits.com
Fri Apr 24 16:25:26 UTC 2020


More or less, yes--we had a request from a customer to take just the
extensions and the elliptic curve format points data from your patch
and make them available in the main package

On Fri, Apr 24, 2020 at 11:17 AM Paulo Pacheco <fooinha at gmail.com> wrote:
>
> Hello, this looks very similar with what I've done here.
>
> https://github.com/fooinha/nginx-ssl-ja3/blob/master/patches/nginx.1.17.1.ssl.extensions.patch
>
> Is this the same code?
>
>
> Thanx.
>
>
>
>
>
>
> On 24 Apr 2020, at 16:17, Garret Reece <garret at trailofbits.com> wrote:
>
> # HG changeset patch
> # User Garret Reece <garret at trailofbits.com>
> # Date 1587691836 18000
> #      Thu Apr 23 20:30:36 2020 -0500
> # Node ID 86d2f46807f597249fa59072b920a389f8c082ee
> # Parent  716eddd74bc2831537f5b3f7ecd16ad3e516d043
> Expose additional SSL variables.
>
> Expose the ssl extensions and elliptic curve point formats provided by client.
> This enables ja3 fingerprinting of TLS connections.
>
> diff -r 716eddd74bc2 -r 86d2f46807f5 src/event/ngx_event_openssl.c
> --- a/src/event/ngx_event_openssl.c Thu Apr 23 15:10:26 2020 +0300
> +++ b/src/event/ngx_event_openssl.c Thu Apr 23 20:30:36 2020 -0500
> @@ -1588,6 +1588,100 @@
>     return NGX_OK;
> }
>
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +
> +void
> +ngx_SSL_client_features(ngx_connection_t *c)
> +{
> +    unsigned short                *ciphers_out = NULL;
> +    int                           *curves_out = NULL;
> +    int                           *point_formats_out = NULL;
> +    size_t                         len = 0;
> +    SSL                           *s = NULL;
> +
> +    if (c == NULL) {
> +        return;
> +    }
> +    s = c->ssl->connection;
> +
> +    /* Cipher suites */
> +    c->ssl->ciphers = NULL;
> +    c->ssl->ciphers_sz = SSL_get0_raw_cipherlist(s, &ciphers_out);
> +    c->ssl->ciphers_sz /= 2;
> +
> +    if (c->ssl->ciphers_sz && ciphers_out) {
> +        len = c->ssl->ciphers_sz * sizeof(unsigned short);
> +        c->ssl->ciphers = ngx_pnalloc(c->pool, len);
> +        ngx_memcpy(c->ssl->ciphers, ciphers_out, len);
> +    }
> +
> +    /* Elliptic curve points */
> +    c->ssl->curves_sz = SSL_get1_curves(s, NULL);
> +    if (c->ssl->curves_sz) {
> +        curves_out = OPENSSL_malloc(c->ssl->curves_sz * sizeof(int));
> +        if (curves_out != NULL) {
> +            SSL_get1_curves(s, curves_out);
> +            len = c->ssl->curves_sz * sizeof(unsigned short);
> +            c->ssl->curves = ngx_pnalloc(c->pool, len);
> +            if (c->ssl->curves != NULL) {
> +                for (size_t i = 0; i < c->ssl->curves_sz; i++) {
> +                     c->ssl->curves[i] = curves_out[i];
> +                }
> +            }
> +            OPENSSL_free(curves_out);
> +        }
> +    }
> +
> +    /* Elliptic curve point formats */
> +    c->ssl->point_formats_sz = SSL_get0_ec_point_formats(s,
> +                                        &point_formats_out);
> +    if (c->ssl->point_formats_sz && point_formats_out != NULL) {
> +        len = c->ssl->point_formats_sz * sizeof(unsigned char);
> +        c->ssl->point_formats = ngx_pnalloc(c->pool, len);
> +        if (c->ssl->point_formats != NULL) {
> +            ngx_memcpy(c->ssl->point_formats, point_formats_out, len);
> +        }
> +    }
> +}
> +
> +int
> +ngx_SSL_early_cb_fn(SSL *s, int *al, void *arg)
> +{
> +    int                            got_extensions;
> +    int                           *ext_out;
> +    size_t                         ext_len;
> +    ngx_connection_t              *c;
> +
> +    c = arg;
> +
> +    if (c == NULL) {
> +        return 1;
> +    }
> +
> +    if (c->ssl == NULL) {
> +        return 1;
> +    }
> +
> +    c->ssl->extensions_size = 0;
> +    c->ssl->extensions = NULL;
> +    got_extensions = SSL_client_hello_get1_extensions_present(s,
> +                                                       &ext_out,
> +                                                       &ext_len);
> +    if (got_extensions) {
> +        if (ext_out && ext_len) {
> +            c->ssl->extensions =
> +                ngx_palloc(c->pool, sizeof(int) * ext_len);
> +            if (c->ssl->extensions != NULL) {
> +                c->ssl->extensions_size = ext_len;
> +                ngx_memcpy(c->ssl->extensions, ext_out, sizeof(int) * ext_len);
> +                OPENSSL_free(ext_out);
> +            }
> +        }
> +    }
> +
> +    return 1;
> +}
> +#endif
>
> ngx_int_t
> ngx_ssl_handshake(ngx_connection_t *c)
> @@ -1603,6 +1697,10 @@
>
>     ngx_ssl_clear_error(c->log);
>
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +    SSL_CTX_set_client_hello_cb(c->ssl->session_ctx, ngx_SSL_early_cb_fn, c);
> +#endif
> +
>     n = SSL_do_handshake(c->ssl->connection);
>
>     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
> @@ -1623,6 +1721,10 @@
>
>         c->ssl->handshaked = 1;
>
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +        ngx_SSL_client_features(c);
> +#endif
> +
>         c->recv = ngx_ssl_recv;
>         c->send = ngx_ssl_write;
>         c->recv_chain = ngx_ssl_recv_chain;
> @@ -5044,6 +5146,86 @@
>     return NGX_OK;
> }
>
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +
> +ngx_int_t
> +ngx_ssl_get_extensions(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
> +{
> +    size_t   len;
> +    u_char  *p;
> +
> +    len = 0;
> +    s->len = 0;
> +
> +    if (c->ssl->extensions_size && c->ssl->extensions) {
> +        for (int n = c->ssl->extensions[0]; n > 9; n /= 10) {
> +            len += 1;
> +        }
> +        len += 1;
> +        for (size_t i = 1; i < c->ssl->extensions_size; ++i) {
> +            len += 1; /* for the '-' separator */
> +            for (int n = c->ssl->extensions[i]; n > 9; n /= 10) {
> +                len += 1;
> +            }
> +            len += 1;
> +        }
> +
> +        s->data = ngx_pnalloc(pool, len+1);
> +        if (s->data == NULL) {
> +            return NGX_ERROR;
> +        }
> +        s->len = len;
> +
> +        p = ngx_sprintf(s->data, "%d", c->ssl->extensions[0]);
> +        for (size_t i = 1; i < c->ssl->extensions_size; ++i) {
> +            p = ngx_sprintf(p, "-%d", c->ssl->extensions[i]);
> +        }
> +
> +    }
> +    return NGX_OK;
> +}
> +
> +
> +ngx_int_t
> +ngx_ssl_get_ec_point_formats(ngx_connection_t *c, ngx_pool_t *pool,
> +    ngx_str_t *s)
> +{
> +    size_t   len;
> +    u_char  *p;
> +
> +    len = 0;
> +    s->len = 0;
> +
> +    if (c->ssl->point_formats_sz && c->ssl->point_formats) {
> +        for (unsigned char n = c->ssl->point_formats[0]; n > 9; n /= 10) {
> +            len += 1;
> +        }
> +        len += 1;
> +        for (size_t i = 1; i < c->ssl->point_formats_sz; ++i) {
> +            len += 1; /* for the '-' separator */
> +            for (unsigned char n = c->ssl->point_formats[i]; n > 9; n /= 10) {
> +                len += 1;
> +            }
> +            len += 1;
> +        }
> +
> +        s->data = ngx_pnalloc(pool, len+1);
> +        if (s->data == NULL) {
> +            return NGX_ERROR;
> +        }
> +        s->len = len;
> +
> +        p = ngx_sprintf(s->data, "%d", c->ssl->point_formats[0]);
> +        for (size_t i = 1; i < c->ssl->point_formats_sz; ++i) {
> +            p = ngx_sprintf(p, "-%d", c->ssl->point_formats[i]);
> +        }
> +    }
> +
> +    return NGX_OK;
> +}
> +
> +#endif
> +
>
> static time_t
> ngx_ssl_parse_time(
> diff -r 716eddd74bc2 -r 86d2f46807f5 src/event/ngx_event_openssl.h
> --- a/src/event/ngx_event_openssl.h Thu Apr 23 15:10:26 2020 +0300
> +++ b/src/event/ngx_event_openssl.h Thu Apr 23 20:30:36 2020 -0500
> @@ -99,6 +99,21 @@
>     unsigned                    in_early:1;
>     unsigned                    early_preread:1;
>     unsigned                    write_blocked:1;
> +
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +
> +    size_t                      ciphers_sz;
> +    unsigned short             *ciphers;
> +
> +    size_t                      extensions_size;
> +    int                        *extensions;
> +
> +    size_t                      curves_sz;
> +    unsigned short             *curves;
> +
> +    size_t                      point_formats_sz;
> +    unsigned char              *point_formats;
> +#endif
> };
>
>
> @@ -263,6 +278,14 @@
> ngx_int_t ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool,
>     ngx_str_t *s);
>
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +
> +ngx_int_t ngx_ssl_get_extensions(ngx_connection_t *c, ngx_pool_t *pool,
> +    ngx_str_t *s);
> +ngx_int_t ngx_ssl_get_ec_point_formats(ngx_connection_t *c, ngx_pool_t *pool,
> +    ngx_str_t *s);
> +
> +#endif
>
> ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
> ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
> diff -r 716eddd74bc2 -r 86d2f46807f5 src/http/modules/ngx_http_ssl_module.c
> --- a/src/http/modules/ngx_http_ssl_module.c Thu Apr 23 15:10:26 2020 +0300
> +++ b/src/http/modules/ngx_http_ssl_module.c Thu Apr 23 20:30:36 2020 -0500
> @@ -352,6 +352,17 @@
>     { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable,
>       (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 },
>
> +#if OPENSSL_VERSION_NUMBER >= 0x10101000L
> +
> +    { ngx_string("ssl_extensions"), NULL, ngx_http_ssl_variable,
> +      (uintptr_t) ngx_ssl_get_extensions, NGX_HTTP_VAR_CHANGEABLE, 0 },
> +
> +    { ngx_string("ssl_elliptic_curve_point_formats"), NULL,
> +      ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_ec_point_formats,
> +      NGX_HTTP_VAR_CHANGEABLE, 0 },
> +
> +#endif
> +
>       ngx_http_null_variable
> };
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>
>


More information about the nginx-devel mailing list