blob: ec74c179df880ceb7353b0424976b9889022c116 [file] [log] [blame]
William Lallemand03c331c2020-05-13 10:10:01 +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 */
11
12#define _GNU_SOURCE
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020019#include <syslog.h>
William Lallemand03c331c2020-05-13 10:10:01 +020020#include <unistd.h>
21
22#include <sys/stat.h>
23#include <sys/types.h>
24
Willy Tarreaub2551052020-06-09 09:07:15 +020025#include <import/ebsttree.h>
26
Willy Tarreau8d366972020-05-27 16:10:29 +020027#include <haproxy/base64.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020028#include <haproxy/channel.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020029#include <haproxy/cli.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020030#include <haproxy/errors.h>
Willy Tarreau47d7f902020-06-04 14:25:47 +020031#include <haproxy/ssl_ckch.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020032#include <haproxy/ssl_sock.h>
Willy Tarreaub2bd8652020-06-04 14:21:22 +020033#include <haproxy/ssl_utils.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020034#include <haproxy/stream_interface.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020035#include <haproxy/tools.h>
William Lallemand03c331c2020-05-13 10:10:01 +020036
William Lallemandda8584c2020-05-14 10:14:37 +020037/* Uncommitted CKCH transaction */
38
39static struct {
40 struct ckch_store *new_ckchs;
41 struct ckch_store *old_ckchs;
42 char *path;
43} ckchs_transaction;
44
45
William Lallemand03c331c2020-05-13 10:10:01 +020046
47/******************** cert_key_and_chain functions *************************
48 * These are the functions that fills a cert_key_and_chain structure. For the
49 * functions filling a SSL_CTX from a cert_key_and_chain, see ssl_sock.c
50 */
51
52/*
53 * Try to parse Signed Certificate Timestamp List structure. This function
54 * makes only basic test if the data seems like SCTL. No signature validation
55 * is performed.
56 */
57static int ssl_sock_parse_sctl(struct buffer *sctl)
58{
59 int ret = 1;
60 int len, pos, sct_len;
61 unsigned char *data;
62
63 if (sctl->data < 2)
64 goto out;
65
66 data = (unsigned char *) sctl->area;
67 len = (data[0] << 8) | data[1];
68
69 if (len + 2 != sctl->data)
70 goto out;
71
72 data = data + 2;
73 pos = 0;
74 while (pos < len) {
75 if (len - pos < 2)
76 goto out;
77
78 sct_len = (data[pos] << 8) | data[pos + 1];
79 if (pos + sct_len + 2 > len)
80 goto out;
81
82 pos += sct_len + 2;
83 }
84
85 ret = 0;
86
87out:
88 return ret;
89}
90
91/* Try to load a sctl from a buffer <buf> if not NULL, or read the file <sctl_path>
92 * It fills the ckch->sctl buffer
93 * return 0 on success or != 0 on failure */
94int ssl_sock_load_sctl_from_file(const char *sctl_path, char *buf, struct cert_key_and_chain *ckch, char **err)
95{
96 int fd = -1;
97 int r = 0;
98 int ret = 1;
99 struct buffer tmp;
100 struct buffer *src;
101 struct buffer *sctl;
102
103 if (buf) {
104 tmp.area = buf;
105 tmp.data = strlen(buf);
106 tmp.size = tmp.data + 1;
107 src = &tmp;
108 } else {
109 fd = open(sctl_path, O_RDONLY);
110 if (fd == -1)
111 goto end;
112
113 trash.data = 0;
114 while (trash.data < trash.size) {
115 r = read(fd, trash.area + trash.data, trash.size - trash.data);
116 if (r < 0) {
117 if (errno == EINTR)
118 continue;
119 goto end;
120 }
121 else if (r == 0) {
122 break;
123 }
124 trash.data += r;
125 }
126 src = &trash;
127 }
128
129 ret = ssl_sock_parse_sctl(src);
130 if (ret)
131 goto end;
132
133 sctl = calloc(1, sizeof(*sctl));
134 if (!chunk_dup(sctl, src)) {
135 free(sctl);
136 sctl = NULL;
137 goto end;
138 }
139 /* no error, fill ckch with new context, old context must be free */
140 if (ckch->sctl) {
141 free(ckch->sctl->area);
142 ckch->sctl->area = NULL;
143 free(ckch->sctl);
144 }
145 ckch->sctl = sctl;
146 ret = 0;
147end:
148 if (fd != -1)
149 close(fd);
150
151 return ret;
152}
153
154#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) || defined OPENSSL_IS_BORINGSSL)
155/*
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500156 * This function load the OCSP Response in DER format contained in file at
William Lallemand03c331c2020-05-13 10:10:01 +0200157 * path 'ocsp_path' or base64 in a buffer <buf>
158 *
159 * Returns 0 on success, 1 in error case.
160 */
161int ssl_sock_load_ocsp_response_from_file(const char *ocsp_path, char *buf, struct cert_key_and_chain *ckch, char **err)
162{
163 int fd = -1;
164 int r = 0;
165 int ret = 1;
166 struct buffer *ocsp_response;
167 struct buffer *src = NULL;
168
169 if (buf) {
170 int i, j;
171 /* if it's from a buffer it will be base64 */
172
173 /* remove \r and \n from the payload */
174 for (i = 0, j = 0; buf[i]; i++) {
175 if (buf[i] == '\r' || buf[i] == '\n')
176 continue;
177 buf[j++] = buf[i];
178 }
179 buf[j] = 0;
180
181 ret = base64dec(buf, j, trash.area, trash.size);
182 if (ret < 0) {
183 memprintf(err, "Error reading OCSP response in base64 format");
184 goto end;
185 }
186 trash.data = ret;
187 src = &trash;
188 } else {
189 fd = open(ocsp_path, O_RDONLY);
190 if (fd == -1) {
191 memprintf(err, "Error opening OCSP response file");
192 goto end;
193 }
194
195 trash.data = 0;
196 while (trash.data < trash.size) {
197 r = read(fd, trash.area + trash.data, trash.size - trash.data);
198 if (r < 0) {
199 if (errno == EINTR)
200 continue;
201
202 memprintf(err, "Error reading OCSP response from file");
203 goto end;
204 }
205 else if (r == 0) {
206 break;
207 }
208 trash.data += r;
209 }
210 close(fd);
211 fd = -1;
212 src = &trash;
213 }
214
215 ocsp_response = calloc(1, sizeof(*ocsp_response));
216 if (!chunk_dup(ocsp_response, src)) {
217 free(ocsp_response);
218 ocsp_response = NULL;
219 goto end;
220 }
221 /* no error, fill ckch with new context, old context must be free */
222 if (ckch->ocsp_response) {
223 free(ckch->ocsp_response->area);
224 ckch->ocsp_response->area = NULL;
225 free(ckch->ocsp_response);
226 }
227 ckch->ocsp_response = ocsp_response;
228 ret = 0;
229end:
230 if (fd != -1)
231 close(fd);
232
233 return ret;
234}
235#endif
236
237/*
238 * Try to load in a ckch every files related to a ckch.
239 * (PEM, sctl, ocsp, issuer etc.)
240 *
241 * This function is only used to load files during the configuration parsing,
242 * it is not used with the CLI.
243 *
244 * This allows us to carry the contents of the file without having to read the
245 * file multiple times. The caller must call
246 * ssl_sock_free_cert_key_and_chain_contents.
247 *
248 * returns:
249 * 0 on Success
250 * 1 on SSL Failure
251 */
252int ssl_sock_load_files_into_ckch(const char *path, struct cert_key_and_chain *ckch, char **err)
253{
254 int ret = 1;
255
256 /* try to load the PEM */
257 if (ssl_sock_load_pem_into_ckch(path, NULL, ckch , err) != 0) {
258 goto end;
259 }
260
261 /* try to load an external private key if it wasn't in the PEM */
262 if ((ckch->key == NULL) && (global_ssl.extra_files & SSL_GF_KEY)) {
263 char fp[MAXPATHLEN+1];
264 struct stat st;
265
266 snprintf(fp, MAXPATHLEN+1, "%s.key", path);
267 if (stat(fp, &st) == 0) {
268 if (ssl_sock_load_key_into_ckch(fp, NULL, ckch, err)) {
269 memprintf(err, "%s '%s' is present but cannot be read or parsed'.\n",
270 err && *err ? *err : "", fp);
271 goto end;
272 }
273 }
274 }
275
276 if (ckch->key == NULL) {
277 memprintf(err, "%sNo Private Key found in '%s' or '%s.key'.\n", err && *err ? *err : "", path, path);
278 goto end;
279 }
280
281 if (!X509_check_private_key(ckch->cert, ckch->key)) {
282 memprintf(err, "%sinconsistencies between private key and certificate loaded '%s'.\n",
283 err && *err ? *err : "", path);
284 goto end;
285 }
286
287#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL)
288 /* try to load the sctl file */
289 if (global_ssl.extra_files & SSL_GF_SCTL) {
290 char fp[MAXPATHLEN+1];
291 struct stat st;
292
293 snprintf(fp, MAXPATHLEN+1, "%s.sctl", path);
294 if (stat(fp, &st) == 0) {
295 if (ssl_sock_load_sctl_from_file(fp, NULL, ckch, err)) {
296 memprintf(err, "%s '%s.sctl' is present but cannot be read or parsed'.\n",
297 err && *err ? *err : "", fp);
298 ret = 1;
299 goto end;
300 }
301 }
302 }
303#endif
304
305 /* try to load an ocsp response file */
306 if (global_ssl.extra_files & SSL_GF_OCSP) {
307 char fp[MAXPATHLEN+1];
308 struct stat st;
309
310 snprintf(fp, MAXPATHLEN+1, "%s.ocsp", path);
311 if (stat(fp, &st) == 0) {
312 if (ssl_sock_load_ocsp_response_from_file(fp, NULL, ckch, err)) {
313 ret = 1;
314 goto end;
315 }
316 }
317 }
318
319#ifndef OPENSSL_IS_BORINGSSL /* Useless for BoringSSL */
320 if (ckch->ocsp_response && (global_ssl.extra_files & SSL_GF_OCSP_ISSUER)) {
321 /* if no issuer was found, try to load an issuer from the .issuer */
322 if (!ckch->ocsp_issuer) {
323 struct stat st;
324 char fp[MAXPATHLEN+1];
325
326 snprintf(fp, MAXPATHLEN+1, "%s.issuer", path);
327 if (stat(fp, &st) == 0) {
328 if (ssl_sock_load_issuer_file_into_ckch(fp, NULL, ckch, err)) {
329 ret = 1;
330 goto end;
331 }
332
333 if (X509_check_issued(ckch->ocsp_issuer, ckch->cert) != X509_V_OK) {
334 memprintf(err, "%s '%s' is not an issuer'.\n",
335 err && *err ? *err : "", fp);
336 ret = 1;
337 goto end;
338 }
339 }
340 }
341 }
342#endif
343
344 ret = 0;
345
346end:
347
348 ERR_clear_error();
349
350 /* Something went wrong in one of the reads */
351 if (ret != 0)
352 ssl_sock_free_cert_key_and_chain_contents(ckch);
353
354 return ret;
355}
356
357/*
358 * Try to load a private key file from a <path> or a buffer <buf>
359 *
360 * If it failed you should not attempt to use the ckch but free it.
361 *
362 * Return 0 on success or != 0 on failure
363 */
364int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch , char **err)
365{
366 BIO *in = NULL;
367 int ret = 1;
368 EVP_PKEY *key = NULL;
369
370 if (buf) {
371 /* reading from a buffer */
372 in = BIO_new_mem_buf(buf, -1);
373 if (in == NULL) {
374 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
375 goto end;
376 }
377
378 } else {
379 /* reading from a file */
380 in = BIO_new(BIO_s_file());
381 if (in == NULL)
382 goto end;
383
384 if (BIO_read_filename(in, path) <= 0)
385 goto end;
386 }
387
388 /* Read Private Key */
389 key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
390 if (key == NULL) {
391 memprintf(err, "%sunable to load private key from file '%s'.\n",
392 err && *err ? *err : "", path);
393 goto end;
394 }
395
396 ret = 0;
397
398 SWAP(ckch->key, key);
399
400end:
401
402 ERR_clear_error();
403 if (in)
404 BIO_free(in);
405 if (key)
406 EVP_PKEY_free(key);
407
408 return ret;
409}
410
411/*
412 * Try to load a PEM file from a <path> or a buffer <buf>
413 * The PEM must contain at least a Certificate,
414 * It could contain a DH, a certificate chain and a PrivateKey.
415 *
416 * If it failed you should not attempt to use the ckch but free it.
417 *
418 * Return 0 on success or != 0 on failure
419 */
420int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch , char **err)
421{
422 BIO *in = NULL;
423 int ret = 1;
424 X509 *ca;
425 X509 *cert = NULL;
426 EVP_PKEY *key = NULL;
427 DH *dh = NULL;
428 STACK_OF(X509) *chain = NULL;
429
430 if (buf) {
431 /* reading from a buffer */
432 in = BIO_new_mem_buf(buf, -1);
433 if (in == NULL) {
434 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
435 goto end;
436 }
437
438 } else {
439 /* reading from a file */
440 in = BIO_new(BIO_s_file());
441 if (in == NULL) {
442 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
443 goto end;
444 }
445
446 if (BIO_read_filename(in, path) <= 0) {
447 memprintf(err, "%scannot open the file '%s'.\n",
448 err && *err ? *err : "", path);
449 goto end;
450 }
451 }
452
453 /* Read Private Key */
454 key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
455 /* no need to check for errors here, because the private key could be loaded later */
456
457#ifndef OPENSSL_NO_DH
458 /* Seek back to beginning of file */
459 if (BIO_reset(in) == -1) {
460 memprintf(err, "%san error occurred while reading the file '%s'.\n",
461 err && *err ? *err : "", path);
462 goto end;
463 }
464
465 dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
466 /* no need to return an error there, dh is not mandatory */
467#endif
468
469 /* Seek back to beginning of file */
470 if (BIO_reset(in) == -1) {
471 memprintf(err, "%san error occurred while reading the file '%s'.\n",
472 err && *err ? *err : "", path);
473 goto end;
474 }
475
476 /* Read Certificate */
477 cert = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
478 if (cert == NULL) {
479 memprintf(err, "%sunable to load certificate from file '%s'.\n",
480 err && *err ? *err : "", path);
481 goto end;
482 }
483
484 /* Look for a Certificate Chain */
485 while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
486 if (chain == NULL)
487 chain = sk_X509_new_null();
488 if (!sk_X509_push(chain, ca)) {
489 X509_free(ca);
490 goto end;
491 }
492 }
493
494 ret = ERR_get_error();
495 if (ret && (ERR_GET_LIB(ret) != ERR_LIB_PEM && ERR_GET_REASON(ret) != PEM_R_NO_START_LINE)) {
496 memprintf(err, "%sunable to load certificate chain from file '%s'.\n",
497 err && *err ? *err : "", path);
498 goto end;
499 }
500
501 /* once it loaded the PEM, it should remove everything else in the ckch */
502 if (ckch->ocsp_response) {
503 free(ckch->ocsp_response->area);
504 ckch->ocsp_response->area = NULL;
505 free(ckch->ocsp_response);
506 ckch->ocsp_response = NULL;
507 }
508
509 if (ckch->sctl) {
510 free(ckch->sctl->area);
511 ckch->sctl->area = NULL;
512 free(ckch->sctl);
513 ckch->sctl = NULL;
514 }
515
516 if (ckch->ocsp_issuer) {
517 X509_free(ckch->ocsp_issuer);
518 ckch->ocsp_issuer = NULL;
519 }
520
521 /* no error, fill ckch with new context, old context will be free at end: */
522 SWAP(ckch->key, key);
523 SWAP(ckch->dh, dh);
524 SWAP(ckch->cert, cert);
525 SWAP(ckch->chain, chain);
526
527 ret = 0;
528
529end:
530
531 ERR_clear_error();
532 if (in)
533 BIO_free(in);
534 if (key)
535 EVP_PKEY_free(key);
536 if (dh)
537 DH_free(dh);
538 if (cert)
539 X509_free(cert);
540 if (chain)
541 sk_X509_pop_free(chain, X509_free);
542
543 return ret;
544}
545
546/* Frees the contents of a cert_key_and_chain
547 */
548void ssl_sock_free_cert_key_and_chain_contents(struct cert_key_and_chain *ckch)
549{
550 if (!ckch)
551 return;
552
553 /* Free the certificate and set pointer to NULL */
554 if (ckch->cert)
555 X509_free(ckch->cert);
556 ckch->cert = NULL;
557
558 /* Free the key and set pointer to NULL */
559 if (ckch->key)
560 EVP_PKEY_free(ckch->key);
561 ckch->key = NULL;
562
563 /* Free each certificate in the chain */
564 if (ckch->chain)
565 sk_X509_pop_free(ckch->chain, X509_free);
566 ckch->chain = NULL;
567
568 if (ckch->dh)
569 DH_free(ckch->dh);
570 ckch->dh = NULL;
571
572 if (ckch->sctl) {
573 free(ckch->sctl->area);
574 ckch->sctl->area = NULL;
575 free(ckch->sctl);
576 ckch->sctl = NULL;
577 }
578
579 if (ckch->ocsp_response) {
580 free(ckch->ocsp_response->area);
581 ckch->ocsp_response->area = NULL;
582 free(ckch->ocsp_response);
583 ckch->ocsp_response = NULL;
584 }
585
586 if (ckch->ocsp_issuer)
587 X509_free(ckch->ocsp_issuer);
588 ckch->ocsp_issuer = NULL;
589}
590
591/*
592 *
593 * This function copy a cert_key_and_chain in memory
594 *
595 * It's used to try to apply changes on a ckch before committing them, because
596 * most of the time it's not possible to revert those changes
597 *
598 * Return a the dst or NULL
599 */
600struct cert_key_and_chain *ssl_sock_copy_cert_key_and_chain(struct cert_key_and_chain *src,
601 struct cert_key_and_chain *dst)
602{
603 if (src->cert) {
604 dst->cert = src->cert;
605 X509_up_ref(src->cert);
606 }
607
608 if (src->key) {
609 dst->key = src->key;
610 EVP_PKEY_up_ref(src->key);
611 }
612
613 if (src->chain) {
614 dst->chain = X509_chain_up_ref(src->chain);
615 }
616
617 if (src->dh) {
618 DH_up_ref(src->dh);
619 dst->dh = src->dh;
620 }
621
622 if (src->sctl) {
623 struct buffer *sctl;
624
625 sctl = calloc(1, sizeof(*sctl));
626 if (!chunk_dup(sctl, src->sctl)) {
627 free(sctl);
628 sctl = NULL;
629 goto error;
630 }
631 dst->sctl = sctl;
632 }
633
634 if (src->ocsp_response) {
635 struct buffer *ocsp_response;
636
637 ocsp_response = calloc(1, sizeof(*ocsp_response));
638 if (!chunk_dup(ocsp_response, src->ocsp_response)) {
639 free(ocsp_response);
640 ocsp_response = NULL;
641 goto error;
642 }
643 dst->ocsp_response = ocsp_response;
644 }
645
646 if (src->ocsp_issuer) {
647 X509_up_ref(src->ocsp_issuer);
648 dst->ocsp_issuer = src->ocsp_issuer;
649 }
650
651 return dst;
652
653error:
654
655 /* free everything */
656 ssl_sock_free_cert_key_and_chain_contents(dst);
657
658 return NULL;
659}
660
661/*
662 * return 0 on success or != 0 on failure
663 */
664int ssl_sock_load_issuer_file_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch, char **err)
665{
666 int ret = 1;
667 BIO *in = NULL;
668 X509 *issuer;
669
670 if (buf) {
671 /* reading from a buffer */
672 in = BIO_new_mem_buf(buf, -1);
673 if (in == NULL) {
674 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
675 goto end;
676 }
677
678 } else {
679 /* reading from a file */
680 in = BIO_new(BIO_s_file());
681 if (in == NULL)
682 goto end;
683
684 if (BIO_read_filename(in, path) <= 0)
685 goto end;
686 }
687
688 issuer = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
689 if (!issuer) {
690 memprintf(err, "%s'%s' cannot be read or parsed'.\n",
691 err && *err ? *err : "", path);
692 goto end;
693 }
694 /* no error, fill ckch with new context, old context must be free */
695 if (ckch->ocsp_issuer)
696 X509_free(ckch->ocsp_issuer);
697 ckch->ocsp_issuer = issuer;
698 ret = 0;
699
700end:
701
702 ERR_clear_error();
703 if (in)
704 BIO_free(in);
705
706 return ret;
707}
708
709/******************** ckch_store functions ***********************************
710 * The ckch_store is a structure used to cache and index the SSL files used in
711 * configuration
712 */
713
714/*
715 * Free a ckch_store, its ckch, its instances and remove it from the ebtree
716 */
717void ckch_store_free(struct ckch_store *store)
718{
719 struct ckch_inst *inst, *inst_s;
720
721 if (!store)
722 return;
723
724#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200L
725 if (store->multi) {
726 int n;
727
728 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++)
729 ssl_sock_free_cert_key_and_chain_contents(&store->ckch[n]);
730 } else
731#endif
732 {
733 ssl_sock_free_cert_key_and_chain_contents(store->ckch);
734 }
735
736 free(store->ckch);
737 store->ckch = NULL;
738
739 list_for_each_entry_safe(inst, inst_s, &store->ckch_inst, by_ckchs) {
740 ckch_inst_free(inst);
741 }
742 ebmb_delete(&store->node);
743 free(store);
744}
745
746/*
747 * create and initialize a ckch_store
748 * <path> is the key name
749 * <nmemb> is the number of store->ckch objects to allocate
750 *
751 * Return a ckch_store or NULL upon failure.
752 */
753struct ckch_store *ckch_store_new(const char *filename, int nmemb)
754{
755 struct ckch_store *store;
756 int pathlen;
757
758 pathlen = strlen(filename);
759 store = calloc(1, sizeof(*store) + pathlen + 1);
760 if (!store)
761 return NULL;
762
763 if (nmemb > 1)
764 store->multi = 1;
765 else
766 store->multi = 0;
767
768 memcpy(store->path, filename, pathlen + 1);
769
770 LIST_INIT(&store->ckch_inst);
771 LIST_INIT(&store->crtlist_entry);
772
773 store->ckch = calloc(nmemb, sizeof(*store->ckch));
774 if (!store->ckch)
775 goto error;
776
777 return store;
778error:
779 ckch_store_free(store);
780 return NULL;
781}
782
783/* allocate and duplicate a ckch_store
784 * Return a new ckch_store or NULL */
785struct ckch_store *ckchs_dup(const struct ckch_store *src)
786{
787 struct ckch_store *dst;
788
789 dst = ckch_store_new(src->path, src->multi ? SSL_SOCK_NUM_KEYTYPES : 1);
790
791#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
792 if (src->multi) {
793 int n;
794
795 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
796 if (&src->ckch[n]) {
797 if (!ssl_sock_copy_cert_key_and_chain(&src->ckch[n], &dst->ckch[n]))
798 goto error;
799 }
800 }
801 } else
802#endif
803 {
804 if (!ssl_sock_copy_cert_key_and_chain(src->ckch, dst->ckch))
805 goto error;
806 }
807
808 return dst;
809
810error:
811 ckch_store_free(dst);
812
813 return NULL;
814}
815
816/*
817 * lookup a path into the ckchs tree.
818 */
819struct ckch_store *ckchs_lookup(char *path)
820{
821 struct ebmb_node *eb;
822
823 eb = ebst_lookup(&ckchs_tree, path);
824 if (!eb)
825 return NULL;
826
827 return ebmb_entry(eb, struct ckch_store, node);
828}
829
830/*
831 * This function allocate a ckch_store and populate it with certificates from files.
832 */
833struct ckch_store *ckchs_load_cert_file(char *path, int multi, char **err)
834{
835 struct ckch_store *ckchs;
836
837 ckchs = ckch_store_new(path, multi ? SSL_SOCK_NUM_KEYTYPES : 1);
838 if (!ckchs) {
839 memprintf(err, "%sunable to allocate memory.\n", err && *err ? *err : "");
840 goto end;
841 }
842 if (!multi) {
843
844 if (ssl_sock_load_files_into_ckch(path, ckchs->ckch, err) == 1)
845 goto end;
846
847 /* insert into the ckchs tree */
848 memcpy(ckchs->path, path, strlen(path) + 1);
849 ebst_insert(&ckchs_tree, &ckchs->node);
850 } else {
851 int found = 0;
852#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
853 char fp[MAXPATHLEN+1] = {0};
854 int n = 0;
855
856 /* Load all possible certs and keys */
857 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
858 struct stat buf;
859 snprintf(fp, sizeof(fp), "%s.%s", path, SSL_SOCK_KEYTYPE_NAMES[n]);
860 if (stat(fp, &buf) == 0) {
861 if (ssl_sock_load_files_into_ckch(fp, &ckchs->ckch[n], err) == 1)
862 goto end;
863 found = 1;
864 ckchs->multi = 1;
865 }
866 }
867#endif
868
869 if (!found) {
870 memprintf(err, "%sDidn't find any certificate for bundle '%s'.\n", err && *err ? *err : "", path);
871 goto end;
872 }
873 /* insert into the ckchs tree */
874 memcpy(ckchs->path, path, strlen(path) + 1);
875 ebst_insert(&ckchs_tree, &ckchs->node);
876 }
877 return ckchs;
878
879end:
880 ckch_store_free(ckchs);
881
882 return NULL;
883}
884
William Lallemandfa1d8b42020-05-13 15:46:10 +0200885
886/******************** ckch_inst functions ******************************/
887
888/* unlink a ckch_inst, free all SNIs, free the ckch_inst */
889/* The caller must use the lock of the bind_conf if used with inserted SNIs */
890void ckch_inst_free(struct ckch_inst *inst)
891{
892 struct sni_ctx *sni, *sni_s;
893
894 if (inst == NULL)
895 return;
896
897 list_for_each_entry_safe(sni, sni_s, &inst->sni_ctx, by_ckch_inst) {
898 SSL_CTX_free(sni->ctx);
899 LIST_DEL(&sni->by_ckch_inst);
900 ebmb_delete(&sni->name);
901 free(sni);
902 }
903 LIST_DEL(&inst->by_ckchs);
904 LIST_DEL(&inst->by_crtlist_entry);
905 free(inst);
906}
907
908/* Alloc and init a ckch_inst */
909struct ckch_inst *ckch_inst_new()
910{
911 struct ckch_inst *ckch_inst;
912
913 ckch_inst = calloc(1, sizeof *ckch_inst);
914 if (!ckch_inst)
915 return NULL;
916
917 LIST_INIT(&ckch_inst->sni_ctx);
918 LIST_INIT(&ckch_inst->by_ckchs);
919 LIST_INIT(&ckch_inst->by_crtlist_entry);
920
921 return ckch_inst;
922}
923
William Lallemandda8584c2020-05-14 10:14:37 +0200924/*************************** CLI commands ***********************/
925
926/* Type of SSL payloads that can be updated over the CLI */
927
928enum {
929 CERT_TYPE_PEM = 0,
930 CERT_TYPE_KEY,
931#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) || defined OPENSSL_IS_BORINGSSL)
932 CERT_TYPE_OCSP,
933#endif
934 CERT_TYPE_ISSUER,
935#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL)
936 CERT_TYPE_SCTL,
937#endif
938 CERT_TYPE_MAX,
939};
940
941struct {
942 const char *ext;
943 int type;
944 int (*load)(const char *path, char *payload, struct cert_key_and_chain *ckch, char **err);
945 /* add a parsing callback */
946} cert_exts[CERT_TYPE_MAX+1] = {
947 [CERT_TYPE_PEM] = { "", CERT_TYPE_PEM, &ssl_sock_load_pem_into_ckch }, /* default mode, no extensions */
948 [CERT_TYPE_KEY] = { "key", CERT_TYPE_KEY, &ssl_sock_load_key_into_ckch },
949#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) || defined OPENSSL_IS_BORINGSSL)
950 [CERT_TYPE_OCSP] = { "ocsp", CERT_TYPE_OCSP, &ssl_sock_load_ocsp_response_from_file },
951#endif
952#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL)
953 [CERT_TYPE_SCTL] = { "sctl", CERT_TYPE_SCTL, &ssl_sock_load_sctl_from_file },
954#endif
955 [CERT_TYPE_ISSUER] = { "issuer", CERT_TYPE_ISSUER, &ssl_sock_load_issuer_file_into_ckch },
956 [CERT_TYPE_MAX] = { NULL, CERT_TYPE_MAX, NULL },
957};
958
959
960/* release function of the `show ssl cert' command */
961static void cli_release_show_cert(struct appctx *appctx)
962{
963 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
964}
965
966/* IO handler of "show ssl cert <filename>" */
967static int cli_io_handler_show_cert(struct appctx *appctx)
968{
969 struct buffer *trash = alloc_trash_chunk();
970 struct ebmb_node *node;
971 struct stream_interface *si = appctx->owner;
972 struct ckch_store *ckchs;
973
974 if (trash == NULL)
975 return 1;
976
977 if (!appctx->ctx.ssl.old_ckchs) {
978 if (ckchs_transaction.old_ckchs) {
979 ckchs = ckchs_transaction.old_ckchs;
980 chunk_appendf(trash, "# transaction\n");
981 if (!ckchs->multi) {
982 chunk_appendf(trash, "*%s\n", ckchs->path);
983#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
984 } else {
985 int n;
986
987 chunk_appendf(trash, "*%s:", ckchs->path);
988 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
989 if (ckchs->ckch[n].cert)
990 chunk_appendf(trash, " %s.%s\n", ckchs->path, SSL_SOCK_KEYTYPE_NAMES[n]);
991 }
992 chunk_appendf(trash, "\n");
993#endif
994 }
995 }
996 }
997
998 if (!appctx->ctx.cli.p0) {
999 chunk_appendf(trash, "# filename\n");
1000 node = ebmb_first(&ckchs_tree);
1001 } else {
1002 node = &((struct ckch_store *)appctx->ctx.cli.p0)->node;
1003 }
1004 while (node) {
1005 ckchs = ebmb_entry(node, struct ckch_store, node);
1006 if (!ckchs->multi) {
1007 chunk_appendf(trash, "%s\n", ckchs->path);
1008#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
1009 } else {
1010 int n;
1011
1012 chunk_appendf(trash, "%s:", ckchs->path);
1013 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
1014 if (ckchs->ckch[n].cert)
1015 chunk_appendf(trash, " %s.%s", ckchs->path, SSL_SOCK_KEYTYPE_NAMES[n]);
1016 }
1017 chunk_appendf(trash, "\n");
1018#endif
1019 }
1020
1021 node = ebmb_next(node);
1022 if (ci_putchk(si_ic(si), trash) == -1) {
1023 si_rx_room_blk(si);
1024 goto yield;
1025 }
1026 }
1027
1028 appctx->ctx.cli.p0 = NULL;
1029 free_trash_chunk(trash);
1030 return 1;
1031yield:
1032
1033 free_trash_chunk(trash);
1034 appctx->ctx.cli.p0 = ckchs;
1035 return 0; /* should come back */
1036}
1037
1038/*
1039 * Extract and format the DNS SAN extensions and copy result into a chuink
1040 * Return 0;
1041 */
1042#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1043static int ssl_sock_get_san_oneline(X509 *cert, struct buffer *out)
1044{
1045 int i;
1046 char *str;
1047 STACK_OF(GENERAL_NAME) *names = NULL;
1048
1049 names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1050 if (names) {
1051 for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
1052 GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
1053 if (i > 0)
1054 chunk_appendf(out, ", ");
1055 if (name->type == GEN_DNS) {
1056 if (ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.dNSName) >= 0) {
1057 chunk_appendf(out, "DNS:%s", str);
1058 OPENSSL_free(str);
1059 }
1060 }
1061 }
1062 sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
1063 }
1064 return 0;
1065}
1066#endif
1067
1068
1069
1070
1071/* IO handler of the details "show ssl cert <filename>" */
1072static int cli_io_handler_show_cert_detail(struct appctx *appctx)
1073{
1074 struct stream_interface *si = appctx->owner;
1075 struct ckch_store *ckchs = appctx->ctx.cli.p0;
1076 struct buffer *out = alloc_trash_chunk();
1077 struct buffer *tmp = alloc_trash_chunk();
1078 X509_NAME *name = NULL;
1079 STACK_OF(X509) *chain;
1080 unsigned int len = 0;
1081 int write = -1;
1082 BIO *bio = NULL;
1083 int i;
1084
1085 if (!tmp || !out)
1086 goto end_no_putchk;
1087
1088 if (!ckchs->multi) {
1089 chunk_appendf(out, "Filename: ");
1090 if (ckchs == ckchs_transaction.new_ckchs)
1091 chunk_appendf(out, "*");
1092 chunk_appendf(out, "%s\n", ckchs->path);
1093
1094 chunk_appendf(out, "Status: ");
1095 if (ckchs->ckch->cert == NULL)
1096 chunk_appendf(out, "Empty\n");
1097 else if (LIST_ISEMPTY(&ckchs->ckch_inst))
1098 chunk_appendf(out, "Unused\n");
1099 else
1100 chunk_appendf(out, "Used\n");
1101
1102 if (ckchs->ckch->cert == NULL)
1103 goto end;
1104
1105 chain = ckchs->ckch->chain;
1106 if (chain == NULL) {
1107 struct issuer_chain *issuer;
1108 issuer = ssl_get0_issuer_chain(ckchs->ckch->cert);
1109 if (issuer) {
1110 chain = issuer->chain;
1111 chunk_appendf(out, "Chain Filename: ");
1112 chunk_appendf(out, "%s\n", issuer->path);
1113 }
1114 }
1115 chunk_appendf(out, "Serial: ");
1116 if (ssl_sock_get_serial(ckchs->ckch->cert, tmp) == -1)
1117 goto end;
1118 dump_binary(out, tmp->area, tmp->data);
1119 chunk_appendf(out, "\n");
1120
1121 chunk_appendf(out, "notBefore: ");
1122 chunk_reset(tmp);
1123 if ((bio = BIO_new(BIO_s_mem())) == NULL)
1124 goto end;
1125 if (ASN1_TIME_print(bio, X509_getm_notBefore(ckchs->ckch->cert)) == 0)
1126 goto end;
1127 write = BIO_read(bio, tmp->area, tmp->size-1);
1128 tmp->area[write] = '\0';
1129 BIO_free(bio);
1130 bio = NULL;
1131 chunk_appendf(out, "%s\n", tmp->area);
1132
1133 chunk_appendf(out, "notAfter: ");
1134 chunk_reset(tmp);
1135 if ((bio = BIO_new(BIO_s_mem())) == NULL)
1136 goto end;
1137 if (ASN1_TIME_print(bio, X509_getm_notAfter(ckchs->ckch->cert)) == 0)
1138 goto end;
1139 if ((write = BIO_read(bio, tmp->area, tmp->size-1)) <= 0)
1140 goto end;
1141 tmp->area[write] = '\0';
1142 BIO_free(bio);
1143 bio = NULL;
1144 chunk_appendf(out, "%s\n", tmp->area);
1145
1146#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1147 chunk_appendf(out, "Subject Alternative Name: ");
1148 if (ssl_sock_get_san_oneline(ckchs->ckch->cert, out) == -1)
1149 goto end;
1150 *(out->area + out->data) = '\0';
1151 chunk_appendf(out, "\n");
1152#endif
1153 chunk_reset(tmp);
1154 chunk_appendf(out, "Algorithm: ");
1155 if (cert_get_pkey_algo(ckchs->ckch->cert, tmp) == 0)
1156 goto end;
1157 chunk_appendf(out, "%s\n", tmp->area);
1158
1159 chunk_reset(tmp);
1160 chunk_appendf(out, "SHA1 FingerPrint: ");
1161 if (X509_digest(ckchs->ckch->cert, EVP_sha1(), (unsigned char *) tmp->area, &len) == 0)
1162 goto end;
1163 tmp->data = len;
1164 dump_binary(out, tmp->area, tmp->data);
1165 chunk_appendf(out, "\n");
1166
1167 chunk_appendf(out, "Subject: ");
1168 if ((name = X509_get_subject_name(ckchs->ckch->cert)) == NULL)
1169 goto end;
1170 if ((ssl_sock_get_dn_oneline(name, tmp)) == -1)
1171 goto end;
1172 *(tmp->area + tmp->data) = '\0';
1173 chunk_appendf(out, "%s\n", tmp->area);
1174
1175 chunk_appendf(out, "Issuer: ");
1176 if ((name = X509_get_issuer_name(ckchs->ckch->cert)) == NULL)
1177 goto end;
1178 if ((ssl_sock_get_dn_oneline(name, tmp)) == -1)
1179 goto end;
1180 *(tmp->area + tmp->data) = '\0';
1181 chunk_appendf(out, "%s\n", tmp->area);
1182
1183 /* Displays subject of each certificate in the chain */
1184 for (i = 0; i < sk_X509_num(chain); i++) {
1185 X509 *ca = sk_X509_value(chain, i);
1186
1187 chunk_appendf(out, "Chain Subject: ");
1188 if ((name = X509_get_subject_name(ca)) == NULL)
1189 goto end;
1190 if ((ssl_sock_get_dn_oneline(name, tmp)) == -1)
1191 goto end;
1192 *(tmp->area + tmp->data) = '\0';
1193 chunk_appendf(out, "%s\n", tmp->area);
1194
1195 chunk_appendf(out, "Chain Issuer: ");
1196 if ((name = X509_get_issuer_name(ca)) == NULL)
1197 goto end;
1198 if ((ssl_sock_get_dn_oneline(name, tmp)) == -1)
1199 goto end;
1200 *(tmp->area + tmp->data) = '\0';
1201 chunk_appendf(out, "%s\n", tmp->area);
1202 }
1203 }
1204
1205end:
1206 if (ci_putchk(si_ic(si), out) == -1) {
1207 si_rx_room_blk(si);
1208 goto yield;
1209 }
1210
1211end_no_putchk:
1212 if (bio)
1213 BIO_free(bio);
1214 free_trash_chunk(tmp);
1215 free_trash_chunk(out);
1216 return 1;
1217yield:
1218 free_trash_chunk(tmp);
1219 free_trash_chunk(out);
1220 return 0; /* should come back */
1221}
1222
1223/* parsing function for 'show ssl cert [certfile]' */
1224static int cli_parse_show_cert(char **args, char *payload, struct appctx *appctx, void *private)
1225{
1226 struct ckch_store *ckchs;
1227
1228 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
1229 return cli_err(appctx, "Can't allocate memory!\n");
1230
1231 /* The operations on the CKCH architecture are locked so we can
1232 * manipulate ckch_store and ckch_inst */
1233 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1234 return cli_err(appctx, "Can't show!\nOperations on certificates are currently locked!\n");
1235
1236 /* check if there is a certificate to lookup */
1237 if (*args[3]) {
1238 if (*args[3] == '*') {
1239 if (!ckchs_transaction.new_ckchs)
1240 goto error;
1241
1242 ckchs = ckchs_transaction.new_ckchs;
1243
1244 if (strcmp(args[3] + 1, ckchs->path))
1245 goto error;
1246
1247 } else {
1248 if ((ckchs = ckchs_lookup(args[3])) == NULL)
1249 goto error;
1250
1251 }
1252
1253 if (ckchs->multi)
1254 goto error;
1255
1256 appctx->ctx.cli.p0 = ckchs;
1257 /* use the IO handler that shows details */
1258 appctx->io_handler = cli_io_handler_show_cert_detail;
1259 }
1260
1261 return 0;
1262
1263error:
1264 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1265 return cli_err(appctx, "Can't display the certificate: Not found or the certificate is a bundle!\n");
1266}
1267
1268/* release function of the `set ssl cert' command, free things and unlock the spinlock */
1269static void cli_release_commit_cert(struct appctx *appctx)
1270{
1271 struct ckch_store *new_ckchs;
1272
1273 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1274
1275 if (appctx->st2 != SETCERT_ST_FIN) {
1276 /* free every new sni_ctx and the new store, which are not in the trees so no spinlock there */
1277 new_ckchs = appctx->ctx.ssl.new_ckchs;
1278
1279 /* if the allocation failed, we need to free everything from the temporary list */
1280 ckch_store_free(new_ckchs);
1281 }
1282}
1283
1284/*
1285 * This function tries to create the new ckch_inst and their SNIs
1286 */
1287static int cli_io_handler_commit_cert(struct appctx *appctx)
1288{
1289 struct stream_interface *si = appctx->owner;
1290 int y = 0;
1291 char *err = NULL;
1292 int errcode = 0;
1293 struct ckch_store *old_ckchs, *new_ckchs = NULL;
1294 struct ckch_inst *ckchi, *ckchis;
1295 struct buffer *trash = alloc_trash_chunk();
1296 struct sni_ctx *sc0, *sc0s;
1297 struct crtlist_entry *entry;
1298
1299 if (trash == NULL)
1300 goto error;
1301
1302 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
1303 goto error;
1304
1305 while (1) {
1306 switch (appctx->st2) {
1307 case SETCERT_ST_INIT:
1308 /* This state just print the update message */
1309 chunk_printf(trash, "Committing %s", ckchs_transaction.path);
1310 if (ci_putchk(si_ic(si), trash) == -1) {
1311 si_rx_room_blk(si);
1312 goto yield;
1313 }
1314 appctx->st2 = SETCERT_ST_GEN;
1315 /* fallthrough */
1316 case SETCERT_ST_GEN:
1317 /*
1318 * This state generates the ckch instances with their
1319 * sni_ctxs and SSL_CTX.
1320 *
1321 * Since the SSL_CTX generation can be CPU consumer, we
1322 * yield every 10 instances.
1323 */
1324
1325 old_ckchs = appctx->ctx.ssl.old_ckchs;
1326 new_ckchs = appctx->ctx.ssl.new_ckchs;
1327
1328 if (!new_ckchs)
1329 continue;
1330
1331 /* get the next ckchi to regenerate */
1332 ckchi = appctx->ctx.ssl.next_ckchi;
1333 /* we didn't start yet, set it to the first elem */
1334 if (ckchi == NULL)
1335 ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
1336
1337 /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
1338 list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
1339 struct ckch_inst *new_inst;
1340 char **sni_filter = NULL;
1341 int fcount = 0;
1342
1343 /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
1344 if (y >= 10) {
1345 /* save the next ckchi to compute */
1346 appctx->ctx.ssl.next_ckchi = ckchi;
1347 goto yield;
1348 }
1349
1350 if (ckchi->crtlist_entry) {
1351 sni_filter = ckchi->crtlist_entry->filters;
1352 fcount = ckchi->crtlist_entry->fcount;
1353 }
1354
1355 if (new_ckchs->multi)
1356 errcode |= ckch_inst_new_load_multi_store(new_ckchs->path, new_ckchs, ckchi->bind_conf, ckchi->ssl_conf, sni_filter, fcount, &new_inst, &err);
1357 else
1358 errcode |= ckch_inst_new_load_store(new_ckchs->path, new_ckchs, ckchi->bind_conf, ckchi->ssl_conf, sni_filter, fcount, &new_inst, &err);
1359
1360 if (errcode & ERR_CODE)
1361 goto error;
1362
1363 /* if the previous ckchi was used as the default */
1364 if (ckchi->is_default)
1365 new_inst->is_default = 1;
1366
1367 /* we need to initialize the SSL_CTX generated */
1368 /* this iterate on the newly generated SNIs in the new instance to prepare their SSL_CTX */
1369 list_for_each_entry_safe(sc0, sc0s, &new_inst->sni_ctx, by_ckch_inst) {
1370 if (!sc0->order) { /* we initialized only the first SSL_CTX because it's the same in the other sni_ctx's */
1371 errcode |= ssl_sock_prepare_ctx(ckchi->bind_conf, ckchi->ssl_conf, sc0->ctx, &err);
1372 if (errcode & ERR_CODE)
1373 goto error;
1374 }
1375 }
1376
1377
1378 /* display one dot per new instance */
1379 chunk_appendf(trash, ".");
1380 /* link the new ckch_inst to the duplicate */
1381 LIST_ADDQ(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
1382 y++;
1383 }
1384 appctx->st2 = SETCERT_ST_INSERT;
1385 /* fallthrough */
1386 case SETCERT_ST_INSERT:
1387 /* The generation is finished, we can insert everything */
1388
1389 old_ckchs = appctx->ctx.ssl.old_ckchs;
1390 new_ckchs = appctx->ctx.ssl.new_ckchs;
1391
1392 if (!new_ckchs)
1393 continue;
1394
1395 /* get the list of crtlist_entry in the old store, and update the pointers to the store */
1396 LIST_SPLICE(&new_ckchs->crtlist_entry, &old_ckchs->crtlist_entry);
1397 list_for_each_entry(entry, &new_ckchs->crtlist_entry, by_ckch_store) {
1398 ebpt_delete(&entry->node);
1399 /* change the ptr and reinsert the node */
1400 entry->node.key = new_ckchs;
1401 ebpt_insert(&entry->crtlist->entries, &entry->node);
1402 }
1403
1404 /* First, we insert every new SNIs in the trees, also replace the default_ctx */
1405 list_for_each_entry_safe(ckchi, ckchis, &new_ckchs->ckch_inst, by_ckchs) {
1406 HA_RWLOCK_WRLOCK(SNI_LOCK, &ckchi->bind_conf->sni_lock);
1407 ssl_sock_load_cert_sni(ckchi, ckchi->bind_conf);
1408 HA_RWLOCK_WRUNLOCK(SNI_LOCK, &ckchi->bind_conf->sni_lock);
1409 }
1410
1411 /* delete the old sni_ctx, the old ckch_insts and the ckch_store */
1412 list_for_each_entry_safe(ckchi, ckchis, &old_ckchs->ckch_inst, by_ckchs) {
1413 struct bind_conf __maybe_unused *bind_conf = ckchi->bind_conf;
1414
1415 HA_RWLOCK_WRLOCK(SNI_LOCK, &bind_conf->sni_lock);
1416 ckch_inst_free(ckchi);
1417 HA_RWLOCK_WRUNLOCK(SNI_LOCK, &bind_conf->sni_lock);
1418 }
1419
1420 /* Replace the old ckchs by the new one */
1421 ckch_store_free(old_ckchs);
1422 ebst_insert(&ckchs_tree, &new_ckchs->node);
1423 appctx->st2 = SETCERT_ST_FIN;
1424 /* fallthrough */
1425 case SETCERT_ST_FIN:
1426 /* we achieved the transaction, we can set everything to NULL */
1427 free(ckchs_transaction.path);
1428 ckchs_transaction.path = NULL;
1429 ckchs_transaction.new_ckchs = NULL;
1430 ckchs_transaction.old_ckchs = NULL;
1431 goto end;
1432 }
1433 }
1434end:
1435
1436 chunk_appendf(trash, "\n");
1437 if (errcode & ERR_WARN)
1438 chunk_appendf(trash, "%s", err);
1439 chunk_appendf(trash, "Success!\n");
1440 if (ci_putchk(si_ic(si), trash) == -1)
1441 si_rx_room_blk(si);
1442 free_trash_chunk(trash);
1443 /* success: call the release function and don't come back */
1444 return 1;
1445yield:
1446 /* store the state */
1447 if (ci_putchk(si_ic(si), trash) == -1)
1448 si_rx_room_blk(si);
1449 free_trash_chunk(trash);
1450 si_rx_endp_more(si); /* let's come back later */
1451 return 0; /* should come back */
1452
1453error:
1454 /* spin unlock and free are done in the release function */
1455 if (trash) {
1456 chunk_appendf(trash, "\n%sFailed!\n", err);
1457 if (ci_putchk(si_ic(si), trash) == -1)
1458 si_rx_room_blk(si);
1459 free_trash_chunk(trash);
1460 }
1461 /* error: call the release function and don't come back */
1462 return 1;
1463}
1464
1465/*
1466 * Parsing function of 'commit ssl cert'
1467 */
1468static int cli_parse_commit_cert(char **args, char *payload, struct appctx *appctx, void *private)
1469{
1470 char *err = NULL;
1471
1472 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1473 return 1;
1474
1475 if (!*args[3])
1476 return cli_err(appctx, "'commit ssl cert expects a filename\n");
1477
1478 /* The operations on the CKCH architecture are locked so we can
1479 * manipulate ckch_store and ckch_inst */
1480 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1481 return cli_err(appctx, "Can't commit the certificate!\nOperations on certificates are currently locked!\n");
1482
1483 if (!ckchs_transaction.path) {
1484 memprintf(&err, "No ongoing transaction! !\n");
1485 goto error;
1486 }
1487
1488 if (strcmp(ckchs_transaction.path, args[3]) != 0) {
1489 memprintf(&err, "The ongoing transaction is about '%s' but you are trying to set '%s'\n", ckchs_transaction.path, args[3]);
1490 goto error;
1491 }
1492
1493#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
1494 if (ckchs_transaction.new_ckchs->multi) {
1495 int n;
1496
1497 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
William Lallemanda9419522020-06-24 16:26:41 +02001498 /* if a certificate is here, a private key must be here too */
1499 if (ckchs_transaction.new_ckchs->ckch[n].cert && !ckchs_transaction.new_ckchs->ckch[n].key) {
1500 memprintf(&err, "The transaction must contain at least a certificate and a private key!\n");
1501 goto error;
1502 }
1503
William Lallemandda8584c2020-05-14 10:14:37 +02001504 if (ckchs_transaction.new_ckchs->ckch[n].cert && !X509_check_private_key(ckchs_transaction.new_ckchs->ckch[n].cert, ckchs_transaction.new_ckchs->ckch[n].key)) {
1505 memprintf(&err, "inconsistencies between private key and certificate loaded '%s'.\n", ckchs_transaction.path);
1506 goto error;
1507 }
1508 }
1509 } else
1510#endif
1511 {
William Lallemanda9419522020-06-24 16:26:41 +02001512 /* if a certificate is here, a private key must be here too */
1513 if (ckchs_transaction.new_ckchs->ckch->cert && !ckchs_transaction.new_ckchs->ckch->key) {
1514 memprintf(&err, "The transaction must contain at least a certificate and a private key!\n");
1515 goto error;
1516 }
1517
William Lallemandda8584c2020-05-14 10:14:37 +02001518 if (!X509_check_private_key(ckchs_transaction.new_ckchs->ckch->cert, ckchs_transaction.new_ckchs->ckch->key)) {
1519 memprintf(&err, "inconsistencies between private key and certificate loaded '%s'.\n", ckchs_transaction.path);
1520 goto error;
1521 }
1522 }
1523
1524 /* init the appctx structure */
1525 appctx->st2 = SETCERT_ST_INIT;
1526 appctx->ctx.ssl.next_ckchi = NULL;
1527 appctx->ctx.ssl.new_ckchs = ckchs_transaction.new_ckchs;
1528 appctx->ctx.ssl.old_ckchs = ckchs_transaction.old_ckchs;
1529
1530 /* we don't unlock there, it will be unlock after the IO handler, in the release handler */
1531 return 0;
1532
1533error:
1534
1535 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1536 err = memprintf(&err, "%sCan't commit %s!\n", err ? err : "", args[3]);
1537
1538 return cli_dynerr(appctx, err);
1539}
1540
1541
1542
1543
1544/*
1545 * Parsing function of `set ssl cert`, it updates or creates a temporary ckch.
1546 */
1547static int cli_parse_set_cert(char **args, char *payload, struct appctx *appctx, void *private)
1548{
1549 struct ckch_store *new_ckchs = NULL;
1550 struct ckch_store *old_ckchs = NULL;
1551 char *err = NULL;
1552 int i;
1553 int bundle = -1; /* TRUE if >= 0 (ckch index) */
1554 int errcode = 0;
1555 char *end;
1556 int type = CERT_TYPE_PEM;
1557 struct cert_key_and_chain *ckch;
1558 struct buffer *buf;
1559
1560 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1561 return 1;
1562
William Lallemandda8584c2020-05-14 10:14:37 +02001563 if (!*args[3] || !payload)
1564 return cli_err(appctx, "'set ssl cert expects a filename and a certificate as a payload\n");
1565
1566 /* The operations on the CKCH architecture are locked so we can
1567 * manipulate ckch_store and ckch_inst */
1568 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1569 return cli_err(appctx, "Can't update the certificate!\nOperations on certificates are currently locked!\n");
1570
William Lallemande5ff4ad2020-06-08 09:40:37 +02001571 if ((buf = alloc_trash_chunk()) == NULL)
1572 return cli_err(appctx, "Can't allocate memory\n");
1573
William Lallemandda8584c2020-05-14 10:14:37 +02001574 if (!chunk_strcpy(buf, args[3])) {
1575 memprintf(&err, "%sCan't allocate memory\n", err ? err : "");
1576 errcode |= ERR_ALERT | ERR_FATAL;
1577 goto end;
1578 }
1579
1580 /* check which type of file we want to update */
1581 for (i = 0; cert_exts[i].type < CERT_TYPE_MAX; i++) {
1582 end = strrchr(buf->area, '.');
1583 if (end && *cert_exts[i].ext && (!strcmp(end + 1, cert_exts[i].ext))) {
1584 *end = '\0';
1585 type = cert_exts[i].type;
1586 break;
1587 }
1588 }
1589
1590 appctx->ctx.ssl.old_ckchs = NULL;
1591 appctx->ctx.ssl.new_ckchs = NULL;
1592
1593 /* if there is an ongoing transaction */
1594 if (ckchs_transaction.path) {
1595 /* if the ongoing transaction is a bundle, we need to find which part of the bundle need to be updated */
1596#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
1597 if (ckchs_transaction.new_ckchs->multi) {
1598 char *end;
1599 int j;
1600
1601 /* check if it was used in a bundle by removing the
1602 * .dsa/.rsa/.ecdsa at the end of the filename */
1603 end = strrchr(buf->area, '.');
1604 for (j = 0; end && j < SSL_SOCK_NUM_KEYTYPES; j++) {
1605 if (!strcmp(end + 1, SSL_SOCK_KEYTYPE_NAMES[j])) {
1606 bundle = j; /* keep the type of certificate so we insert it at the right place */
1607 *end = '\0'; /* it's a bundle let's end the string*/
1608 break;
1609 }
1610 }
1611 if (bundle < 0) {
1612 memprintf(&err, "The ongoing transaction is the '%s' bundle. You need to specify which part of the bundle you want to update ('%s.{rsa,ecdsa,dsa}')\n", ckchs_transaction.path, buf->area);
1613 errcode |= ERR_ALERT | ERR_FATAL;
1614 goto end;
1615 }
1616 }
1617#endif
1618
1619 /* if there is an ongoing transaction, check if this is the same file */
1620 if (strcmp(ckchs_transaction.path, buf->area) != 0) {
1621 memprintf(&err, "The ongoing transaction is about '%s' but you are trying to set '%s'\n", ckchs_transaction.path, buf->area);
1622 errcode |= ERR_ALERT | ERR_FATAL;
1623 goto end;
1624 }
1625
1626 appctx->ctx.ssl.old_ckchs = ckchs_transaction.new_ckchs;
1627
1628 } else {
1629 struct ckch_store *find_ckchs[2] = { NULL, NULL };
1630
1631 /* lookup for the certificate in the tree:
1632 * check if this is used as a bundle AND as a unique certificate */
1633 for (i = 0; i < 2; i++) {
1634
1635 if ((find_ckchs[i] = ckchs_lookup(buf->area)) != NULL) {
1636 /* only the bundle name is in the tree and you should
1637 * never update a bundle name, only a filename */
1638 if (bundle < 0 && find_ckchs[i]->multi) {
1639 /* we tried to look for a non-bundle and we found a bundle */
1640 memprintf(&err, "%s%s is a multi-cert bundle. Try updating %s.{dsa,rsa,ecdsa}\n",
1641 err ? err : "", args[3], args[3]);
1642 errcode |= ERR_ALERT | ERR_FATAL;
1643 goto end;
1644 }
1645 /* If we want a bundle but this is not a bundle
1646 * example: When you try to update <file>.rsa, but
1647 * <file> is a regular file */
1648 if (bundle >= 0 && find_ckchs[i]->multi == 0) {
1649 find_ckchs[i] = NULL;
1650 break;
1651 }
1652 }
1653#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
1654 {
1655 char *end;
1656 int j;
1657
1658 /* check if it was used in a bundle by removing the
1659 * .dsa/.rsa/.ecdsa at the end of the filename */
1660 end = strrchr(buf->area, '.');
1661 for (j = 0; end && j < SSL_SOCK_NUM_KEYTYPES; j++) {
1662 if (!strcmp(end + 1, SSL_SOCK_KEYTYPE_NAMES[j])) {
1663 bundle = j; /* keep the type of certificate so we insert it at the right place */
1664 *end = '\0'; /* it's a bundle let's end the string*/
1665 break;
1666 }
1667 }
1668 if (bundle < 0) /* we didn't find a bundle extension */
1669 break;
1670 }
1671#else
1672 /* bundles are not supported here, so we don't need to lookup again */
1673 break;
1674#endif
1675 }
1676
1677 if (find_ckchs[0] && find_ckchs[1]) {
1678 memprintf(&err, "%sUpdating a certificate which is used in the HAProxy configuration as a bundle and as a unique certificate is not supported. ('%s' and '%s')\n",
1679 err ? err : "", find_ckchs[0]->path, find_ckchs[1]->path);
1680 errcode |= ERR_ALERT | ERR_FATAL;
1681 goto end;
1682 }
1683
1684 appctx->ctx.ssl.old_ckchs = find_ckchs[0] ? find_ckchs[0] : find_ckchs[1];
1685 }
1686
1687 if (!appctx->ctx.ssl.old_ckchs) {
1688 memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!\n",
1689 err ? err : "");
1690 errcode |= ERR_ALERT | ERR_FATAL;
1691 goto end;
1692 }
1693
1694 if (!appctx->ctx.ssl.path) {
1695 /* this is a new transaction, set the path of the transaction */
1696 appctx->ctx.ssl.path = strdup(appctx->ctx.ssl.old_ckchs->path);
1697 if (!appctx->ctx.ssl.path) {
1698 memprintf(&err, "%sCan't allocate memory\n", err ? err : "");
1699 errcode |= ERR_ALERT | ERR_FATAL;
1700 goto end;
1701 }
1702 }
1703
1704 old_ckchs = appctx->ctx.ssl.old_ckchs;
1705
1706 /* duplicate the ckch store */
1707 new_ckchs = ckchs_dup(old_ckchs);
1708 if (!new_ckchs) {
1709 memprintf(&err, "%sCannot allocate memory!\n",
1710 err ? err : "");
1711 errcode |= ERR_ALERT | ERR_FATAL;
1712 goto end;
1713 }
1714
1715 if (!new_ckchs->multi)
1716 ckch = new_ckchs->ckch;
1717 else
1718 ckch = &new_ckchs->ckch[bundle];
1719
1720 /* appply the change on the duplicate */
1721 if (cert_exts[type].load(buf->area, payload, ckch, &err) != 0) {
1722 memprintf(&err, "%sCan't load the payload\n", err ? err : "");
1723 errcode |= ERR_ALERT | ERR_FATAL;
1724 goto end;
1725 }
1726
1727 appctx->ctx.ssl.new_ckchs = new_ckchs;
1728
1729 /* we succeed, we can save the ckchs in the transaction */
1730
1731 /* if there wasn't a transaction, update the old ckchs */
1732 if (!ckchs_transaction.old_ckchs) {
1733 ckchs_transaction.old_ckchs = appctx->ctx.ssl.old_ckchs;
1734 ckchs_transaction.path = appctx->ctx.ssl.path;
1735 err = memprintf(&err, "Transaction created for certificate %s!\n", ckchs_transaction.path);
1736 } else {
1737 err = memprintf(&err, "Transaction updated for certificate %s!\n", ckchs_transaction.path);
1738
1739 }
1740
1741 /* free the previous ckchs if there was a transaction */
1742 ckch_store_free(ckchs_transaction.new_ckchs);
1743
1744 ckchs_transaction.new_ckchs = appctx->ctx.ssl.new_ckchs;
1745
1746
1747 /* creates the SNI ctxs later in the IO handler */
1748
1749end:
1750 free_trash_chunk(buf);
1751
1752 if (errcode & ERR_CODE) {
1753
1754 ckch_store_free(appctx->ctx.ssl.new_ckchs);
1755 appctx->ctx.ssl.new_ckchs = NULL;
1756
1757 appctx->ctx.ssl.old_ckchs = NULL;
1758
1759 free(appctx->ctx.ssl.path);
1760 appctx->ctx.ssl.path = NULL;
1761
1762 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1763 return cli_dynerr(appctx, memprintf(&err, "%sCan't update %s!\n", err ? err : "", args[3]));
1764 } else {
1765
1766 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1767 return cli_dynmsg(appctx, LOG_NOTICE, err);
1768 }
1769 /* TODO: handle the ERR_WARN which are not handled because of the io_handler */
1770}
1771
1772/* parsing function of 'abort ssl cert' */
1773static int cli_parse_abort_cert(char **args, char *payload, struct appctx *appctx, void *private)
1774{
1775 char *err = NULL;
1776
1777 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1778 return 1;
1779
1780 if (!*args[3])
1781 return cli_err(appctx, "'abort ssl cert' expects a filename\n");
1782
1783 /* The operations on the CKCH architecture are locked so we can
1784 * manipulate ckch_store and ckch_inst */
1785 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1786 return cli_err(appctx, "Can't abort!\nOperations on certificates are currently locked!\n");
1787
1788 if (!ckchs_transaction.path) {
1789 memprintf(&err, "No ongoing transaction!\n");
1790 goto error;
1791 }
1792
1793 if (strcmp(ckchs_transaction.path, args[3]) != 0) {
1794 memprintf(&err, "The ongoing transaction is about '%s' but you are trying to abort a transaction for '%s'\n", ckchs_transaction.path, args[3]);
1795 goto error;
1796 }
1797
1798 /* Only free the ckchs there, because the SNI and instances were not generated yet */
1799 ckch_store_free(ckchs_transaction.new_ckchs);
1800 ckchs_transaction.new_ckchs = NULL;
1801 ckch_store_free(ckchs_transaction.old_ckchs);
1802 ckchs_transaction.old_ckchs = NULL;
1803 free(ckchs_transaction.path);
1804 ckchs_transaction.path = NULL;
1805
1806 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1807
1808 err = memprintf(&err, "Transaction aborted for certificate '%s'!\n", args[3]);
1809 return cli_dynmsg(appctx, LOG_NOTICE, err);
1810
1811error:
1812 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1813
1814 return cli_dynerr(appctx, err);
1815}
1816
1817/* parsing function of 'new ssl cert' */
1818static int cli_parse_new_cert(char **args, char *payload, struct appctx *appctx, void *private)
1819{
1820 struct ckch_store *store;
1821 char *err = NULL;
1822 char *path;
1823
1824 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1825 return 1;
1826
1827 if (!*args[3])
1828 return cli_err(appctx, "'new ssl cert' expects a filename\n");
1829
1830 path = args[3];
1831
1832 /* The operations on the CKCH architecture are locked so we can
1833 * manipulate ckch_store and ckch_inst */
1834 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1835 return cli_err(appctx, "Can't create a certificate!\nOperations on certificates are currently locked!\n");
1836
1837 store = ckchs_lookup(path);
1838 if (store != NULL) {
1839 memprintf(&err, "Certificate '%s' already exists!\n", path);
1840 store = NULL; /* we don't want to free it */
1841 goto error;
1842 }
1843 /* we won't support multi-certificate bundle here */
1844 store = ckch_store_new(path, 1);
1845 if (!store) {
1846 memprintf(&err, "unable to allocate memory.\n");
1847 goto error;
1848 }
1849
1850 /* insert into the ckchs tree */
1851 ebst_insert(&ckchs_tree, &store->node);
1852 memprintf(&err, "New empty certificate store '%s'!\n", args[3]);
1853
1854 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1855 return cli_dynmsg(appctx, LOG_NOTICE, err);
1856error:
1857 free(store);
1858 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1859 return cli_dynerr(appctx, err);
1860}
1861
1862/* parsing function of 'del ssl cert' */
1863static int cli_parse_del_cert(char **args, char *payload, struct appctx *appctx, void *private)
1864{
1865 struct ckch_store *store;
1866 char *err = NULL;
1867 char *filename;
1868
1869 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1870 return 1;
1871
1872 if (!*args[3])
1873 return cli_err(appctx, "'del ssl cert' expects a certificate name\n");
1874
1875 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
1876 return cli_err(appctx, "Can't delete the certificate!\nOperations on certificates are currently locked!\n");
1877
1878 filename = args[3];
1879
1880 store = ckchs_lookup(filename);
1881 if (store == NULL) {
1882 memprintf(&err, "certificate '%s' doesn't exist!\n", filename);
1883 goto error;
1884 }
1885 if (!LIST_ISEMPTY(&store->ckch_inst)) {
1886 memprintf(&err, "certificate '%s' in use, can't be deleted!\n", filename);
1887 goto error;
1888 }
1889
1890 ebmb_delete(&store->node);
1891 ckch_store_free(store);
1892
1893 memprintf(&err, "Certificate '%s' deleted!\n", filename);
1894
1895 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1896 return cli_dynmsg(appctx, LOG_NOTICE, err);
1897
1898error:
1899 memprintf(&err, "Can't remove the certificate: %s\n", err ? err : "");
1900 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
1901 return cli_dynerr(appctx, err);
1902}
1903
William Lallemandee8530c2020-06-23 18:19:42 +02001904void ckch_deinit()
1905{
1906 struct eb_node *node, *next;
1907 struct ckch_store *store;
1908
1909 node = eb_first(&ckchs_tree);
1910 while (node) {
1911 next = eb_next(node);
1912 store = ebmb_entry(node, struct ckch_store, node);
1913 ckch_store_free(store);
1914 node = next;
1915 }
1916}
William Lallemandda8584c2020-05-14 10:14:37 +02001917
1918/* register cli keywords */
1919static struct cli_kw_list cli_kws = {{ },{
1920 { { "new", "ssl", "cert", NULL }, "new ssl cert <certfile> : create a new certificate file to be used in a crt-list or a directory", cli_parse_new_cert, NULL, NULL },
1921 { { "set", "ssl", "cert", NULL }, "set ssl cert <certfile> <payload> : replace a certificate file", cli_parse_set_cert, NULL, NULL },
1922 { { "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 },
1923 { { "abort", "ssl", "cert", NULL }, "abort ssl cert <certfile> : abort a transaction for a certificate file", cli_parse_abort_cert, NULL, NULL },
1924 { { "del", "ssl", "cert", NULL }, "del ssl cert <certfile> : delete an unused certificate file", cli_parse_del_cert, NULL, NULL },
1925 { { "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 },
1926 { { NULL }, NULL, NULL, NULL }
1927}};
1928
1929INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
1930