60dbdf619e256f9cbe15ddc45710d78a58097402
[strongswan.git] / src / libcharon / plugins / stroke / stroke_cred.c
1 /*
2 * Copyright (C) 2008-2012 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 <libgen.h>
21 #include <sys/mman.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <unistd.h>
25
26 #ifdef HAVE_GLOB_H
27 #include <glob.h>
28 #endif
29
30 #include "stroke_cred.h"
31
32 #include <credentials/certificates/x509.h>
33 #include <credentials/certificates/crl.h>
34 #include <credentials/certificates/ac.h>
35 #include <credentials/sets/mem_cred.h>
36 #include <credentials/sets/callback_cred.h>
37 #include <utils/linked_list.h>
38 #include <utils/lexparser.h>
39 #include <threading/rwlock.h>
40 #include <daemon.h>
41
42 /* configuration directories and files */
43 #define CONFIG_DIR IPSEC_CONFDIR
44 #define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
45 #define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
46 #define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
47 #define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
48 #define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
49 #define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
50 #define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
51 #define CRL_DIR IPSEC_D_DIR "/crls"
52 #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
53
54 #define MAX_SECRETS_RECURSION 10
55
56 typedef struct private_stroke_cred_t private_stroke_cred_t;
57
58 /**
59 * private data of stroke_cred
60 */
61 struct private_stroke_cred_t {
62
63 /**
64 * public functions
65 */
66 stroke_cred_t public;
67
68 /**
69 * credentials
70 */
71 mem_cred_t *creds;
72
73 /**
74 * ignore missing CA basic constraint (i.e. treat all certificates in
75 * ipsec.conf ca sections and ipsec.d/cacert as CA certificates)
76 */
77 bool force_ca_cert;
78
79 /**
80 * cache CRLs to disk?
81 */
82 bool cachecrl;
83 };
84
85 METHOD(stroke_cred_t, load_ca, certificate_t*,
86 private_stroke_cred_t *this, char *filename)
87 {
88 certificate_t *cert;
89 char path[PATH_MAX];
90
91 if (*filename == '/')
92 {
93 snprintf(path, sizeof(path), "%s", filename);
94 }
95 else
96 {
97 snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
98 }
99
100 if (this->force_ca_cert)
101 { /* we treat this certificate as a CA certificate even if it has no
102 * CA basic constraint */
103 cert = lib->creds->create(lib->creds,
104 CRED_CERTIFICATE, CERT_X509,
105 BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
106 BUILD_END);
107 }
108 else
109 {
110 cert = lib->creds->create(lib->creds,
111 CRED_CERTIFICATE, CERT_X509,
112 BUILD_FROM_FILE, path,
113 BUILD_END);
114 }
115 if (cert)
116 {
117 x509_t *x509 = (x509_t*)cert;
118
119 if (!(x509->get_flags(x509) & X509_CA))
120 {
121 DBG1(DBG_CFG, " ca certificate \"%Y\" misses ca basic constraint, "
122 "discarded", cert->get_subject(cert));
123 cert->destroy(cert);
124 return NULL;
125 }
126 return this->creds->add_cert_ref(this->creds, TRUE, cert);
127 }
128 return NULL;
129 }
130
131 METHOD(stroke_cred_t, load_peer, certificate_t*,
132 private_stroke_cred_t *this, char *filename)
133 {
134 certificate_t *cert;
135 char path[PATH_MAX];
136 chunk_t keyid;
137
138 if (strneq(filename, "%smartcard:", strlen("%smartcard:")))
139 {
140 keyid = chunk_create(filename, strlen(filename));
141 keyid = chunk_from_hex(chunk_skip(keyid, strlen("%smartcard:")), NULL);
142 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
143 BUILD_PKCS11_KEYID, keyid, BUILD_END);
144 free(keyid.ptr);
145 }
146 else
147 {
148 if (*filename == '/')
149 {
150 snprintf(path, sizeof(path), "%s", filename);
151 }
152 else
153 {
154 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
155 }
156
157 cert = lib->creds->create(lib->creds,
158 CRED_CERTIFICATE, CERT_ANY,
159 BUILD_FROM_FILE, path,
160 BUILD_END);
161 }
162 if (cert)
163 {
164 cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
165 DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
166 cert->get_subject(cert), filename);
167 return cert;
168 }
169 DBG1(DBG_CFG, " loading certificate from '%s' failed", filename);
170 return NULL;
171 }
172
173 METHOD(stroke_cred_t, load_pubkey, certificate_t*,
174 private_stroke_cred_t *this, key_type_t type, char *filename,
175 identification_t *identity)
176 {
177 certificate_t *cert;
178 char path[PATH_MAX];
179
180 if (streq(filename, "%dns"))
181 {
182
183 }
184 else if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
185 {
186 chunk_t printable_key, rfc3110_key;
187 public_key_t *key;
188
189 printable_key = chunk_create(filename + 2, strlen(filename) - 2);
190 rfc3110_key = strncaseeq(filename, "0x", 2) ?
191 chunk_from_hex(printable_key, NULL) :
192 chunk_from_base64(printable_key, NULL);
193 key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
194 BUILD_BLOB_DNSKEY, rfc3110_key,
195 BUILD_END);
196 free(rfc3110_key.ptr);
197 if (key)
198 {
199 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
200 CERT_TRUSTED_PUBKEY,
201 BUILD_PUBLIC_KEY, key,
202 BUILD_SUBJECT, identity,
203 BUILD_END);
204 key->destroy(key);
205 if (cert)
206 {
207 cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
208 DBG1(DBG_CFG, " loaded %N public key for \"%Y\"",
209 key_type_names, type, identity);
210 return cert;
211 }
212 }
213 DBG1(DBG_CFG, " loading %N public key for \"%Y\" failed",
214 key_type_names, type, identity);
215 }
216 else
217 {
218 if (*filename == '/')
219 {
220 snprintf(path, sizeof(path), "%s", filename);
221 }
222 else
223 {
224 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
225 }
226
227 cert = lib->creds->create(lib->creds,
228 CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
229 BUILD_FROM_FILE, path,
230 BUILD_SUBJECT, identity,
231 BUILD_END);
232 if (cert)
233 {
234 cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
235 DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'",
236 key_type_names, type, identity, filename);
237 return cert;
238 }
239 DBG1(DBG_CFG, " loading %N public key for \"%Y\" from '%s' failed",
240 key_type_names, type, identity, filename);
241 }
242 return NULL;
243 }
244
245 /**
246 * load trusted certificates from a directory
247 */
248 static void load_certdir(private_stroke_cred_t *this, char *path,
249 certificate_type_t type, x509_flag_t flag)
250 {
251 struct stat st;
252 char *file;
253
254 enumerator_t *enumerator = enumerator_create_directory(path);
255
256 if (!enumerator)
257 {
258 DBG1(DBG_CFG, " reading directory failed");
259 return;
260 }
261
262 while (enumerator->enumerate(enumerator, NULL, &file, &st))
263 {
264 certificate_t *cert;
265
266 if (!S_ISREG(st.st_mode))
267 {
268 /* skip special file */
269 continue;
270 }
271 switch (type)
272 {
273 case CERT_X509:
274 if (flag & X509_CA)
275 {
276 if (this->force_ca_cert)
277 { /* treat this certificate as CA cert even it has no
278 * CA basic constraint */
279 cert = lib->creds->create(lib->creds,
280 CRED_CERTIFICATE, CERT_X509,
281 BUILD_FROM_FILE, file, BUILD_X509_FLAG,
282 X509_CA, BUILD_END);
283 }
284 else
285 {
286 cert = lib->creds->create(lib->creds,
287 CRED_CERTIFICATE, CERT_X509,
288 BUILD_FROM_FILE, file, BUILD_END);
289 }
290 if (cert)
291 {
292 x509_t *x509 = (x509_t*)cert;
293
294 if (!(x509->get_flags(x509) & X509_CA))
295 {
296 DBG1(DBG_CFG, " ca certificate \"%Y\" lacks "
297 "ca basic constraint, discarded",
298 cert->get_subject(cert));
299 cert->destroy(cert);
300 cert = NULL;
301 }
302 else
303 {
304 DBG1(DBG_CFG, " loaded ca certificate \"%Y\" "
305 "from '%s'", cert->get_subject(cert), file);
306 }
307 }
308 else
309 {
310 DBG1(DBG_CFG, " loading ca certificate from '%s' "
311 "failed", file);
312 }
313 }
314 else
315 { /* for all other flags, we add them to the certificate. */
316 cert = lib->creds->create(lib->creds,
317 CRED_CERTIFICATE, CERT_X509,
318 BUILD_FROM_FILE, file,
319 BUILD_X509_FLAG, flag, BUILD_END);
320 if (cert)
321 {
322 DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
323 cert->get_subject(cert), file);
324 }
325 else
326 {
327 DBG1(DBG_CFG, " loading certificate from '%s' "
328 "failed", file);
329 }
330 }
331 if (cert)
332 {
333 this->creds->add_cert(this->creds, TRUE, cert);
334 }
335 break;
336 case CERT_X509_CRL:
337 cert = lib->creds->create(lib->creds,
338 CRED_CERTIFICATE, CERT_X509_CRL,
339 BUILD_FROM_FILE, file,
340 BUILD_END);
341 if (cert)
342 {
343 this->creds->add_crl(this->creds, (crl_t*)cert);
344 DBG1(DBG_CFG, " loaded crl from '%s'", file);
345 }
346 else
347 {
348 DBG1(DBG_CFG, " loading crl from '%s' failed", file);
349 }
350 break;
351 case CERT_X509_AC:
352 cert = lib->creds->create(lib->creds,
353 CRED_CERTIFICATE, CERT_X509_AC,
354 BUILD_FROM_FILE, file,
355 BUILD_END);
356 if (cert)
357 {
358 this->creds->add_cert(this->creds, FALSE, cert);
359 DBG1(DBG_CFG, " loaded attribute certificate from '%s'",
360 file);
361 }
362 else
363 {
364 DBG1(DBG_CFG, " loading attribute certificate from '%s' "
365 "failed", file);
366 }
367 break;
368 default:
369 break;
370 }
371 }
372 enumerator->destroy(enumerator);
373 }
374
375 METHOD(stroke_cred_t, cache_cert, void,
376 private_stroke_cred_t *this, certificate_t *cert)
377 {
378 if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl)
379 {
380 /* CRLs get written to /etc/ipsec.d/crls/<authkeyId>.crl */
381 crl_t *crl = (crl_t*)cert;
382
383 cert->get_ref(cert);
384 if (this->creds->add_crl(this->creds, crl))
385 {
386 char buf[BUF_LEN];
387 chunk_t chunk, hex;
388
389 chunk = crl->get_authKeyIdentifier(crl);
390 hex = chunk_to_hex(chunk, NULL, FALSE);
391 snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_DIR, hex.ptr);
392 free(hex.ptr);
393
394 if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
395 {
396 chunk_write(chunk, buf, "crl", 022, TRUE);
397 free(chunk.ptr);
398 }
399 }
400 }
401 }
402
403 METHOD(stroke_cred_t, cachecrl, void,
404 private_stroke_cred_t *this, bool enabled)
405 {
406 DBG1(DBG_CFG, "crl caching to %s %s",
407 CRL_DIR, enabled ? "enabled" : "disabled");
408 this->cachecrl = enabled;
409 }
410
411
412 /**
413 * Convert a string of characters into a binary secret
414 * A string between single or double quotes is treated as ASCII characters
415 * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
416 */
417 static err_t extract_secret(chunk_t *secret, chunk_t *line)
418 {
419 chunk_t raw_secret;
420 char delimiter = ' ';
421 bool quotes = FALSE;
422
423 if (!eat_whitespace(line))
424 {
425 return "missing secret";
426 }
427
428 if (*line->ptr == '\'' || *line->ptr == '"')
429 {
430 quotes = TRUE;
431 delimiter = *line->ptr;
432 line->ptr++; line->len--;
433 }
434
435 if (!extract_token(&raw_secret, delimiter, line))
436 {
437 if (delimiter == ' ')
438 {
439 raw_secret = *line;
440 }
441 else
442 {
443 return "missing second delimiter";
444 }
445 }
446
447 if (quotes)
448 {
449 /* treat as an ASCII string */
450 *secret = chunk_clone(raw_secret);
451 return NULL;
452 }
453 /* treat 0x as hex, 0s as base64 */
454 if (raw_secret.len > 2)
455 {
456 if (strncasecmp("0x", raw_secret.ptr, 2) == 0)
457 {
458 *secret = chunk_from_hex(chunk_skip(raw_secret, 2), NULL);
459 return NULL;
460 }
461 if (strncasecmp("0s", raw_secret.ptr, 2) == 0)
462 {
463 *secret = chunk_from_base64(chunk_skip(raw_secret, 2), NULL);
464 return NULL;
465 }
466 }
467 *secret = chunk_clone(raw_secret);
468 return NULL;
469 }
470
471 /**
472 * Data for passphrase callback
473 */
474 typedef struct {
475 /** socket we use for prompting */
476 FILE *prompt;
477 /** private key file */
478 char *path;
479 /** number of tries */
480 int try;
481 } passphrase_cb_data_t;
482
483 /**
484 * Callback function to receive Passphrases
485 */
486 static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
487 shared_key_type_t type,
488 identification_t *me, identification_t *other,
489 id_match_t *match_me, id_match_t *match_other)
490 {
491 chunk_t secret;
492 char buf[256];
493
494 if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS)
495 {
496 return NULL;
497 }
498
499 if (data->try > 1)
500 {
501 if (data->try > 5)
502 {
503 fprintf(data->prompt, "PIN invalid, giving up.\n");
504 return NULL;
505 }
506 fprintf(data->prompt, "PIN invalid!\n");
507 }
508 data->try++;
509 fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path);
510 fprintf(data->prompt, "Passphrase:\n");
511 if (fgets(buf, sizeof(buf), data->prompt))
512 {
513 secret = chunk_create(buf, strlen(buf));
514 if (secret.len > 1)
515 { /* trim appended \n */
516 secret.len--;
517 if (match_me)
518 {
519 *match_me = ID_MATCH_PERFECT;
520 }
521 if (match_other)
522 {
523 *match_other = ID_MATCH_NONE;
524 }
525 return shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(secret));
526 }
527 }
528 return NULL;
529 }
530
531 /**
532 * Data for PIN callback
533 */
534 typedef struct {
535 /** socket we use for prompting */
536 FILE *prompt;
537 /** card label */
538 char *card;
539 /** card keyid */
540 chunk_t keyid;
541 /** number of tries */
542 int try;
543 } pin_cb_data_t;
544
545 /**
546 * Callback function to receive PINs
547 */
548 static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
549 identification_t *me, identification_t *other,
550 id_match_t *match_me, id_match_t *match_other)
551 {
552 chunk_t secret;
553 char buf[256];
554
555 if (type != SHARED_ANY && type != SHARED_PIN)
556 {
557 return NULL;
558 }
559
560 if (!me || !chunk_equals(me->get_encoding(me), data->keyid))
561 {
562 return NULL;
563 }
564
565 if (data->try > 1)
566 {
567 fprintf(data->prompt, "PIN invalid, aborting.\n");
568 return NULL;
569 }
570 data->try++;
571 fprintf(data->prompt, "Login to '%s' required\n", data->card);
572 fprintf(data->prompt, "PIN:\n");
573 if (fgets(buf, sizeof(buf), data->prompt))
574 {
575 secret = chunk_create(buf, strlen(buf));
576 if (secret.len > 1)
577 { /* trim appended \n */
578 secret.len--;
579 if (match_me)
580 {
581 *match_me = ID_MATCH_PERFECT;
582 }
583 if (match_other)
584 {
585 *match_other = ID_MATCH_NONE;
586 }
587 return shared_key_create(SHARED_PIN, chunk_clone(secret));
588 }
589 }
590 return NULL;
591 }
592
593 /**
594 * Load a smartcard with a PIN
595 */
596 static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr,
597 FILE *prompt)
598 {
599 chunk_t sc = chunk_empty, secret = chunk_empty;
600 char smartcard[64], keyid[64], module[64], *pos;
601 private_key_t *key = NULL;
602 u_int slot;
603 chunk_t chunk;
604 shared_key_t *shared;
605 identification_t *id;
606 mem_cred_t *mem = NULL;
607 callback_cred_t *cb = NULL;
608 pin_cb_data_t pin_data;
609 enum {
610 SC_FORMAT_SLOT_MODULE_KEYID,
611 SC_FORMAT_SLOT_KEYID,
612 SC_FORMAT_KEYID,
613 } format;
614
615 err_t ugh = extract_value(&sc, &line);
616
617 if (ugh != NULL)
618 {
619 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
620 return FALSE;
621 }
622 if (sc.len == 0)
623 {
624 DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr);
625 return FALSE;
626 }
627 snprintf(smartcard, sizeof(smartcard), "%.*s", (int)sc.len, sc.ptr);
628 smartcard[sizeof(smartcard) - 1] = '\0';
629
630 /* parse slot and key id. Three formats are supported:
631 * - %smartcard<slot>@<module>:<keyid>
632 * - %smartcard<slot>:<keyid>
633 * - %smartcard:<keyid>
634 */
635 if (sscanf(smartcard, "%%smartcard%u@%s", &slot, module) == 2)
636 {
637 pos = strchr(module, ':');
638 if (!pos)
639 {
640 DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is "
641 "invalid", line_nr);
642 return FALSE;
643 }
644 *pos = '\0';
645 strncpy(keyid, pos + 1, sizeof(keyid));
646 format = SC_FORMAT_SLOT_MODULE_KEYID;
647 }
648 else if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2)
649 {
650 format = SC_FORMAT_SLOT_KEYID;
651 }
652 else if (sscanf(smartcard, "%%smartcard:%s", keyid) == 1)
653 {
654 format = SC_FORMAT_KEYID;
655 }
656 else
657 {
658 DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
659 " supported or invalid", line_nr);
660 return FALSE;
661 }
662
663 if (!eat_whitespace(&line))
664 {
665 DBG1(DBG_CFG, "line %d: expected PIN", line_nr);
666 return FALSE;
667 }
668 ugh = extract_secret(&secret, &line);
669 if (ugh != NULL)
670 {
671 DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh);
672 return FALSE;
673 }
674
675 chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
676 if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
677 {
678 free(secret.ptr);
679 if (!prompt)
680 { /* no IO channel to prompt, skip */
681 chunk_clear(&chunk);
682 return TRUE;
683 }
684 /* use callback credential set to prompt for the pin */
685 pin_data.prompt = prompt;
686 pin_data.card = smartcard;
687 pin_data.keyid = chunk;
688 pin_data.try = 1;
689 cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
690 lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
691 }
692 else
693 {
694 /* provide our pin in a temporary credential set */
695 shared = shared_key_create(SHARED_PIN, secret);
696 id = identification_create_from_encoding(ID_KEY_ID, chunk);
697 mem = mem_cred_create();
698 mem->add_shared(mem, shared, id, NULL);
699 lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
700 }
701
702 /* unlock: smartcard needs the pin and potentially calls public set */
703 switch (format)
704 {
705 case SC_FORMAT_SLOT_MODULE_KEYID:
706 key = lib->creds->create(lib->creds,
707 CRED_PRIVATE_KEY, KEY_ANY,
708 BUILD_PKCS11_SLOT, slot,
709 BUILD_PKCS11_MODULE, module,
710 BUILD_PKCS11_KEYID, chunk, BUILD_END);
711 break;
712 case SC_FORMAT_SLOT_KEYID:
713 key = lib->creds->create(lib->creds,
714 CRED_PRIVATE_KEY, KEY_ANY,
715 BUILD_PKCS11_SLOT, slot,
716 BUILD_PKCS11_KEYID, chunk, BUILD_END);
717 break;
718 case SC_FORMAT_KEYID:
719 key = lib->creds->create(lib->creds,
720 CRED_PRIVATE_KEY, KEY_ANY,
721 BUILD_PKCS11_KEYID, chunk, BUILD_END);
722 break;
723 }
724 if (mem)
725 {
726 lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
727 mem->destroy(mem);
728 }
729 if (cb)
730 {
731 lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
732 cb->destroy(cb);
733 }
734 chunk_clear(&chunk);
735
736 if (key)
737 {
738 DBG1(DBG_CFG, " loaded private key from %.*s", (int)sc.len, sc.ptr);
739 this->creds->add_key(this->creds, key);
740 }
741 return TRUE;
742 }
743
744 /**
745 * Load a private key
746 */
747 static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr,
748 FILE *prompt, key_type_t key_type)
749 {
750 char path[PATH_MAX];
751 chunk_t filename;
752 chunk_t secret = chunk_empty;
753 private_key_t *key;
754
755 err_t ugh = extract_value(&filename, &line);
756
757 if (ugh != NULL)
758 {
759 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
760 return FALSE;
761 }
762 if (filename.len == 0)
763 {
764 DBG1(DBG_CFG, "line %d: empty filename", line_nr);
765 return FALSE;
766 }
767 if (*filename.ptr == '/')
768 {
769 /* absolute path name */
770 snprintf(path, sizeof(path), "%.*s", (int)filename.len, filename.ptr);
771 }
772 else
773 {
774 /* relative path name */
775 snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR,
776 (int)filename.len, filename.ptr);
777 }
778
779 /* check for optional passphrase */
780 if (eat_whitespace(&line))
781 {
782 ugh = extract_secret(&secret, &line);
783 if (ugh != NULL)
784 {
785 DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
786 return FALSE;
787 }
788 }
789 if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
790 {
791 callback_cred_t *cb = NULL;
792 passphrase_cb_data_t pp_data = {
793 .prompt = prompt,
794 .path = path,
795 .try = 1,
796 };
797
798 free(secret.ptr);
799 if (!prompt)
800 {
801 return TRUE;
802 }
803 /* use callback credential set to prompt for the passphrase */
804 pp_data.prompt = prompt;
805 pp_data.path = path;
806 pp_data.try = 1;
807 cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
808 lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
809
810 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
811 BUILD_FROM_FILE, path, BUILD_END);
812
813 lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
814 cb->destroy(cb);
815 }
816 else
817 {
818 mem_cred_t *mem = NULL;
819 shared_key_t *shared;
820
821 /* provide our pin in a temporary credential set */
822 shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
823 mem = mem_cred_create();
824 mem->add_shared(mem, shared, NULL);
825 lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
826
827 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
828 BUILD_FROM_FILE, path, BUILD_END);
829
830 lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
831 mem->destroy(mem);
832 }
833 if (key)
834 {
835 DBG1(DBG_CFG, " loaded %N private key from '%s'",
836 key_type_names, key->get_type(key), path);
837 this->creds->add_key(this->creds, key);
838 }
839 else
840 {
841 DBG1(DBG_CFG, " loading private key from '%s' failed", path);
842 }
843 return TRUE;
844 }
845
846 /**
847 * Load a shared key
848 */
849 static bool load_shared(private_stroke_cred_t *this, chunk_t line, int line_nr,
850 shared_key_type_t type, chunk_t ids)
851 {
852 shared_key_t *shared_key;
853 linked_list_t *owners;
854 chunk_t secret = chunk_empty;
855 bool any = TRUE;
856
857 err_t ugh = extract_secret(&secret, &line);
858 if (ugh != NULL)
859 {
860 DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
861 return FALSE;
862 }
863 shared_key = shared_key_create(type, secret);
864 DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type,
865 ids.len > 0 ? (char*)ids.ptr : "%any");
866 DBG4(DBG_CFG, " secret: %#B", &secret);
867
868 owners = linked_list_create();
869 while (ids.len > 0)
870 {
871 chunk_t id;
872 identification_t *peer_id;
873
874 ugh = extract_value(&id, &ids);
875 if (ugh != NULL)
876 {
877 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
878 shared_key->destroy(shared_key);
879 owners->destroy_offset(owners, offsetof(identification_t, destroy));
880 return FALSE;
881 }
882 if (id.len == 0)
883 {
884 continue;
885 }
886
887 /* NULL terminate the ID string */
888 *(id.ptr + id.len) = '\0';
889 peer_id = identification_create_from_string(id.ptr);
890 if (peer_id->get_type(peer_id) == ID_ANY)
891 {
892 peer_id->destroy(peer_id);
893 continue;
894 }
895
896 owners->insert_last(owners, peer_id);
897 any = FALSE;
898 }
899 if (any)
900 {
901 owners->insert_last(owners,
902 identification_create_from_encoding(ID_ANY, chunk_empty));
903 }
904 this->creds->add_shared_list(this->creds, shared_key, owners);
905 return TRUE;
906 }
907
908 /**
909 * reload ipsec.secrets
910 */
911 static void load_secrets(private_stroke_cred_t *this, char *file, int level,
912 FILE *prompt)
913 {
914 int line_nr = 0, fd;
915 chunk_t src, line;
916 struct stat sb;
917 void *addr;
918
919 DBG1(DBG_CFG, "loading secrets from '%s'", file);
920 fd = open(file, O_RDONLY);
921 if (fd == -1)
922 {
923 DBG1(DBG_CFG, "opening secrets file '%s' failed: %s", file,
924 strerror(errno));
925 return;
926 }
927 if (fstat(fd, &sb) == -1)
928 {
929 DBG1(DBG_LIB, "getting file size of '%s' failed: %s", file,
930 strerror(errno));
931 close(fd);
932 return;
933 }
934 addr = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
935 if (addr == MAP_FAILED)
936 {
937 DBG1(DBG_LIB, "mapping '%s' failed: %s", file, strerror(errno));
938 close(fd);
939 return;
940 }
941 src = chunk_create(addr, sb.st_size);
942
943 if (level == 0)
944 { /* flush secrets on non-recursive invocation */
945 this->creds->clear_secrets(this->creds);
946 }
947
948 while (fetchline(&src, &line))
949 {
950 chunk_t ids, token;
951 shared_key_type_t type;
952
953 line_nr++;
954
955 if (!eat_whitespace(&line))
956 {
957 continue;
958 }
959 if (line.len > strlen("include ") &&
960 strneq(line.ptr, "include ", strlen("include ")))
961 {
962 char **expanded, *dir, pattern[PATH_MAX];
963 u_char *pos;
964
965 if (level > MAX_SECRETS_RECURSION)
966 {
967 DBG1(DBG_CFG, "maximum level of %d includes reached, ignored",
968 MAX_SECRETS_RECURSION);
969 continue;
970 }
971 /* terminate filename by space */
972 line = chunk_skip(line, strlen("include "));
973 pos = memchr(line.ptr, ' ', line.len);
974 if (pos)
975 {
976 line.len = pos - line.ptr;
977 }
978 if (line.len && line.ptr[0] == '/')
979 {
980 if (line.len + 1 > sizeof(pattern))
981 {
982 DBG1(DBG_CFG, "include pattern too long, ignored");
983 continue;
984 }
985 snprintf(pattern, sizeof(pattern), "%.*s",
986 (int)line.len, line.ptr);
987 }
988 else
989 { /* use directory of current file if relative */
990 dir = strdup(file);
991 dir = dirname(dir);
992
993 if (line.len + 1 + strlen(dir) + 1 > sizeof(pattern))
994 {
995 DBG1(DBG_CFG, "include pattern too long, ignored");
996 free(dir);
997 continue;
998 }
999 snprintf(pattern, sizeof(pattern), "%s/%.*s",
1000 dir, (int)line.len, line.ptr);
1001 free(dir);
1002 }
1003 #ifdef HAVE_GLOB_H
1004 {
1005 glob_t buf;
1006 if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
1007 {
1008 DBG1(DBG_CFG, "expanding file expression '%s' failed",
1009 pattern);
1010 }
1011 else
1012 {
1013 for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
1014 {
1015 load_secrets(this, *expanded, level + 1, prompt);
1016 }
1017 }
1018 globfree(&buf);
1019 }
1020 #else /* HAVE_GLOB_H */
1021 /* if glob(3) is not available, try to load pattern directly */
1022 load_secrets(this, pattern, level + 1, prompt);
1023 #endif /* HAVE_GLOB_H */
1024 continue;
1025 }
1026
1027 if (line.len > 2 && strneq(": ", line.ptr, 2))
1028 {
1029 /* no ids, skip the ':' */
1030 ids = chunk_empty;
1031 line.ptr++;
1032 line.len--;
1033 }
1034 else if (extract_token_str(&ids, " : ", &line))
1035 {
1036 /* NULL terminate the extracted id string */
1037 *(ids.ptr + ids.len) = '\0';
1038 }
1039 else
1040 {
1041 DBG1(DBG_CFG, "line %d: missing ' : ' separator", line_nr);
1042 break;
1043 }
1044
1045 if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
1046 {
1047 DBG1(DBG_CFG, "line %d: missing token", line_nr);
1048 break;
1049 }
1050 if (match("RSA", &token) || match("ECDSA", &token))
1051 {
1052 if (!load_private(this, line, line_nr, prompt,
1053 match("RSA", &token) ? KEY_RSA : KEY_ECDSA))
1054 {
1055 break;
1056 }
1057 }
1058 else if (match("PIN", &token))
1059 {
1060 if (!load_pin(this, line, line_nr, prompt))
1061 {
1062 break;
1063 }
1064 }
1065 else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
1066 (match("EAP", &token) && (type = SHARED_EAP)) ||
1067 (match("NTLM", &token) && (type = SHARED_NT_HASH)) ||
1068 (match("XAUTH", &token) && (type = SHARED_EAP)))
1069 {
1070 if (!load_shared(this, line, line_nr, type, ids))
1071 {
1072 break;
1073 }
1074 }
1075 else
1076 {
1077 DBG1(DBG_CFG, "line %d: token must be either "
1078 "RSA, ECDSA, PSK, EAP, XAUTH or PIN", line_nr);
1079 break;
1080 }
1081 }
1082 munmap(addr, sb.st_size);
1083 close(fd);
1084 }
1085
1086 /**
1087 * load all certificates from ipsec.d
1088 */
1089 static void load_certs(private_stroke_cred_t *this)
1090 {
1091 DBG1(DBG_CFG, "loading ca certificates from '%s'",
1092 CA_CERTIFICATE_DIR);
1093 load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
1094
1095 DBG1(DBG_CFG, "loading aa certificates from '%s'",
1096 AA_CERTIFICATE_DIR);
1097 load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
1098
1099 DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
1100 OCSP_CERTIFICATE_DIR);
1101 load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER);
1102
1103 DBG1(DBG_CFG, "loading attribute certificates from '%s'",
1104 ATTR_CERTIFICATE_DIR);
1105 load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
1106
1107 DBG1(DBG_CFG, "loading crls from '%s'",
1108 CRL_DIR);
1109 load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
1110 }
1111
1112 METHOD(stroke_cred_t, reread, void,
1113 private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
1114 {
1115 if (msg->reread.flags & REREAD_SECRETS)
1116 {
1117 DBG1(DBG_CFG, "rereading secrets");
1118 load_secrets(this, SECRETS_FILE, 0, prompt);
1119 }
1120 if (msg->reread.flags & REREAD_CACERTS)
1121 {
1122 DBG1(DBG_CFG, "rereading ca certificates from '%s'",
1123 CA_CERTIFICATE_DIR);
1124 load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
1125 }
1126 if (msg->reread.flags & REREAD_OCSPCERTS)
1127 {
1128 DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
1129 OCSP_CERTIFICATE_DIR);
1130 load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
1131 X509_OCSP_SIGNER);
1132 }
1133 if (msg->reread.flags & REREAD_AACERTS)
1134 {
1135 DBG1(DBG_CFG, "rereading aa certificates from '%s'",
1136 AA_CERTIFICATE_DIR);
1137 load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
1138 }
1139 if (msg->reread.flags & REREAD_ACERTS)
1140 {
1141 DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
1142 ATTR_CERTIFICATE_DIR);
1143 load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
1144 }
1145 if (msg->reread.flags & REREAD_CRLS)
1146 {
1147 DBG1(DBG_CFG, "rereading crls from '%s'",
1148 CRL_DIR);
1149 load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
1150 }
1151 }
1152
1153 METHOD(stroke_cred_t, add_shared, void,
1154 private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners)
1155 {
1156 this->creds->add_shared_list(this->creds, shared, owners);
1157 }
1158
1159 METHOD(stroke_cred_t, destroy, void,
1160 private_stroke_cred_t *this)
1161 {
1162 lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
1163 this->creds->destroy(this->creds);
1164 free(this);
1165 }
1166
1167 /*
1168 * see header file
1169 */
1170 stroke_cred_t *stroke_cred_create()
1171 {
1172 private_stroke_cred_t *this;
1173
1174 INIT(this,
1175 .public = {
1176 .set = {
1177 .create_private_enumerator = (void*)return_null,
1178 .create_cert_enumerator = (void*)return_null,
1179 .create_shared_enumerator = (void*)return_null,
1180 .create_cdp_enumerator = (void*)return_null,
1181 .cache_cert = (void*)_cache_cert,
1182 },
1183 .reread = _reread,
1184 .load_ca = _load_ca,
1185 .load_peer = _load_peer,
1186 .load_pubkey = _load_pubkey,
1187 .add_shared = _add_shared,
1188 .cachecrl = _cachecrl,
1189 .destroy = _destroy,
1190 },
1191 .creds = mem_cred_create(),
1192 );
1193
1194 lib->credmgr->add_set(lib->credmgr, &this->creds->set);
1195
1196 this->force_ca_cert = lib->settings->get_bool(lib->settings,
1197 "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
1198 FALSE, charon->name);
1199
1200 load_certs(this);
1201 load_secrets(this, SECRETS_FILE, 0, NULL);
1202
1203 return &this->public;
1204 }
1205