From 00b7b49a4668546e10b5b31ca5f43f11ba3c1d8d Mon Sep 17 00:00:00 2001 From: Mariam John Date: Mon, 17 Jul 2023 08:22:59 -0500 Subject: [PATCH] MEDIUM: ssl: new sample fetch method to get curve name 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 | 10 +++++++ reg-tests/ssl/ssl_curve_name.vtc | 51 ++++++++++++++++++++++++++++++++ src/ssl_sample.c | 46 ++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 reg-tests/ssl/ssl_curve_name.vtc diff --git a/doc/configuration.txt b/doc/configuration.txt index 807548b1a..9537f203d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 index 000000000..a285a8f86 --- /dev/null +++ b/reg-tests/ssl/ssl_curve_name.vtc @@ -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 + diff --git a/src/ssl_sample.c b/src/ssl_sample.c index 5aec97fef..d7a7a09f9 100644 --- a/src/ssl_sample.c +++ b/src/ssl_sample.c @@ -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 },