From: Remi Tricot-Le Breton Date: Thu, 29 Jul 2021 07:45:51 +0000 (+0200) Subject: MINOR: ssl: Add new ssl_fc_hsk_err sample fetch X-Git-Tag: v2.5-dev3~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7c6898ee4907e66c000a77ec32effd5acf1b99d8;p=thirdparty%2Fhaproxy.git MINOR: ssl: Add new ssl_fc_hsk_err sample fetch This new sample fetch along the ssl_fc_hsk_err_str fetch contain the last SSL error of the error stack that occurred during the SSL handshake (from the frontend's perspective). The errors happening during the client's certificate verification will still be given by the ssl_c_err and ssl_c_ca_err fetches. This new fetch will only hold errors retrieved by the OpenSSL ERR_get_error function. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index b3ac72be62..cd40d1cde2 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -18925,6 +18925,25 @@ ssl_fc_has_sni : boolean that the SSL library is built with support for TLS extensions enabled (check haproxy -vv). +ssl_fc_hsk_err : integer + When the incoming connection was made over an SSL/TLS transport layer, + returns the ID of the latest error that happened during the handshake on the + frontend side, or 0 if no error was encountered. Any error happening during + the client's certificate verification process will not be raised through this + fetch but via the existing "ssl_c_err", "ssl_c_ca_err" and + "ssl_c_ca_err_depth" fetches. In order to get a text description of this + error code, you can either use the "ssl_fc_hsk_err_str" sample fetch or use + the "openssl errstr" command (which takes an error code in hexadecimal + representation as parameter). Please refer to your SSL library's + documentation to find the exhaustive list of error codes. + +ssl_fc_hsk_err_str : string + When the incoming connection was made over an SSL/TLS transport layer, + returns a string representation of the latest error that happened during the + handshake on the frontend side. Any error happening during the client's + certificate verification process will not be raised through this fetch. See + also "ssl_fc_hsk_err". + ssl_fc_is_resumed : boolean Returns true if the SSL/TLS session has been resumed through the use of SSL session cache or TLS tickets on an incoming connection over an SSL/TLS diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h index 98390113f8..5acedcfc5d 100644 --- a/include/haproxy/ssl_sock-t.h +++ b/include/haproxy/ssl_sock-t.h @@ -235,6 +235,7 @@ struct ssl_sock_ctx { struct wait_event wait_event; struct wait_event *subs; int xprt_st; /* transport layer state, initialized to zero */ + unsigned long hsk_error_code; /* last handshake error code of the error stack */ struct buffer early_buf; /* buffer to store the early data received */ int sent_early_data; /* Amount of early data we sent so far */ diff --git a/src/ssl_sample.c b/src/ssl_sample.c index d6315267f9..8bfea07f0b 100644 --- a/src/ssl_sample.c +++ b/src/ssl_sample.c @@ -1188,6 +1188,61 @@ smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char return 1; } +static int +smp_fetch_ssl_fc_hsk_err(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *conn; + struct ssl_sock_ctx *ctx; + + conn = objt_conn(smp->sess->origin); + if (!conn || conn->xprt != &ssl_sock) + return 0; + ctx = conn->xprt_ctx; + + if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) { + smp->flags = SMP_F_MAY_CHANGE; + return 0; + } + + if (!ctx) + return 0; + + smp->flags = SMP_F_VOL_SESS; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = ctx->hsk_error_code; + return 1; +} + +static int +smp_fetch_ssl_fc_hsk_err_str(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *conn; + struct ssl_sock_ctx *ctx; + const char *err_code_str; + + conn = objt_conn(smp->sess->origin); + if (!conn || conn->xprt != &ssl_sock) + return 0; + ctx = conn->xprt_ctx; + + if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) { + smp->flags = SMP_F_MAY_CHANGE; + return 0; + } + + if (!ctx || !ctx->hsk_error_code) + return 0; + + err_code_str = ERR_error_string(ctx->hsk_error_code, NULL); + + smp->flags = SMP_F_VOL_SESS; + smp->data.type = SMP_T_STR; + smp->data.u.str.area = (char*)err_code_str; + smp->data.u.str.data = strlen(err_code_str); + + return 1; +} + /* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */ #ifdef HAVE_SSL_KEYLOG static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private) @@ -1546,6 +1601,8 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { { "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI }, { "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI }, { "ssl_fc_cipherlist_xxh", smp_fetch_ssl_fc_cl_xxh64, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI }, + { "ssl_fc_hsk_err", smp_fetch_ssl_fc_hsk_err, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI }, + { "ssl_fc_hsk_err_str", smp_fetch_ssl_fc_hsk_err_str, 0, NULL, SMP_T_STR, SMP_USE_L5CLI }, /* SSL server certificate fetches */ { "ssl_s_der", smp_fetch_ssl_x_der, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI }, diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 997ab8de49..ba61243aca 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -5278,6 +5278,7 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx) ctx->subs = NULL; ctx->xprt_st = 0; ctx->xprt_ctx = NULL; + ctx->hsk_error_code = 0; /* Only work with sockets for now, this should be adapted when we'll * add QUIC support. @@ -5556,6 +5557,9 @@ check_error: /* handshake did not complete, let's find why */ ret = SSL_get_error(ctx->ssl, ret); + if (!ctx->hsk_error_code) + ctx->hsk_error_code = ERR_peek_error(); + if (ret == SSL_ERROR_WANT_WRITE) { /* SSL handshake needs to write, L4 connection may not be ready */ if (!(ctx->wait_event.events & SUB_RETRY_SEND))