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