[PATCH] Expose additional SSL variables
Garret Reece
garret at trailofbits.com
Fri Apr 24 15:17:46 UTC 2020
# 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
};
More information about the nginx-devel
mailing list