From d4bb9983fa8afaf4f87c3a90f10ff409bd10ed30 Mon Sep 17 00:00:00 2001 From: Remi Tricot-Le Breton Date: Thu, 2 Oct 2025 15:32:47 +0200 Subject: [PATCH] MINOR: jwt: Add new "add/del/show ssl jwt" CLI commands The new "add/del ssl jwt " commands allow to change the "jwt" flag of an already loaded certificate. It allows to delete certificates used for JWT validation, which was not yet possible. The "show ssl jwt" command iterates over all the ckch_stores and dumps the ones that have the option set. --- doc/configuration.txt | 3 ++ doc/management.txt | 24 +++++++++ src/ssl_ckch.c | 116 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index 021721e0a..14b2e8812 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -30742,6 +30742,9 @@ jwt [ off | on ] not work. In order to be deleted, a certificate must not be used, either for SSL handshakes or JWT validation. + This option can be changed during runtime via the "add ssl jwt" and "del ssl + jwt" CLI commands. See also "show ssl jwt" CLI command. + 12.8. ACME ---------- diff --git a/doc/management.txt b/doc/management.txt index dc01a00b1..e98a4a961 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1834,6 +1834,13 @@ add ssl crt-list $ echo -e 'add ssl crt-list certlist1 <<\nfoobar.pem [allow-0rtt] foo.bar.com !test1.com\n' | socat /tmp/sock1 - +add ssl jwt + Add an already loaded certificate to the list of certificates that can be + used for JWT validation (see "jwt_verify_cert" converter). This command does + not work on ongoing transactions. + See also "del ssl jwt" and "show ssl jwt" commands. + See "jwt" certificate option for more information. + clear counters Clear the max values of the statistics counters in each proxy (frontend & backend) and in each server. The accumulated counters are not affected. The @@ -2103,6 +2110,13 @@ del ssl crt-list you will need to provide which line you want to delete. To display the line numbers, use "show ssl crt-list -n ". +del ssl jwt + Remove an already loaded certificate to the list of certificates that can be + used for JWT validation (see "jwt_verify_cert" converter). This command does + not work on ongoing transactions. + See also "add ssl jwt" and "show ssl jwt" commands. + See "jwt" certificate option for more information. + del server / Delete a removable server attached to the backend . A removable server is the server which satisfies all of these conditions : @@ -3779,6 +3793,16 @@ show ssl crt-list [-n] [] ecdsa.pem:3 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com ecdsa.pem:4 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] +show ssl jwt + Display the list of certificates that can be used for JWT validation. + See also "add ssl jwt" and "del ssl jwt" commands. + See "jwt" certificate option for more information. + + Example: + echo "show ssl jwt" | socat /tmp/sock1 - + #filename + jwt.pem + show ssl ocsp-response [[text|base64] ] Display the IDs of the OCSP tree entries corresponding to all the OCSP responses used in HAProxy, as well as the corresponding frontend diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c index f720f3729..43a76ca74 100644 --- a/src/ssl_ckch.c +++ b/src/ssl_ckch.c @@ -88,6 +88,11 @@ struct show_cert_ctx { int transaction; }; +/* CLI context used by "show ssl jwt" */ +struct show_jwt_ctx { + struct ckch_store *cur_ckchs; +}; + #define SHOW_SNI_OPT_1FRONTEND (1 << 0) /* show only the selected frontend */ #define SHOW_SNI_OPT_NOTAFTER (1 << 1) /* show certificates that are [A]fter the notAfter date */ @@ -2444,6 +2449,113 @@ error: return cli_err(appctx, "Can't display the certificate: Not found or the certificate is a bundle!\n"); } +static inline int cli_set_ssl_jwt(char **args, struct appctx *appctx, int value) +{ + struct ckch_store *ckchs; + char *err = NULL; + + if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) + return cli_err(appctx, "Can't allocate memory!\n"); + + /* check if there is a certificate to lookup */ + if (!*args[3]) + return cli_dynerr(appctx, memprintf(&err, "'%s ssl cert' expects a filename\n", args[0])); + + /* The operations on the CKCH architecture are locked so we can + * manipulate ckch_store and ckch_inst */ + if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock)) + return cli_err(appctx, "Can't show!\nOperations on certificates are currently locked!\n"); + + if ((ckchs = ckchs_lookup(args[3])) == NULL) + goto error; + + ckchs->conf.jwt = value; + + HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock); + return 0; + +error: + HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock); + return cli_err(appctx, "Can't display the certificate: Not found or the certificate is a bundle!\n"); +} + +/* parsing function for 'add ssl jwt ' */ +static int cli_parse_add_jwt(char **args, char *payload, struct appctx *appctx, void *private) +{ + return cli_set_ssl_jwt(args, appctx, 1); +} + +/* parsing function for 'del ssl jwt ' */ +static int cli_parse_del_jwt(char **args, char *payload, struct appctx *appctx, void *private) +{ + return cli_set_ssl_jwt(args, appctx, 0); +} + +/* parsing function for 'show ssl jwt ' */ +static int cli_parse_show_jwt(char **args, char *payload, struct appctx *appctx, void *private) +{ + struct show_jwt_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + + if (!cli_has_level(appctx, ACCESS_LVL_OPER)) + return cli_err(appctx, "Can't allocate memory!\n"); + + /* The operations on the CKCH architecture are locked so we can + * manipulate ckch_store and ckch_inst */ + if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock)) + return cli_err(appctx, "Can't show!\nOperations on certificates are currently locked!\n"); + + return 0; + +error: + HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock); + return cli_err(appctx, "Can't display the certificate: Not found or the certificate is a bundle!\n"); +} + +/* IO handler of "show ssl jwt". + * It makes use of a show_jwt_ctx context. + */ +static int cli_io_handler_show_jwt(struct appctx *appctx) +{ + struct show_jwt_ctx *ctx = appctx->svcctx; + struct buffer *trash = alloc_trash_chunk(); + struct ebmb_node *node; + struct ckch_store *ckchs = NULL; + + if (trash == NULL) + return 1; + + if (!ctx->cur_ckchs) { + chunk_appendf(trash, "# filename\n"); + node = ebmb_first(&ckchs_tree); + } else { + node = &ctx->cur_ckchs->node; + } + while (node) { + ckchs = ebmb_entry(node, struct ckch_store, node); + if (ckchs->conf.jwt) + chunk_appendf(trash, "%s\n", ckchs->path); + + node = ebmb_next(node); + if (applet_putchk(appctx, trash) == -1) + goto yield; + } + + ctx->cur_ckchs = NULL; + free_trash_chunk(trash); + return 1; +yield: + + free_trash_chunk(trash); + ctx->cur_ckchs = ckchs; + return 0; /* should come back */ +} + +/* release function of the 'show ssl jwt' command */ +static void cli_release_show_jwt(struct appctx *appctx) +{ + HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock); +} + /* * Dump a CKCH in PEM format over the CLI @@ -4570,6 +4682,10 @@ static struct cli_kw_list cli_kws = {{ },{ { { "show", "ssl", "cert", NULL }, "show ssl cert [] : display the SSL certificates used in memory, or the details of a file", cli_parse_show_cert, cli_io_handler_show_cert, cli_release_show_cert }, { { "dump", "ssl", "cert", NULL }, "dump ssl cert : dump the SSL certificates in PEM format", cli_parse_dump_cert, cli_io_handler_dump_cert, cli_release_dump_cert }, + { { "add", "ssl", "jwt", NULL }, "add ssl jwt : add certificate to list of certificates used for JWT validation", cli_parse_add_jwt, NULL, NULL }, + { { "del", "ssl", "jwt", NULL }, "del ssl jwt : remove certificate from list of certificates used for JWT validation", cli_parse_del_jwt, NULL, NULL }, + { { "show", "ssl", "jwt", NULL }, "show ssl jwt : show list of certificates used for JWT validation", cli_parse_show_jwt, cli_io_handler_show_jwt, cli_release_show_jwt }, + { { "new", "ssl", "ca-file", NULL }, "new ssl ca-file : create a new CA file to be used in a crt-list", cli_parse_new_cafile, NULL, NULL }, { { "add", "ssl", "ca-file", NULL }, "add ssl ca-file : add a certificate into the CA file", cli_parse_set_cafile, NULL, NULL },