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