2654774fa4785fdddecf1bc49eb5cb2d95c7b4f1
[strongswan.git] / src / pluto / ca.c
1 /* Certification Authority (CA) support for IKE authentication
2 * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <time.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #include <debug.h>
23 #include <utils/enumerator.h>
24 #include <credentials/certificates/x509.h>
25
26 #include <freeswan.h>
27
28 #include "constants.h"
29 #include "defs.h"
30 #include "log.h"
31 #include "x509.h"
32 #include "ca.h"
33 #include "certs.h"
34 #include "whack.h"
35 #include "fetch.h"
36 #include "smartcard.h"
37
38 /* chained list of X.509 authority certificates (ca, aa, and ocsp) */
39
40 static cert_t *x509authcerts = NULL;
41
42 /* chained list of X.509 certification authority information records */
43
44 static ca_info_t *ca_infos = NULL;
45
46 /*
47 * Checks if CA a is trusted by CA b
48 */
49 bool trusted_ca(identification_t *a, identification_t *b, int *pathlen)
50 {
51 bool match = FALSE;
52
53 /* no CA b specified -> any CA a is accepted */
54 if (b == NULL)
55 {
56 *pathlen = (a == NULL) ? 0 : X509_MAX_PATH_LEN;
57 return TRUE;
58 }
59
60 /* no CA a specified -> trust cannot be established */
61 if (a == NULL)
62 {
63 *pathlen = X509_MAX_PATH_LEN;
64 return FALSE;
65 }
66
67 *pathlen = 0;
68
69 /* CA a equals CA b -> we have a match */
70 if (a->equals(a, b))
71 {
72 return TRUE;
73 }
74
75 /* CA a might be a subordinate CA of b */
76 lock_authcert_list("trusted_ca");
77
78 while ((*pathlen)++ < X509_MAX_PATH_LEN)
79 {
80 certificate_t *certificate;
81 identification_t *issuer;
82 cert_t *cacert;
83
84 cacert = get_authcert(a, chunk_empty, X509_CA);
85 if (cacert == NULL)
86 {
87 break;
88 }
89 certificate = cacert->cert;
90
91 /* is the certificate self-signed? */
92 {
93 x509_t *x509 = (x509_t*)certificate;
94
95 if (x509->get_flags(x509) & X509_SELF_SIGNED)
96 {
97 break;
98 }
99 }
100
101 /* does the issuer of CA a match CA b? */
102 issuer = certificate->get_issuer(certificate);
103 match = b->equals(b, issuer);
104
105 /* we have a match and exit the loop */
106 if (match)
107 {
108 break;
109 }
110 /* go one level up in the CA chain */
111 a = issuer;
112 }
113
114 unlock_authcert_list("trusted_ca");
115 return match;
116 }
117
118 /*
119 * does our CA match one of the requested CAs?
120 */
121 bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca,
122 int *our_pathlen)
123 {
124 identification_t *ca;
125 enumerator_t *enumerator;
126
127 /* if no ca is requested than any ca will match */
128 if (requested_ca == NULL || requested_ca->get_count(requested_ca) == 0)
129 {
130 *our_pathlen = 0;
131 return TRUE;
132 }
133
134 *our_pathlen = X509_MAX_PATH_LEN + 1;
135
136 enumerator = requested_ca->create_enumerator(requested_ca);
137 while (enumerator->enumerate(enumerator, &ca))
138 {
139 int pathlen;
140
141 if (trusted_ca(our_ca, ca, &pathlen) && pathlen < *our_pathlen)
142 {
143 *our_pathlen = pathlen;
144 }
145 }
146 enumerator->destroy(enumerator);
147
148 if (*our_pathlen > X509_MAX_PATH_LEN)
149 {
150 *our_pathlen = X509_MAX_PATH_LEN;
151 return FALSE;
152 }
153 else
154 {
155 return TRUE;
156 }
157 }
158
159 /*
160 * free the first authority certificate in the chain
161 */
162 static void free_first_authcert(void)
163 {
164 cert_t *first = x509authcerts;
165
166 x509authcerts = first->next;
167 cert_free(first);
168 }
169
170 /*
171 * free all CA certificates
172 */
173 void free_authcerts(void)
174 {
175 lock_authcert_list("free_authcerts");
176
177 while (x509authcerts != NULL)
178 {
179 free_first_authcert();
180 }
181 unlock_authcert_list("free_authcerts");
182 }
183
184 /*
185 * get a X.509 authority certificate with a given subject or keyid
186 */
187 cert_t* get_authcert(identification_t *subject, chunk_t keyid,
188 x509_flag_t auth_flags)
189 {
190 cert_t *cert, *prev_cert = NULL;
191
192 /* the authority certificate list is empty */
193 if (x509authcerts == NULL)
194 {
195 return NULL;
196 }
197
198 for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next)
199 {
200 certificate_t *certificate = cert->cert;
201 x509_t *x509 = (x509_t*)certificate;
202
203 /* skip non-matching types of authority certificates */
204 if (!(x509->get_flags(x509) & auth_flags))
205 {
206 continue;
207 }
208
209 /* compare the keyid with the certificate's subjectKeyIdentifier */
210 if (keyid.ptr)
211 {
212 chunk_t subjectKeyId;
213
214 subjectKeyId = x509->get_subjectKeyIdentifier(x509);
215 if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
216 {
217 continue;
218 }
219 }
220
221 /* compare the subjectDistinguishedNames */
222 if (!certificate->has_subject(certificate, subject))
223 {
224 continue;
225 }
226
227 /* found the authcert */
228 if (cert != x509authcerts)
229 {
230 /* bring the certificate up front */
231 prev_cert->next = cert->next;
232 cert->next = x509authcerts;
233 x509authcerts = cert;
234 }
235 return cert;
236 }
237 return NULL;
238 }
239
240 /*
241 * add an authority certificate to the chained list
242 */
243 cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags)
244 {
245 certificate_t *certificate = cert->cert;
246 x509_t *x509 = (x509_t*)certificate;
247 cert_t *old_cert;
248
249 lock_authcert_list("add_authcert");
250
251 old_cert = get_authcert(certificate->get_subject(certificate),
252 x509->get_subjectKeyIdentifier(x509),
253 auth_flags);
254 if (old_cert)
255 {
256 if (certificate->equals(certificate, old_cert->cert))
257 {
258 DBG(DBG_CONTROL | DBG_PARSING ,
259 DBG_log(" authcert is already present and identical")
260 )
261 unlock_authcert_list("add_authcert");
262
263 cert_free(cert);
264 return old_cert;
265 }
266 else
267 {
268 /* cert is already present but will be replaced by new cert */
269 free_first_authcert();
270 DBG(DBG_CONTROL | DBG_PARSING ,
271 DBG_log(" existing authcert deleted")
272 )
273 }
274 }
275
276 /* add new authcert to chained list */
277 cert->next = x509authcerts;
278 x509authcerts = cert;
279 cert_share(cert); /* set count to one */
280 DBG(DBG_CONTROL | DBG_PARSING,
281 DBG_log(" authcert inserted")
282 )
283 unlock_authcert_list("add_authcert");
284 return cert;
285 }
286
287 /*
288 * Loads authority certificates
289 */
290 void load_authcerts(char *type, char *path, x509_flag_t auth_flags)
291 {
292 enumerator_t *enumerator;
293 struct stat st;
294 char *file;
295
296 DBG1(DBG_LIB, "loading %s certificates from '%s'", type, path);
297
298 enumerator = enumerator_create_directory(path);
299 if (!enumerator)
300 {
301 DBG1(DBG_LIB, " reading directory '%s' failed", path);
302 return;
303 }
304
305 while (enumerator->enumerate(enumerator, NULL, &file, &st))
306 {
307 cert_t *cert;
308
309 if (!S_ISREG(st.st_mode))
310 {
311 /* skip special file */
312 continue;
313 }
314 cert = load_cert(file, type, auth_flags);
315 if (cert)
316 {
317 add_authcert(cert, auth_flags);
318 }
319 }
320 enumerator->destroy(enumerator);
321 }
322
323 /*
324 * list all X.509 authcerts with given auth flags in a chained list
325 */
326 void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc)
327 {
328 lock_authcert_list("list_authcerts");
329 list_x509cert_chain(caption, x509authcerts, auth_flags, utc);
330 unlock_authcert_list("list_authcerts");
331 }
332
333 /*
334 * get a cacert with a given subject or keyid from an alternative list
335 */
336 static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid,
337 const cert_t *cert)
338 {
339 if (cert == NULL)
340 {
341 return NULL;
342 }
343 for (; cert != NULL; cert = cert->next)
344 {
345 certificate_t *certificate = cert->cert;
346
347 /* compare the keyid with the certificate's subjectKeyIdentifier */
348 if (keyid.ptr)
349 {
350 x509_t *x509 = (x509_t*)certificate;
351 chunk_t subjectKeyId;
352
353 subjectKeyId = x509->get_subjectKeyIdentifier(x509);
354 if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
355 {
356 continue;
357 }
358 }
359
360 /* compare the subjectDistinguishedNames */
361 if (!certificate->has_subject(certificate, subject))
362 {
363 continue;
364 }
365
366 /* we found the cacert */
367 return cert;
368 }
369 return NULL;
370 }
371
372 /* establish trust into a candidate authcert by going up the trust chain.
373 * validity and revocation status are not checked.
374 */
375 bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain)
376 {
377 int pathlen;
378
379 lock_authcert_list("trust_authcert_candidate");
380
381 for (pathlen = 0; pathlen < X509_MAX_PATH_LEN; pathlen++)
382 {
383 certificate_t *certificate = cert->cert;
384 x509_t *x509 = (x509_t*)certificate;
385 identification_t *subject = certificate->get_subject(certificate);
386 identification_t *issuer = certificate->get_issuer(certificate);
387 chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
388 const cert_t *authcert = NULL;
389
390 DBG(DBG_CONTROL,
391 DBG_log("subject: '%Y'", subject);
392 DBG_log("issuer: '%Y'", issuer);
393 if (authKeyID.ptr != NULL)
394 {
395 DBG_log("authkey: %#B", &authKeyID);
396 }
397 )
398
399 /* search in alternative chain first */
400 authcert = get_alt_cacert(issuer, authKeyID, alt_chain);
401
402 if (authcert != NULL)
403 {
404 DBG(DBG_CONTROL,
405 DBG_log("issuer cacert found in alternative chain")
406 )
407 }
408 else
409 {
410 /* search in trusted chain */
411 authcert = get_authcert(issuer, authKeyID, X509_CA);
412
413 if (authcert != NULL)
414 {
415 DBG(DBG_CONTROL,
416 DBG_log("issuer cacert found")
417 )
418 }
419 else
420 {
421 plog("issuer cacert not found");
422 unlock_authcert_list("trust_authcert_candidate");
423 return FALSE;
424 }
425 }
426
427 if (!certificate->issued_by(certificate, authcert->cert))
428 {
429 plog("certificate signature is invalid");
430 unlock_authcert_list("trust_authcert_candidate");
431 return FALSE;
432 }
433 DBG(DBG_CONTROL,
434 DBG_log("certificate signature is valid")
435 )
436
437 /* check if cert is a self-signed root ca */
438 if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED))
439 {
440 DBG(DBG_CONTROL,
441 DBG_log("reached self-signed root ca")
442 )
443 unlock_authcert_list("trust_authcert_candidate");
444 return TRUE;
445 }
446
447 /* go up one step in the trust chain */
448 cert = authcert;
449 }
450 plog("maximum ca path length of %d levels exceeded", X509_MAX_PATH_LEN);
451 unlock_authcert_list("trust_authcert_candidate");
452 return FALSE;
453 }
454
455 /*
456 * get a CA info record with a given authName or authKeyID
457 */
458 ca_info_t* get_ca_info(identification_t *name, chunk_t keyid)
459 {
460 ca_info_t *ca= ca_infos;
461
462 while (ca != NULL)
463 {
464 if ((keyid.ptr) ? same_keyid(keyid, ca->authKeyID)
465 : name->equals(name, ca->authName))
466 {
467 return ca;
468 }
469 ca = ca->next;
470 }
471 return NULL;
472 }
473
474
475 /*
476 * free the dynamic memory used by a ca_info record
477 */
478 static void
479 free_ca_info(ca_info_t* ca_info)
480 {
481 if (ca_info == NULL)
482 {
483 return;
484 }
485 ca_info->crluris->destroy_function(ca_info->crluris, free);
486 DESTROY_IF(ca_info->authName);
487 free(ca_info->name);
488 free(ca_info->ldaphost);
489 free(ca_info->ldapbase);
490 free(ca_info->ocspuri);
491 free(ca_info->authKeyID.ptr);
492 free(ca_info);
493 }
494
495 /*
496 * free all CA certificates
497 */
498 void free_ca_infos(void)
499 {
500 while (ca_infos != NULL)
501 {
502 ca_info_t *ca = ca_infos;
503
504 ca_infos = ca_infos->next;
505 free_ca_info(ca);
506 }
507 }
508
509 /*
510 * find a CA information record by name and optionally delete it
511 */
512 bool find_ca_info_by_name(const char *name, bool delete)
513 {
514 ca_info_t **ca_p = &ca_infos;
515 ca_info_t *ca = *ca_p;
516
517 while (ca != NULL)
518 {
519 /* is there already an entry? */
520 if (streq(name, ca->name))
521 {
522 if (delete)
523 {
524 lock_ca_info_list("find_ca_info_by_name");
525 *ca_p = ca->next;
526 free_ca_info(ca);
527 plog("deleting ca description \"%s\"", name);
528 unlock_ca_info_list("find_ca_info_by_name");
529 }
530 return TRUE;
531 }
532 ca_p = &ca->next;
533 ca = *ca_p;
534 }
535 return FALSE;
536 }
537
538 /*
539 * Create an empty ca_info_t record
540 */
541 ca_info_t* create_ca_info(void)
542 {
543 ca_info_t *ca_info = malloc_thing(ca_info_t);
544
545 memset(ca_info, 0, sizeof(ca_info_t));
546 ca_info->crluris = linked_list_create();
547
548 return ca_info;
549 }
550
551 /**
552 * Adds a CA description to a chained list
553 */
554 void add_ca_info(const whack_message_t *msg)
555 {
556 smartcard_t *sc = NULL;
557 cert_t *cert = NULL;
558 bool cached_cert = FALSE;
559
560 if (find_ca_info_by_name(msg->name, FALSE))
561 {
562 loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name);
563 return;
564 }
565
566 if (scx_on_smartcard(msg->cacert))
567 {
568 /* load CA cert from smartcard */
569 cert = scx_load_cert(msg->cacert, &sc, &cached_cert);
570 }
571 else
572 {
573 /* load CA cert from file */
574 cert = load_ca_cert(msg->cacert);
575 }
576
577 if (cert)
578 {
579 certificate_t *certificate = cert->cert;
580 x509_t *x509 = (x509_t*)certificate;
581 identification_t *subject = certificate->get_subject(certificate);
582 chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509);
583 ca_info_t *ca = NULL;
584
585 /* does the authname already exist? */
586 ca = get_ca_info(subject, subjectKeyID);
587
588 if (ca != NULL)
589 {
590 /* ca_info is already present */
591 loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found,"
592 "ignoring \"%s\"", ca->name, msg->name);
593 cert_free(cert);
594 return;
595 }
596
597 plog("added ca description \"%s\"", msg->name);
598
599 /* create and initialize new ca_info record */
600 ca = create_ca_info();
601
602 /* name */
603 ca->name = clone_str(msg->name);
604
605 /* authName */
606 ca->authName = subject->clone(subject);
607 DBG(DBG_CONTROL,
608 DBG_log("authname: '%Y'", subject)
609 )
610
611 /* authKeyID */
612 if (subjectKeyID.ptr)
613 {
614 ca->authKeyID = chunk_clone(subjectKeyID);
615 DBG(DBG_CONTROL | DBG_PARSING ,
616 DBG_log("authkey: %#B", &subjectKeyID)
617 )
618 }
619
620 /* ldaphost */
621 ca->ldaphost = clone_str(msg->ldaphost);
622
623 /* ldapbase */
624 ca->ldapbase = clone_str(msg->ldapbase);
625
626 /* ocspuri */
627 if (msg->ocspuri != NULL)
628 {
629 if (strncasecmp(msg->ocspuri, "http", 4) == 0)
630 ca->ocspuri = clone_str(msg->ocspuri);
631 else
632 plog(" ignoring ocspuri with unkown protocol");
633 }
634
635 /* add crl uris */
636 add_distribution_point(ca->crluris, msg->crluri);
637 add_distribution_point(ca->crluris, msg->crluri2);
638
639 /* strictrlpolicy */
640 ca->strictcrlpolicy = msg->whack_strict;
641
642 /* insert ca_info record into the chained list */
643 lock_ca_info_list("add_ca_info");
644
645 ca->next = ca_infos;
646 ca_infos = ca;
647
648 unlock_ca_info_list("add_ca_info");
649
650 /* add cacert to list of authcerts */
651 cert = add_authcert(cert, X509_CA);
652 if (!cached_cert && sc != NULL)
653 {
654 if (sc->last_cert != NULL)
655 {
656 sc->last_cert->count--;
657 }
658 sc->last_cert = cert;
659 cert_share(sc->last_cert);
660 }
661 if (sc != NULL)
662 time(&sc->last_load);
663 }
664 }
665
666 /*
667 * list all ca_info records in the chained list
668 */
669 void list_ca_infos(bool utc)
670 {
671 ca_info_t *ca = ca_infos;
672
673 if (ca != NULL)
674 {
675 whack_log(RC_COMMENT, " ");
676 whack_log(RC_COMMENT, "List of X.509 CA Information Records:");
677 }
678
679 while (ca != NULL)
680 {
681 /* strictpolicy per CA not supported yet
682 *
683 whack_log(RC_COMMENT, "%T, \"%s\", strictcrlpolicy: %s"
684 , &ca->installed, utc, ca->name
685 , ca->strictcrlpolicy? "yes":"no");
686 */
687 whack_log(RC_COMMENT, " ");
688 whack_log(RC_COMMENT, " authname: \"%Y\"", ca->authName);
689 if (ca->ldaphost)
690 {
691 whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost);
692 }
693 if (ca->ldapbase)
694 {
695 whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase);
696 }
697 if (ca->ocspuri)
698 {
699 whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri);
700 }
701
702 list_distribution_points(ca->crluris);
703
704 if (ca->authKeyID.ptr)
705 {
706 whack_log(RC_COMMENT, " authkey: %#B", &ca->authKeyID);
707 }
708 ca = ca->next;
709 }
710 }
711