MINOR: ssl: add the ssl_fc_crtname sample fetch

This new sample fetch returns the name of the certificate selected for
an incoming SSL/TLS connection, as it would appear in "show ssl cert".
It may be a filename with its relative or absolute path, or an alias,
depending on how the certificate was declared in the configuration.

The certificate name is stored as ex_data on the SSL_CTX at load time
in ckch_inst_new_load_store(), and freed via a dedicated free callback.
This commit is contained in:
William Lallemand 2026-04-02 23:34:50 +02:00 committed by William Lallemand
parent efb1ab57be
commit d89ae36adc
4 changed files with 71 additions and 0 deletions

View File

@ -25659,6 +25659,7 @@ ssl_fc_client_early_traffic_secret string
ssl_fc_client_handshake_traffic_secret string
ssl_fc_client_random binary
ssl_fc_client_traffic_secret_0 string
ssl_fc_crtname string
ssl_fc_curve string
ssl_fc_early_exporter_secret string
ssl_fc_ecformats_bin binary
@ -26283,6 +26284,21 @@ ssl_fc_client_traffic_secret_0 : string
activated with "tune.ssl.keylog on" in the global section. See also
"tune.ssl.keylog"
ssl_fc_crtname : string
Returns the name of the certificate that was selected for the incoming
SSL/TLS connection. This is the name as it appears in "show ssl cert": it
may be the filename with its relative or absolute path, or an alias,
depending on how the certificate was declared in the configuration.
Example :
crt-store example
load crt "example.com.pem"
frontend www
bind *:443 ssl crt "@example/example.com.pem"
acl match_certificate ssl_fc_crtname -m beg -i "@example/"
http-request set-header X-Cert-Name %[ssl_fc_crtname] if match_certificate
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

View File

@ -54,6 +54,7 @@ extern struct xprt_ops ssl_sock;
extern int ssl_capture_ptr_index;
extern int ssl_keylog_index;
extern int ssl_client_sni_index;
extern int ssl_crtname_index;
extern struct pool_head *pool_head_ssl_keylog;
extern struct pool_head *pool_head_ssl_keylog_str;
extern struct list openssl_providers;

View File

@ -2034,6 +2034,39 @@ smp_fetch_ssl_fc_sni(const struct arg *args, struct sample *smp, const char *kw,
#endif
}
/* ssl_fc_crtname */
static int smp_fetch_ssl_fc_crtname(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
struct connection *conn;
SSL *ssl;
SSL_CTX *ctx;
smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
smp->data.type = SMP_T_STR;
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;
ctx = SSL_get_SSL_CTX(ssl);
if (!ctx)
return 0;
smp->data.u.str.area = SSL_CTX_get_ex_data(ctx, ssl_crtname_index);
if (!smp->data.u.str.area)
return 0;
smp->data.u.str.data = strlen(smp->data.u.str.area);
return 1;
}
#ifdef USE_ECH
static int
smp_fetch_ssl_fc_ech_status(const struct arg *args, struct sample *smp,
@ -2768,6 +2801,7 @@ 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 },
{ "ssl_fc_crtname", smp_fetch_ssl_fc_crtname, 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 },

View File

@ -764,6 +764,8 @@ int ssl_client_crt_ref_index = -1;
/* Used to store the client's SNI in case of ClientHello callback error */
int ssl_client_sni_index = -1;
/* store the name of the certificate */
int ssl_crtname_index = -1;
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
@ -3160,6 +3162,7 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
STACK_OF(GENERAL_NAME) *names;
#endif
char *crtname = NULL;
struct ckch_data *data;
struct ckch_inst *ckch_inst = NULL;
int errcode = 0;
@ -3179,6 +3182,16 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
goto error;
}
crtname = strdup(path);
if (!crtname) {
memprintf(err, "%sunable to allocate SSL context for cert '%s'.\n",
err && *err ? *err : "", path);
errcode |= ERR_ALERT | ERR_FATAL;
goto error;
}
SSL_CTX_set_ex_data(ctx, ssl_crtname_index, crtname);
if (global_ssl.security_level > -1)
SSL_CTX_set_security_level(ctx, global_ssl.security_level);
@ -8361,6 +8374,11 @@ static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *
pool_free(pool_head_ssl_capture, ptr);
}
static void ssl_sock_free_crtname(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
{
free(ptr);
}
#ifdef HAVE_SSL_KEYLOG
static void ssl_sock_keylog_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
{
@ -8488,6 +8506,8 @@ static void __ssl_sock_init(void)
#endif
ssl_client_crt_ref_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_clt_crt_free_func);
ssl_client_sni_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_clt_sni_free_func);
ssl_crtname_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_free_crtname);
#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
ENGINE_load_builtin_engines();
hap_register_post_check(ssl_check_async_engine_count);