stroke: Use separate credential sets for CA/AA certificates
[strongswan.git] / src / libcharon / plugins / stroke / stroke_cred.c
1 /*
2 * Copyright (C) 2008-2013 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <limits.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <unistd.h>
23
24 #ifdef HAVE_GLOB_H
25 #include <glob.h>
26 #endif
27
28 #include "stroke_cred.h"
29
30 #include <credentials/certificates/x509.h>
31 #include <credentials/certificates/crl.h>
32 #include <credentials/certificates/ac.h>
33 #include <credentials/containers/pkcs12.h>
34 #include <credentials/sets/mem_cred.h>
35 #include <credentials/sets/callback_cred.h>
36 #include <collections/linked_list.h>
37 #include <utils/lexparser.h>
38 #include <threading/rwlock.h>
39 #include <daemon.h>
40
41 /* configuration directories and files */
42 #define CONFIG_DIR IPSEC_CONFDIR
43 #define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
44 #define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
45 #define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
46 #define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
47 #define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
48 #define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
49 #define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
50 #define CRL_DIR IPSEC_D_DIR "/crls"
51 #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
52
53 #define MAX_SECRETS_RECURSION 10
54
55 typedef struct private_stroke_cred_t private_stroke_cred_t;
56
57 /**
58 * private data of stroke_cred
59 */
60 struct private_stroke_cred_t {
61
62 /**
63 * public functions
64 */
65 stroke_cred_t public;
66
67 /**
68 * secrets file with credential information
69 */
70 char *secrets_file;
71
72 /**
73 * credentials: end entity certs, attribute certs, CRLs, etc.
74 */
75 mem_cred_t *creds;
76
77 /**
78 * CA certificates
79 */
80 mem_cred_t *cacerts;
81
82 /**
83 * Attribute Authority certificates
84 */
85 mem_cred_t *aacerts;
86
87 /**
88 * ignore missing CA basic constraint (i.e. treat all certificates in
89 * ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
90 */
91 bool force_ca_cert;
92
93 /**
94 * cache CRLs to disk?
95 */
96 bool cachecrl;
97 };
98
99 /** Length of smartcard specifier parts (module, keyid) */
100 #define SC_PART_LEN 128
101
102 /**
103 * Kind of smartcard specifier token
104 */
105 typedef enum {
106 SC_FORMAT_SLOT_MODULE_KEYID,
107 SC_FORMAT_SLOT_KEYID,
108 SC_FORMAT_KEYID,
109 SC_FORMAT_INVALID,
110 } smartcard_format_t;
111
112 /**
113 * Parse a smartcard specifier token
114 */
115 static smartcard_format_t parse_smartcard(char *smartcard, u_int *slot,
116 char *module, char *keyid)
117 {
118 /* The token has one of the following three formats:
119 * - %smartcard<slot>@<module>:<keyid>
120 * - %smartcard<slot>:<keyid>
121 * - %smartcard:<keyid>
122 */
123 char buf[2 * SC_PART_LEN], *pos;
124
125 if (sscanf(smartcard, "%%smartcard%u@%255s", slot, buf) == 2)
126 {
127 pos = strchr(buf, ':');
128 if (!pos)
129 {
130 return SC_FORMAT_INVALID;
131 }
132 *pos++ = '\0';
133 snprintf(module, SC_PART_LEN, "%s", buf);
134 snprintf(keyid, SC_PART_LEN, "%s", pos);
135 return SC_FORMAT_SLOT_MODULE_KEYID;
136 }
137 if (sscanf(smartcard, "%%smartcard%u:%127s", slot, keyid) == 2)
138 {
139 return SC_FORMAT_SLOT_KEYID;
140 }
141 if (sscanf(smartcard, "%%smartcard:%127s", keyid) == 1)
142 {
143 return SC_FORMAT_KEYID;
144 }
145 return SC_FORMAT_INVALID;
146 }
147
148 /**
149 * Load a credential from a smartcard
150 */
151 static certificate_t *load_from_smartcard(smartcard_format_t format,
152 u_int slot, char *module, char *keyid,
153 credential_type_t type, int subtype)
154 {
155 chunk_t chunk;
156 void *cred;
157
158 chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
159 switch (format)
160 {
161 case SC_FORMAT_SLOT_MODULE_KEYID:
162 cred = lib->creds->create(lib->creds, type, subtype,
163 BUILD_PKCS11_SLOT, slot,
164 BUILD_PKCS11_MODULE, module,
165 BUILD_PKCS11_KEYID, chunk, BUILD_END);
166 break;
167 case SC_FORMAT_SLOT_KEYID:
168 cred = lib->creds->create(lib->creds, type, subtype,
169 BUILD_PKCS11_SLOT, slot,
170 BUILD_PKCS11_KEYID, chunk, BUILD_END);
171 break;
172 case SC_FORMAT_KEYID:
173 cred = lib->creds->create(lib->creds, type, subtype,
174 BUILD_PKCS11_KEYID, chunk, BUILD_END);
175 break;
176 default:
177 cred = NULL;
178 break;
179 }
180 free(chunk.ptr);
181
182 return cred;
183 }
184
185 METHOD(stroke_cred_t, load_ca, certificate_t*,
186 private_stroke_cred_t *this, char *filename)
187 {
188 certificate_t *cert = NULL;
189 char path[PATH_MAX];
190
191 if (strpfx(filename, "%smartcard"))
192 {
193 smartcard_format_t format;
194 char module[SC_PART_LEN], keyid[SC_PART_LEN];
195 u_int slot;
196
197 format = parse_smartcard(filename, &slot, module, keyid);
198 if (format != SC_FORMAT_INVALID)
199 {
200 cert = (certificate_t*)load_from_smartcard(format,
201 slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
202 }
203 }
204 else
205 {
206 if (*filename == '/')
207 {
208 snprintf(path, sizeof(path), "%s", filename);
209 }
210 else
211 {
212 snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
213 }
214
215 if (this->force_ca_cert)
216 { /* we treat this certificate as a CA certificate even if it has no
217 * CA basic constraint */
218 cert = lib->creds->create(lib->creds,
219 CRED_CERTIFICATE, CERT_X509,
220 BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
221 BUILD_END);
222 }
223 else
224 {
225 cert = lib->creds->create(lib->creds,
226 CRED_CERTIFICATE, CERT_X509,
227 BUILD_FROM_FILE, path,
228 BUILD_END);
229 }
230 }
231 if (cert)
232 {
233 x509_t *x509 = (x509_t*)cert;
234
235 if (!(x509->get_flags(x509) & X509_CA))
236 {
237 DBG1(DBG_CFG, " ca certificate \"%Y\" misses ca basic constraint, "
238 "discarded", cert->get_subject(cert));
239 cert->destroy(cert);
240 return NULL;
241 }
242 DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
243 cert->get_subject(cert), filename);
244 return this->creds->add_cert_ref(this->creds, TRUE, cert);
245 }
246 return NULL;
247 }
248
249 METHOD(stroke_cred_t, load_peer, certificate_t*,
250 private_stroke_cred_t *this, char *filename)
251 {
252 certificate_t *cert = NULL;
253 char path[PATH_MAX];
254
255 if (strpfx(filename, "%smartcard"))
256 {
257 smartcard_format_t format;
258 char module[SC_PART_LEN], keyid[SC_PART_LEN];
259 u_int slot;
260
261 format = parse_smartcard(filename, &slot, module, keyid);
262 if (format != SC_FORMAT_INVALID)
263 {
264 cert = (certificate_t*)load_from_smartcard(format,
265 slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
266 }
267 }
268 else
269 {
270 if (*filename == '/')
271 {
272 snprintf(path, sizeof(path), "%s", filename);
273 }
274 else
275 {
276 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
277 }
278
279 cert = lib->creds->create(lib->creds,
280 CRED_CERTIFICATE, CERT_ANY,
281 BUILD_FROM_FILE, path,
282 BUILD_END);
283 }
284 if (cert)
285 {
286 cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
287 DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
288 cert->get_subject(cert), filename);
289 return cert;
290 }
291 DBG1(DBG_CFG, " loading certificate from '%s' failed", filename);
292 return NULL;
293 }
294
295 METHOD(stroke_cred_t, load_pubkey, certificate_t*,
296 private_stroke_cred_t *this, char *filename, identification_t *identity)
297 {
298 certificate_t *cert;
299 public_key_t *key;
300 char path[PATH_MAX];
301 builder_part_t build_part;
302 key_type_t type = KEY_ANY;
303
304 if (streq(filename, "%dns"))
305 {
306 return NULL;
307 }
308 if (strncaseeq(filename, "dns:", 4))
309 { /* RFC 3110 format */
310 build_part = BUILD_BLOB_DNSKEY;
311 /* not a complete RR, only RSA supported */
312 type = KEY_RSA;
313 filename += 4;
314 }
315 else if (strncaseeq(filename, "ssh:", 4))
316 { /* SSH key */
317 build_part = BUILD_BLOB_SSHKEY;
318 filename += 4;
319 }
320 else
321 { /* try PKCS#1 by default */
322 build_part = BUILD_BLOB_ASN1_DER;
323 }
324 if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
325 {
326 chunk_t printable_key, raw_key;
327
328 printable_key = chunk_create(filename + 2, strlen(filename) - 2);
329 raw_key = strncaseeq(filename, "0x", 2) ?
330 chunk_from_hex(printable_key, NULL) :
331 chunk_from_base64(printable_key, NULL);
332 key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
333 build_part, raw_key, BUILD_END);
334 chunk_free(&raw_key);
335 if (key)
336 {
337 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
338 CERT_TRUSTED_PUBKEY,
339 BUILD_PUBLIC_KEY, key,
340 BUILD_SUBJECT, identity,
341 BUILD_END);
342 type = key->get_type(key);
343 key->destroy(key);
344 if (cert)
345 {
346 cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
347 DBG1(DBG_CFG, " loaded %N public key for \"%Y\"",
348 key_type_names, type, identity);
349 return cert;
350 }
351 }
352 DBG1(DBG_CFG, " loading public key for \"%Y\" failed", identity);
353 }
354 else
355 {
356 if (*filename == '/')
357 {
358 snprintf(path, sizeof(path), "%s", filename);
359 }
360 else
361 {
362 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
363 }
364
365 cert = lib->creds->create(lib->creds,
366 CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
367 BUILD_FROM_FILE, path,
368 BUILD_SUBJECT, identity,
369 BUILD_END);
370 if (cert)
371 {
372 cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
373 key = cert->get_public_key(cert);
374 type = key->get_type(key);
375 key->destroy(key);
376 DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'",
377 key_type_names, type, identity, filename);
378 return cert;
379 }
380 DBG1(DBG_CFG, " loading public key for \"%Y\" from '%s' failed",
381 identity, filename);
382 }
383 return NULL;
384 }
385
386 /**
387 * Load a CA certificate from disk
388 */
389 static void load_x509_ca(private_stroke_cred_t *this, char *file)
390 {
391 certificate_t *cert;
392
393 if (this->force_ca_cert)
394 { /* treat certificate as CA cert even it has no CA basic constraint */
395 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
396 BUILD_FROM_FILE, file,
397 BUILD_X509_FLAG, X509_CA, BUILD_END);
398 }
399 else
400 {
401 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
402 BUILD_FROM_FILE, file, BUILD_END);
403 }
404 if (cert)
405 {
406 x509_t *x509 = (x509_t*)cert;
407
408 if (!(x509->get_flags(x509) & X509_CA))
409 {
410 DBG1(DBG_CFG, " ca certificate \"%Y\" lacks ca basic constraint, "
411 "discarded", cert->get_subject(cert));
412 cert->destroy(cert);
413 }
414 else
415 {
416 DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
417 cert->get_subject(cert), file);
418 this->cacerts->add_cert(this->cacerts, TRUE, cert);
419 }
420 }
421 else
422 {
423 DBG1(DBG_CFG, " loading ca certificate from '%s' failed", file);
424 }
425 }
426
427 /**
428 * Load AA certificate with flags from disk
429 */
430 static void load_x509_aa(private_stroke_cred_t *this, char *file)
431 {
432 certificate_t *cert;
433
434 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
435 BUILD_FROM_FILE, file,
436 BUILD_X509_FLAG, X509_AA, BUILD_END);
437 if (cert)
438 {
439 DBG1(DBG_CFG, " loaded AA certificate \"%Y\" from '%s'",
440 cert->get_subject(cert), file);
441 this->aacerts->add_cert(this->aacerts, TRUE, cert);
442 }
443 else
444 {
445 DBG1(DBG_CFG, " loading AA certificate from '%s' failed", file);
446 }
447 }
448
449 /**
450 * Load a certificate with flags from disk
451 */
452 static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag)
453 {
454 certificate_t *cert;
455
456 /* for all other flags, we add them to the certificate. */
457 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
458 BUILD_FROM_FILE, file,
459 BUILD_X509_FLAG, flag, BUILD_END);
460 if (cert)
461 {
462 DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
463 cert->get_subject(cert), file);
464 this->creds->add_cert(this->creds, TRUE, cert);
465 }
466 else
467 {
468 DBG1(DBG_CFG, " loading certificate from '%s' failed", file);
469 }
470 }
471
472 /**
473 * Load a CRL from a file
474 */
475 static void load_x509_crl(private_stroke_cred_t *this, char *file)
476 {
477 certificate_t *cert;
478
479 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
480 BUILD_FROM_FILE, file, BUILD_END);
481 if (cert)
482 {
483 this->creds->add_crl(this->creds, (crl_t*)cert);
484 DBG1(DBG_CFG, " loaded crl from '%s'", file);
485 }
486 else
487 {
488 DBG1(DBG_CFG, " loading crl from '%s' failed", file);
489 }
490 }
491
492 /**
493 * Load an attribute certificate from a file
494 */
495 static void load_x509_ac(private_stroke_cred_t *this, char *file)
496 {
497 certificate_t *cert;
498
499 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
500 BUILD_FROM_FILE, file, BUILD_END);
501 if (cert)
502 {
503 DBG1(DBG_CFG, " loaded attribute certificate from '%s'", file);
504 this->creds->add_cert(this->creds, FALSE, cert);
505 }
506 else
507 {
508 DBG1(DBG_CFG, " loading attribute certificate from '%s' failed", file);
509 }
510 }
511
512 /**
513 * load trusted certificates from a directory
514 */
515 static void load_certdir(private_stroke_cred_t *this, char *path,
516 certificate_type_t type, x509_flag_t flag)
517 {
518 enumerator_t *enumerator;
519 struct stat st;
520 char *file;
521
522 enumerator = enumerator_create_directory(path);
523 if (enumerator)
524 {
525 while (enumerator->enumerate(enumerator, NULL, &file, &st))
526 {
527 if (!S_ISREG(st.st_mode))
528 {
529 /* skip special file */
530 continue;
531 }
532 switch (type)
533 {
534 case CERT_X509:
535 if (flag & X509_CA)
536 {
537 load_x509_ca(this, file);
538 }
539 else if (flag & X509_AA)
540 {
541 load_x509_aa(this, file);
542 }
543 else
544 {
545 load_x509(this, file, flag);
546 }
547 break;
548 case CERT_X509_CRL:
549 load_x509_crl(this, file);
550 break;
551 case CERT_X509_AC:
552 load_x509_ac(this, file);
553 break;
554 default:
555 break;
556 }
557 }
558 enumerator->destroy(enumerator);
559 }
560 else
561 {
562 DBG1(DBG_CFG, " reading directory failed");
563 }
564 }
565
566 METHOD(stroke_cred_t, cache_cert, void,
567 private_stroke_cred_t *this, certificate_t *cert)
568 {
569 if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl)
570 {
571 /* CRLs get written to /etc/ipsec.d/crls/<authkeyId>.crl */
572 crl_t *crl = (crl_t*)cert;
573
574 cert->get_ref(cert);
575 if (this->creds->add_crl(this->creds, crl))
576 {
577 char buf[BUF_LEN];
578 chunk_t chunk, hex;
579
580 chunk = crl->get_authKeyIdentifier(crl);
581 hex = chunk_to_hex(chunk, NULL, FALSE);
582 snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_DIR, hex.ptr);
583 free(hex.ptr);
584
585 if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
586 {
587 if (chunk_write(chunk, buf, 022, TRUE))
588 {
589 DBG1(DBG_CFG, " written crl file '%s' (%d bytes)",
590 buf, chunk.len);
591 }
592 else
593 {
594 DBG1(DBG_CFG, " writing crl file '%s' failed: %s",
595 buf, strerror(errno));
596 }
597 free(chunk.ptr);
598 }
599 }
600 }
601 }
602
603 METHOD(stroke_cred_t, cachecrl, void,
604 private_stroke_cred_t *this, bool enabled)
605 {
606 DBG1(DBG_CFG, "crl caching to %s %s",
607 CRL_DIR, enabled ? "enabled" : "disabled");
608 this->cachecrl = enabled;
609 }
610
611
612 /**
613 * Convert a string of characters into a binary secret
614 * A string between single or double quotes is treated as ASCII characters
615 * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
616 */
617 static err_t extract_secret(chunk_t *secret, chunk_t *line)
618 {
619 chunk_t raw_secret;
620 char delimiter = ' ';
621 bool quotes = FALSE;
622
623 if (!eat_whitespace(line))
624 {
625 return "missing secret";
626 }
627
628 if (*line->ptr == '\'' || *line->ptr == '"')
629 {
630 quotes = TRUE;
631 delimiter = *line->ptr;
632 line->ptr++; line->len--;
633 }
634
635 if (!extract_token(&raw_secret, delimiter, line))
636 {
637 if (delimiter == ' ')
638 {
639 raw_secret = *line;
640 }
641 else
642 {
643 return "missing second delimiter";
644 }
645 }
646
647 if (quotes)
648 {
649 /* treat as an ASCII string */
650 *secret = chunk_clone(raw_secret);
651 return NULL;
652 }
653 /* treat 0x as hex, 0s as base64 */
654 if (raw_secret.len > 2)
655 {
656 if (strncasecmp("0x", raw_secret.ptr, 2) == 0)
657 {
658 *secret = chunk_from_hex(chunk_skip(raw_secret, 2), NULL);
659 return NULL;
660 }
661 if (strncasecmp("0s", raw_secret.ptr, 2) == 0)
662 {
663 *secret = chunk_from_base64(chunk_skip(raw_secret, 2), NULL);
664 return NULL;
665 }
666 }
667 *secret = chunk_clone(raw_secret);
668 return NULL;
669 }
670
671 /**
672 * Data for passphrase callback
673 */
674 typedef struct {
675 /** cached passphrases */
676 mem_cred_t *cache;
677 /** socket we use for prompting */
678 FILE *prompt;
679 /** type of secret to unlock */
680 int type;
681 /** private key file */
682 char *path;
683 /** number of tries */
684 int try;
685 } passphrase_cb_data_t;
686
687 /**
688 * Callback function to receive passphrases
689 */
690 static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
691 shared_key_type_t type, identification_t *me,
692 identification_t *other, id_match_t *match_me,
693 id_match_t *match_other)
694 {
695 static const int max_tries = 3;
696 shared_key_t *shared;
697 chunk_t secret;
698 char buf[256];
699
700 if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS)
701 {
702 return NULL;
703 }
704
705 data->try++;
706 if (data->try > max_tries + 1)
707 { /* another builder might call this after we gave up, fail silently */
708 return NULL;
709 }
710 if (data->try > max_tries)
711 {
712 fprintf(data->prompt, "Passphrase invalid, giving up.\n");
713 return NULL;
714 }
715 if (data->try > 1)
716 {
717 fprintf(data->prompt, "Passphrase invalid!\n");
718 }
719 fprintf(data->prompt, "%s '%s' is encrypted.\n",
720 data->type == CRED_PRIVATE_KEY ? "Private key" : "PKCS#12 file",
721 data->path);
722 fprintf(data->prompt, "Passphrase:\n");
723 if (fgets(buf, sizeof(buf), data->prompt))
724 {
725 secret = chunk_create(buf, strlen(buf));
726 if (secret.len > 1)
727 { /* trim appended \n */
728 secret.len--;
729 if (match_me)
730 {
731 *match_me = ID_MATCH_PERFECT;
732 }
733 if (match_other)
734 {
735 *match_other = ID_MATCH_NONE;
736 }
737 shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
738 chunk_clone(secret));
739 data->cache->add_shared(data->cache, shared->get_ref(shared), NULL);
740 return shared;
741 }
742 }
743 return NULL;
744 }
745
746 /**
747 * Data for PIN callback
748 */
749 typedef struct {
750 /** socket we use for prompting */
751 FILE *prompt;
752 /** card label */
753 char *card;
754 /** card keyid */
755 chunk_t keyid;
756 /** number of tries */
757 int try;
758 } pin_cb_data_t;
759
760 /**
761 * Callback function to receive PINs
762 */
763 static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
764 identification_t *me, identification_t *other,
765 id_match_t *match_me, id_match_t *match_other)
766 {
767 chunk_t secret;
768 char buf[256];
769
770 if (type != SHARED_ANY && type != SHARED_PIN)
771 {
772 return NULL;
773 }
774
775 if (!me || !chunk_equals(me->get_encoding(me), data->keyid))
776 {
777 return NULL;
778 }
779
780 data->try++;
781 if (data->try > 1)
782 {
783 fprintf(data->prompt, "PIN invalid, aborting.\n");
784 return NULL;
785 }
786 fprintf(data->prompt, "Login to '%s' required\n", data->card);
787 fprintf(data->prompt, "PIN:\n");
788 if (fgets(buf, sizeof(buf), data->prompt))
789 {
790 secret = chunk_create(buf, strlen(buf));
791 if (secret.len > 1)
792 { /* trim appended \n */
793 secret.len--;
794 if (match_me)
795 {
796 *match_me = ID_MATCH_PERFECT;
797 }
798 if (match_other)
799 {
800 *match_other = ID_MATCH_NONE;
801 }
802 return shared_key_create(SHARED_PIN, chunk_clone(secret));
803 }
804 }
805 return NULL;
806 }
807
808 /**
809 * Load a smartcard with a PIN
810 */
811 static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
812 FILE *prompt)
813 {
814 chunk_t sc = chunk_empty, secret = chunk_empty;
815 char smartcard[BUF_LEN], keyid[SC_PART_LEN], module[SC_PART_LEN];
816 private_key_t *key = NULL;
817 u_int slot;
818 chunk_t chunk;
819 shared_key_t *shared;
820 identification_t *id;
821 mem_cred_t *mem = NULL;
822 callback_cred_t *cb = NULL;
823 pin_cb_data_t pin_data;
824 smartcard_format_t format;
825
826 err_t ugh = extract_value(&sc, &line);
827
828 if (ugh != NULL)
829 {
830 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
831 return FALSE;
832 }
833 if (sc.len == 0)
834 {
835 DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr);
836 return FALSE;
837 }
838 snprintf(smartcard, sizeof(smartcard), "%.*s", (int)sc.len, sc.ptr);
839 smartcard[sizeof(smartcard) - 1] = '\0';
840
841 format = parse_smartcard(smartcard, &slot, module, keyid);
842 if (format == SC_FORMAT_INVALID)
843 {
844 DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
845 " supported or invalid", line_nr);
846 return FALSE;
847 }
848
849 if (!eat_whitespace(&line))
850 {
851 DBG1(DBG_CFG, "line %d: expected PIN", line_nr);
852 return FALSE;
853 }
854 ugh = extract_secret(&secret, &line);
855 if (ugh != NULL)
856 {
857 DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh);
858 return FALSE;
859 }
860
861 chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
862 if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
863 {
864 free(secret.ptr);
865 if (!prompt)
866 { /* no IO channel to prompt, skip */
867 chunk_clear(&chunk);
868 return TRUE;
869 }
870 /* use callback credential set to prompt for the pin */
871 pin_data.prompt = prompt;
872 pin_data.card = smartcard;
873 pin_data.keyid = chunk;
874 pin_data.try = 0;
875 cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
876 lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
877 }
878 else
879 {
880 /* provide our pin in a temporary credential set */
881 shared = shared_key_create(SHARED_PIN, secret);
882 id = identification_create_from_encoding(ID_KEY_ID, chunk);
883 mem = mem_cred_create();
884 mem->add_shared(mem, shared, id, NULL);
885 lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
886 }
887
888 /* unlock: smartcard needs the pin and potentially calls public set */
889 key = (private_key_t*)load_from_smartcard(format, slot, module, keyid,
890 CRED_PRIVATE_KEY, KEY_ANY);
891 if (mem)
892 {
893 lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
894 mem->destroy(mem);
895 }
896 if (cb)
897 {
898 lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
899 cb->destroy(cb);
900 }
901 chunk_clear(&chunk);
902
903 if (key)
904 {
905 DBG1(DBG_CFG, " loaded private key from %.*s", (int)sc.len, sc.ptr);
906 secrets->add_key(secrets, key);
907 }
908 return TRUE;
909 }
910
911 /**
912 * Load a private key or PKCS#12 container from a file
913 */
914 static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
915 char *path, int type, int subtype,
916 void **result)
917 {
918 chunk_t filename;
919 chunk_t secret = chunk_empty;
920
921 err_t ugh = extract_value(&filename, &line);
922
923 if (ugh != NULL)
924 {
925 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
926 return FALSE;
927 }
928 if (filename.len == 0)
929 {
930 DBG1(DBG_CFG, "line %d: empty filename", line_nr);
931 return FALSE;
932 }
933 if (*filename.ptr == '/')
934 {
935 /* absolute path name */
936 snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
937 }
938 else
939 {
940 /* relative path name */
941 snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
942 (int)filename.len, filename.ptr);
943 }
944
945 /* check for optional passphrase */
946 if (eat_whitespace(&line))
947 {
948 ugh = extract_secret(&secret, &line);
949 if (ugh != NULL)
950 {
951 DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
952 return FALSE;
953 }
954 }
955 if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
956 {
957 callback_cred_t *cb;
958 passphrase_cb_data_t pp_data = {
959 .prompt = prompt,
960 .type = type,
961 .path = path,
962 .try = 0,
963 };
964
965 free(secret.ptr);
966 if (!prompt)
967 {
968 *result = NULL;
969 return TRUE;
970 }
971 /* add cache first so if valid passphrases are needed multiple times
972 * the callback is not called anymore */
973 pp_data.cache = mem_cred_create();
974 lib->credmgr->add_local_set(lib->credmgr, &pp_data.cache->set, FALSE);
975 /* use callback credential set to prompt for the passphrase */
976 cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
977 lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
978
979 *result = lib->creds->create(lib->creds, type, subtype,
980 BUILD_FROM_FILE, path, BUILD_END);
981
982 lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
983 cb->destroy(cb);
984 lib->credmgr->remove_local_set(lib->credmgr, &pp_data.cache->set);
985 pp_data.cache->destroy(pp_data.cache);
986 }
987 else
988 {
989 mem_cred_t *mem = NULL;
990 shared_key_t *shared;
991
992 /* provide our pin in a temporary credential set */
993 shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
994 mem = mem_cred_create();
995 mem->add_shared(mem, shared, NULL);
996 if (eat_whitespace(&line))
997 { /* if there is a second passphrase add that too, could be needed for
998 * PKCS#12 files using different passwords for MAC and encryption */
999 ugh = extract_secret(&secret, &line);
1000 if (ugh != NULL)
1001 {
1002 DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
1003 mem->destroy(mem);
1004 return FALSE;
1005 }
1006 shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
1007 mem->add_shared(mem, shared, NULL);
1008 }
1009 lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
1010
1011 *result = lib->creds->create(lib->creds, type, subtype,
1012 BUILD_FROM_FILE, path, BUILD_END);
1013
1014 lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
1015 mem->destroy(mem);
1016 }
1017 return TRUE;
1018 }
1019
1020 /**
1021 * Load a private key
1022 */
1023 static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
1024 FILE *prompt, key_type_t key_type)
1025 {
1026 char path[PATH_MAX];
1027 private_key_t *key;
1028
1029 if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
1030 key_type, (void**)&key))
1031 {
1032 return FALSE;
1033 }
1034 if (key)
1035 {
1036 DBG1(DBG_CFG, " loaded %N private key from '%s'",
1037 key_type_names, key->get_type(key), path);
1038 secrets->add_key(secrets, key);
1039 }
1040 else
1041 {
1042 DBG1(DBG_CFG, " loading private key from '%s' failed", path);
1043 }
1044 return TRUE;
1045 }
1046
1047 /**
1048 * Load a PKCS#12 container
1049 */
1050 static bool load_pkcs12(private_stroke_cred_t *this, mem_cred_t *secrets,
1051 chunk_t line, int line_nr, FILE *prompt)
1052 {
1053 enumerator_t *enumerator;
1054 char path[PATH_MAX];
1055 certificate_t *cert;
1056 private_key_t *key;
1057 pkcs12_t *pkcs12;
1058
1059 if (!load_from_file(line, line_nr, prompt, path, CRED_CONTAINER,
1060 CONTAINER_PKCS12, (void**)&pkcs12))
1061 {
1062 return FALSE;
1063 }
1064 if (!pkcs12)
1065 {
1066 DBG1(DBG_CFG, " loading credentials from '%s' failed", path);
1067 return TRUE;
1068 }
1069 enumerator = pkcs12->create_cert_enumerator(pkcs12);
1070 while (enumerator->enumerate(enumerator, &cert))
1071 {
1072 x509_t *x509 = (x509_t*)cert;
1073
1074 if (x509->get_flags(x509) & X509_CA)
1075 {
1076 DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
1077 cert->get_subject(cert), path);
1078 }
1079 else
1080 {
1081 DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
1082 cert->get_subject(cert), path);
1083 }
1084 this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
1085 }
1086 enumerator->destroy(enumerator);
1087 enumerator = pkcs12->create_key_enumerator(pkcs12);
1088 while (enumerator->enumerate(enumerator, &key))
1089 {
1090 DBG1(DBG_CFG, " loaded %N private key from '%s'",
1091 key_type_names, key->get_type(key), path);
1092 secrets->add_key(secrets, key->get_ref(key));
1093 }
1094 enumerator->destroy(enumerator);
1095 pkcs12->container.destroy(&pkcs12->container);
1096 return TRUE;
1097 }
1098
1099 /**
1100 * Load a shared key
1101 */
1102 static bool load_shared(mem_cred_t *secrets, chunk_t line, int line_nr,
1103 shared_key_type_t type, chunk_t ids)
1104 {
1105 shared_key_t *shared_key;
1106 linked_list_t *owners;
1107 chunk_t secret = chunk_empty;
1108 bool any = TRUE;
1109
1110 err_t ugh = extract_secret(&secret, &line);
1111 if (ugh != NULL)
1112 {
1113 DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
1114 return FALSE;
1115 }
1116 shared_key = shared_key_create(type, secret);
1117 DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type,
1118 ids.len > 0 ? (char*)ids.ptr : "%any");
1119 DBG4(DBG_CFG, " secret: %#B", &secret);
1120
1121 owners = linked_list_create();
1122 while (ids.len > 0)
1123 {
1124 chunk_t id;
1125 identification_t *peer_id;
1126
1127 ugh = extract_value(&id, &ids);
1128 if (ugh != NULL)
1129 {
1130 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
1131 shared_key->destroy(shared_key);
1132 owners->destroy_offset(owners, offsetof(identification_t, destroy));
1133 return FALSE;
1134 }
1135 if (id.len == 0)
1136 {
1137 continue;
1138 }
1139
1140 /* NULL terminate the ID string */
1141 *(id.ptr + id.len) = '\0';
1142 peer_id = identification_create_from_string(id.ptr);
1143 if (peer_id->get_type(peer_id) == ID_ANY)
1144 {
1145 peer_id->destroy(peer_id);
1146 continue;
1147 }
1148
1149 owners->insert_last(owners, peer_id);
1150 any = FALSE;
1151 }
1152 if (any)
1153 {
1154 owners->insert_last(owners,
1155 identification_create_from_encoding(ID_ANY, chunk_empty));
1156 }
1157 secrets->add_shared_list(secrets, shared_key, owners);
1158 return TRUE;
1159 }
1160
1161 /**
1162 * reload ipsec.secrets
1163 */
1164 static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
1165 char *file, int level, FILE *prompt)
1166 {
1167 int line_nr = 0;
1168 chunk_t *src, line;
1169
1170 DBG1(DBG_CFG, "loading secrets from '%s'", file);
1171 src = chunk_map(file, FALSE);
1172 if (!src)
1173 {
1174 DBG1(DBG_CFG, "opening secrets file '%s' failed: %s", file,
1175 strerror(errno));
1176 return;
1177 }
1178
1179 if (!secrets)
1180 {
1181 secrets = mem_cred_create();
1182 }
1183
1184 while (fetchline(src, &line))
1185 {
1186 chunk_t ids, token;
1187 key_type_t key_type;
1188 shared_key_type_t type;
1189
1190 line_nr++;
1191
1192 if (!eat_whitespace(&line))
1193 {
1194 continue;
1195 }
1196 if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
1197 {
1198 char **expanded, *dir, pattern[PATH_MAX];
1199 u_char *pos;
1200
1201 if (level > MAX_SECRETS_RECURSION)
1202 {
1203 DBG1(DBG_CFG, "maximum level of %d includes reached, ignored",
1204 MAX_SECRETS_RECURSION);
1205 continue;
1206 }
1207 /* terminate filename by space */
1208 line = chunk_skip(line, strlen("include "));
1209 pos = memchr(line.ptr, ' ', line.len);
1210 if (pos)
1211 {
1212 line.len = pos - line.ptr;
1213 }
1214 if (line.len && line.ptr[0] == '/')
1215 {
1216 if (line.len + 1 > sizeof(pattern))
1217 {
1218 DBG1(DBG_CFG, "include pattern too long, ignored");
1219 continue;
1220 }
1221 snprintf(pattern, sizeof(pattern), "%.*s",
1222 (int)line.len, line.ptr);
1223 }
1224 else
1225 { /* use directory of current file if relative */
1226 dir = path_dirname(file);
1227
1228 if (line.len + 1 + strlen(dir) + 1 > sizeof(pattern))
1229 {
1230 DBG1(DBG_CFG, "include pattern too long, ignored");
1231 free(dir);
1232 continue;
1233 }
1234 snprintf(pattern, sizeof(pattern), "%s/%.*s",
1235 dir, (int)line.len, line.ptr);
1236 free(dir);
1237 }
1238 #ifdef HAVE_GLOB_H
1239 {
1240 glob_t buf;
1241 if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
1242 {
1243 DBG1(DBG_CFG, "expanding file expression '%s' failed",
1244 pattern);
1245 }
1246 else
1247 {
1248 for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
1249 {
1250 load_secrets(this, secrets, *expanded, level + 1,
1251 prompt);
1252 }
1253 }
1254 globfree(&buf);
1255 }
1256 #else /* HAVE_GLOB_H */
1257 /* if glob(3) is not available, try to load pattern directly */
1258 load_secrets(this, secrets, pattern, level + 1, prompt);
1259 #endif /* HAVE_GLOB_H */
1260 continue;
1261 }
1262
1263 if (line.len > 2 && strpfx(line.ptr, ": "))
1264 {
1265 /* no ids, skip the ':' */
1266 ids = chunk_empty;
1267 line.ptr++;
1268 line.len--;
1269 }
1270 else if (extract_token_str(&ids, " : ", &line))
1271 {
1272 /* NULL terminate the extracted id string */
1273 *(ids.ptr + ids.len) = '\0';
1274 }
1275 else
1276 {
1277 DBG1(DBG_CFG, "line %d: missing ' : ' separator", line_nr);
1278 break;
1279 }
1280
1281 if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
1282 {
1283 DBG1(DBG_CFG, "line %d: missing token", line_nr);
1284 break;
1285 }
1286 if (match("RSA", &token) || match("ECDSA", &token) ||
1287 match("BLISS", &token))
1288 {
1289 if (match("RSA", &token))
1290 {
1291 key_type = KEY_RSA;
1292 }
1293 else if (match("ECDSA", &token))
1294 {
1295 key_type = KEY_ECDSA;
1296 }
1297 else
1298 {
1299 key_type = KEY_BLISS;
1300 }
1301 if (!load_private(secrets, line, line_nr, prompt, key_type))
1302 {
1303 break;
1304 }
1305 }
1306 else if (match("P12", &token))
1307 {
1308 if (!load_pkcs12(this, secrets, line, line_nr, prompt))
1309 {
1310 break;
1311 }
1312 }
1313 else if (match("PIN", &token))
1314 {
1315 if (!load_pin(secrets, line, line_nr, prompt))
1316 {
1317 break;
1318 }
1319 }
1320 else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
1321 (match("EAP", &token) && (type = SHARED_EAP)) ||
1322 (match("NTLM", &token) && (type = SHARED_NT_HASH)) ||
1323 (match("XAUTH", &token) && (type = SHARED_EAP)))
1324 {
1325 if (!load_shared(secrets, line, line_nr, type, ids))
1326 {
1327 break;
1328 }
1329 }
1330 else
1331 {
1332 DBG1(DBG_CFG, "line %d: token must be either RSA, ECDSA, BLISS, "
1333 "P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
1334 break;
1335 }
1336 }
1337 chunk_unmap(src);
1338
1339 if (level == 0)
1340 { /* replace secrets in active credential set */
1341 this->creds->replace_secrets(this->creds, secrets, FALSE);
1342 secrets->destroy(secrets);
1343 }
1344 }
1345
1346 /**
1347 * load all certificates from ipsec.d
1348 */
1349 static void load_certs(private_stroke_cred_t *this)
1350 {
1351 DBG1(DBG_CFG, "loading ca certificates from '%s'",
1352 CA_CERTIFICATE_DIR);
1353 load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
1354
1355 DBG1(DBG_CFG, "loading aa certificates from '%s'",
1356 AA_CERTIFICATE_DIR);
1357 load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
1358
1359 DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
1360 OCSP_CERTIFICATE_DIR);
1361 load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER);
1362
1363 DBG1(DBG_CFG, "loading attribute certificates from '%s'",
1364 ATTR_CERTIFICATE_DIR);
1365 load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
1366
1367 DBG1(DBG_CFG, "loading crls from '%s'",
1368 CRL_DIR);
1369 load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
1370 }
1371
1372 METHOD(stroke_cred_t, reread, void,
1373 private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
1374 {
1375 if (msg->reread.flags & REREAD_SECRETS)
1376 {
1377 DBG1(DBG_CFG, "rereading secrets");
1378 load_secrets(this, NULL, this->secrets_file, 0, prompt);
1379 }
1380 if (msg->reread.flags & REREAD_CACERTS)
1381 {
1382 DBG1(DBG_CFG, "rereading ca certificates from '%s'",
1383 CA_CERTIFICATE_DIR);
1384 load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
1385 }
1386 if (msg->reread.flags & REREAD_OCSPCERTS)
1387 {
1388 DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
1389 OCSP_CERTIFICATE_DIR);
1390 load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
1391 X509_OCSP_SIGNER);
1392 }
1393 if (msg->reread.flags & REREAD_AACERTS)
1394 {
1395 DBG1(DBG_CFG, "rereading aa certificates from '%s'",
1396 AA_CERTIFICATE_DIR);
1397 load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
1398 }
1399 if (msg->reread.flags & REREAD_ACERTS)
1400 {
1401 DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
1402 ATTR_CERTIFICATE_DIR);
1403 load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
1404 }
1405 if (msg->reread.flags & REREAD_CRLS)
1406 {
1407 DBG1(DBG_CFG, "rereading crls from '%s'",
1408 CRL_DIR);
1409 load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
1410 }
1411 }
1412
1413 METHOD(stroke_cred_t, add_shared, void,
1414 private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners)
1415 {
1416 this->creds->add_shared_list(this->creds, shared, owners);
1417 }
1418
1419 METHOD(stroke_cred_t, destroy, void,
1420 private_stroke_cred_t *this)
1421 {
1422 lib->credmgr->remove_set(lib->credmgr, &this->aacerts->set);
1423 lib->credmgr->remove_set(lib->credmgr, &this->cacerts->set);
1424 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
1425 this->aacerts->destroy(this->aacerts);
1426 this->cacerts->destroy(this->cacerts);
1427 this->creds->destroy(this->creds);
1428 free(this);
1429 }
1430
1431 /*
1432 * see header file
1433 */
1434 stroke_cred_t *stroke_cred_create()
1435 {
1436 private_stroke_cred_t *this;
1437
1438 INIT(this,
1439 .public = {
1440 .set = {
1441 .create_private_enumerator = (void*)return_null,
1442 .create_cert_enumerator = (void*)return_null,
1443 .create_shared_enumerator = (void*)return_null,
1444 .create_cdp_enumerator = (void*)return_null,
1445 .cache_cert = (void*)_cache_cert,
1446 },
1447 .reread = _reread,
1448 .load_ca = _load_ca,
1449 .load_peer = _load_peer,
1450 .load_pubkey = _load_pubkey,
1451 .add_shared = _add_shared,
1452 .cachecrl = _cachecrl,
1453 .destroy = _destroy,
1454 },
1455 .secrets_file = lib->settings->get_str(lib->settings,
1456 "%s.plugins.stroke.secrets_file", SECRETS_FILE,
1457 lib->ns),
1458 .creds = mem_cred_create(),
1459 .cacerts = mem_cred_create(),
1460 .aacerts = mem_cred_create(),
1461 );
1462
1463 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
1464 lib->credmgr->add_set(lib->credmgr, &this->cacerts->set);
1465 lib->credmgr->add_set(lib->credmgr, &this->aacerts->set);
1466
1467 this->force_ca_cert = lib->settings->get_bool(lib->settings,
1468 "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
1469 FALSE, lib->ns);
1470
1471 load_certs(this);
1472 load_secrets(this, NULL, this->secrets_file, 0, NULL);
1473
1474 return &this->public;
1475 }