blob: aa7fdb2edb281071d18b910ec876477df219a61d [file] [log] [blame]
William Lallemand6e9556b2020-05-12 17:52:44 +02001/*
2 *
3 * Copyright (C) 2020 HAProxy Technologies, William Lallemand <wlallemand@haproxy.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 */
Willy Tarreaub2551052020-06-09 09:07:15 +020011#include <sys/stat.h>
12#include <sys/types.h>
William Lallemand6e9556b2020-05-12 17:52:44 +020013
Willy Tarreaub2551052020-06-09 09:07:15 +020014#include <dirent.h>
William Lallemand212e9932020-05-18 08:33:09 +020015#include <errno.h>
William Lallemand6e9556b2020-05-12 17:52:44 +020016#include <stdlib.h>
17#include <string.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020018#include <syslog.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020019
20#include <import/ebpttree.h>
21#include <import/ebsttree.h>
William Lallemand6e9556b2020-05-12 17:52:44 +020022
Willy Tarreaua2fcca02022-05-05 11:53:23 +020023#include <haproxy/applet.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020024#include <haproxy/channel.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020025#include <haproxy/cli.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020026#include <haproxy/errors.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020027#include <haproxy/sc_strm.h>
Willy Tarreau47d7f902020-06-04 14:25:47 +020028#include <haproxy/ssl_ckch.h>
Willy Tarreau52d88722020-06-04 14:29:23 +020029#include <haproxy/ssl_crtlist.h>
William Lallemanda14686d2023-02-07 18:38:05 +010030#include <haproxy/ssl_ocsp.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020031#include <haproxy/ssl_sock.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020032#include <haproxy/stconn.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020033#include <haproxy/tools.h>
William Lallemand6e9556b2020-05-12 17:52:44 +020034
Willy Tarreaua2fcca02022-05-05 11:53:23 +020035/* CLI context for "show ssl crt-list" or "dump ssl crt-list" */
36struct show_crtlist_ctx {
37 struct ebmb_node *crtlist_node; /* ebmb_node for the current crtlist */
38 struct crtlist_entry *entry; /* current entry */
39 int mode; /* 'd' for dump, 's' for show */
40};
William Lallemand6e9556b2020-05-12 17:52:44 +020041
Willy Tarreau6b6c3632022-05-05 13:43:49 +020042/* CLI context for "add ssl crt-list" */
43struct add_crtlist_ctx {
44 struct crtlist *crtlist;
45 struct crtlist_entry *entry;
46 struct bind_conf_list *bind_conf_node;
Christopher Fauletc642d7c2022-06-01 16:31:09 +020047 char *err;
Willy Tarreaufa11df52022-05-05 13:48:40 +020048 enum {
49 ADDCRT_ST_INIT = 0,
50 ADDCRT_ST_GEN,
51 ADDCRT_ST_INSERT,
Christopher Fauletc642d7c2022-06-01 16:31:09 +020052 ADDCRT_ST_SUCCESS,
53 ADDCRT_ST_ERROR,
Willy Tarreaufa11df52022-05-05 13:48:40 +020054 ADDCRT_ST_FIN,
55 } state;
Willy Tarreau6b6c3632022-05-05 13:43:49 +020056};
57
William Lallemand6e9556b2020-05-12 17:52:44 +020058/* release ssl bind conf */
59void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf)
60{
61 if (conf) {
62#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
Willy Tarreau61cfdf42021-02-20 10:46:51 +010063 ha_free(&conf->npn_str);
William Lallemand6e9556b2020-05-12 17:52:44 +020064#endif
65#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
Willy Tarreau61cfdf42021-02-20 10:46:51 +010066 ha_free(&conf->alpn_str);
William Lallemand6e9556b2020-05-12 17:52:44 +020067#endif
Willy Tarreau61cfdf42021-02-20 10:46:51 +010068 ha_free(&conf->ca_file);
69 ha_free(&conf->ca_verify_file);
70 ha_free(&conf->crl_file);
71 ha_free(&conf->ciphers);
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +050072#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
Willy Tarreau61cfdf42021-02-20 10:46:51 +010073 ha_free(&conf->ciphersuites);
William Lallemand6e9556b2020-05-12 17:52:44 +020074#endif
Willy Tarreau61cfdf42021-02-20 10:46:51 +010075 ha_free(&conf->curves);
76 ha_free(&conf->ecdhe);
William Lallemand6e9556b2020-05-12 17:52:44 +020077 }
78}
79
William Lallemand82f2d2f2020-09-10 19:06:43 +020080/*
81 * Allocate and copy a ssl_bind_conf structure
82 */
83struct ssl_bind_conf *crtlist_dup_ssl_conf(struct ssl_bind_conf *src)
84{
85 struct ssl_bind_conf *dst;
86
87 if (!src)
88 return NULL;
89
90 dst = calloc(1, sizeof(*dst));
91 if (!dst)
92 return NULL;
93
94#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
95 if (src->npn_str) {
96 dst->npn_str = strdup(src->npn_str);
97 if (!dst->npn_str)
98 goto error;
99 }
100#endif
101#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
102 if (src->alpn_str) {
103 dst->alpn_str = strdup(src->alpn_str);
104 if (!dst->alpn_str)
105 goto error;
106 }
107#endif
108 if (src->ca_file) {
109 dst->ca_file = strdup(src->ca_file);
110 if (!dst->ca_file)
111 goto error;
112 }
113 if (src->ca_verify_file) {
114 dst->ca_verify_file = strdup(src->ca_verify_file);
115 if (!dst->ca_verify_file)
116 goto error;
117 }
118 if (src->crl_file) {
119 dst->crl_file = strdup(src->crl_file);
120 if (!dst->crl_file)
121 goto error;
122 }
123 if (src->ciphers) {
124 dst->ciphers = strdup(src->ciphers);
125 if (!dst->ciphers)
126 goto error;
127 }
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +0500128#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemand82f2d2f2020-09-10 19:06:43 +0200129 if (src->ciphersuites) {
130 dst->ciphersuites = strdup(src->ciphersuites);
131 if (!dst->ciphersuites)
132 goto error;
133 }
134#endif
135 if (src->curves) {
136 dst->curves = strdup(src->curves);
137 if (!dst->curves)
138 goto error;
139 }
140 if (src->ecdhe) {
141 dst->ecdhe = strdup(src->ecdhe);
142 if (!dst->ecdhe)
143 goto error;
144 }
145 return dst;
146
147error:
148 ssl_sock_free_ssl_conf(dst);
149 free(dst);
150
151 return NULL;
152}
William Lallemand6e9556b2020-05-12 17:52:44 +0200153
154/* free sni filters */
155void crtlist_free_filters(char **args)
156{
157 int i;
158
159 if (!args)
160 return;
161
162 for (i = 0; args[i]; i++)
163 free(args[i]);
164
165 free(args);
166}
167
168/* Alloc and duplicate a char ** array */
169char **crtlist_dup_filters(char **args, int fcount)
170{
171 char **dst;
172 int i;
173
174 if (fcount == 0)
175 return NULL;
176
177 dst = calloc(fcount + 1, sizeof(*dst));
178 if (!dst)
179 return NULL;
180
181 for (i = 0; i < fcount; i++) {
182 dst[i] = strdup(args[i]);
183 if (!dst[i])
184 goto error;
185 }
186 return dst;
187
188error:
189 crtlist_free_filters(dst);
190 return NULL;
191}
192
193/*
194 * Detach and free a crtlist_entry.
195 * Free the filters, the ssl_conf and call ckch_inst_free() for each ckch_inst
196 */
197void crtlist_entry_free(struct crtlist_entry *entry)
198{
199 struct ckch_inst *inst, *inst_s;
200
201 if (entry == NULL)
202 return;
203
204 ebpt_delete(&entry->node);
Willy Tarreau2b718102021-04-21 07:32:39 +0200205 LIST_DELETE(&entry->by_crtlist);
206 LIST_DELETE(&entry->by_ckch_store);
William Lallemand6e9556b2020-05-12 17:52:44 +0200207 crtlist_free_filters(entry->filters);
208 ssl_sock_free_ssl_conf(entry->ssl_conf);
209 free(entry->ssl_conf);
210 list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
211 ckch_inst_free(inst);
212 }
213 free(entry);
214}
William Lallemand5622c452020-09-10 19:08:49 +0200215/*
216 * Duplicate a crt_list entry and its content (ssl_conf, filters/fcount)
217 * Return a pointer to the new entry
218 */
219struct crtlist_entry *crtlist_entry_dup(struct crtlist_entry *src)
220{
221 struct crtlist_entry *entry;
222
223 if (src == NULL)
224 return NULL;
225
226 entry = crtlist_entry_new();
227 if (entry == NULL)
228 return NULL;
229
230 if (src->filters) {
231 entry->filters = crtlist_dup_filters(src->filters, src->fcount);
232 if (!entry->filters)
233 goto error;
234 }
235 entry->fcount = src->fcount;
236 if (src->ssl_conf) {
237 entry->ssl_conf = crtlist_dup_ssl_conf(src->ssl_conf);
238 if (!entry->ssl_conf)
239 goto error;
240 }
241 entry->crtlist = src->crtlist;
242
243 return entry;
244
245error:
246
247 crtlist_free_filters(entry->filters);
248 ssl_sock_free_ssl_conf(entry->ssl_conf);
249 free(entry->ssl_conf);
250 free(entry);
251
252 return NULL;
253}
William Lallemand6e9556b2020-05-12 17:52:44 +0200254
255/*
256 * Allocate and initialize a crtlist_entry
257 */
258struct crtlist_entry *crtlist_entry_new()
259{
260 struct crtlist_entry *entry;
261
262 entry = calloc(1, sizeof(*entry));
263 if (entry == NULL)
264 return NULL;
265
266 LIST_INIT(&entry->ckch_inst);
267
Willy Tarreau2b718102021-04-21 07:32:39 +0200268 /* initialize the nodes so we can LIST_DELETE in any cases */
William Lallemand6e9556b2020-05-12 17:52:44 +0200269 LIST_INIT(&entry->by_crtlist);
270 LIST_INIT(&entry->by_ckch_store);
271
272 return entry;
273}
274
275/* Free a crtlist, from the crt_entry to the content of the ssl_conf */
276void crtlist_free(struct crtlist *crtlist)
277{
278 struct crtlist_entry *entry, *s_entry;
William Lallemand6a3168a2020-06-23 11:43:35 +0200279 struct bind_conf_list *bind_conf_node;
William Lallemand6e9556b2020-05-12 17:52:44 +0200280
281 if (crtlist == NULL)
282 return;
283
William Lallemand6a3168a2020-06-23 11:43:35 +0200284 bind_conf_node = crtlist->bind_conf;
285 while (bind_conf_node) {
286 struct bind_conf_list *next = bind_conf_node->next;
287 free(bind_conf_node);
288 bind_conf_node = next;
289 }
290
William Lallemand6e9556b2020-05-12 17:52:44 +0200291 list_for_each_entry_safe(entry, s_entry, &crtlist->ord_entries, by_crtlist) {
292 crtlist_entry_free(entry);
293 }
294 ebmb_delete(&crtlist->node);
295 free(crtlist);
296}
297
298/* Alloc and initialize a struct crtlist
299 * <filename> is the key of the ebmb_node
300 * <unique> initialize the list of entries to be unique (1) or not (0)
301 */
302struct crtlist *crtlist_new(const char *filename, int unique)
303{
304 struct crtlist *newlist;
305
306 newlist = calloc(1, sizeof(*newlist) + strlen(filename) + 1);
307 if (newlist == NULL)
308 return NULL;
309
310 memcpy(newlist->node.key, filename, strlen(filename) + 1);
311 if (unique)
312 newlist->entries = EB_ROOT_UNIQUE;
313 else
314 newlist->entries = EB_ROOT;
315
316 LIST_INIT(&newlist->ord_entries);
317
318 return newlist;
319}
320
321/*
322 * Read a single crt-list line. /!\ alter the <line> string.
323 * Fill <crt_path> and <crtlist_entry>
324 * <crtlist_entry> must be alloc and free by the caller
325 * <crtlist_entry->ssl_conf> is alloc by the function
326 * <crtlist_entry->filters> is alloc by the function
327 * <crt_path> is a ptr in <line>
328 * Return an error code
329 */
Remi Tricot-Le Bretonfb00f312021-03-23 16:41:53 +0100330int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, int from_cli, char **err)
William Lallemand6e9556b2020-05-12 17:52:44 +0200331{
332 int cfgerr = 0;
333 int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0;
334 char *end;
335 char *args[MAX_CRT_ARGS + 1];
336 struct ssl_bind_conf *ssl_conf = NULL;
337
338 if (!line || !crt_path || !entry)
339 return ERR_ALERT | ERR_FATAL;
340
341 end = line + strlen(line);
342 if (end-line >= CRT_LINESIZE-1 && *(end-1) != '\n') {
343 /* Check if we reached the limit and the last char is not \n.
344 * Watch out for the last line without the terminating '\n'!
345 */
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200346 memprintf(err, "parsing [%s:%d]: line too long, limit is %d characters",
347 file, linenum, CRT_LINESIZE-1);
William Lallemand6e9556b2020-05-12 17:52:44 +0200348 cfgerr |= ERR_ALERT | ERR_FATAL;
349 goto error;
350 }
351 arg = 0;
352 newarg = 1;
353 while (*line) {
354 if (isspace((unsigned char)*line)) {
355 newarg = 1;
356 *line = 0;
357 } else if (*line == '[') {
358 if (ssl_b) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200359 memprintf(err, "parsing [%s:%d]: too many '['", file, linenum);
William Lallemand6e9556b2020-05-12 17:52:44 +0200360 cfgerr |= ERR_ALERT | ERR_FATAL;
361 goto error;
362 }
363 if (!arg) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200364 memprintf(err, "parsing [%s:%d]: file must start with a cert", file, linenum);
William Lallemand6e9556b2020-05-12 17:52:44 +0200365 cfgerr |= ERR_ALERT | ERR_FATAL;
366 goto error;
367 }
368 ssl_b = arg;
369 newarg = 1;
370 *line = 0;
371 } else if (*line == ']') {
372 if (ssl_e) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200373 memprintf(err, "parsing [%s:%d]: too many ']'", file, linenum);
William Lallemand6e9556b2020-05-12 17:52:44 +0200374 cfgerr |= ERR_ALERT | ERR_FATAL;
375 goto error;
376 }
377 if (!ssl_b) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200378 memprintf(err, "parsing [%s:%d]: missing '['", file, linenum);
William Lallemand6e9556b2020-05-12 17:52:44 +0200379 cfgerr |= ERR_ALERT | ERR_FATAL;
380 goto error;
381 }
382 ssl_e = arg;
383 newarg = 1;
384 *line = 0;
385 } else if (newarg) {
386 if (arg == MAX_CRT_ARGS) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200387 memprintf(err, "parsing [%s:%d]: too many args ", file, linenum);
William Lallemand6e9556b2020-05-12 17:52:44 +0200388 cfgerr |= ERR_ALERT | ERR_FATAL;
389 goto error;
390 }
391 newarg = 0;
392 args[arg++] = line;
393 }
394 line++;
395 }
396 args[arg++] = line;
397
398 /* empty line */
399 if (!*args[0]) {
400 cfgerr |= ERR_NONE;
401 goto error;
402 }
403
404 *crt_path = args[0];
405
406 if (ssl_b) {
William Lallemandd85227f2023-02-07 17:06:35 +0100407 if (ssl_b > 1) {
408 memprintf(err, "parsing [%s:%d]: malformated line, filters can't be between filename and options!", file, linenum);
409 cfgerr |= ERR_WARN;
410 }
411
William Lallemand6e9556b2020-05-12 17:52:44 +0200412 ssl_conf = calloc(1, sizeof *ssl_conf);
413 if (!ssl_conf) {
414 memprintf(err, "not enough memory!");
415 cfgerr |= ERR_ALERT | ERR_FATAL;
416 goto error;
417 }
418 }
Remi Tricot-Le Bretonfb00f312021-03-23 16:41:53 +0100419
William Lallemand6e9556b2020-05-12 17:52:44 +0200420 cur_arg = ssl_b ? ssl_b : 1;
421 while (cur_arg < ssl_e) {
422 newarg = 0;
William Lallemandaf678062023-02-13 10:58:13 +0100423 for (i = 0; ssl_crtlist_kws[i].kw != NULL; i++) {
424 if (strcmp(ssl_crtlist_kws[i].kw, args[cur_arg]) == 0) {
William Lallemand6e9556b2020-05-12 17:52:44 +0200425 newarg = 1;
William Lallemandaf678062023-02-13 10:58:13 +0100426 cfgerr |= ssl_crtlist_kws[i].parse(args, cur_arg, NULL, ssl_conf, from_cli, err);
427 if (cur_arg + 1 + ssl_crtlist_kws[i].skip > ssl_e) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200428 memprintf(err, "parsing [%s:%d]: ssl args out of '[]' for %s",
429 file, linenum, args[cur_arg]);
William Lallemand6e9556b2020-05-12 17:52:44 +0200430 cfgerr |= ERR_ALERT | ERR_FATAL;
431 goto error;
432 }
William Lallemandaf678062023-02-13 10:58:13 +0100433 cur_arg += 1 + ssl_crtlist_kws[i].skip;
William Lallemand6e9556b2020-05-12 17:52:44 +0200434 break;
435 }
436 }
437 if (!cfgerr && !newarg) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200438 memprintf(err, "parsing [%s:%d]: unknown ssl keyword %s",
439 file, linenum, args[cur_arg]);
William Lallemand6e9556b2020-05-12 17:52:44 +0200440 cfgerr |= ERR_ALERT | ERR_FATAL;
441 goto error;
442 }
443 }
444 entry->linenum = linenum;
445 entry->ssl_conf = ssl_conf;
446 entry->filters = crtlist_dup_filters(&args[cur_arg], arg - cur_arg - 1);
447 entry->fcount = arg - cur_arg - 1;
448
449 return cfgerr;
450
451error:
452 crtlist_free_filters(entry->filters);
453 entry->filters = NULL;
454 ssl_sock_free_ssl_conf(entry->ssl_conf);
Willy Tarreau61cfdf42021-02-20 10:46:51 +0100455 ha_free(&entry->ssl_conf);
William Lallemand6e9556b2020-05-12 17:52:44 +0200456 return cfgerr;
457}
458
459
460
461/* This function parse a crt-list file and store it in a struct crtlist, each line is a crtlist_entry structure
462 * Fill the <crtlist> argument with a pointer to a new crtlist struct
463 *
464 * This function tries to open and store certificate files.
465 */
466int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *curproxy, struct crtlist **crtlist, char **err)
467{
468 struct crtlist *newlist;
469 struct crtlist_entry *entry = NULL;
470 char thisline[CRT_LINESIZE];
William Lallemand6e9556b2020-05-12 17:52:44 +0200471 FILE *f;
472 struct stat buf;
473 int linenum = 0;
474 int cfgerr = 0;
Tim Duesterhusb9f6acc2020-09-29 18:00:28 +0200475 int missing_lf = -1;
William Lallemand6e9556b2020-05-12 17:52:44 +0200476
477 if ((f = fopen(file, "r")) == NULL) {
478 memprintf(err, "cannot open file '%s' : %s", file, strerror(errno));
479 return ERR_ALERT | ERR_FATAL;
480 }
481
482 newlist = crtlist_new(file, 0);
483 if (newlist == NULL) {
484 memprintf(err, "Not enough memory!");
485 cfgerr |= ERR_ALERT | ERR_FATAL;
486 goto error;
487 }
488
489 while (fgets(thisline, sizeof(thisline), f) != NULL) {
490 char *end;
491 char *line = thisline;
492 char *crt_path;
William Lallemand86c2dd62020-11-20 14:23:38 +0100493 char path[MAXPATHLEN+1];
William Lallemand6e9556b2020-05-12 17:52:44 +0200494 struct ckch_store *ckchs;
William Lallemand77e1c6f2020-11-20 18:26:09 +0100495 int found = 0;
William Lallemand6e9556b2020-05-12 17:52:44 +0200496
Tim Duesterhusb9f6acc2020-09-29 18:00:28 +0200497 if (missing_lf != -1) {
498 memprintf(err, "parsing [%s:%d]: Stray NUL character at position %d.\n",
499 file, linenum, (missing_lf + 1));
500 cfgerr |= ERR_ALERT | ERR_FATAL;
501 missing_lf = -1;
502 break;
503 }
504
William Lallemand6e9556b2020-05-12 17:52:44 +0200505 linenum++;
506 end = line + strlen(line);
507 if (end-line == sizeof(thisline)-1 && *(end-1) != '\n') {
508 /* Check if we reached the limit and the last char is not \n.
509 * Watch out for the last line without the terminating '\n'!
510 */
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200511 memprintf(err, "parsing [%s:%d]: line too long, limit is %d characters",
512 file, linenum, (int)sizeof(thisline)-1);
William Lallemand6e9556b2020-05-12 17:52:44 +0200513 cfgerr |= ERR_ALERT | ERR_FATAL;
514 break;
515 }
516
517 if (*line == '#' || *line == '\n' || *line == '\r')
518 continue;
519
Tim Duesterhusb9f6acc2020-09-29 18:00:28 +0200520 if (end > line && *(end-1) == '\n') {
521 /* kill trailing LF */
522 *(end - 1) = 0;
523 }
524 else {
525 /* mark this line as truncated */
526 missing_lf = end - line;
527 }
528
William Lallemand6e9556b2020-05-12 17:52:44 +0200529 entry = crtlist_entry_new();
530 if (entry == NULL) {
531 memprintf(err, "Not enough memory!");
532 cfgerr |= ERR_ALERT | ERR_FATAL;
533 goto error;
534 }
Tim Duesterhusb9f6acc2020-09-29 18:00:28 +0200535
Remi Tricot-Le Bretonfb00f312021-03-23 16:41:53 +0100536 cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, file, linenum, 0, err);
William Lallemand20b0fed2020-09-28 15:45:16 +0200537 if (cfgerr & ERR_CODE)
William Lallemand6e9556b2020-05-12 17:52:44 +0200538 goto error;
539
540 /* empty line */
541 if (!crt_path || !*crt_path) {
542 crtlist_entry_free(entry);
543 entry = NULL;
544 continue;
545 }
546
547 if (*crt_path != '/' && global_ssl.crt_base) {
Willy Tarreau393e42a2022-05-09 10:31:28 +0200548 if ((strlen(global_ssl.crt_base) + 1 + strlen(crt_path)) > sizeof(path) ||
Willy Tarreau63fc9002022-05-09 21:14:04 +0200549 snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, crt_path) > sizeof(path)) {
Tim Duesterhus6d07fae2020-09-29 18:00:27 +0200550 memprintf(err, "parsing [%s:%d]: '%s' : path too long",
551 file, linenum, crt_path);
William Lallemand6e9556b2020-05-12 17:52:44 +0200552 cfgerr |= ERR_ALERT | ERR_FATAL;
553 goto error;
554 }
William Lallemand6e9556b2020-05-12 17:52:44 +0200555 crt_path = path;
556 }
557
558 /* Look for a ckch_store or create one */
559 ckchs = ckchs_lookup(crt_path);
560 if (ckchs == NULL) {
William Lallemand47da8212020-09-10 19:13:27 +0200561 if (stat(crt_path, &buf) == 0) {
William Lallemand77e1c6f2020-11-20 18:26:09 +0100562 found++;
William Lallemand47da8212020-09-10 19:13:27 +0200563
William Lallemandbd8e6ed2020-09-16 16:08:08 +0200564 ckchs = ckchs_load_cert_file(crt_path, err);
William Lallemand47da8212020-09-10 19:13:27 +0200565 if (ckchs == NULL) {
566 cfgerr |= ERR_ALERT | ERR_FATAL;
567 goto error;
568 }
569
570 entry->node.key = ckchs;
571 entry->crtlist = newlist;
Remi Tricot-Le Bretonfb2b9982022-12-20 11:11:11 +0100572 if (entry->ssl_conf)
573 ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
William Lallemand47da8212020-09-10 19:13:27 +0200574 ebpt_insert(&newlist->entries, &entry->node);
Willy Tarreau2b718102021-04-21 07:32:39 +0200575 LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
576 LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
William Lallemand6e9556b2020-05-12 17:52:44 +0200577
William Lallemand73404572020-11-20 18:23:40 +0100578 } else if (global_ssl.extra_files & SSL_GF_BUNDLE) {
William Lallemand47da8212020-09-10 19:13:27 +0200579 /* If we didn't find the file, this could be a
William Lallemand51f784b2020-10-02 18:08:18 +0200580 bundle, since 2.3 we don't support multiple
581 certificate in the same OpenSSL store, so we
582 emulate it by loading each file separately. To
583 do so we need to duplicate the entry in the
584 crt-list because it becomes independent */
William Lallemand47da8212020-09-10 19:13:27 +0200585 char fp[MAXPATHLEN+1] = {0};
586 int n = 0;
587 struct crtlist_entry *entry_dup = entry; /* use the previous created entry */
588 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
589 struct stat buf;
590 int ret;
591
William Lallemand86c2dd62020-11-20 14:23:38 +0100592 ret = snprintf(fp, sizeof(fp), "%s.%s", crt_path, SSL_SOCK_KEYTYPE_NAMES[n]);
William Lallemand47da8212020-09-10 19:13:27 +0200593 if (ret > sizeof(fp))
594 continue;
595
596 ckchs = ckchs_lookup(fp);
William Lallemand77e1c6f2020-11-20 18:26:09 +0100597 if (!ckchs) {
598 if (stat(fp, &buf) == 0) {
599 ckchs = ckchs_load_cert_file(fp, err);
600 if (!ckchs) {
William Lallemand47da8212020-09-10 19:13:27 +0200601 cfgerr |= ERR_ALERT | ERR_FATAL;
602 goto error;
603 }
William Lallemand77e1c6f2020-11-20 18:26:09 +0100604 } else {
605 continue; /* didn't find this extension, skip */
606 }
607 }
608 found++;
609 linenum++; /* we duplicate the line for this entry in the bundle */
610 if (!entry_dup) { /* if the entry was used, duplicate one */
611 linenum++;
612 entry_dup = crtlist_entry_dup(entry);
613 if (!entry_dup) {
614 cfgerr |= ERR_ALERT | ERR_FATAL;
615 goto error;
William Lallemand47da8212020-09-10 19:13:27 +0200616 }
William Lallemand77e1c6f2020-11-20 18:26:09 +0100617 entry_dup->linenum = linenum;
618 }
William Lallemand47da8212020-09-10 19:13:27 +0200619
William Lallemand77e1c6f2020-11-20 18:26:09 +0100620 entry_dup->node.key = ckchs;
621 entry_dup->crtlist = newlist;
William Lallemanda14686d2023-02-07 18:38:05 +0100622
623 cfgerr |= ocsp_update_check_cfg_consistency(ckchs, entry, crt_path, err);
624 if (cfgerr & ERR_FATAL)
625 goto error;
626
Remi Tricot-Le Bretonfc92b8b2023-01-09 12:02:46 +0100627 if (entry->ssl_conf)
628 ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
William Lallemand77e1c6f2020-11-20 18:26:09 +0100629 ebpt_insert(&newlist->entries, &entry_dup->node);
Willy Tarreau2b718102021-04-21 07:32:39 +0200630 LIST_APPEND(&newlist->ord_entries, &entry_dup->by_crtlist);
631 LIST_APPEND(&ckchs->crtlist_entry, &entry_dup->by_ckch_store);
William Lallemand47da8212020-09-10 19:13:27 +0200632
William Lallemand77e1c6f2020-11-20 18:26:09 +0100633 entry_dup = NULL; /* the entry was used, we need a new one next round */
William Lallemand47da8212020-09-10 19:13:27 +0200634 }
William Lallemandb7fdfdf2020-12-04 15:45:02 +0100635#if HA_OPENSSL_VERSION_NUMBER < 0x10101000L
636 if (found) {
637 memprintf(err, "%sCan't load '%s'. Loading a multi certificates bundle requires OpenSSL >= 1.1.1\n",
638 err && *err ? *err : "", crt_path);
639 cfgerr |= ERR_ALERT | ERR_FATAL;
640 }
641#endif
William Lallemand47da8212020-09-10 19:13:27 +0200642 }
William Lallemand77e1c6f2020-11-20 18:26:09 +0100643 if (!found) {
644 memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
645 err && *err ? *err : "", crt_path, strerror(errno));
646 cfgerr |= ERR_ALERT | ERR_FATAL;
647 }
648
William Lallemand50c03aa2020-11-06 16:24:07 +0100649 } else {
650 entry->node.key = ckchs;
651 entry->crtlist = newlist;
William Lallemanda14686d2023-02-07 18:38:05 +0100652
653 cfgerr |= ocsp_update_check_cfg_consistency(ckchs, entry, crt_path, err);
654 if (cfgerr & ERR_FATAL)
655 goto error;
656
Remi Tricot-Le Bretonfc92b8b2023-01-09 12:02:46 +0100657 if (entry->ssl_conf)
658 ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
William Lallemand50c03aa2020-11-06 16:24:07 +0100659 ebpt_insert(&newlist->entries, &entry->node);
Willy Tarreau2b718102021-04-21 07:32:39 +0200660 LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
661 LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
William Lallemand77e1c6f2020-11-20 18:26:09 +0100662 found++;
William Lallemand47da8212020-09-10 19:13:27 +0200663 }
William Lallemand6e9556b2020-05-12 17:52:44 +0200664 entry = NULL;
665 }
Tim Duesterhusb9f6acc2020-09-29 18:00:28 +0200666
667 if (missing_lf != -1) {
668 memprintf(err, "parsing [%s:%d]: Missing LF on last line, file might have been truncated at position %d.\n",
669 file, linenum, (missing_lf + 1));
670 cfgerr |= ERR_ALERT | ERR_FATAL;
671 }
672
William Lallemand6e9556b2020-05-12 17:52:44 +0200673 if (cfgerr & ERR_CODE)
674 goto error;
675
676 newlist->linecount = linenum;
677
678 fclose(f);
679 *crtlist = newlist;
680
681 return cfgerr;
682error:
683 crtlist_entry_free(entry);
684
685 fclose(f);
686 crtlist_free(newlist);
687 return cfgerr;
688}
689
690/* This function reads a directory and stores it in a struct crtlist, each file is a crtlist_entry structure
691 * Fill the <crtlist> argument with a pointer to a new crtlist struct
692 *
693 * This function tries to open and store certificate files.
694 */
695int crtlist_load_cert_dir(char *path, struct bind_conf *bind_conf, struct crtlist **crtlist, char **err)
696{
697 struct crtlist *dir;
698 struct dirent **de_list;
699 int i, n;
700 struct stat buf;
701 char *end;
702 char fp[MAXPATHLEN+1];
703 int cfgerr = 0;
704 struct ckch_store *ckchs;
William Lallemand6e9556b2020-05-12 17:52:44 +0200705
706 dir = crtlist_new(path, 1);
707 if (dir == NULL) {
708 memprintf(err, "not enough memory");
709 return ERR_ALERT | ERR_FATAL;
710 }
711
712 n = scandir(path, &de_list, 0, alphasort);
713 if (n < 0) {
714 memprintf(err, "%sunable to scan directory '%s' : %s.\n",
715 err && *err ? *err : "", path, strerror(errno));
716 cfgerr |= ERR_ALERT | ERR_FATAL;
717 }
718 else {
719 for (i = 0; i < n; i++) {
720 struct crtlist_entry *entry;
721 struct dirent *de = de_list[i];
722
723 end = strrchr(de->d_name, '.');
William Lallemand589570d2022-05-09 10:30:51 +0200724 if (end && (de->d_name[0] == '.' ||
725 strcmp(end, ".issuer") == 0 || strcmp(end, ".ocsp") == 0 ||
726 strcmp(end, ".sctl") == 0 || strcmp(end, ".key") == 0))
William Lallemand6e9556b2020-05-12 17:52:44 +0200727 goto ignore_entry;
728
729 snprintf(fp, sizeof(fp), "%s/%s", path, de->d_name);
730 if (stat(fp, &buf) != 0) {
731 memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
732 err && *err ? *err : "", fp, strerror(errno));
733 cfgerr |= ERR_ALERT | ERR_FATAL;
734 goto ignore_entry;
735 }
736 if (!S_ISREG(buf.st_mode))
737 goto ignore_entry;
738
739 entry = crtlist_entry_new();
740 if (entry == NULL) {
741 memprintf(err, "not enough memory '%s'", fp);
742 cfgerr |= ERR_ALERT | ERR_FATAL;
743 goto ignore_entry;
744 }
745
William Lallemand6e9556b2020-05-12 17:52:44 +0200746 ckchs = ckchs_lookup(fp);
747 if (ckchs == NULL)
William Lallemandbd8e6ed2020-09-16 16:08:08 +0200748 ckchs = ckchs_load_cert_file(fp, err);
William Lallemand6e9556b2020-05-12 17:52:44 +0200749 if (ckchs == NULL) {
750 free(de);
751 free(entry);
752 cfgerr |= ERR_ALERT | ERR_FATAL;
753 goto end;
754 }
755 entry->node.key = ckchs;
756 entry->crtlist = dir;
Willy Tarreau2b718102021-04-21 07:32:39 +0200757 LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
758 LIST_APPEND(&dir->ord_entries, &entry->by_crtlist);
William Lallemand6e9556b2020-05-12 17:52:44 +0200759 ebpt_insert(&dir->entries, &entry->node);
760
761ignore_entry:
762 free(de);
763 }
764end:
765 free(de_list);
766 }
767
768 if (cfgerr & ERR_CODE) {
769 /* free the dir and entries on error */
770 crtlist_free(dir);
771 } else {
772 *crtlist = dir;
773 }
774 return cfgerr;
775
776}
777
William Lallemandc756bbd2020-05-13 17:23:59 +0200778/*
779 * Take an ssl_bind_conf structure and append the configuration line used to
780 * create it in the buffer
781 */
782static void dump_crtlist_sslconf(struct buffer *buf, const struct ssl_bind_conf *conf)
783{
784 int space = 0;
785
786 if (conf == NULL)
787 return;
788
789 chunk_appendf(buf, " [");
790#ifdef OPENSSL_NPN_NEGOTIATED
791 if (conf->npn_str) {
792 int len = conf->npn_len;
793 char *ptr = conf->npn_str;
794 int comma = 0;
795
796 if (space) chunk_appendf(buf, " ");
797 chunk_appendf(buf, "npn ");
798 while (len) {
799 unsigned short size;
800
801 size = *ptr;
802 ptr++;
803 if (comma)
804 chunk_memcat(buf, ",", 1);
805 chunk_memcat(buf, ptr, size);
806 ptr += size;
807 len -= size + 1;
808 comma = 1;
809 }
810 chunk_memcat(buf, "", 1); /* finish with a \0 */
811 space++;
812 }
813#endif
814#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
815 if (conf->alpn_str) {
816 int len = conf->alpn_len;
817 char *ptr = conf->alpn_str;
818 int comma = 0;
819
820 if (space) chunk_appendf(buf, " ");
821 chunk_appendf(buf, "alpn ");
822 while (len) {
823 unsigned short size;
824
825 size = *ptr;
826 ptr++;
827 if (comma)
828 chunk_memcat(buf, ",", 1);
829 chunk_memcat(buf, ptr, size);
830 ptr += size;
831 len -= size + 1;
832 comma = 1;
833 }
834 chunk_memcat(buf, "", 1); /* finish with a \0 */
835 space++;
836 }
837#endif
838 /* verify */
839 {
840 if (conf->verify == SSL_SOCK_VERIFY_NONE) {
841 if (space) chunk_appendf(buf, " ");
842 chunk_appendf(buf, "verify none");
843 space++;
844 } else if (conf->verify == SSL_SOCK_VERIFY_OPTIONAL) {
845 if (space) chunk_appendf(buf, " ");
846 chunk_appendf(buf, "verify optional");
847 space++;
848 } else if (conf->verify == SSL_SOCK_VERIFY_REQUIRED) {
849 if (space) chunk_appendf(buf, " ");
850 chunk_appendf(buf, "verify required");
851 space++;
852 }
853 }
854
855 if (conf->no_ca_names) {
856 if (space) chunk_appendf(buf, " ");
857 chunk_appendf(buf, "no-ca-names");
858 space++;
859 }
860
861 if (conf->early_data) {
862 if (space) chunk_appendf(buf, " ");
863 chunk_appendf(buf, "allow-0rtt");
864 space++;
865 }
866 if (conf->ca_file) {
867 if (space) chunk_appendf(buf, " ");
868 chunk_appendf(buf, "ca-file %s", conf->ca_file);
869 space++;
870 }
871 if (conf->crl_file) {
872 if (space) chunk_appendf(buf, " ");
873 chunk_appendf(buf, "crl-file %s", conf->crl_file);
874 space++;
875 }
876 if (conf->ciphers) {
877 if (space) chunk_appendf(buf, " ");
878 chunk_appendf(buf, "ciphers %s", conf->ciphers);
879 space++;
880 }
Ilya Shipitsinf34ed0b2020-11-21 14:37:34 +0500881#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
William Lallemandc756bbd2020-05-13 17:23:59 +0200882 if (conf->ciphersuites) {
883 if (space) chunk_appendf(buf, " ");
884 chunk_appendf(buf, "ciphersuites %s", conf->ciphersuites);
885 space++;
886 }
887#endif
888 if (conf->curves) {
889 if (space) chunk_appendf(buf, " ");
890 chunk_appendf(buf, "curves %s", conf->curves);
891 space++;
892 }
893 if (conf->ecdhe) {
894 if (space) chunk_appendf(buf, " ");
895 chunk_appendf(buf, "ecdhe %s", conf->ecdhe);
896 space++;
897 }
898
899 /* the crt-lists only support ssl-min-ver and ssl-max-ver */
William Lallemand8177ad92020-05-20 16:49:02 +0200900 if (conf->ssl_methods_cfg.min) {
William Lallemandc756bbd2020-05-13 17:23:59 +0200901 if (space) chunk_appendf(buf, " ");
William Lallemand8177ad92020-05-20 16:49:02 +0200902 chunk_appendf(buf, "ssl-min-ver %s", methodVersions[conf->ssl_methods_cfg.min].name);
William Lallemandc756bbd2020-05-13 17:23:59 +0200903 space++;
904 }
905
William Lallemand8177ad92020-05-20 16:49:02 +0200906 if (conf->ssl_methods_cfg.max) {
William Lallemandc756bbd2020-05-13 17:23:59 +0200907 if (space) chunk_appendf(buf, " ");
William Lallemand8177ad92020-05-20 16:49:02 +0200908 chunk_appendf(buf, "ssl-max-ver %s", methodVersions[conf->ssl_methods_cfg.max].name);
William Lallemandc756bbd2020-05-13 17:23:59 +0200909 space++;
910 }
911
912 chunk_appendf(buf, "]");
913
914 return;
915}
916
917/* dump a list of filters */
918static void dump_crtlist_filters(struct buffer *buf, struct crtlist_entry *entry)
919{
920 int i;
921
922 if (!entry->fcount)
923 return;
924
925 for (i = 0; i < entry->fcount; i++) {
926 chunk_appendf(buf, " %s", entry->filters[i]);
927 }
928 return;
929}
930
931/************************** CLI functions ****************************/
932
933
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200934/* CLI IO handler for '(show|dump) ssl crt-list'.
935 * It uses show_crtlist_ctx for the context.
936 */
William Lallemandc756bbd2020-05-13 17:23:59 +0200937static int cli_io_handler_dump_crtlist(struct appctx *appctx)
938{
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200939 struct show_crtlist_ctx *ctx = appctx->svcctx;
William Lallemandc756bbd2020-05-13 17:23:59 +0200940 struct buffer *trash = alloc_trash_chunk();
William Lallemandc756bbd2020-05-13 17:23:59 +0200941 struct ebmb_node *lnode;
942
943 if (trash == NULL)
944 return 1;
945
946 /* dump the list of crt-lists */
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200947 lnode = ctx->crtlist_node;
William Lallemandc756bbd2020-05-13 17:23:59 +0200948 if (lnode == NULL)
949 lnode = ebmb_first(&crtlists_tree);
950 while (lnode) {
951 chunk_appendf(trash, "%s\n", lnode->key);
Willy Tarreaud0a06d52022-05-18 15:07:19 +0200952 if (applet_putchk(appctx, trash) == -1)
William Lallemandc756bbd2020-05-13 17:23:59 +0200953 goto yield;
William Lallemandc756bbd2020-05-13 17:23:59 +0200954 lnode = ebmb_next(lnode);
955 }
956 free_trash_chunk(trash);
957 return 1;
958yield:
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200959 ctx->crtlist_node = lnode;
William Lallemandc756bbd2020-05-13 17:23:59 +0200960 free_trash_chunk(trash);
961 return 0;
962}
963
964/* CLI IO handler for '(show|dump) ssl crt-list <filename>' */
965static int cli_io_handler_dump_crtlist_entries(struct appctx *appctx)
966{
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200967 struct show_crtlist_ctx *ctx = appctx->svcctx;
William Lallemandc756bbd2020-05-13 17:23:59 +0200968 struct buffer *trash = alloc_trash_chunk();
969 struct crtlist *crtlist;
William Lallemandc756bbd2020-05-13 17:23:59 +0200970 struct crtlist_entry *entry;
971
972 if (trash == NULL)
973 return 1;
974
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200975 crtlist = ebmb_entry(ctx->crtlist_node, struct crtlist, node);
William Lallemandc756bbd2020-05-13 17:23:59 +0200976
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200977 entry = ctx->entry;
William Lallemandc756bbd2020-05-13 17:23:59 +0200978 if (entry == NULL) {
979 entry = LIST_ELEM((crtlist->ord_entries).n, typeof(entry), by_crtlist);
980 chunk_appendf(trash, "# %s\n", crtlist->node.key);
Willy Tarreaud0a06d52022-05-18 15:07:19 +0200981 if (applet_putchk(appctx, trash) == -1)
William Lallemandc756bbd2020-05-13 17:23:59 +0200982 goto yield;
William Lallemandc756bbd2020-05-13 17:23:59 +0200983 }
984
985 list_for_each_entry_from(entry, &crtlist->ord_entries, by_crtlist) {
986 struct ckch_store *store;
987 const char *filename;
988
989 store = entry->node.key;
990 filename = store->path;
991 chunk_appendf(trash, "%s", filename);
Willy Tarreaua2fcca02022-05-05 11:53:23 +0200992 if (ctx->mode == 's') /* show */
William Lallemandc756bbd2020-05-13 17:23:59 +0200993 chunk_appendf(trash, ":%d", entry->linenum);
994 dump_crtlist_sslconf(trash, entry->ssl_conf);
995 dump_crtlist_filters(trash, entry);
996 chunk_appendf(trash, "\n");
997
Willy Tarreaud0a06d52022-05-18 15:07:19 +0200998 if (applet_putchk(appctx, trash) == -1)
William Lallemandc756bbd2020-05-13 17:23:59 +0200999 goto yield;
William Lallemandc756bbd2020-05-13 17:23:59 +02001000 }
1001 free_trash_chunk(trash);
1002 return 1;
1003yield:
Willy Tarreaua2fcca02022-05-05 11:53:23 +02001004 ctx->entry = entry;
William Lallemandc756bbd2020-05-13 17:23:59 +02001005 free_trash_chunk(trash);
1006 return 0;
1007}
1008
1009/* CLI argument parser for '(show|dump) ssl crt-list' */
1010static int cli_parse_dump_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
1011{
Willy Tarreaua2fcca02022-05-05 11:53:23 +02001012 struct show_crtlist_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
William Lallemandc756bbd2020-05-13 17:23:59 +02001013 struct ebmb_node *lnode;
1014 char *filename = NULL;
1015 int mode;
William Lallemand99cc2182020-06-25 15:19:51 +02001016 char *end;
William Lallemandc756bbd2020-05-13 17:23:59 +02001017
1018 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1019 return 1;
1020
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001021 if (*args[3] && strcmp(args[3], "-n") == 0) {
William Lallemandc756bbd2020-05-13 17:23:59 +02001022 mode = 's';
1023 filename = args[4];
1024 } else {
1025 mode = 'd';
1026 filename = args[3];
1027 }
1028
1029 if (mode == 's' && !*args[4])
1030 return cli_err(appctx, "'show ssl crt-list -n' expects a filename or a directory\n");
1031
1032 if (filename && *filename) {
William Lallemand99cc2182020-06-25 15:19:51 +02001033
1034
1035 /* strip trailing slashes, including first one */
1036 for (end = filename + strlen(filename) - 1; end >= filename && *end == '/'; end--)
1037 *end = 0;
1038
William Lallemandc756bbd2020-05-13 17:23:59 +02001039 lnode = ebst_lookup(&crtlists_tree, filename);
1040 if (lnode == NULL)
1041 return cli_err(appctx, "didn't find the specified filename\n");
1042
Willy Tarreaua2fcca02022-05-05 11:53:23 +02001043 ctx->crtlist_node = lnode;
William Lallemandc756bbd2020-05-13 17:23:59 +02001044 appctx->io_handler = cli_io_handler_dump_crtlist_entries;
1045 }
Willy Tarreaua2fcca02022-05-05 11:53:23 +02001046 ctx->mode = mode;
William Lallemandc756bbd2020-05-13 17:23:59 +02001047
1048 return 0;
1049}
1050
1051/* release function of the "add ssl crt-list' command, free things and unlock
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001052 * the spinlock. It uses the add_crtlist_ctx.
1053 */
William Lallemandc756bbd2020-05-13 17:23:59 +02001054static void cli_release_add_crtlist(struct appctx *appctx)
1055{
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001056 struct add_crtlist_ctx *ctx = appctx->svcctx;
1057 struct crtlist_entry *entry = ctx->entry;
William Lallemandc756bbd2020-05-13 17:23:59 +02001058
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001059 if (entry) {
William Lallemandc756bbd2020-05-13 17:23:59 +02001060 struct ckch_inst *inst, *inst_s;
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001061
William Lallemandc756bbd2020-05-13 17:23:59 +02001062 /* upon error free the ckch_inst and everything inside */
1063 ebpt_delete(&entry->node);
Willy Tarreau2b718102021-04-21 07:32:39 +02001064 LIST_DELETE(&entry->by_crtlist);
1065 LIST_DELETE(&entry->by_ckch_store);
William Lallemandc756bbd2020-05-13 17:23:59 +02001066
1067 list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_ckchs) {
1068 ckch_inst_free(inst);
1069 }
1070 crtlist_free_filters(entry->filters);
1071 ssl_sock_free_ssl_conf(entry->ssl_conf);
1072 free(entry->ssl_conf);
1073 free(entry);
1074 }
William Lallemandc756bbd2020-05-13 17:23:59 +02001075 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001076 ha_free(&ctx->err);
William Lallemandc756bbd2020-05-13 17:23:59 +02001077}
1078
1079
1080/* IO Handler for the "add ssl crt-list" command It adds a new entry in the
1081 * crt-list and generates the ckch_insts for each bind_conf that uses this crt-list
1082 *
1083 * The logic is the same as the "commit ssl cert" command but without the
1084 * freeing of the old structures, because there are none.
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001085 *
1086 * It uses the add_crtlist_ctx for the context.
William Lallemandc756bbd2020-05-13 17:23:59 +02001087 */
1088static int cli_io_handler_add_crtlist(struct appctx *appctx)
1089{
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001090 struct add_crtlist_ctx *ctx = appctx->svcctx;
William Lallemandc756bbd2020-05-13 17:23:59 +02001091 struct bind_conf_list *bind_conf_node;
Willy Tarreauc12b3212022-05-27 11:08:15 +02001092 struct stconn *sc = appctx_sc(appctx);
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001093 struct crtlist *crtlist = ctx->crtlist;
1094 struct crtlist_entry *entry = ctx->entry;
William Lallemandc756bbd2020-05-13 17:23:59 +02001095 struct ckch_store *store = entry->node.key;
William Lallemandc756bbd2020-05-13 17:23:59 +02001096 struct ckch_inst *new_inst;
William Lallemandc756bbd2020-05-13 17:23:59 +02001097 int i = 0;
1098 int errcode = 0;
1099
William Lallemandc756bbd2020-05-13 17:23:59 +02001100 /* for each bind_conf which use the crt-list, a new ckch_inst must be
1101 * created.
1102 */
Christopher Fauletda89e9b2023-01-04 14:11:10 +01001103 if (unlikely(sc_ic(sc)->flags & CF_SHUTW))
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001104 goto end;
William Lallemandc756bbd2020-05-13 17:23:59 +02001105
Willy Tarreaufa11df52022-05-05 13:48:40 +02001106 switch (ctx->state) {
1107 case ADDCRT_ST_INIT:
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001108 /* This state just print the update message */
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001109 chunk_printf(&trash, "Inserting certificate '%s' in crt-list '%s'", store->path, crtlist->node.key);
1110 if (applet_putchk(appctx, &trash) == -1)
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001111 goto yield;
Willy Tarreaufa11df52022-05-05 13:48:40 +02001112 ctx->state = ADDCRT_ST_GEN;
Willy Tarreauaef84482022-11-14 07:03:16 +01001113 __fallthrough;
Willy Tarreaufa11df52022-05-05 13:48:40 +02001114 case ADDCRT_ST_GEN:
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001115 bind_conf_node = ctx->bind_conf_node; /* get the previous ptr from the yield */
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001116 if (bind_conf_node == NULL)
1117 bind_conf_node = crtlist->bind_conf;
1118 for (; bind_conf_node; bind_conf_node = bind_conf_node->next) {
1119 struct bind_conf *bind_conf = bind_conf_node->bind_conf;
1120 struct sni_ctx *sni;
1121
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001122 ctx->bind_conf_node = bind_conf_node;
1123
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001124 /* yield every 10 generations */
1125 if (i > 10) {
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001126 applet_have_more_data(appctx); /* let's come back later */
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001127 goto yield;
1128 }
William Lallemandc756bbd2020-05-13 17:23:59 +02001129
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001130 /* display one dot for each new instance */
1131 if (applet_putstr(appctx, ".") == -1)
1132 goto yield;
1133
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001134 /* we don't support multi-cert bundles, only simple ones */
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001135 ctx->err = NULL;
1136 errcode |= ckch_inst_new_load_store(store->path, store, bind_conf, entry->ssl_conf, entry->filters, entry->fcount, &new_inst, &ctx->err);
1137 if (errcode & ERR_CODE) {
1138 ctx->state = ADDCRT_ST_ERROR;
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001139 goto error;
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001140 }
William Lallemandc756bbd2020-05-13 17:23:59 +02001141
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001142 /* we need to initialize the SSL_CTX generated */
1143 /* this iterate on the newly generated SNIs in the new instance to prepare their SSL_CTX */
1144 list_for_each_entry(sni, &new_inst->sni_ctx, by_ckch_inst) {
1145 if (!sni->order) { /* we initialized only the first SSL_CTX because it's the same in the other sni_ctx's */
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001146 ctx->err = NULL;
1147 errcode |= ssl_sock_prep_ctx_and_inst(bind_conf, new_inst->ssl_conf, sni->ctx, sni->ckch_inst, &ctx->err);
1148 if (errcode & ERR_CODE) {
1149 ctx->state = ADDCRT_ST_ERROR;
William Lallemandc756bbd2020-05-13 17:23:59 +02001150 goto error;
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001151 }
William Lallemandc756bbd2020-05-13 17:23:59 +02001152 }
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001153 }
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001154
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001155 i++;
1156 LIST_APPEND(&store->ckch_inst, &new_inst->by_ckchs);
1157 LIST_APPEND(&entry->ckch_inst, &new_inst->by_crtlist_entry);
1158 new_inst->crtlist_entry = entry;
William Lallemandc756bbd2020-05-13 17:23:59 +02001159 }
Willy Tarreaufa11df52022-05-05 13:48:40 +02001160 ctx->state = ADDCRT_ST_INSERT;
Willy Tarreauaef84482022-11-14 07:03:16 +01001161 __fallthrough;
Willy Tarreaufa11df52022-05-05 13:48:40 +02001162 case ADDCRT_ST_INSERT:
William Lallemandcb6c5f42022-06-20 16:51:53 +02001163 /* the insertion is called for every instance of the store, not
1164 * only the one we generated.
1165 * But the ssl_sock_load_cert_sni() skip the sni already
1166 * inserted. Not every instance has a bind_conf, it could be
1167 * the store of a server so we should be careful */
1168
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001169 list_for_each_entry(new_inst, &store->ckch_inst, by_ckchs) {
William Lallemandcb6c5f42022-06-20 16:51:53 +02001170 if (!new_inst->bind_conf) /* this is a server instance */
1171 continue;
Willy Tarreau1b948ef2022-05-05 13:50:46 +02001172 HA_RWLOCK_WRLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
1173 ssl_sock_load_cert_sni(new_inst, new_inst->bind_conf);
1174 HA_RWLOCK_WRUNLOCK(SNI_LOCK, &new_inst->bind_conf->sni_lock);
1175 }
1176 entry->linenum = ++crtlist->linecount;
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001177 ctx->entry = NULL;
1178 ctx->state = ADDCRT_ST_SUCCESS;
Willy Tarreauaef84482022-11-14 07:03:16 +01001179 __fallthrough;
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001180 case ADDCRT_ST_SUCCESS:
1181 chunk_reset(&trash);
1182 chunk_appendf(&trash, "\n");
1183 if (ctx->err)
1184 chunk_appendf(&trash, "%s", ctx->err);
1185 chunk_appendf(&trash, "Success!\n");
1186 if (applet_putchk(appctx, &trash) == -1)
1187 goto yield;
1188 ctx->state = ADDCRT_ST_FIN;
1189 break;
1190
1191 case ADDCRT_ST_ERROR:
1192 error:
1193 chunk_printf(&trash, "\n%sFailed!\n", ctx->err);
1194 if (applet_putchk(appctx, &trash) == -1)
1195 goto yield;
1196 break;
1197
Willy Tarreaufa11df52022-05-05 13:48:40 +02001198 default:
1199 break;
William Lallemandc756bbd2020-05-13 17:23:59 +02001200 }
1201
Christopher Fauletc642d7c2022-06-01 16:31:09 +02001202end:
William Lallemandc756bbd2020-05-13 17:23:59 +02001203 /* success: call the release function and don't come back */
1204 return 1;
1205yield:
William Lallemandc756bbd2020-05-13 17:23:59 +02001206 return 0; /* should come back */
William Lallemandc756bbd2020-05-13 17:23:59 +02001207}
1208
1209
1210/*
1211 * Parse a "add ssl crt-list <crt-list> <certfile>" line.
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001212 * Filters and option must be passed through payload.
1213 * It sets a struct add_crtlist_ctx.
William Lallemandc756bbd2020-05-13 17:23:59 +02001214 */
1215static int cli_parse_add_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
1216{
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001217 struct add_crtlist_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
William Lallemandc756bbd2020-05-13 17:23:59 +02001218 int cfgerr = 0;
1219 struct ckch_store *store;
1220 char *err = NULL;
1221 char path[MAXPATHLEN+1];
1222 char *crtlist_path;
1223 char *cert_path = NULL;
1224 struct ebmb_node *eb;
1225 struct ebpt_node *inserted;
1226 struct crtlist *crtlist;
1227 struct crtlist_entry *entry = NULL;
William Lallemand99cc2182020-06-25 15:19:51 +02001228 char *end;
William Lallemandc756bbd2020-05-13 17:23:59 +02001229
1230 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1231 return 1;
1232
1233 if (!*args[3] || (!payload && !*args[4]))
1234 return cli_err(appctx, "'add ssl crtlist' expects a filename and a certificate name\n");
1235
1236 crtlist_path = args[3];
1237
William Lallemand99cc2182020-06-25 15:19:51 +02001238 /* strip trailing slashes, including first one */
1239 for (end = crtlist_path + strlen(crtlist_path) - 1; end >= crtlist_path && *end == '/'; end--)
1240 *end = 0;
1241
William Lallemandc756bbd2020-05-13 17:23:59 +02001242 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1243 return cli_err(appctx, "Operations on certificates are currently locked!\n");
1244
1245 eb = ebst_lookup(&crtlists_tree, crtlist_path);
1246 if (!eb) {
1247 memprintf(&err, "crt-list '%s' does not exist!", crtlist_path);
1248 goto error;
1249 }
1250 crtlist = ebmb_entry(eb, struct crtlist, node);
1251
1252 entry = crtlist_entry_new();
1253 if (entry == NULL) {
1254 memprintf(&err, "Not enough memory!");
1255 goto error;
1256 }
1257
1258 if (payload) {
1259 char *lf;
1260
1261 lf = strrchr(payload, '\n');
1262 if (lf) {
1263 memprintf(&err, "only one line of payload is supported!");
1264 goto error;
1265 }
1266 /* cert_path is filled here */
Remi Tricot-Le Bretonfb00f312021-03-23 16:41:53 +01001267 cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 1, 1, &err);
William Lallemandc756bbd2020-05-13 17:23:59 +02001268 if (cfgerr & ERR_CODE)
1269 goto error;
1270 } else {
1271 cert_path = args[4];
1272 }
1273
1274 if (!cert_path) {
1275 memprintf(&err, "'add ssl crtlist' should contain the certificate name in the payload");
1276 cfgerr |= ERR_ALERT | ERR_FATAL;
1277 goto error;
1278 }
1279
1280 if (eb_gettag(crtlist->entries.b[EB_RGHT])) {
1281 char *slash;
1282
1283 slash = strrchr(cert_path, '/');
1284 if (!slash) {
1285 memprintf(&err, "'%s' is a directory, certificate path '%s' must contain the directory path", (char *)crtlist->node.key, cert_path);
1286 goto error;
1287 }
1288 /* temporary replace / by 0 to do an strcmp */
1289 *slash = '\0';
1290 if (strcmp(cert_path, (char*)crtlist->node.key) != 0) {
1291 *slash = '/';
1292 memprintf(&err, "'%s' is a directory, certificate path '%s' must contain the directory path", (char *)crtlist->node.key, cert_path);
1293 goto error;
1294 }
1295 *slash = '/';
1296 }
1297
1298 if (*cert_path != '/' && global_ssl.crt_base) {
Willy Tarreau393e42a2022-05-09 10:31:28 +02001299 if ((strlen(global_ssl.crt_base) + 1 + strlen(cert_path)) > sizeof(path) ||
1300 snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, cert_path) > sizeof(path)) {
William Lallemandc756bbd2020-05-13 17:23:59 +02001301 memprintf(&err, "'%s' : path too long", cert_path);
1302 cfgerr |= ERR_ALERT | ERR_FATAL;
1303 goto error;
1304 }
William Lallemandc756bbd2020-05-13 17:23:59 +02001305 cert_path = path;
1306 }
1307
1308 store = ckchs_lookup(cert_path);
1309 if (store == NULL) {
1310 memprintf(&err, "certificate '%s' does not exist!", cert_path);
1311 goto error;
1312 }
William Lallemand52ddd992022-11-22 11:51:53 +01001313 if (store->data == NULL || store->data->cert == NULL) {
William Lallemandc756bbd2020-05-13 17:23:59 +02001314 memprintf(&err, "certificate '%s' is empty!", cert_path);
1315 goto error;
1316 }
1317
1318 /* check if it's possible to insert this new crtlist_entry */
1319 entry->node.key = store;
1320 inserted = ebpt_insert(&crtlist->entries, &entry->node);
1321 if (inserted != &entry->node) {
1322 memprintf(&err, "file already exists in this directory!");
1323 goto error;
1324 }
1325
1326 /* this is supposed to be a directory (EB_ROOT_UNIQUE), so no ssl_conf are allowed */
1327 if ((entry->ssl_conf || entry->filters) && eb_gettag(crtlist->entries.b[EB_RGHT])) {
1328 memprintf(&err, "this is a directory, SSL configuration and filters are not allowed");
1329 goto error;
1330 }
1331
Willy Tarreau2b718102021-04-21 07:32:39 +02001332 LIST_APPEND(&crtlist->ord_entries, &entry->by_crtlist);
William Lallemandc756bbd2020-05-13 17:23:59 +02001333 entry->crtlist = crtlist;
Willy Tarreau2b718102021-04-21 07:32:39 +02001334 LIST_APPEND(&store->crtlist_entry, &entry->by_ckch_store);
William Lallemandc756bbd2020-05-13 17:23:59 +02001335
Willy Tarreaufa11df52022-05-05 13:48:40 +02001336 ctx->state = ADDCRT_ST_INIT;
Willy Tarreau6b6c3632022-05-05 13:43:49 +02001337 ctx->crtlist = crtlist;
1338 ctx->entry = entry;
William Lallemandc756bbd2020-05-13 17:23:59 +02001339
1340 /* unlock is done in the release handler */
1341 return 0;
1342
1343error:
1344 crtlist_entry_free(entry);
1345 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1346 err = memprintf(&err, "Can't edit the crt-list: %s\n", err ? err : "");
1347 return cli_dynerr(appctx, err);
1348}
1349
1350/* Parse a "del ssl crt-list <crt-list> <certfile>" line. */
1351static int cli_parse_del_crtlist(char **args, char *payload, struct appctx *appctx, void *private)
1352{
1353 struct ckch_store *store;
1354 char *err = NULL;
1355 char *crtlist_path, *cert_path;
1356 struct ebmb_node *ebmb;
1357 struct ebpt_node *ebpt;
1358 struct crtlist *crtlist;
1359 struct crtlist_entry *entry = NULL;
1360 struct ckch_inst *inst, *inst_s;
1361 int linenum = 0;
1362 char *colons;
William Lallemand99cc2182020-06-25 15:19:51 +02001363 char *end;
Remi Tricot-Le Bretonbc2c3862021-03-26 10:47:50 +01001364 int error_message_dumped = 0;
William Lallemandc756bbd2020-05-13 17:23:59 +02001365
1366 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1367 return 1;
1368
1369 if (!*args[3] || !*args[4])
1370 return cli_err(appctx, "'del ssl crtlist' expects a filename and a certificate name\n");
1371
1372 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1373 return cli_err(appctx, "Can't delete!\nOperations on certificates are currently locked!\n");
1374
1375 crtlist_path = args[3];
1376 cert_path = args[4];
1377
1378 colons = strchr(cert_path, ':');
1379 if (colons) {
1380 char *endptr;
1381
1382 linenum = strtol(colons + 1, &endptr, 10);
1383 if (colons + 1 == endptr || *endptr != '\0') {
1384 memprintf(&err, "wrong line number after colons in '%s'!", cert_path);
1385 goto error;
1386 }
1387 *colons = '\0';
1388 }
William Lallemand99cc2182020-06-25 15:19:51 +02001389
1390 /* strip trailing slashes, including first one */
1391 for (end = crtlist_path + strlen(crtlist_path) - 1; end >= crtlist_path && *end == '/'; end--)
1392 *end = 0;
1393
William Lallemandc756bbd2020-05-13 17:23:59 +02001394 /* look for crtlist */
1395 ebmb = ebst_lookup(&crtlists_tree, crtlist_path);
1396 if (!ebmb) {
1397 memprintf(&err, "crt-list '%s' does not exist!", crtlist_path);
1398 goto error;
1399 }
1400 crtlist = ebmb_entry(ebmb, struct crtlist, node);
1401
1402 /* look for store */
1403 store = ckchs_lookup(cert_path);
1404 if (store == NULL) {
1405 memprintf(&err, "certificate '%s' does not exist!", cert_path);
1406 goto error;
1407 }
William Lallemand52ddd992022-11-22 11:51:53 +01001408 if (store->data == NULL || store->data->cert == NULL) {
William Lallemandc756bbd2020-05-13 17:23:59 +02001409 memprintf(&err, "certificate '%s' is empty!", cert_path);
1410 goto error;
1411 }
1412
1413 ebpt = ebpt_lookup(&crtlist->entries, store);
1414 if (!ebpt) {
1415 memprintf(&err, "certificate '%s' can't be found in crt-list '%s'!", cert_path, crtlist_path);
1416 goto error;
1417 }
1418
1419 /* list the line number of entries for errors in err, and select the right ebpt */
1420 for (; ebpt; ebpt = ebpt_next_dup(ebpt)) {
1421 struct crtlist_entry *tmp;
1422
1423 tmp = ebpt_entry(ebpt, struct crtlist_entry, node);
1424 memprintf(&err, "%s%s%d", err ? err : "", err ? ", " : "", tmp->linenum);
1425
1426 /* select the entry we wanted */
1427 if (linenum == 0 || tmp->linenum == linenum) {
1428 if (!entry)
1429 entry = tmp;
1430 }
1431 }
1432
1433 /* we didn't found the specified entry */
1434 if (!entry) {
1435 memprintf(&err, "found a certificate '%s' but the line number is incorrect, please specify a correct line number preceded by colons (%s)!", cert_path, err ? err : NULL);
1436 goto error;
1437 }
1438
1439 /* we didn't specified a line number but there were several entries */
1440 if (linenum == 0 && ebpt_next_dup(&entry->node)) {
1441 memprintf(&err, "found the certificate '%s' in several entries, please specify a line number preceded by colons (%s)!", cert_path, err ? err : NULL);
1442 goto error;
1443 }
1444
Remi Tricot-Le Bretonbc2c3862021-03-26 10:47:50 +01001445 /* Iterate over all the instances in order to see if any of them is a
1446 * default instance. If this is the case, the entry won't be suppressed. */
1447 list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
1448 if (inst->is_default && !inst->bind_conf->strict_sni) {
1449 if (!error_message_dumped) {
1450 memprintf(&err, "certificate '%s' cannot be deleted, it is used as default certificate by the following frontends:\n", cert_path);
1451 error_message_dumped = 1;
1452 }
1453 memprintf(&err, "%s\t- %s:%d\n", err, inst->bind_conf->file, inst->bind_conf->line);
1454 }
1455 }
1456 if (error_message_dumped)
1457 goto error;
1458
William Lallemandc756bbd2020-05-13 17:23:59 +02001459 /* upon error free the ckch_inst and everything inside */
1460
1461 ebpt_delete(&entry->node);
Willy Tarreau2b718102021-04-21 07:32:39 +02001462 LIST_DELETE(&entry->by_crtlist);
1463 LIST_DELETE(&entry->by_ckch_store);
William Lallemandc756bbd2020-05-13 17:23:59 +02001464
1465 list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
1466 struct sni_ctx *sni, *sni_s;
Remi Tricot-Le Breton4458b972021-02-19 17:41:55 +01001467 struct ckch_inst_link_ref *link_ref, *link_ref_s;
William Lallemandc756bbd2020-05-13 17:23:59 +02001468
1469 HA_RWLOCK_WRLOCK(SNI_LOCK, &inst->bind_conf->sni_lock);
1470 list_for_each_entry_safe(sni, sni_s, &inst->sni_ctx, by_ckch_inst) {
1471 ebmb_delete(&sni->name);
Willy Tarreau2b718102021-04-21 07:32:39 +02001472 LIST_DELETE(&sni->by_ckch_inst);
William Lallemandc756bbd2020-05-13 17:23:59 +02001473 SSL_CTX_free(sni->ctx);
1474 free(sni);
1475 }
1476 HA_RWLOCK_WRUNLOCK(SNI_LOCK, &inst->bind_conf->sni_lock);
Willy Tarreau2b718102021-04-21 07:32:39 +02001477 LIST_DELETE(&inst->by_ckchs);
Remi Tricot-Le Breton4458b972021-02-19 17:41:55 +01001478 list_for_each_entry_safe(link_ref, link_ref_s, &inst->cafile_link_refs, list) {
1479 LIST_DELETE(&link_ref->link->list);
1480 LIST_DELETE(&link_ref->list);
1481 free(link_ref);
1482 }
William Lallemandc756bbd2020-05-13 17:23:59 +02001483 free(inst);
1484 }
1485
1486 crtlist_free_filters(entry->filters);
1487 ssl_sock_free_ssl_conf(entry->ssl_conf);
1488 free(entry->ssl_conf);
1489 free(entry);
1490
1491 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1492 err = memprintf(&err, "Entry '%s' deleted in crtlist '%s'!\n", cert_path, crtlist_path);
1493 return cli_dynmsg(appctx, LOG_NOTICE, err);
1494
1495error:
1496 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1497 err = memprintf(&err, "Can't delete the entry: %s\n", err ? err : "");
1498 return cli_dynerr(appctx, err);
1499}
1500
1501
William Lallemandee8530c2020-06-23 18:19:42 +02001502/* unlink and free all crt-list and crt-list entries */
1503void crtlist_deinit()
1504{
1505 struct eb_node *node, *next;
1506 struct crtlist *crtlist;
1507
1508 node = eb_first(&crtlists_tree);
1509 while (node) {
1510 next = eb_next(node);
1511 crtlist = ebmb_entry(node, struct crtlist, node);
1512 crtlist_free(crtlist);
1513 node = next;
1514 }
1515}
1516
William Lallemandc756bbd2020-05-13 17:23:59 +02001517
1518/* register cli keywords */
1519static struct cli_kw_list cli_kws = {{ },{
Willy Tarreaub205bfd2021-05-07 11:38:37 +02001520 { { "add", "ssl", "crt-list", NULL }, "add ssl crt-list <list> <cert> [opts]* : add to crt-list file <list> a line <cert> or a payload", cli_parse_add_crtlist, cli_io_handler_add_crtlist, cli_release_add_crtlist },
1521 { { "del", "ssl", "crt-list", NULL }, "del ssl crt-list <list> <cert[:line]> : delete a line <cert> from crt-list file <list>", cli_parse_del_crtlist, NULL, NULL },
1522 { { "show", "ssl", "crt-list", NULL }, "show ssl crt-list [-n] [<list>] : show the list of crt-lists or the content of a crt-list file <list>", cli_parse_dump_crtlist, cli_io_handler_dump_crtlist, NULL },
William Lallemandc756bbd2020-05-13 17:23:59 +02001523 { { NULL }, NULL, NULL, NULL } }
1524};
1525
1526INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
1527