53957b72a453386d3c2788a74c0cbd524a82614d
[strongswan.git] / src / charon / config / credentials / local_credential_store.c
1 /**
2 * @file local_credential_store.c
3 *
4 * @brief Implementation of local_credential_store_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include <library.h>
29 #include <utils/lexparser.h>
30 #include <utils/linked_list.h>
31 #include <crypto/rsa/rsa_public_key.h>
32 #include <crypto/certinfo.h>
33 #include <crypto/x509.h>
34 #include <crypto/ca.h>
35 #include <crypto/crl.h>
36 #include <asn1/ttodata.h>
37
38 #include "local_credential_store.h"
39
40 #define PATH_BUF 256
41 #define MAX_CA_PATH_LEN 7
42
43 typedef struct shared_key_t shared_key_t;
44
45 /**
46 * Private date of a shared_key_t object
47 */
48 struct shared_key_t {
49
50 /**
51 * shared secret
52 */
53 chunk_t secret;
54
55 /**
56 * list of peer IDs
57 */
58 linked_list_t *peers;
59 };
60
61
62 /**
63 * Implementation of shared_key_t.destroy.
64 */
65 static void shared_key_destroy(shared_key_t *this)
66 {
67 this->peers->destroy_offset(this->peers, offsetof(identification_t, destroy));
68 chunk_free(&this->secret);
69 free(this);
70 }
71
72 /**
73 * @brief Creates a shared_key_t object.
74 *
75 * @param shared_key shared key value
76 * @return shared_key_t object
77 *
78 * @ingroup config
79 */
80 static shared_key_t *shared_key_create(chunk_t secret)
81 {
82 shared_key_t *this = malloc_thing(shared_key_t);
83
84 /* private data */
85 this->secret = chunk_clone(secret);
86 this->peers = linked_list_create();
87
88 return (this);
89 }
90
91 /* ---------------------------------------------------------------------- *
92 * the ca_info_t object as a central control element
93
94 +------------------------------------------------------+
95 | local_credential_store_t |
96 +------------------------------------------------------+
97 | |
98 +-------------------------+ +-------------------------+
99 | linked_list_t *ca_certs | | linked_list_t *ca_infos |
100 +-------------------------+ +-------------------------+
101 | |
102 | +------------------------- +
103 | | ca_info_t |
104 | +--------------------------+
105 +---------------+ | char *name |
106 | x509_t |<--| x509_t *cacert | +----------------------+
107 +---------------+ | linked_list_t *certinfos |-->| certinfo_t |
108 | chunk_t keyid | | linked_list_t *ocspuris | +----------------------+
109 +---------------+ | bool ocsp_fetch_pending | | chunk_t serialNumber |
110 | | crl_t *crl | | cert_status_t status |
111 | | linked_list_t *crluris | | time_t thisUpdate |
112 | | bool crl_fetch_pending | | time_t nextUpdate |
113 | | pthread_mutex_t mutex | | bool once |
114 | +--------------------------+ +----------------------+
115 | | |
116 | +------------------------- + +----------------------+
117 | | ca_info_t | | certinfo_t |
118 | +--------------------------+ +----------------------+
119 +---------------+ | char *name | | chunk_t serialNumber |
120 | x509_t |<--| x509_t *cacert | | cert_status_t status |
121 +---------------+ | linked_list_t *certinfos | | time_t thisUpdate |
122 | chunk_t keyid | | linked_list_t *ocspuris | | time_t nextUpdate |
123 +---------------+ | bool ocsp_fetch_pending | | bool once |
124 | | crl_t *crl | +----------------------+
125 | | linked_list_t *crluris | |
126 | | bool crl_fetch_pending |
127 | | pthread_mutex_t mutex; |
128 | +--------------------------+
129 | |
130
131 * ---------------------------------------------------------------------- */
132
133 typedef struct private_local_credential_store_t private_local_credential_store_t;
134
135 /**
136 * Private data of an local_credential_store_t object
137 */
138 struct private_local_credential_store_t {
139
140 /**
141 * Public part
142 */
143 local_credential_store_t public;
144
145 /**
146 * list of shared keys
147 */
148 linked_list_t *shared_keys;
149
150 /**
151 * list of key_entry_t's with private keys
152 */
153 linked_list_t *private_keys;
154
155 /**
156 * list of X.509 certificates with public keys
157 */
158 linked_list_t *certs;
159
160 /**
161 * list of X.509 CA certificates with public keys
162 */
163 linked_list_t *ca_certs;
164
165 /**
166 * list of X.509 CA information records
167 */
168 linked_list_t *ca_infos;
169
170 /**
171 * enforce strict crl policy
172 */
173 bool strict;
174 };
175
176
177 /**
178 * Implementation of local_credential_store_t.get_shared_key.
179 */
180 static status_t get_shared_key(private_local_credential_store_t *this,
181 identification_t *my_id,
182 identification_t *other_id, chunk_t *secret)
183 {
184 typedef enum {
185 PRIO_UNDEFINED= 0x00,
186 PRIO_ANY_MATCH= 0x01,
187 PRIO_MY_MATCH= 0x02,
188 PRIO_OTHER_MATCH= 0x04,
189 } prio_t;
190
191 prio_t best_prio = PRIO_UNDEFINED;
192 chunk_t found = chunk_empty;
193 shared_key_t *shared_key;
194
195 iterator_t *iterator = this->shared_keys->create_iterator(this->shared_keys, TRUE);
196
197 while (iterator->iterate(iterator, (void**)&shared_key))
198 {
199 iterator_t *peer_iterator;
200 identification_t *peer_id;
201 prio_t prio = PRIO_UNDEFINED;
202
203 peer_iterator = shared_key->peers->create_iterator(shared_key->peers, TRUE);
204
205 if (peer_iterator->get_count(peer_iterator) == 0)
206 {
207 /* this is a wildcard shared key */
208 prio = PRIO_ANY_MATCH;
209 }
210 else
211 {
212 while (peer_iterator->iterate(peer_iterator, (void**)&peer_id))
213 {
214 if (my_id->equals(my_id, peer_id))
215 {
216 prio |= PRIO_MY_MATCH;
217 }
218 if (other_id->equals(other_id, peer_id))
219 {
220 prio |= PRIO_OTHER_MATCH;
221 }
222 }
223 }
224 peer_iterator->destroy(peer_iterator);
225
226 if (prio > best_prio)
227 {
228 best_prio = prio;
229 found = shared_key->secret;
230 }
231 }
232 iterator->destroy(iterator);
233
234 if (best_prio == PRIO_UNDEFINED)
235 {
236 return NOT_FOUND;
237 }
238 else
239 {
240 *secret = chunk_clone(found);
241 return SUCCESS;
242 }
243 }
244
245 /**
246 * Implementation of credential_store_t.get_certificate.
247 */
248 static x509_t* get_certificate(private_local_credential_store_t *this,
249 identification_t *id)
250 {
251 x509_t *found = NULL;
252 x509_t *current_cert;
253
254 iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
255
256 while (iterator->iterate(iterator, (void**)&current_cert))
257 {
258 if (id->equals(id, current_cert->get_subject(current_cert)) ||
259 current_cert->equals_subjectAltName(current_cert, id))
260 {
261 found = current_cert;
262 break;
263 }
264 }
265 iterator->destroy(iterator);
266 return found;
267 }
268
269 /**
270 * Implementation of local_credential_store_t.get_rsa_public_key.
271 */
272 static rsa_public_key_t *get_rsa_public_key(private_local_credential_store_t *this,
273 identification_t *id)
274 {
275 x509_t *cert = get_certificate(this, id);
276
277 return (cert == NULL)? NULL:cert->get_public_key(cert);
278 }
279
280 /**
281 * Implementation of local_credential_store_t.get_trusted_public_key.
282 */
283 static rsa_public_key_t *get_trusted_public_key(private_local_credential_store_t *this,
284 identification_t *id)
285 {
286 cert_status_t status;
287 err_t ugh;
288
289 x509_t *cert = get_certificate(this, id);
290
291 if (cert == NULL)
292 return NULL;
293
294 ugh = cert->is_valid(cert, NULL);
295 if (ugh != NULL)
296 {
297 DBG1(DBG_CFG, "certificate %s", ugh);
298 return NULL;
299 }
300
301 status = cert->get_status(cert);
302 if (status == CERT_REVOKED || status == CERT_UNTRUSTED || (this->strict && status != CERT_GOOD))
303 {
304 DBG1(DBG_CFG, "certificate status: %N", cert_status_names, status);
305 return NULL;
306 }
307 if (status == CERT_GOOD && cert->get_until(cert) < time(NULL))
308 {
309 DBG1(DBG_CFG, "certificate is good but crl is stale");
310 return NULL;
311 }
312
313 return cert->get_public_key(cert);
314 }
315
316 /**
317 * Implementation of local_credential_store_t.get_rsa_private_key.
318 */
319 static rsa_private_key_t *get_rsa_private_key(private_local_credential_store_t *this,
320 rsa_public_key_t *pubkey)
321 {
322 rsa_private_key_t *found = NULL, *current;
323
324 iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
325
326 while (iterator->iterate(iterator, (void**)&current))
327 {
328 if (current->belongs_to(current, pubkey))
329 {
330 found = current->clone(current);
331 break;
332 }
333 }
334 iterator->destroy(iterator);
335 return found;
336 }
337
338 /**
339 * Implementation of local_credential_store_t.has_rsa_private_key.
340 */
341 static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_public_key_t *pubkey)
342 {
343 bool found = FALSE;
344 rsa_private_key_t *current;
345
346 iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
347
348 while (iterator->iterate(iterator, (void**)&current))
349 {
350 if (current->belongs_to(current, pubkey))
351 {
352 found = TRUE;
353 break;
354 }
355 }
356 iterator->destroy(iterator);
357 return found;
358 }
359
360 /**
361 * Implementation of credential_store_t.get_ca_certificate.
362 */
363 static x509_t* get_ca_certificate(private_local_credential_store_t *this,
364 identification_t *id)
365 {
366 x509_t *found = NULL;
367 x509_t *current_cert;
368
369 iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
370
371 while (iterator->iterate(iterator, (void**)&current_cert))
372 {
373 if (id->equals(id, current_cert->get_subject(current_cert)))
374 {
375 found = current_cert;
376 break;
377 }
378 }
379 iterator->destroy(iterator);
380
381 return found;
382 }
383
384 /**
385 * Implementation of credential_store_t.get_ca_certificate_by_keyid.
386 */
387 static x509_t* get_ca_certificate_by_keyid(private_local_credential_store_t *this,
388 chunk_t keyid)
389 {
390 x509_t *found = NULL;
391 x509_t *current_cert;
392
393 iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
394
395 while (iterator->iterate(iterator, (void**)&current_cert))
396 {
397 rsa_public_key_t *pubkey = current_cert->get_public_key(current_cert);
398
399 if (chunk_equals(keyid, pubkey->get_keyid(pubkey)))
400 {
401 found = current_cert;
402 break;
403 }
404 }
405 iterator->destroy(iterator);
406
407 return found;
408 }
409
410 /**
411 * Implementation of credential_store_t.get_issuer.
412 */
413 static ca_info_t* get_issuer(private_local_credential_store_t *this, const x509_t *cert)
414 {
415 ca_info_t *found = NULL;
416 ca_info_t *ca_info;
417
418 iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
419
420 while (iterator->iterate(iterator, (void**)&ca_info))
421 {
422 if (ca_info->is_cert_issuer(ca_info, cert))
423 {
424 found = ca_info;
425 break;
426 }
427 }
428 iterator->destroy(iterator);
429
430 return found;
431 }
432
433 /**
434 * Find an exact copy of a certificate in a linked list
435 */
436 static x509_t* find_certificate(linked_list_t *certs, x509_t *cert)
437 {
438 x509_t *found_cert = NULL, *current_cert;
439
440 iterator_t *iterator = certs->create_iterator(certs, TRUE);
441
442 while (iterator->iterate(iterator, (void**)&current_cert))
443 {
444 if (cert->equals(cert, current_cert))
445 {
446 found_cert = current_cert;
447 break;
448 }
449 }
450 iterator->destroy(iterator);
451
452 return found_cert;
453 }
454
455 /**
456 * Implementation of credential_store_t.verify.
457 */
458 static bool verify(private_local_credential_store_t *this, x509_t *cert, bool *found)
459 {
460 int pathlen;
461 time_t until = UNDEFINED_TIME;
462
463 x509_t *end_cert = cert;
464 x509_t *cert_copy = find_certificate(this->certs, end_cert);
465
466 *found = (cert_copy != NULL);
467 if (*found)
468 {
469 DBG2(DBG_CFG,
470 "end entitity certificate is already in credential store");
471 }
472
473 for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
474 {
475 err_t ugh = NULL;
476 ca_info_t *issuer;
477 x509_t *issuer_cert;
478 rsa_public_key_t *issuer_public_key;
479 bool valid_signature;
480
481 DBG2(DBG_CFG, "subject: '%D'", cert->get_subject(cert));
482 DBG2(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert));
483
484 ugh = cert->is_valid(cert, &until);
485 if (ugh != NULL)
486 {
487 DBG1(DBG_CFG, "certificate %s", ugh);
488 return FALSE;
489 }
490 DBG2(DBG_CFG, "certificate is valid");
491
492 issuer = get_issuer(this, cert);
493 if (issuer == NULL)
494 {
495 DBG1(DBG_CFG, "issuer info not found");
496 return FALSE;
497 }
498 DBG2(DBG_CFG, "issuer info found");
499
500 issuer_cert = issuer->get_certificate(issuer);
501 issuer_public_key = issuer_cert->get_public_key(issuer_cert);
502 valid_signature = cert->verify(cert, issuer_public_key);
503
504 if (!valid_signature)
505 {
506 DBG1(DBG_CFG, "certificate signature is invalid");
507 return FALSE;
508 }
509 DBG2(DBG_CFG, "certificate signature is valid");
510
511 /* check if cert is a self-signed root ca */
512 if (pathlen > 0 && cert->is_self_signed(cert))
513 {
514 DBG2(DBG_CFG, "reached self-signed root ca");
515
516 /* set the definite status and trust interval of the end entity certificate */
517 end_cert->set_until(end_cert, until);
518 if (cert_copy)
519 {
520 cert_copy->set_status(cert_copy, end_cert->get_status(end_cert));
521 cert_copy->set_until(cert_copy, until);
522 }
523 return TRUE;
524 }
525 else
526 {
527 time_t nextUpdate;
528 cert_status_t status;
529 certinfo_t *certinfo = certinfo_create(cert->get_serialNumber(cert));
530
531 certinfo->set_nextUpdate(certinfo, until);
532
533 /* first check certificate revocation using ocsp */
534 status = issuer->verify_by_ocsp(issuer, cert, certinfo);
535
536 /* if ocsp service is not available then fall back to crl */
537 if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && this->strict))
538 {
539 status = issuer->verify_by_crl(issuer, cert, certinfo);
540 }
541
542 nextUpdate = certinfo->get_nextUpdate(certinfo);
543 cert->set_status(cert, status);
544
545 switch (status)
546 {
547 case CERT_GOOD:
548 /* set nextUpdate */
549 cert->set_until(cert, nextUpdate);
550
551 /* if status information is stale */
552 if (this->strict && nextUpdate < time(NULL))
553 {
554 DBG2(DBG_CFG, "certificate is good but status is stale");
555 return FALSE;
556 }
557 DBG2(DBG_CFG, "certificate is good");
558
559 /* with strict crl policy the public key must have the same
560 * lifetime as the validity of the ocsp status or crl lifetime
561 */
562 if (this->strict && nextUpdate < until)
563 until = nextUpdate;
564 break;
565 case CERT_REVOKED:
566 {
567 time_t revocationTime = certinfo->get_revocationTime(certinfo);
568 DBG1(DBG_CFG,
569 "certificate was revoked on %T, reason: %N",
570 &revocationTime, crl_reason_names,
571 certinfo->get_revocationReason(certinfo));
572
573 /* set revocationTime */
574 cert->set_until(cert, revocationTime);
575
576 /* update status of end certificate in the credential store */
577 if (cert_copy)
578 {
579 if (pathlen > 0)
580 {
581 cert_copy->set_status(cert_copy, CERT_UNTRUSTED);
582 }
583 else
584 {
585 cert_copy->set_status(cert_copy, CERT_REVOKED);
586 cert_copy->set_until(cert_copy,
587 certinfo->get_revocationTime(certinfo));
588 }
589 }
590 return FALSE;
591 }
592 case CERT_UNKNOWN:
593 case CERT_UNDEFINED:
594 default:
595 DBG2(DBG_CFG, "certificate status unknown");
596 if (this->strict)
597 {
598 /* update status of end certificate in the credential store */
599 if (cert_copy)
600 {
601 cert_copy->set_status(cert_copy, CERT_UNTRUSTED);
602 }
603 return FALSE;
604 }
605 break;
606 }
607 certinfo->destroy(certinfo);
608 }
609 /* go up one step in the trust chain */
610 cert = issuer_cert;
611 }
612 DBG1(DBG_CFG, "maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
613 return FALSE;
614 }
615
616 /**
617 * Add a unique certificate to a linked list
618 */
619 static x509_t* add_certificate(linked_list_t *certs, x509_t *cert)
620 {
621 x509_t *found_cert = find_certificate(certs, cert);
622
623 if (found_cert)
624 {
625 cert->destroy(cert);
626 return found_cert;
627 }
628 else
629 {
630 certs->insert_last(certs, (void*)cert);
631 return cert;
632 }
633 }
634
635 /**
636 * Add a unique ca info record to a linked list
637 */
638 static void add_ca_info(private_local_credential_store_t *this, ca_info_t *ca_info)
639 {
640 ca_info_t *current_ca_info;
641 ca_info_t *found_ca_info = NULL;
642
643 iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
644
645 while (iterator->iterate(iterator, (void**)&current_ca_info))
646 {
647 if (current_ca_info->equals(current_ca_info, ca_info))
648 {
649 found_ca_info = current_ca_info;
650 break;
651 }
652 }
653 iterator->destroy(iterator);
654
655 if (found_ca_info)
656 {
657 current_ca_info->add_info(current_ca_info, ca_info);
658 ca_info->destroy(ca_info);
659 }
660 else
661 {
662 this->ca_infos->insert_last(this->ca_infos, (void*)ca_info);
663 }
664 }
665
666 /**
667 * Release ca info record of a given name
668 */
669 static status_t release_ca_info(private_local_credential_store_t *this, const char *name)
670 {
671 status_t status = NOT_FOUND;
672 ca_info_t *ca_info;
673
674 iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
675
676 while (iterator->iterate(iterator, (void**)&ca_info))
677 {
678 if (ca_info->equals_name_release_info(ca_info, name))
679 {
680 status = SUCCESS;
681 break;
682 }
683 }
684 iterator->destroy(iterator);
685
686 return status;
687 }
688
689 /**
690 * Implements local_credential_store_t.add_end_certificate
691 */
692 static x509_t* add_end_certificate(private_local_credential_store_t *this, x509_t *cert)
693 {
694 x509_t *ret_cert = add_certificate(this->certs, cert);
695
696 if (ret_cert == cert)
697 {
698 ca_info_t *issuer = get_issuer(this, cert);
699
700 if (issuer)
701 {
702 /* add any crl distribution points to the issuer ca info record */
703 {
704 iterator_t *iterator = cert->create_crluri_iterator(cert);
705 identification_t *uri;
706
707 while (iterator->iterate(iterator, (void**)&uri))
708 {
709 issuer->add_crluri(issuer, uri->get_encoding(uri));
710 }
711 iterator->destroy(iterator);
712 }
713 /* add any ocsp access points to the issuer ca info record */
714 {
715 iterator_t *iterator = cert->create_ocspuri_iterator(cert);
716 identification_t *uri;
717
718 while (iterator->iterate(iterator, (void**)&uri))
719 {
720 issuer->add_ocspuri(issuer, uri->get_encoding(uri));
721 }
722 iterator->destroy(iterator);
723 }
724 }
725 }
726 return ret_cert;
727 }
728
729 /**
730 * Implements local_credential_store_t.add_ca_certificate
731 */
732 static x509_t* add_ca_certificate(private_local_credential_store_t *this, x509_t *cert)
733 {
734 return add_certificate(this->ca_certs, cert);
735 }
736
737 /**
738 * Implements local_credential_store_t.create_cert_iterator
739 */
740 static iterator_t* create_cert_iterator(private_local_credential_store_t *this)
741 {
742 return this->certs->create_iterator(this->certs, TRUE);
743 }
744
745 /**
746 * Implements local_credential_store_t.create_cacert_iterator
747 */
748 static iterator_t* create_cacert_iterator(private_local_credential_store_t *this)
749 {
750 return this->ca_certs->create_iterator(this->ca_certs, TRUE);
751 }
752
753 /**
754 * Implements local_credential_store_t.create_cainfo_iterator
755 */
756 static iterator_t* create_cainfo_iterator(private_local_credential_store_t *this)
757 {
758 return this->ca_infos->create_iterator(this->ca_infos, TRUE);
759 }
760
761 /**
762 * Implements local_credential_store_t.list_crls
763 */
764 static void list_crls(private_local_credential_store_t *this, FILE *out, bool utc)
765 {
766 iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
767 ca_info_t *ca_info;
768 bool first = TRUE;
769
770 while (iterator->iterate(iterator, (void **)&ca_info))
771 {
772 if (ca_info->has_crl(ca_info))
773 {
774 if (first)
775 {
776 fprintf(out, "\n");
777 fprintf(out, "List of X.509 CRLs:\n");
778 fprintf(out, "\n");
779 first = FALSE;
780 }
781 ca_info->list_crl(ca_info, out, utc);
782 break;
783 }
784 }
785 iterator->destroy(iterator);
786 }
787
788 /**
789 * Implements local_credential_store_t.load_ca_certificates
790 */
791 static void load_ca_certificates(private_local_credential_store_t *this)
792 {
793 struct dirent* entry;
794 struct stat stb;
795 DIR* dir;
796
797 DBG1(DBG_CFG, "loading ca certificates from '%s/'", CA_CERTIFICATE_DIR);
798
799 dir = opendir(CA_CERTIFICATE_DIR);
800 if (dir == NULL)
801 {
802 DBG1(DBG_CFG, "error opening ca certs directory %s'", CA_CERTIFICATE_DIR);
803 return;
804 }
805
806 while ((entry = readdir(dir)) != NULL)
807 {
808 char file[PATH_BUF];
809
810 snprintf(file, sizeof(file), "%s/%s", CA_CERTIFICATE_DIR, entry->d_name);
811
812 if (stat(file, &stb) == -1)
813 {
814 continue;
815 }
816 /* try to parse all regular files */
817 if (stb.st_mode & S_IFREG)
818 {
819 x509_t *cert = x509_create_from_file(file, "ca certificate");
820
821 if (cert)
822 {
823 err_t ugh = cert->is_valid(cert, NULL);
824
825 if (ugh != NULL)
826 {
827 DBG1(DBG_CFG, "warning: ca certificate %s", ugh);
828 }
829 if (cert->is_ca(cert))
830 {
831 x509_t *ret_cert = add_certificate(this->ca_certs, cert);
832
833 if (ret_cert == cert)
834 {
835 ca_info_t *ca_info = ca_info_create(NULL, cert);
836
837 add_ca_info(this, ca_info);
838 }
839 }
840 else
841 {
842 DBG1(DBG_CFG, " CA basic constraints flag not set, cert discarded");
843 cert->destroy(cert);
844 }
845 }
846 }
847 }
848 closedir(dir);
849 }
850
851 /**
852 * Add the latest crl to the issuing ca
853 */
854 static void add_crl(private_local_credential_store_t *this, crl_t *crl)
855 {
856 iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
857 ca_info_t *ca_info;
858 bool found = FALSE;
859
860 while (iterator->iterate(iterator, (void**)&ca_info))
861 {
862 if (ca_info->is_crl_issuer(ca_info, crl))
863 {
864 found = TRUE;
865 ca_info->add_crl(ca_info, crl);
866 break;
867 }
868 }
869 iterator->destroy(iterator);
870
871 if (!found)
872 {
873 crl->destroy(crl);
874 DBG2(DBG_CFG, " no issuing ca found for this crl - discarded");
875 }
876 }
877
878 /**
879 * Implements local_credential_store_t.load_crls
880 */
881 static void load_crls(private_local_credential_store_t *this)
882 {
883 struct dirent* entry;
884 struct stat stb;
885 DIR* dir;
886 crl_t *crl;
887
888 DBG1(DBG_CFG, "loading crls from '%s/'", CRL_DIR);
889
890 dir = opendir(CRL_DIR);
891 if (dir == NULL)
892 {
893 DBG1(DBG_CFG, "error opening crl directory %s'", CRL_DIR);
894 return;
895 }
896
897 while ((entry = readdir(dir)) != NULL)
898 {
899 char file[PATH_BUF];
900
901 snprintf(file, sizeof(file), "%s/%s", CRL_DIR, entry->d_name);
902
903 if (stat(file, &stb) == -1)
904 {
905 continue;
906 }
907 /* try to parse all regular files */
908 if (stb.st_mode & S_IFREG)
909 {
910 crl = crl_create_from_file(file);
911 if (crl)
912 {
913 err_t ugh = crl->is_valid(crl, NULL, this->strict);
914
915 if (ugh != NULL)
916 {
917 DBG1(DBG_CFG, " warning: crl %s", ugh);
918 }
919 add_crl(this, crl);
920 }
921 }
922 }
923 closedir(dir);
924 }
925
926 /**
927 * Convert a string of characters into a binary secret
928 * A string between single or double quotes is treated as ASCII characters
929 * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
930 */
931 static err_t extract_secret(chunk_t *secret, chunk_t *line)
932 {
933 chunk_t raw_secret;
934 char delimiter = ' ';
935 bool quotes = FALSE;
936
937 if (!eat_whitespace(line))
938 {
939 return "missing secret";
940 }
941
942 if (*line->ptr == '\'' || *line->ptr == '"')
943 {
944 quotes = TRUE;
945 delimiter = *line->ptr;
946 line->ptr++; line->len--;
947 }
948
949 if (!extract_token(&raw_secret, delimiter, line))
950 {
951 if (delimiter == ' ')
952 {
953 raw_secret = *line;
954 }
955 else
956 {
957 return "missing second delimiter";
958 }
959 }
960
961 if (quotes)
962 { /* treat as an ASCII string */
963 if (raw_secret.len > secret->len)
964 return "secret larger than buffer";
965 memcpy(secret->ptr, raw_secret.ptr, raw_secret.len);
966 secret->len = raw_secret.len;
967 }
968 else
969 { /* convert from HEX or Base64 to binary */
970 size_t len;
971 err_t ugh = ttodata(raw_secret.ptr, raw_secret.len, 0, secret->ptr, secret->len, &len);
972
973 if (ugh != NULL)
974 return ugh;
975 if (len > secret->len)
976 return "secret larger than buffer";
977 secret->len = len;
978 }
979 return NULL;
980 }
981
982 /**
983 * Implements local_credential_store_t.load_secrets
984 */
985 static void load_secrets(private_local_credential_store_t *this)
986 {
987 FILE *fd = fopen(SECRETS_FILE, "r");
988
989 if (fd)
990 {
991 int bytes;
992 int line_nr = 0;
993 chunk_t chunk, src, line;
994
995 DBG1(DBG_CFG, "loading secrets from \"%s\"", SECRETS_FILE);
996
997 fseek(fd, 0, SEEK_END);
998 chunk.len = ftell(fd);
999 rewind(fd);
1000 chunk.ptr = malloc(chunk.len);
1001 bytes = fread(chunk.ptr, 1, chunk.len, fd);
1002 fclose(fd);
1003
1004 src = chunk;
1005
1006 while (fetchline(&src, &line))
1007 {
1008 chunk_t ids, token;
1009
1010 line_nr++;
1011
1012 if (!eat_whitespace(&line))
1013 {
1014 continue;
1015 }
1016 if (!extract_token(&ids, ':', &line))
1017 {
1018 DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr);
1019 goto error;
1020 }
1021 /* NULL terminate the ids string by replacing the : separator */
1022 *(ids.ptr + ids.len) = '\0';
1023
1024 if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
1025 {
1026 DBG1(DBG_CFG, "line %d: missing token", line_nr);
1027 goto error;
1028 }
1029 if (match("RSA", &token))
1030 {
1031 char path[PATH_BUF];
1032 chunk_t filename;
1033
1034 char buf[BUF_LEN];
1035 chunk_t secret = { buf, BUF_LEN };
1036 chunk_t *passphrase = NULL;
1037
1038 rsa_private_key_t *key;
1039
1040 err_t ugh = extract_value(&filename, &line);
1041
1042 if (ugh != NULL)
1043 {
1044 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
1045 goto error;
1046 }
1047 if (filename.len == 0)
1048 {
1049 DBG1(DBG_CFG, "line %d: empty filename", line_nr);
1050 goto error;
1051 }
1052 if (*filename.ptr == '/')
1053 {
1054 /* absolute path name */
1055 snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
1056 }
1057 else
1058 {
1059 /* relative path name */
1060 snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR,
1061 filename.len, filename.ptr);
1062 }
1063
1064 /* check for optional passphrase */
1065 if (eat_whitespace(&line))
1066 {
1067 ugh = extract_secret(&secret, &line);
1068 if (ugh != NULL)
1069 {
1070 DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
1071 goto error;
1072 }
1073 if (secret.len > 0)
1074 passphrase = &secret;
1075 }
1076 key = rsa_private_key_create_from_file(path, passphrase);
1077 if (key)
1078 {
1079 this->private_keys->insert_last(this->private_keys, (void*)key);
1080 }
1081 }
1082 else if (match("PSK", &token))
1083 {
1084 shared_key_t *shared_key;
1085
1086 char buf[BUF_LEN];
1087 chunk_t secret = { buf, BUF_LEN };
1088
1089 err_t ugh = extract_secret(&secret, &line);
1090 if (ugh != NULL)
1091 {
1092 DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
1093 goto error;
1094 }
1095
1096 if (ids.len > 0)
1097 {
1098 DBG1(DBG_CFG, " loading shared key for %s", ids.ptr);
1099 }
1100 else
1101 {
1102 DBG1(DBG_CFG, " loading shared key for %%any");
1103 }
1104
1105 DBG4(DBG_CFG, " secret:", secret);
1106
1107 shared_key = shared_key_create(secret);
1108 if (shared_key)
1109 {
1110 this->shared_keys->insert_last(this->shared_keys, (void*)shared_key);
1111 }
1112 while (ids.len > 0)
1113 {
1114 chunk_t id;
1115 identification_t *peer_id;
1116
1117 ugh = extract_value(&id, &ids);
1118 if (ugh != NULL)
1119 {
1120 DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
1121 goto error;
1122 }
1123 if (id.len == 0)
1124 {
1125 continue;
1126 }
1127
1128 /* NULL terminate the ID string */
1129 *(id.ptr + id.len) = '\0';
1130
1131 peer_id = identification_create_from_string(id.ptr);
1132 if (peer_id == NULL)
1133 {
1134 DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr);
1135 goto error;
1136 }
1137
1138 if (peer_id->get_type(peer_id) == ID_ANY)
1139 {
1140 peer_id->destroy(peer_id);
1141 continue;
1142 }
1143 shared_key->peers->insert_last(shared_key->peers, (void*)peer_id);
1144 }
1145 }
1146 else if (match("PIN", &token))
1147 {
1148
1149 }
1150 else
1151 {
1152 DBG1(DBG_CFG, "line %d: token must be either "
1153 "RSA, PSK, or PIN", line_nr, token.len);
1154 goto error;
1155 }
1156 }
1157 error:
1158 free(chunk.ptr);
1159 }
1160 else
1161 {
1162 DBG1(DBG_CFG, "could not open file '%s'", SECRETS_FILE);
1163 }
1164 }
1165
1166 /**
1167 * Implementation of local_credential_store_t.destroy.
1168 */
1169 static void destroy(private_local_credential_store_t *this)
1170 {
1171 this->certs->destroy_offset(this->certs, offsetof(x509_t, destroy));
1172 this->ca_certs->destroy_offset(this->ca_certs, offsetof(x509_t, destroy));
1173 this->ca_infos->destroy_offset(this->ca_infos, offsetof(ca_info_t, destroy));
1174 this->private_keys->destroy_offset(this->private_keys, offsetof(rsa_private_key_t, destroy));
1175 this->shared_keys->destroy_function(this->shared_keys, (void*)shared_key_destroy);
1176 free(this);
1177 }
1178
1179 /**
1180 * Described in header.
1181 */
1182 local_credential_store_t * local_credential_store_create(bool strict)
1183 {
1184 private_local_credential_store_t *this = malloc_thing(private_local_credential_store_t);
1185
1186 this->public.credential_store.get_shared_key = (status_t (*) (credential_store_t*,identification_t*,identification_t*,chunk_t*))get_shared_key;
1187 this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
1188 this->public.credential_store.get_rsa_private_key = (rsa_private_key_t* (*) (credential_store_t*,rsa_public_key_t*))get_rsa_private_key;
1189 this->public.credential_store.has_rsa_private_key = (bool (*) (credential_store_t*,rsa_public_key_t*))has_rsa_private_key;
1190 this->public.credential_store.get_trusted_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_trusted_public_key;
1191 this->public.credential_store.get_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_certificate;
1192 this->public.credential_store.get_ca_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_ca_certificate;
1193 this->public.credential_store.get_ca_certificate_by_keyid = (x509_t* (*) (credential_store_t*,chunk_t))get_ca_certificate_by_keyid;
1194 this->public.credential_store.get_issuer = (ca_info_t* (*) (credential_store_t*,const x509_t*))get_issuer;
1195 this->public.credential_store.verify = (bool (*) (credential_store_t*,x509_t*,bool*))verify;
1196 this->public.credential_store.add_end_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_end_certificate;
1197 this->public.credential_store.add_ca_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_ca_certificate;
1198 this->public.credential_store.add_ca_info = (void (*) (credential_store_t*,ca_info_t*))add_ca_info;
1199 this->public.credential_store.release_ca_info = (status_t (*) (credential_store_t*,const char*))release_ca_info;
1200 this->public.credential_store.create_cert_iterator = (iterator_t* (*) (credential_store_t*))create_cert_iterator;
1201 this->public.credential_store.create_cacert_iterator = (iterator_t* (*) (credential_store_t*))create_cacert_iterator;
1202 this->public.credential_store.create_cainfo_iterator = (iterator_t* (*) (credential_store_t*))create_cainfo_iterator;
1203 this->public.credential_store.list_crls = (void (*) (credential_store_t*,FILE*,bool))list_crls;
1204 this->public.credential_store.load_ca_certificates = (void (*) (credential_store_t*))load_ca_certificates;
1205 this->public.credential_store.load_crls = (void (*) (credential_store_t*))load_crls;
1206 this->public.credential_store.load_secrets = (void (*) (credential_store_t*))load_secrets;
1207 this->public.credential_store.destroy = (void (*) (credential_store_t*))destroy;
1208
1209 /* private variables */
1210 this->shared_keys = linked_list_create();
1211 this->private_keys = linked_list_create();
1212 this->certs = linked_list_create();
1213 this->ca_certs = linked_list_create();
1214 this->ca_infos = linked_list_create();
1215 this->strict = strict;
1216
1217 return (&this->public);
1218 }