]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: Add ciphers in ssl traces
authorRemi Tricot-Le Breton <rlebreton@haproxy.com>
Tue, 15 Jul 2025 08:45:07 +0000 (10:45 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Mon, 21 Jul 2025 14:44:50 +0000 (16:44 +0200)
Decode the contents of the ClientHello ciphers extension and dump a
human readable list in the ssl traces.

include/haproxy/ssl_trace.h
src/ssl_clienthello.c
src/ssl_trace.c

index cd22ffc4795885d7b8a78beb7d9ee8519df26a7e..c7ffd5a52a4d5ce2bde9c409d546145a81c63f7e 100644 (file)
@@ -22,6 +22,14 @@ extern struct trace_source trace_ssl;
 #define SSL_EV_CONN_SWITCHCTX_CB   (1ULL << 12)
 #define SSL_EV_CONN_CHOOSE_SNI_CTX (1ULL << 13)
 #define SSL_EV_CONN_SIGALG_EXT     (1ULL << 14)
+#define SSL_EV_CONN_CIPHERS_EXT    (1ULL << 15)
+
+
+#define SSL_VERB_CLEAN    1
+#define SSL_VERB_MINIMAL  2
+#define SSL_VERB_SIMPLE   3
+#define SSL_VERB_ADVANCED 4
+#define SSL_VERB_COMPLETE 5
 
 #define TRACE_SOURCE &trace_ssl
 
index 9f7ec16d94c00b6ed139130569de01f16f066f65..daa950626c65148c6b9b0f27e6bedacc1a182b40 100644 (file)
@@ -345,6 +345,21 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
                TRACE_DEVEL("Sigalg parsing: has_rsa_sig (default)", SSL_EV_CONN_SWITCHCTX_CB, conn);
                has_rsa_sig = 1;
        }
+
+       if ((TRACE_SOURCE)->verbosity > SSL_VERB_ADVANCED &&
+           TRACE_ENABLED(TRACE_LEVEL_DATA, SSL_EV_CONN_CIPHERS_EXT, conn, 0, 0, 0)) {
+               const uint8_t *cipher_suites;
+               size_t len;
+
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+               len = ctx->cipher_suites_len;
+               cipher_suites = ctx->cipher_suites;
+#else
+               len = SSL_client_hello_get0_ciphers(ssl, &cipher_suites);
+#endif
+               TRACE_DATA("Ciphers value", SSL_EV_CONN_CIPHERS_EXT, conn, ssl, cipher_suites, &len);
+       }
+
        if (has_ecdsa_sig) {  /* in very rare case: has ecdsa sign but not a ECDSA cipher */
                const SSL_CIPHER *cipher;
                STACK_OF(SSL_CIPHER) *ha_ciphers; /* haproxy side ciphers */
index 47332b5d9117ae902df4a65e53978aaa852d78a9..6a1a8a96684a600dad99d744bd6a7a633a7cc768 100644 (file)
@@ -41,6 +41,7 @@ static const struct trace_event ssl_trace_events[] = {
        { .mask = SSL_EV_CONN_SWITCHCTX_CB,   .name = "sslc_switchctx_cb",   .desc = "SSL switchctx callback"},
        { .mask = SSL_EV_CONN_CHOOSE_SNI_CTX, .name = "sslc_choose_sni_ctx", .desc = "SSL choose sni context"},
        { .mask = SSL_EV_CONN_SIGALG_EXT,     .name = "sslc_sigalg_ext",     .desc = "SSL sigalg extension parsing"},
+       { .mask = SSL_EV_CONN_CIPHERS_EXT,    .name = "sslc_ciphers_ext",    .desc = "SSL ciphers extension parsing"},
        { }
 };
 
@@ -53,15 +54,10 @@ static const struct name_desc ssl_trace_lockon_args[4] = {
 };
 
 static const struct name_desc ssl_trace_decoding[] = {
-#define SSL_VERB_CLEAN    1
        { .name="clean",    .desc="only user-friendly stuff, generally suitable for level \"user\"" },
-#define SSL_VERB_MINIMAL  2
        { .name="minimal",  .desc="report only conn, no real decoding" },
-#define SSL_VERB_SIMPLE   3
        { .name="simple",   .desc="add error messages" },
-#define SSL_VERB_ADVANCED 4
        { .name="advanced", .desc="add handshake-related details" },
-#define SSL_VERB_COMPLETE 5
        { .name="complete", .desc="add full data dump when available" },
        { /* end */ }
 };
@@ -247,5 +243,37 @@ static void ssl_trace(enum trace_level level, uint64_t mask, const struct trace_
                        }
                }
        }
+
+       if (mask & SSL_EV_CONN_CIPHERS_EXT && src->verbosity > SSL_VERB_ADVANCED) {
+               if (a2 && a3 && a4) {
+                       SSL *ssl = (SSL*)a2;
+                       const uint16_t *extension_data = a3;
+                       size_t extension_len = *((size_t*)a4);
+                       int first = 1;
+
+                       chunk_appendf(&trace_buf, " value=");
+
+                       while (extension_len > 1) {
+                               const char *str;
+                               const SSL_CIPHER *cipher;
+                               uint16_t id = ntohs(*extension_data);
+#if defined(OPENSSL_IS_BORINGSSL)
+                               cipher = SSL_get_cipher_by_value(id);
+#else
+                               cipher = SSL_CIPHER_find(ssl, (unsigned char*)extension_data);
+#endif
+                               str = SSL_CIPHER_get_name(cipher);
+                               if (!str || strcmp(str, "(NONE)") == 0)
+                                       chunk_appendf(&trace_buf, "%sUNKNOWN(%04x)", first ? "" : ",", id);
+                               else
+                                       chunk_appendf(&trace_buf, "%s%s", first ? "" : ",", str);
+
+                               first = 0;
+
+                               extension_len-=sizeof(*extension_data);
+                               ++extension_data;
+                       }
+               }
+       }
 }