]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: new sample fetch method to get curve name
authorMariam John <john.mariam.oss@gmail.com>
Mon, 17 Jul 2023 13:22:59 +0000 (08:22 -0500)
committerWilliam Lallemand <wlallemand@haproxy.org>
Mon, 17 Jul 2023 13:45:41 +0000 (15:45 +0200)
Adds a new sample fetch method to get the curve name used in the
key agreement to enable better observability. In OpenSSLv3, the function
`SSL_get_negotiated_group` returns the NID of the curve and from the NID,
we get the curve name by passing the NID to OBJ_nid2sn. This was not
available in v1.1.1. SSL_get_curve_name(), which returns the curve name
directly was merged into OpenSSL master branch last week but will be available
only in its next release.

doc/configuration.txt
reg-tests/ssl/ssl_curve_name.vtc [new file with mode: 0644]
src/ssl_sample.c

index 807548b1aada1842cfc6185c70e45856abd95013..9537f203d163314fe7f9dec4ca24242e16239e4a 100644 (file)
@@ -20722,6 +20722,11 @@ ssl_bc_client_random : binary
   sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
   It can be used in a tcp-check or an http-check ruleset.
 
+ssl_bc_curve : string
+  Returns the name of the curve used in the key agreement when the outgoing
+  connection was made over an SSL/TLS transport layer. This requires 
+  OpenSSL >= 3.0.0.
+
 ssl_bc_err : integer
   When the outgoing connection was made over an SSL/TLS transport layer,
   returns the ID of the last error of the first error stack raised on the
@@ -21057,6 +21062,11 @@ ssl_fc_cipherlist_xxh : integer
   "tune.ssl.capture-buffer-size" is set greater than 0, however the hash take
   into account all the data of the cipher list.
 
+ssl_fc_curve : string
+  Returns the name of the curve used in the key agreement when the incoming
+  connection was made over an SSL/TLS transport layer. This requires
+  OpenSSL >= 3.0.0.
+
 ssl_fc_ecformats_bin : binary
   Return the binary form of the client hello supported elliptic curve point
   formats. The maximum returned value length is limited by the shared capture
diff --git a/reg-tests/ssl/ssl_curve_name.vtc b/reg-tests/ssl/ssl_curve_name.vtc
new file mode 100644 (file)
index 0000000..a285a8f
--- /dev/null
@@ -0,0 +1,51 @@
+#REGTEST_TYPE=devel
+
+varnishtest "Test the ssl_fc_curve/ssl_bc_curve sample fetches"
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL) && ssllib_name_startswith(OpenSSL) && openssl_version_atleast(3.0.0)'"
+feature ignore_unknown_macro
+
+server s1 -repeat 3 {
+    rxreq
+    txresp
+} -start
+
+haproxy h1 -conf {
+    global
+        tune.ssl.default-dh-param 2048
+        tune.ssl.capture-buffer-size 1
+        crt-base ${testdir}
+
+    defaults
+        mode http
+        option httplog
+        log stderr local0 debug err
+        option logasap
+        timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout client  "${HAPROXY_TEST_TIMEOUT-5s}"
+        timeout server  "${HAPROXY_TEST_TIMEOUT-5s}"
+
+
+    listen clear-lst
+        bind "fd@${clearlst}"
+        balance roundrobin
+        http-response add-header x-ssl-bc-curve-name %[ssl_bc_curve]
+        server s1 "${tmpdir}/ssl.sock" ssl verify none crt ${testdir}/client.ecdsa.pem
+
+    listen ssl-lst
+        mode http
+        http-response add-header x-ssl-fc-curve-name %[ssl_fc_curve]
+        bind "${tmpdir}/ssl.sock" ssl crt ${testdir}/common.pem ca-file ${testdir}/set_cafile_rootCA.crt verify optional curves X25519:P-256:P-384
+
+       server s1 ${s1_addr}:${s1_port}
+} -start
+
+
+client c1 -connect ${h1_clearlst_sock} {
+    txreq
+    rxresp
+    expect resp.status == 200
+    expect resp.http.x-ssl-fc-curve-name == "X25519"
+    expect resp.http.x-ssl-bc-curve-name == "X25519"
+
+} -run
+
index 5aec97fef18b61d8633499e8a5e2d68a3b163b0c..d7a7a09f96f99bd7ccd30b0f10178038ba539a9b 100644 (file)
@@ -1304,6 +1304,46 @@ smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const ch
        return 1;
 }
 
+/*
+ * string, returns the EC curve used for key agreement on the
+ * front and backend connection.
+ *
+ * The function to get the curve name (SSL_get_negotiated_group) is only available
+ * in OpenSSLv3 onwards and not for previous versions.
+ */
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL)
+static int
+smp_fetch_ssl_fc_ec(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+    struct connection *conn;
+    SSL *ssl;
+    int nid;
+
+    if (obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
+        conn = (kw[4] == 'b') ? sc_conn(__objt_check(smp->sess->origin)->sc) : NULL;
+    else
+        conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
+                smp->strm ? sc_conn(smp->strm->scb) : NULL;
+
+    ssl = ssl_sock_get_ssl_object(conn);
+    if (!ssl)
+        return 0;
+
+    nid = SSL_get_negotiated_group(ssl);
+    if (!nid)
+            return 0;
+    smp->data.u.str.area = (char *)OBJ_nid2sn(nid);
+    if (!smp->data.u.str.area)
+        return 0;
+
+    smp->data.type = SMP_T_STR;
+    smp->flags |= SMP_F_VOL_SESS | SMP_F_CONST;
+    smp->data.u.str.data = strlen(smp->data.u.str.area);
+
+    return 1;
+}
+#endif
+
 /* string, returns the used cipher if front conn. transport layer is SSL.
  * This function is also usable on backend conn if the fetch keyword 5th
  * char is 'b'.
@@ -2174,6 +2214,9 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "ssl_bc_alpn",            smp_fetch_ssl_fc_alpn,        0,                   NULL,    SMP_T_STR,  SMP_USE_L5SRV },
 #endif
        { "ssl_bc_cipher",          smp_fetch_ssl_fc_cipher,      0,                   NULL,    SMP_T_STR,  SMP_USE_L5SRV },
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL)
+        { "ssl_bc_curve",           smp_fetch_ssl_fc_ec,          0,                   NULL,    SMP_T_STR,  SMP_USE_L5SRV },
+#endif
 #if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
        { "ssl_bc_npn",             smp_fetch_ssl_fc_npn,         0,                   NULL,    SMP_T_STR,  SMP_USE_L5SRV },
 #endif
@@ -2223,6 +2266,9 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "ssl_fc",                 smp_fetch_ssl_fc,             0,                   NULL,    SMP_T_BOOL, SMP_USE_L5CLI },
        { "ssl_fc_alg_keysize",     smp_fetch_ssl_fc_alg_keysize, 0,                   NULL,    SMP_T_SINT, SMP_USE_L5CLI },
        { "ssl_fc_cipher",          smp_fetch_ssl_fc_cipher,      0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL)
+        { "ssl_fc_curve",           smp_fetch_ssl_fc_ec,          0,                   NULL,    SMP_T_STR,  SMP_USE_L5CLI },
+#endif
        { "ssl_fc_has_crt",         smp_fetch_ssl_fc_has_crt,     0,                   NULL,    SMP_T_BOOL, SMP_USE_L5CLI },
        { "ssl_fc_has_early",       smp_fetch_ssl_fc_has_early,   0,                   NULL,    SMP_T_BOOL, SMP_USE_L5CLI },
        { "ssl_fc_has_sni",         smp_fetch_ssl_fc_has_sni,     0,                   NULL,    SMP_T_BOOL, SMP_USE_L5CLI },