MINOR: ssl/cli: show/dump ssl crt-list

Implement 2 new commands on the CLI:

show ssl crt-list [<filename>]: Without a specified filename, display
the list of crt-lists used by the configuration. If a filename is
specified, it will displays the content of this crt-list, with a line
identifier at the beginning of each line. This output must not be used
as a crt-list file.

dump ssl crt-list <filename>: Dump the content of a crt-list, the output
can be used as a crt-list file.

Note: It currently displays the default ssl-min-ver and ssl-max-ver
which are potentialy not in the original file.
This commit is contained in:
William Lallemand 2020-03-09 13:35:19 +01:00 committed by William Lallemand
parent a48e7ece48
commit a6ffd5bf8a

View File

@ -10848,6 +10848,267 @@ static int cli_parse_set_tlskeys(char **args, char *payload, struct appctx *appc
}
#endif
/*
* Take an ssl_bind_conf structure and append the configuration line used to
* create it in the buffer
*/
static void dump_crtlist_sslconf(struct buffer *buf, const struct ssl_bind_conf *conf)
{
int space = 0;
if (conf == NULL)
return;
chunk_appendf(buf, " [");
#ifdef OPENSSL_NPN_NEGOTIATED
if (conf->npn_str) {
int len = conf->npn_len;
char *ptr = conf->npn_str;
int comma = 0;
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "npn ");
while (len) {
unsigned short size;
size = *ptr;
ptr++;
if (comma)
chunk_memcat(buf, ",", 1);
chunk_memcat(buf, ptr, size);
ptr += size;
len -= size + 1;
comma = 1;
}
chunk_memcat(buf, "", 1); /* finish with a \0 */
space++;
}
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (conf->alpn_str) {
int len = conf->alpn_len;
char *ptr = conf->alpn_str;
int comma = 0;
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "alpn ");
while (len) {
unsigned short size;
size = *ptr;
ptr++;
if (comma)
chunk_memcat(buf, ",", 1);
chunk_memcat(buf, ptr, size);
ptr += size;
len -= size + 1;
comma = 1;
}
chunk_memcat(buf, "", 1); /* finish with a \0 */
space++;
}
#endif
/* verify */
{
if (conf->verify == SSL_SOCK_VERIFY_NONE) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify none");
space++;
} else if (conf->verify == SSL_SOCK_VERIFY_OPTIONAL) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify optional");
space++;
} else if (conf->verify == SSL_SOCK_VERIFY_REQUIRED) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "verify required");
space++;
}
}
if (conf->no_ca_names) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "no-ca-names");
space++;
}
if (conf->early_data) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "allow-0rtt");
space++;
}
if (conf->ca_file) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ca-file %s", conf->ca_file);
space++;
}
if (conf->crl_file) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "crl-file %s", conf->crl_file);
space++;
}
if (conf->ciphers) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ciphers %s", conf->ciphers);
space++;
}
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if (conf->ciphersuites) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ciphersuites %s", conf->ciphersuites);
space++;
}
#endif
if (conf->curves) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "curves %s", conf->curves);
space++;
}
if (conf->ecdhe) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ecdhe %s", conf->ecdhe);
space++;
}
/* the crt-lists only support ssl-min-ver and ssl-max-ver */
/* XXX: this part need to be revamp so we don't dump the default settings */
if (conf->ssl_methods.min) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ssl-min-ver %s", methodVersions[conf->ssl_methods.min].name);
space++;
}
if (conf->ssl_methods.max) {
if (space) chunk_appendf(buf, " ");
chunk_appendf(buf, "ssl-max-ver %s", methodVersions[conf->ssl_methods.max].name);
space++;
}
chunk_appendf(buf, "] ");
return;
}
/* dump a list of filters */
static void dump_crtlist_filters(struct buffer *buf, struct crtlist_entry *entry)
{
int space = 0;
int i;
if (!entry->fcount)
return;
for (i = 0; i < entry->fcount; i++) {
if (space)
chunk_appendf(buf, " ");
chunk_appendf(buf, "%s", entry->filters[i]);
space = 1;
}
return;
}
/* CLI IO handler for '(show|dump) ssl crt-list' */
static int cli_io_handler_dump_crtlist(struct appctx *appctx)
{
struct buffer *trash = alloc_trash_chunk();
struct stream_interface *si = appctx->owner;
struct ebmb_node *lnode;
if (trash == NULL)
return 1;
/* dump the list of crt-lists */
lnode = appctx->ctx.cli.p1;
if (lnode == NULL)
lnode = ebmb_first(&crtlists_tree);
while (lnode) {
chunk_appendf(trash, "%s\n", lnode->key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
lnode = ebmb_next(lnode);
}
return 1;
yield:
appctx->ctx.cli.p1 = lnode;
return 0;
}
/* CLI IO handler for '(show|dump) ssl crt-list <filename>' */
static int cli_io_handler_dump_crtlist_entries(struct appctx *appctx)
{
struct buffer *trash = alloc_trash_chunk();
struct crtlist *crtlist;
struct stream_interface *si = appctx->owner;
struct crtlist_entry *entry;
if (trash == NULL)
return 1;
crtlist = ebmb_entry(appctx->ctx.cli.p0, struct crtlist, node);
entry = appctx->ctx.cli.p1;
if (entry == NULL) {
entry = LIST_ELEM((crtlist->ord_entries).n, typeof(entry), by_crtlist);
chunk_appendf(trash, "# %s\n", crtlist->node.key);
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
}
list_for_each_entry_from(entry, &crtlist->ord_entries, by_crtlist) {
struct ckch_store *store;
const char *filename;
store = entry->node.key;
filename = store->path;
if (appctx->ctx.cli.i0 == 's') /* show */
chunk_appendf(trash, "%p ", entry);
chunk_appendf(trash, "%s", filename);
dump_crtlist_sslconf(trash, entry->ssl_conf);
dump_crtlist_filters(trash, entry);
chunk_appendf(trash, "\n");
if (ci_putchk(si_ic(si), trash) == -1) {
si_rx_room_blk(si);
goto yield;
}
}
return 1;
yield:
appctx->ctx.cli.p1 = entry;
return 0;
}
/* CLI argument parser for '(show|dump) ssl crt-list' */
static int cli_parse_dump_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
{
struct ebmb_node *lnode;
int mode;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
appctx->ctx.cli.p0 = NULL;
appctx->ctx.cli.p1 = NULL;
mode = (int)args[0][0]; /* 'd' or 's' */
if (mode == 'd' && !*args[3])
return cli_err(appctx, "'dump ssl crt-list' expects a filename or a directory\n");
if (*args[3]) {
lnode = ebst_lookup(&crtlists_tree, args[3]);
if (lnode == NULL)
return cli_err(appctx, "didn't find the specified filename\n");
appctx->ctx.cli.p0 = lnode;
appctx->io_handler = cli_io_handler_dump_crtlist_entries;
}
appctx->ctx.cli.i0 = mode;
return 0;
}
/* Type of SSL payloads that can be updated over the CLI */
@ -11897,6 +12158,8 @@ static struct cli_kw_list cli_kws = {{ },{
{ { "commit", "ssl", "cert", NULL }, "commit ssl cert <certfile> : commit a certificate file", cli_parse_commit_cert, cli_io_handler_commit_cert, cli_release_commit_cert },
{ { "abort", "ssl", "cert", NULL }, "abort ssl cert <certfile> : abort a transaction for a certificate file", cli_parse_abort_cert, NULL, NULL },
{ { "show", "ssl", "cert", NULL }, "show ssl cert [<certfile>] : display the SSL certificates used in memory, or the details of a <certfile>", cli_parse_show_cert, cli_io_handler_show_cert, cli_release_show_cert },
{ { "dump", "ssl", "crt-list", NULL }, "dump ssl crt-list <filename> : dump the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
{ { "show", "ssl", "crt-list", NULL }, "show ssl crt-list [<filename>] : show the list of crt-lists or the content of a crt-list <filename>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
{ { NULL }, NULL, NULL, NULL }
}};