diff --git a/include/haproxy/ech.h b/include/haproxy/ech.h index dac74cfba..0772db9b5 100644 --- a/include/haproxy/ech.h +++ b/include/haproxy/ech.h @@ -6,6 +6,8 @@ #include int load_echkeys(SSL_CTX *ctx, char *dirname, int *loaded); +int conn_get_ech_status(struct connection *conn, struct buffer *buf); +int conn_get_ech_outer_sni(struct connection *conn, struct buffer *buf); # endif /* USE_ECH */ #endif /* _HAPROXY_ECH_H */ diff --git a/src/ech.c b/src/ech.c index 69b522c3a..786a4e96d 100644 --- a/src/ech.c +++ b/src/ech.c @@ -74,6 +74,58 @@ end: return rv; } +/* + * Place an ECH status string into a trash buffer + * ECH status string examples: + * SSL_ECH_STATUS_GREASE + * SSL_ECH_STATUS_NOT_TRIED + * SSL_ECH_STATUS_SUCCESS + * The status values are those defined in + * as the define'd returns from `SSL_ech_get1_status()` + */ +int conn_get_ech_status(struct connection *conn, struct buffer *buf) +{ + struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn); + char *sni_ech = NULL; + char *sni_clr = NULL; + const char *lstr = NULL; + + if (!ctx) + return 0; +#define s(x) #x + switch (SSL_ech_get1_status(ctx->ssl, &sni_ech, &sni_clr)) { + case SSL_ECH_STATUS_SUCCESS: lstr = s(SSL_ECH_STATUS_SUCCESS); break; + case SSL_ECH_STATUS_NOT_TRIED: lstr = s(SSL_ECH_STATUS_NOT_TRIED); break; + case SSL_ECH_STATUS_FAILED: lstr = s(SSL_ECH_STATUS_FAILED); break; + case SSL_ECH_STATUS_BAD_NAME: lstr = s(SSL_ECH_STATUS_BAD_NAME); break; + case SSL_ECH_STATUS_BAD_CALL: lstr = s(SSL_ECH_STATUS_BAD_CALL); break; + case SSL_ECH_STATUS_GREASE: lstr = s(SSL_ECH_STATUS_GREASE); break; + case SSL_ECH_STATUS_BACKEND: lstr = s(SSL_ECH_STATUS_BACKEND); break; + default: lstr = ""; break; + } +#undef s + chunk_printf(buf, "%s", lstr); + OPENSSL_free(sni_ech); + OPENSSL_free(sni_clr); + return 1; +} + +/* If ECH succeeded, return the outer SNI value seen */ +int conn_get_ech_outer_sni(struct connection *conn, struct buffer *buf) +{ + struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn); + char *sni_ech = NULL; + char *sni_clr = NULL; + + if (!ctx) + return 0; + if (SSL_ech_get1_status(ctx->ssl, &sni_ech, &sni_clr) + == SSL_ECH_STATUS_SUCCESS && sni_clr != NULL) + chunk_printf(buf, "%s", sni_clr); + OPENSSL_free(sni_ech); + OPENSSL_free(sni_clr); + return 1; +} static int bind_parse_ech(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { @@ -97,4 +149,5 @@ static struct bind_kw_list bind_kws = { "SSL", { }, { INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws); + #endif diff --git a/src/ssl_sample.c b/src/ssl_sample.c index 4746b8c0c..4cf1c6d1d 100644 --- a/src/ssl_sample.c +++ b/src/ssl_sample.c @@ -33,6 +33,9 @@ #include #include #include +#ifdef USE_ECH +#include +#endif /***** Below are some sample fetching functions for ACL/patterns *****/ @@ -1880,6 +1883,48 @@ smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw, #endif } +#ifdef USE_ECH +static int +smp_fetch_ssl_fc_ech_status(const struct arg *args, struct sample *smp, + const char *kw, void *private) +{ + struct buffer *smp_trash; + struct connection *conn; + + smp->flags = SMP_F_VOL_SESS | SMP_F_CONST; + smp->data.type = SMP_T_STR; + conn = objt_conn(smp->sess->origin); + if (!conn) + return 0; + smp_trash = get_trash_chunk(); + if (conn_get_ech_status(conn, smp_trash) == 1) { + smp->data.u.str.area = smp_trash->area; + smp->data.u.str.data = smp_trash->data; + } + return 1; +} + +static int +smp_fetch_ssl_fc_ech_outer_sni(const struct arg *args, struct sample *smp, + const char *kw, void *private) +{ + struct buffer *smp_trash; + struct connection *conn; + + smp->flags = SMP_F_VOL_SESS | SMP_F_CONST; + smp->data.type = SMP_T_STR; + conn = objt_conn(smp->sess->origin); + if (!conn) + return 0; + smp_trash = get_trash_chunk(); + if (conn_get_ech_outer_sni(conn, smp_trash) == 1) { + smp->data.u.str.area = smp_trash->area; + smp->data.u.str.data = smp_trash->data; + } + return 1; +} +#endif + /* binary, returns tls client hello cipher list. * Arguments: filter_option (0,1) */ @@ -2572,6 +2617,10 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { #endif { "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI }, +#ifdef USE_ECH + { "ssl_fc_ech_status", smp_fetch_ssl_fc_ech_status, 0, NULL, SMP_T_STR, SMP_USE_L5CLI }, + { "ssl_fc_ech_outer_sni", smp_fetch_ssl_fc_ech_outer_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI }, +#endif { "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI }, { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI }, { "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },