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