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