blob: 1a5de31acf80883eaaa2af5aeefa03dcc19a366b [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
24#include <common/base64.h>
25#include <common/errors.h>
26#include <common/standard.h>
27
28#include <ebsttree.h>
29
30#include <types/ssl_ckch.h>
31#include <types/ssl_sock.h>
32
33#include <proto/ssl_ckch.h>
34#include <proto/ssl_sock.h>
35
36/******************** cert_key_and_chain functions *************************
37 * These are the functions that fills a cert_key_and_chain structure. For the
38 * functions filling a SSL_CTX from a cert_key_and_chain, see ssl_sock.c
39 */
40
41/*
42 * Try to parse Signed Certificate Timestamp List structure. This function
43 * makes only basic test if the data seems like SCTL. No signature validation
44 * is performed.
45 */
46static int ssl_sock_parse_sctl(struct buffer *sctl)
47{
48 int ret = 1;
49 int len, pos, sct_len;
50 unsigned char *data;
51
52 if (sctl->data < 2)
53 goto out;
54
55 data = (unsigned char *) sctl->area;
56 len = (data[0] << 8) | data[1];
57
58 if (len + 2 != sctl->data)
59 goto out;
60
61 data = data + 2;
62 pos = 0;
63 while (pos < len) {
64 if (len - pos < 2)
65 goto out;
66
67 sct_len = (data[pos] << 8) | data[pos + 1];
68 if (pos + sct_len + 2 > len)
69 goto out;
70
71 pos += sct_len + 2;
72 }
73
74 ret = 0;
75
76out:
77 return ret;
78}
79
80/* Try to load a sctl from a buffer <buf> if not NULL, or read the file <sctl_path>
81 * It fills the ckch->sctl buffer
82 * return 0 on success or != 0 on failure */
83int ssl_sock_load_sctl_from_file(const char *sctl_path, char *buf, struct cert_key_and_chain *ckch, char **err)
84{
85 int fd = -1;
86 int r = 0;
87 int ret = 1;
88 struct buffer tmp;
89 struct buffer *src;
90 struct buffer *sctl;
91
92 if (buf) {
93 tmp.area = buf;
94 tmp.data = strlen(buf);
95 tmp.size = tmp.data + 1;
96 src = &tmp;
97 } else {
98 fd = open(sctl_path, O_RDONLY);
99 if (fd == -1)
100 goto end;
101
102 trash.data = 0;
103 while (trash.data < trash.size) {
104 r = read(fd, trash.area + trash.data, trash.size - trash.data);
105 if (r < 0) {
106 if (errno == EINTR)
107 continue;
108 goto end;
109 }
110 else if (r == 0) {
111 break;
112 }
113 trash.data += r;
114 }
115 src = &trash;
116 }
117
118 ret = ssl_sock_parse_sctl(src);
119 if (ret)
120 goto end;
121
122 sctl = calloc(1, sizeof(*sctl));
123 if (!chunk_dup(sctl, src)) {
124 free(sctl);
125 sctl = NULL;
126 goto end;
127 }
128 /* no error, fill ckch with new context, old context must be free */
129 if (ckch->sctl) {
130 free(ckch->sctl->area);
131 ckch->sctl->area = NULL;
132 free(ckch->sctl);
133 }
134 ckch->sctl = sctl;
135 ret = 0;
136end:
137 if (fd != -1)
138 close(fd);
139
140 return ret;
141}
142
143#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) || defined OPENSSL_IS_BORINGSSL)
144/*
145 * This function load the OCSP Resonse in DER format contained in file at
146 * path 'ocsp_path' or base64 in a buffer <buf>
147 *
148 * Returns 0 on success, 1 in error case.
149 */
150int ssl_sock_load_ocsp_response_from_file(const char *ocsp_path, char *buf, struct cert_key_and_chain *ckch, char **err)
151{
152 int fd = -1;
153 int r = 0;
154 int ret = 1;
155 struct buffer *ocsp_response;
156 struct buffer *src = NULL;
157
158 if (buf) {
159 int i, j;
160 /* if it's from a buffer it will be base64 */
161
162 /* remove \r and \n from the payload */
163 for (i = 0, j = 0; buf[i]; i++) {
164 if (buf[i] == '\r' || buf[i] == '\n')
165 continue;
166 buf[j++] = buf[i];
167 }
168 buf[j] = 0;
169
170 ret = base64dec(buf, j, trash.area, trash.size);
171 if (ret < 0) {
172 memprintf(err, "Error reading OCSP response in base64 format");
173 goto end;
174 }
175 trash.data = ret;
176 src = &trash;
177 } else {
178 fd = open(ocsp_path, O_RDONLY);
179 if (fd == -1) {
180 memprintf(err, "Error opening OCSP response file");
181 goto end;
182 }
183
184 trash.data = 0;
185 while (trash.data < trash.size) {
186 r = read(fd, trash.area + trash.data, trash.size - trash.data);
187 if (r < 0) {
188 if (errno == EINTR)
189 continue;
190
191 memprintf(err, "Error reading OCSP response from file");
192 goto end;
193 }
194 else if (r == 0) {
195 break;
196 }
197 trash.data += r;
198 }
199 close(fd);
200 fd = -1;
201 src = &trash;
202 }
203
204 ocsp_response = calloc(1, sizeof(*ocsp_response));
205 if (!chunk_dup(ocsp_response, src)) {
206 free(ocsp_response);
207 ocsp_response = NULL;
208 goto end;
209 }
210 /* no error, fill ckch with new context, old context must be free */
211 if (ckch->ocsp_response) {
212 free(ckch->ocsp_response->area);
213 ckch->ocsp_response->area = NULL;
214 free(ckch->ocsp_response);
215 }
216 ckch->ocsp_response = ocsp_response;
217 ret = 0;
218end:
219 if (fd != -1)
220 close(fd);
221
222 return ret;
223}
224#endif
225
226/*
227 * Try to load in a ckch every files related to a ckch.
228 * (PEM, sctl, ocsp, issuer etc.)
229 *
230 * This function is only used to load files during the configuration parsing,
231 * it is not used with the CLI.
232 *
233 * This allows us to carry the contents of the file without having to read the
234 * file multiple times. The caller must call
235 * ssl_sock_free_cert_key_and_chain_contents.
236 *
237 * returns:
238 * 0 on Success
239 * 1 on SSL Failure
240 */
241int ssl_sock_load_files_into_ckch(const char *path, struct cert_key_and_chain *ckch, char **err)
242{
243 int ret = 1;
244
245 /* try to load the PEM */
246 if (ssl_sock_load_pem_into_ckch(path, NULL, ckch , err) != 0) {
247 goto end;
248 }
249
250 /* try to load an external private key if it wasn't in the PEM */
251 if ((ckch->key == NULL) && (global_ssl.extra_files & SSL_GF_KEY)) {
252 char fp[MAXPATHLEN+1];
253 struct stat st;
254
255 snprintf(fp, MAXPATHLEN+1, "%s.key", path);
256 if (stat(fp, &st) == 0) {
257 if (ssl_sock_load_key_into_ckch(fp, NULL, ckch, err)) {
258 memprintf(err, "%s '%s' is present but cannot be read or parsed'.\n",
259 err && *err ? *err : "", fp);
260 goto end;
261 }
262 }
263 }
264
265 if (ckch->key == NULL) {
266 memprintf(err, "%sNo Private Key found in '%s' or '%s.key'.\n", err && *err ? *err : "", path, path);
267 goto end;
268 }
269
270 if (!X509_check_private_key(ckch->cert, ckch->key)) {
271 memprintf(err, "%sinconsistencies between private key and certificate loaded '%s'.\n",
272 err && *err ? *err : "", path);
273 goto end;
274 }
275
276#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL)
277 /* try to load the sctl file */
278 if (global_ssl.extra_files & SSL_GF_SCTL) {
279 char fp[MAXPATHLEN+1];
280 struct stat st;
281
282 snprintf(fp, MAXPATHLEN+1, "%s.sctl", path);
283 if (stat(fp, &st) == 0) {
284 if (ssl_sock_load_sctl_from_file(fp, NULL, ckch, err)) {
285 memprintf(err, "%s '%s.sctl' is present but cannot be read or parsed'.\n",
286 err && *err ? *err : "", fp);
287 ret = 1;
288 goto end;
289 }
290 }
291 }
292#endif
293
294 /* try to load an ocsp response file */
295 if (global_ssl.extra_files & SSL_GF_OCSP) {
296 char fp[MAXPATHLEN+1];
297 struct stat st;
298
299 snprintf(fp, MAXPATHLEN+1, "%s.ocsp", path);
300 if (stat(fp, &st) == 0) {
301 if (ssl_sock_load_ocsp_response_from_file(fp, NULL, ckch, err)) {
302 ret = 1;
303 goto end;
304 }
305 }
306 }
307
308#ifndef OPENSSL_IS_BORINGSSL /* Useless for BoringSSL */
309 if (ckch->ocsp_response && (global_ssl.extra_files & SSL_GF_OCSP_ISSUER)) {
310 /* if no issuer was found, try to load an issuer from the .issuer */
311 if (!ckch->ocsp_issuer) {
312 struct stat st;
313 char fp[MAXPATHLEN+1];
314
315 snprintf(fp, MAXPATHLEN+1, "%s.issuer", path);
316 if (stat(fp, &st) == 0) {
317 if (ssl_sock_load_issuer_file_into_ckch(fp, NULL, ckch, err)) {
318 ret = 1;
319 goto end;
320 }
321
322 if (X509_check_issued(ckch->ocsp_issuer, ckch->cert) != X509_V_OK) {
323 memprintf(err, "%s '%s' is not an issuer'.\n",
324 err && *err ? *err : "", fp);
325 ret = 1;
326 goto end;
327 }
328 }
329 }
330 }
331#endif
332
333 ret = 0;
334
335end:
336
337 ERR_clear_error();
338
339 /* Something went wrong in one of the reads */
340 if (ret != 0)
341 ssl_sock_free_cert_key_and_chain_contents(ckch);
342
343 return ret;
344}
345
346/*
347 * Try to load a private key file from a <path> or a buffer <buf>
348 *
349 * If it failed you should not attempt to use the ckch but free it.
350 *
351 * Return 0 on success or != 0 on failure
352 */
353int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch , char **err)
354{
355 BIO *in = NULL;
356 int ret = 1;
357 EVP_PKEY *key = NULL;
358
359 if (buf) {
360 /* reading from a buffer */
361 in = BIO_new_mem_buf(buf, -1);
362 if (in == NULL) {
363 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
364 goto end;
365 }
366
367 } else {
368 /* reading from a file */
369 in = BIO_new(BIO_s_file());
370 if (in == NULL)
371 goto end;
372
373 if (BIO_read_filename(in, path) <= 0)
374 goto end;
375 }
376
377 /* Read Private Key */
378 key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
379 if (key == NULL) {
380 memprintf(err, "%sunable to load private key from file '%s'.\n",
381 err && *err ? *err : "", path);
382 goto end;
383 }
384
385 ret = 0;
386
387 SWAP(ckch->key, key);
388
389end:
390
391 ERR_clear_error();
392 if (in)
393 BIO_free(in);
394 if (key)
395 EVP_PKEY_free(key);
396
397 return ret;
398}
399
400/*
401 * Try to load a PEM file from a <path> or a buffer <buf>
402 * The PEM must contain at least a Certificate,
403 * It could contain a DH, a certificate chain and a PrivateKey.
404 *
405 * If it failed you should not attempt to use the ckch but free it.
406 *
407 * Return 0 on success or != 0 on failure
408 */
409int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch , char **err)
410{
411 BIO *in = NULL;
412 int ret = 1;
413 X509 *ca;
414 X509 *cert = NULL;
415 EVP_PKEY *key = NULL;
416 DH *dh = NULL;
417 STACK_OF(X509) *chain = NULL;
418
419 if (buf) {
420 /* reading from a buffer */
421 in = BIO_new_mem_buf(buf, -1);
422 if (in == NULL) {
423 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
424 goto end;
425 }
426
427 } else {
428 /* reading from a file */
429 in = BIO_new(BIO_s_file());
430 if (in == NULL) {
431 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
432 goto end;
433 }
434
435 if (BIO_read_filename(in, path) <= 0) {
436 memprintf(err, "%scannot open the file '%s'.\n",
437 err && *err ? *err : "", path);
438 goto end;
439 }
440 }
441
442 /* Read Private Key */
443 key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
444 /* no need to check for errors here, because the private key could be loaded later */
445
446#ifndef OPENSSL_NO_DH
447 /* Seek back to beginning of file */
448 if (BIO_reset(in) == -1) {
449 memprintf(err, "%san error occurred while reading the file '%s'.\n",
450 err && *err ? *err : "", path);
451 goto end;
452 }
453
454 dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
455 /* no need to return an error there, dh is not mandatory */
456#endif
457
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 /* Read Certificate */
466 cert = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
467 if (cert == NULL) {
468 memprintf(err, "%sunable to load certificate from file '%s'.\n",
469 err && *err ? *err : "", path);
470 goto end;
471 }
472
473 /* Look for a Certificate Chain */
474 while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
475 if (chain == NULL)
476 chain = sk_X509_new_null();
477 if (!sk_X509_push(chain, ca)) {
478 X509_free(ca);
479 goto end;
480 }
481 }
482
483 ret = ERR_get_error();
484 if (ret && (ERR_GET_LIB(ret) != ERR_LIB_PEM && ERR_GET_REASON(ret) != PEM_R_NO_START_LINE)) {
485 memprintf(err, "%sunable to load certificate chain from file '%s'.\n",
486 err && *err ? *err : "", path);
487 goto end;
488 }
489
490 /* once it loaded the PEM, it should remove everything else in the ckch */
491 if (ckch->ocsp_response) {
492 free(ckch->ocsp_response->area);
493 ckch->ocsp_response->area = NULL;
494 free(ckch->ocsp_response);
495 ckch->ocsp_response = NULL;
496 }
497
498 if (ckch->sctl) {
499 free(ckch->sctl->area);
500 ckch->sctl->area = NULL;
501 free(ckch->sctl);
502 ckch->sctl = NULL;
503 }
504
505 if (ckch->ocsp_issuer) {
506 X509_free(ckch->ocsp_issuer);
507 ckch->ocsp_issuer = NULL;
508 }
509
510 /* no error, fill ckch with new context, old context will be free at end: */
511 SWAP(ckch->key, key);
512 SWAP(ckch->dh, dh);
513 SWAP(ckch->cert, cert);
514 SWAP(ckch->chain, chain);
515
516 ret = 0;
517
518end:
519
520 ERR_clear_error();
521 if (in)
522 BIO_free(in);
523 if (key)
524 EVP_PKEY_free(key);
525 if (dh)
526 DH_free(dh);
527 if (cert)
528 X509_free(cert);
529 if (chain)
530 sk_X509_pop_free(chain, X509_free);
531
532 return ret;
533}
534
535/* Frees the contents of a cert_key_and_chain
536 */
537void ssl_sock_free_cert_key_and_chain_contents(struct cert_key_and_chain *ckch)
538{
539 if (!ckch)
540 return;
541
542 /* Free the certificate and set pointer to NULL */
543 if (ckch->cert)
544 X509_free(ckch->cert);
545 ckch->cert = NULL;
546
547 /* Free the key and set pointer to NULL */
548 if (ckch->key)
549 EVP_PKEY_free(ckch->key);
550 ckch->key = NULL;
551
552 /* Free each certificate in the chain */
553 if (ckch->chain)
554 sk_X509_pop_free(ckch->chain, X509_free);
555 ckch->chain = NULL;
556
557 if (ckch->dh)
558 DH_free(ckch->dh);
559 ckch->dh = NULL;
560
561 if (ckch->sctl) {
562 free(ckch->sctl->area);
563 ckch->sctl->area = NULL;
564 free(ckch->sctl);
565 ckch->sctl = NULL;
566 }
567
568 if (ckch->ocsp_response) {
569 free(ckch->ocsp_response->area);
570 ckch->ocsp_response->area = NULL;
571 free(ckch->ocsp_response);
572 ckch->ocsp_response = NULL;
573 }
574
575 if (ckch->ocsp_issuer)
576 X509_free(ckch->ocsp_issuer);
577 ckch->ocsp_issuer = NULL;
578}
579
580/*
581 *
582 * This function copy a cert_key_and_chain in memory
583 *
584 * It's used to try to apply changes on a ckch before committing them, because
585 * most of the time it's not possible to revert those changes
586 *
587 * Return a the dst or NULL
588 */
589struct cert_key_and_chain *ssl_sock_copy_cert_key_and_chain(struct cert_key_and_chain *src,
590 struct cert_key_and_chain *dst)
591{
592 if (src->cert) {
593 dst->cert = src->cert;
594 X509_up_ref(src->cert);
595 }
596
597 if (src->key) {
598 dst->key = src->key;
599 EVP_PKEY_up_ref(src->key);
600 }
601
602 if (src->chain) {
603 dst->chain = X509_chain_up_ref(src->chain);
604 }
605
606 if (src->dh) {
607 DH_up_ref(src->dh);
608 dst->dh = src->dh;
609 }
610
611 if (src->sctl) {
612 struct buffer *sctl;
613
614 sctl = calloc(1, sizeof(*sctl));
615 if (!chunk_dup(sctl, src->sctl)) {
616 free(sctl);
617 sctl = NULL;
618 goto error;
619 }
620 dst->sctl = sctl;
621 }
622
623 if (src->ocsp_response) {
624 struct buffer *ocsp_response;
625
626 ocsp_response = calloc(1, sizeof(*ocsp_response));
627 if (!chunk_dup(ocsp_response, src->ocsp_response)) {
628 free(ocsp_response);
629 ocsp_response = NULL;
630 goto error;
631 }
632 dst->ocsp_response = ocsp_response;
633 }
634
635 if (src->ocsp_issuer) {
636 X509_up_ref(src->ocsp_issuer);
637 dst->ocsp_issuer = src->ocsp_issuer;
638 }
639
640 return dst;
641
642error:
643
644 /* free everything */
645 ssl_sock_free_cert_key_and_chain_contents(dst);
646
647 return NULL;
648}
649
650/*
651 * return 0 on success or != 0 on failure
652 */
653int ssl_sock_load_issuer_file_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch, char **err)
654{
655 int ret = 1;
656 BIO *in = NULL;
657 X509 *issuer;
658
659 if (buf) {
660 /* reading from a buffer */
661 in = BIO_new_mem_buf(buf, -1);
662 if (in == NULL) {
663 memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
664 goto end;
665 }
666
667 } else {
668 /* reading from a file */
669 in = BIO_new(BIO_s_file());
670 if (in == NULL)
671 goto end;
672
673 if (BIO_read_filename(in, path) <= 0)
674 goto end;
675 }
676
677 issuer = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
678 if (!issuer) {
679 memprintf(err, "%s'%s' cannot be read or parsed'.\n",
680 err && *err ? *err : "", path);
681 goto end;
682 }
683 /* no error, fill ckch with new context, old context must be free */
684 if (ckch->ocsp_issuer)
685 X509_free(ckch->ocsp_issuer);
686 ckch->ocsp_issuer = issuer;
687 ret = 0;
688
689end:
690
691 ERR_clear_error();
692 if (in)
693 BIO_free(in);
694
695 return ret;
696}
697
698/******************** ckch_store functions ***********************************
699 * The ckch_store is a structure used to cache and index the SSL files used in
700 * configuration
701 */
702
703/*
704 * Free a ckch_store, its ckch, its instances and remove it from the ebtree
705 */
706void ckch_store_free(struct ckch_store *store)
707{
708 struct ckch_inst *inst, *inst_s;
709
710 if (!store)
711 return;
712
713#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200L
714 if (store->multi) {
715 int n;
716
717 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++)
718 ssl_sock_free_cert_key_and_chain_contents(&store->ckch[n]);
719 } else
720#endif
721 {
722 ssl_sock_free_cert_key_and_chain_contents(store->ckch);
723 }
724
725 free(store->ckch);
726 store->ckch = NULL;
727
728 list_for_each_entry_safe(inst, inst_s, &store->ckch_inst, by_ckchs) {
729 ckch_inst_free(inst);
730 }
731 ebmb_delete(&store->node);
732 free(store);
733}
734
735/*
736 * create and initialize a ckch_store
737 * <path> is the key name
738 * <nmemb> is the number of store->ckch objects to allocate
739 *
740 * Return a ckch_store or NULL upon failure.
741 */
742struct ckch_store *ckch_store_new(const char *filename, int nmemb)
743{
744 struct ckch_store *store;
745 int pathlen;
746
747 pathlen = strlen(filename);
748 store = calloc(1, sizeof(*store) + pathlen + 1);
749 if (!store)
750 return NULL;
751
752 if (nmemb > 1)
753 store->multi = 1;
754 else
755 store->multi = 0;
756
757 memcpy(store->path, filename, pathlen + 1);
758
759 LIST_INIT(&store->ckch_inst);
760 LIST_INIT(&store->crtlist_entry);
761
762 store->ckch = calloc(nmemb, sizeof(*store->ckch));
763 if (!store->ckch)
764 goto error;
765
766 return store;
767error:
768 ckch_store_free(store);
769 return NULL;
770}
771
772/* allocate and duplicate a ckch_store
773 * Return a new ckch_store or NULL */
774struct ckch_store *ckchs_dup(const struct ckch_store *src)
775{
776 struct ckch_store *dst;
777
778 dst = ckch_store_new(src->path, src->multi ? SSL_SOCK_NUM_KEYTYPES : 1);
779
780#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
781 if (src->multi) {
782 int n;
783
784 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
785 if (&src->ckch[n]) {
786 if (!ssl_sock_copy_cert_key_and_chain(&src->ckch[n], &dst->ckch[n]))
787 goto error;
788 }
789 }
790 } else
791#endif
792 {
793 if (!ssl_sock_copy_cert_key_and_chain(src->ckch, dst->ckch))
794 goto error;
795 }
796
797 return dst;
798
799error:
800 ckch_store_free(dst);
801
802 return NULL;
803}
804
805/*
806 * lookup a path into the ckchs tree.
807 */
808struct ckch_store *ckchs_lookup(char *path)
809{
810 struct ebmb_node *eb;
811
812 eb = ebst_lookup(&ckchs_tree, path);
813 if (!eb)
814 return NULL;
815
816 return ebmb_entry(eb, struct ckch_store, node);
817}
818
819/*
820 * This function allocate a ckch_store and populate it with certificates from files.
821 */
822struct ckch_store *ckchs_load_cert_file(char *path, int multi, char **err)
823{
824 struct ckch_store *ckchs;
825
826 ckchs = ckch_store_new(path, multi ? SSL_SOCK_NUM_KEYTYPES : 1);
827 if (!ckchs) {
828 memprintf(err, "%sunable to allocate memory.\n", err && *err ? *err : "");
829 goto end;
830 }
831 if (!multi) {
832
833 if (ssl_sock_load_files_into_ckch(path, ckchs->ckch, err) == 1)
834 goto end;
835
836 /* insert into the ckchs tree */
837 memcpy(ckchs->path, path, strlen(path) + 1);
838 ebst_insert(&ckchs_tree, &ckchs->node);
839 } else {
840 int found = 0;
841#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
842 char fp[MAXPATHLEN+1] = {0};
843 int n = 0;
844
845 /* Load all possible certs and keys */
846 for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
847 struct stat buf;
848 snprintf(fp, sizeof(fp), "%s.%s", path, SSL_SOCK_KEYTYPE_NAMES[n]);
849 if (stat(fp, &buf) == 0) {
850 if (ssl_sock_load_files_into_ckch(fp, &ckchs->ckch[n], err) == 1)
851 goto end;
852 found = 1;
853 ckchs->multi = 1;
854 }
855 }
856#endif
857
858 if (!found) {
859 memprintf(err, "%sDidn't find any certificate for bundle '%s'.\n", err && *err ? *err : "", path);
860 goto end;
861 }
862 /* insert into the ckchs tree */
863 memcpy(ckchs->path, path, strlen(path) + 1);
864 ebst_insert(&ckchs_tree, &ckchs->node);
865 }
866 return ckchs;
867
868end:
869 ckch_store_free(ckchs);
870
871 return NULL;
872}
873