]> git.kaiwu.me - nginx.git/commitdiff
SSL: add $ssl_sigalgs variable
authorVadim Zhestikov <v.zhestikov@f5.com>
Tue, 2 Jun 2026 15:02:17 +0000 (08:02 -0700)
committerVadimZhestikov <108960056+VadimZhestikov@users.noreply.github.com>
Thu, 4 Jun 2026 16:50:50 +0000 (09:50 -0700)
The new $ssl_sigalgs variable lists all signature algorithms
advertised by the client in its ClientHello message,
colon-separated, in analogy to $ssl_ciphers and $ssl_curves.

On OpenSSL 4.0+, SSL_get0_sigalg() is used, which returns proper
TLS scheme names (e.g. "rsa_pkcs1_sha256", "ecdsa_secp256r1_sha256")
and falls back to "0xHHHH" hex for unknown schemes.

On OpenSSL 1.0.2+, SSL_get_sigalgs() is used.  Since OBJ_nid2sn()
on the combined psignhash NID is not injective across TLS
SignatureScheme codes (e.g. 0x0403 and 0x081a both yield
"ecdsa-with-SHA256"), raw SignatureScheme codes are reported to
avoid ambiguity and to match the hex fallback format of
SSL_get0_sigalg().

With older versions, as well as BoringSSL, LibreSSL, and AWS-LC,
the variable is empty.

src/event/ngx_event_openssl.c
src/event/ngx_event_openssl.h
src/http/modules/ngx_http_ssl_module.c
src/stream/ngx_stream_ssl_module.c

index 1653be0c341035318a831921d4c45057278e7ae4..57389462933f8563d44fac6d38060d1498b56a05 100644 (file)
@@ -5669,6 +5669,104 @@ ngx_ssl_get_sigalg(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 }
 
 
+ngx_int_t
+ngx_ssl_get_sigalgs(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
+
+    int            n, i;
+    size_t         len;
+    u_char        *p;
+    const char    *name;
+    unsigned int   codepoint;
+
+    n = SSL_get0_sigalg(c->ssl->connection, -1, NULL, NULL);
+
+    if (n <= 0) {
+        s->len = 0;
+        return NGX_OK;
+    }
+
+    len = 0;
+
+    for (i = 0; i < n; i++) {
+        SSL_get0_sigalg(c->ssl->connection, i, &codepoint, &name);
+        len += name ? ngx_strlen(name) : sizeof("0x0000") - 1;
+        len += sizeof(":") - 1;
+    }
+
+    s->data = ngx_pnalloc(pool, len);
+    if (s->data == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = s->data;
+
+    for (i = 0; i < n; i++) {
+        SSL_get0_sigalg(c->ssl->connection, i, &codepoint, &name);
+
+        if (name) {
+            p = ngx_cpymem(p, name, ngx_strlen(name));
+
+        } else {
+            p = ngx_sprintf(p, "0x%04xd", codepoint);
+        }
+
+        *p++ = ':';
+    }
+
+    p--;
+
+    s->len = p - s->data;
+
+#elif defined SSL_CTRL_SET_SIGALGS
+
+    /*
+     * SSL_get_sigalgs() is only available in OpenSSL 1.0.2+,
+     * but uses a different naming, so emit raw codes
+     */
+
+    int             n, i;
+    size_t          len;
+    u_char         *p;
+    unsigned char   rsig, rhash;
+
+    n = SSL_get_sigalgs(c->ssl->connection, -1, NULL, NULL, NULL, NULL, NULL);
+
+    if (n <= 0) {
+        s->len = 0;
+        return NGX_OK;
+    }
+
+    len = n * (sizeof("0x0000") - 1 + sizeof(":") - 1);
+
+    s->data = ngx_pnalloc(pool, len);
+    if (s->data == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = s->data;
+
+    for (i = 0; i < n; i++) {
+        SSL_get_sigalgs(c->ssl->connection, i, NULL, NULL, NULL, &rsig, &rhash);
+        p = ngx_sprintf(p, "0x%04xd", rhash << 8 | rsig);
+        *p++ = ':';
+    }
+
+    p--;
+
+    s->len = p - s->data;
+
+#else
+
+    s->len = 0;
+
+#endif
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 {
index 79ae39503a0e6d6f09816611731b2ab92fc07a40..12ac01b3c60c49cafaf8a58c1cefb8c875c3e944 100644 (file)
@@ -337,6 +337,8 @@ ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_sigalg(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_sigalgs(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool,
index 43fcafd50e6326bfc7fe9c1790b80b1641b8c1b3..0afcc9dd1fba76818cca49231c14d359eee37224 100644 (file)
@@ -368,6 +368,9 @@ static ngx_http_variable_t  ngx_http_ssl_vars[] = {
     { ngx_string("ssl_sigalg"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_sigalg, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_sigalgs"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_sigalgs, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
index 0e17cff4d96eba8b0d6aa8b5b492311213ce7e1b..c68333a1cff3e5b9eef35a7f73fff446bdaa6fdb 100644 (file)
@@ -367,6 +367,9 @@ static ngx_stream_variable_t  ngx_stream_ssl_vars[] = {
     { ngx_string("ssl_sigalg"), NULL, ngx_stream_ssl_variable,
       (uintptr_t) ngx_ssl_get_sigalg, NGX_STREAM_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_sigalgs"), NULL, ngx_stream_ssl_variable,
+      (uintptr_t) ngx_ssl_get_sigalgs, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_session_id"), NULL, ngx_stream_ssl_variable,
       (uintptr_t) ngx_ssl_get_session_id, NGX_STREAM_VAR_CHANGEABLE, 0 },