SKEYID derivation based on libstrongswan
[strongswan.git] / src / pluto / crl.c
1 /* Support of X.509 certificate revocation lists (CRLs)
2 * Copyright (C) 2000-2009 Andreas Steffen
3 *
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
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 <asn1/asn1.h>
29 #include <asn1/asn1_parser.h>
30 #include <asn1/oid.h>
31 #include <crypto/hashers/hasher.h>
32
33 #include "constants.h"
34 #include "defs.h"
35 #include "log.h"
36 #include "x509.h"
37 #include "crl.h"
38 #include "ca.h"
39 #include "certs.h"
40 #include "keys.h"
41 #include "whack.h"
42 #include "fetch.h"
43
44
45 /* chained lists of X.509 crls */
46
47 static x509crl_t *x509crls = NULL;
48
49 /**
50 * ASN.1 definition of an X.509 certificate revocation list
51 */
52 static const asn1Object_t crlObjects[] = {
53 { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
54 { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
55 { 2, "version", ASN1_INTEGER, ASN1_OPT |
56 ASN1_BODY }, /* 2 */
57 { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
58 { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
59 { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
60 { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
61 { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
62 { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
63 ASN1_LOOP }, /* 8 */
64 { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
65 { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
66 { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
67 { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
68 ASN1_LOOP }, /* 12 */
69 { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
70 { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
71 { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
72 ASN1_BODY }, /* 15 */
73 { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
74 { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
75 { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
76 { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
77 { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
78 { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
79 { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
80 { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
81 ASN1_BODY }, /* 23 */
82 { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
83 { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
84 { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
85 { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
86 { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */
87 { 0, "exit", ASN1_EOC, ASN1_EXIT }
88 };
89
90 #define CRL_OBJ_CERTIFICATE_LIST 0
91 #define CRL_OBJ_TBS_CERT_LIST 1
92 #define CRL_OBJ_VERSION 2
93 #define CRL_OBJ_SIG_ALG 4
94 #define CRL_OBJ_ISSUER 5
95 #define CRL_OBJ_THIS_UPDATE 6
96 #define CRL_OBJ_NEXT_UPDATE 7
97 #define CRL_OBJ_USER_CERTIFICATE 10
98 #define CRL_OBJ_REVOCATION_DATE 11
99 #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
100 #define CRL_OBJ_CRL_ENTRY_CRITICAL 15
101 #define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
102 #define CRL_OBJ_EXTN_ID 22
103 #define CRL_OBJ_CRITICAL 23
104 #define CRL_OBJ_EXTN_VALUE 24
105 #define CRL_OBJ_ALGORITHM 27
106 #define CRL_OBJ_SIGNATURE 28
107
108 const x509crl_t empty_x509crl = {
109 NULL , /* *next */
110 UNDEFINED_TIME, /* installed */
111 NULL , /* distributionPoints */
112 { NULL, 0 } , /* certificateList */
113 { NULL, 0 } , /* tbsCertList */
114 1 , /* version */
115 OID_UNKNOWN , /* sigAlg */
116 { NULL, 0 } , /* issuer */
117 UNDEFINED_TIME, /* thisUpdate */
118 UNDEFINED_TIME, /* nextUpdate */
119 NULL , /* revokedCertificates */
120 /* crlExtensions */
121 /* extension */
122 /* extnID */
123 /* critical */
124 /* extnValue */
125 { NULL, 0 } , /* authKeyID */
126 { NULL, 0 } , /* authKeySerialNumber */
127 { NULL, 0 } , /* crlNumber */
128 OID_UNKNOWN , /* algorithm */
129 { NULL, 0 } /* signature */
130 };
131
132 /**
133 * Get the X.509 CRL with a given issuer
134 */
135 static x509crl_t* get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
136 {
137 x509crl_t *crl = x509crls;
138 x509crl_t *prev_crl = NULL;
139
140 while (crl != NULL)
141 {
142 if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL)
143 ? same_keyid(keyid, crl->authKeyID)
144 : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber)))
145 {
146 if (crl != x509crls)
147 {
148 /* bring the CRL up front */
149 prev_crl->next = crl->next;
150 crl->next = x509crls;
151 x509crls = crl;
152 }
153 return crl;
154 }
155 prev_crl = crl;
156 crl = crl->next;
157 }
158 return NULL;
159 }
160
161 /**
162 * Free the dynamic memory used to store revoked certificates
163 */
164 static void free_revoked_certs(revokedCert_t* revokedCerts)
165 {
166 while (revokedCerts != NULL)
167 {
168 revokedCert_t * revokedCert = revokedCerts;
169 revokedCerts = revokedCert->next;
170 free(revokedCert);
171 }
172 }
173
174 /**
175 * Free the dynamic memory used to store CRLs
176 */
177 void free_crl(x509crl_t *crl)
178 {
179 free_revoked_certs(crl->revokedCertificates);
180 free_generalNames(crl->distributionPoints, TRUE);
181 free(crl->certificateList.ptr);
182 free(crl);
183 }
184
185 static void free_first_crl(void)
186 {
187 x509crl_t *crl = x509crls;
188
189 x509crls = crl->next;
190 free_crl(crl);
191 }
192
193 void free_crls(void)
194 {
195 lock_crl_list("free_crls");
196
197 while (x509crls != NULL)
198 free_first_crl();
199
200 unlock_crl_list("free_crls");
201 }
202
203 /**
204 * Insert X.509 CRL into chained list
205 */
206 bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
207 {
208 x509crl_t *crl = malloc_thing(x509crl_t);
209
210 *crl = empty_x509crl;
211
212 if (parse_x509crl(blob, 0, crl))
213 {
214 x509cert_t *issuer_cert;
215 x509crl_t *oldcrl;
216 bool valid_sig;
217 generalName_t *gn;
218
219 /* add distribution point */
220 gn = malloc_thing(generalName_t);
221 gn->kind = GN_URI;
222 gn->name = crl_uri;
223 gn->next = crl->distributionPoints;
224 crl->distributionPoints = gn;
225
226 lock_authcert_list("insert_crl");
227 /* get the issuer cacert */
228 issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber,
229 crl->authKeyID, AUTH_CA);
230 if (issuer_cert == NULL)
231 {
232 plog("crl issuer cacert not found");
233 free_crl(crl);
234 unlock_authcert_list("insert_crl");
235 return FALSE;
236 }
237 DBG(DBG_CONTROL,
238 DBG_log("crl issuer cacert found")
239 )
240
241 /* check the issuer's signature of the crl */
242 valid_sig = check_signature(crl->tbsCertList, crl->signature
243 , crl->algorithm, crl->algorithm, issuer_cert);
244 unlock_authcert_list("insert_crl");
245
246 if (!valid_sig)
247 {
248 free_crl(crl);
249 return FALSE;
250 }
251 DBG(DBG_CONTROL,
252 DBG_log("crl signature is valid")
253 )
254
255 lock_crl_list("insert_crl");
256 oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber
257 , crl->authKeyID);
258
259 if (oldcrl != NULL)
260 {
261 if (crl->thisUpdate > oldcrl->thisUpdate)
262 {
263 /* keep any known CRL distribution points */
264 add_distribution_points(oldcrl->distributionPoints
265 , &crl->distributionPoints);
266
267 /* now delete the old CRL */
268 free_first_crl();
269 DBG(DBG_CONTROL,
270 DBG_log("thisUpdate is newer - existing crl deleted")
271 )
272 }
273 else
274 {
275 unlock_crl_list("insert_crls");
276 DBG(DBG_CONTROL,
277 DBG_log("thisUpdate is not newer - existing crl not replaced");
278 )
279 free_crl(crl);
280 return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
281 }
282 }
283
284 /* insert new CRL */
285 crl->next = x509crls;
286 x509crls = crl;
287
288 unlock_crl_list("insert_crl");
289
290 /* If crl caching is enabled then the crl is saved locally.
291 * Only http or ldap URIs are cached but not local file URIs.
292 * The issuer's subjectKeyID is used as a unique filename
293 */
294 if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0)
295 {
296 char path[BUF_LEN], buf[BUF_LEN];
297 char digest_buf[HASH_SIZE_SHA1];
298 chunk_t subjectKeyID = chunk_from_buf(digest_buf);
299 bool has_keyID;
300
301 if (issuer_cert->subjectKeyID.ptr == NULL)
302 {
303 has_keyID = compute_subjectKeyID(issuer_cert, subjectKeyID);
304 }
305 else
306 {
307 subjectKeyID = issuer_cert->subjectKeyID;
308 has_keyID = TRUE;
309 }
310 if (has_keyID)
311 {
312 datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
313 snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
314 chunk_write(crl->certificateList, path, "crl", 0022, TRUE);
315 }
316 }
317
318 /* is the fetched crl valid? */
319 return crl->nextUpdate - time(NULL) > 2*crl_check_interval;
320 }
321 else
322 {
323 plog(" error in X.509 crl");
324 free_crl(crl);
325 return FALSE;
326 }
327 }
328
329 /**
330 * Loads CRLs
331 */
332 void load_crls(void)
333 {
334 struct dirent **filelist;
335 u_char buf[BUF_LEN];
336 u_char *save_dir;
337 int n;
338
339 /* change directory to specified path */
340 save_dir = getcwd(buf, BUF_LEN);
341 if (chdir(CRL_PATH))
342 {
343 plog("Could not change to directory '%s'", CRL_PATH);
344 }
345 else
346 {
347 plog("Changing to directory '%s'", CRL_PATH);
348 n = scandir(CRL_PATH, &filelist, file_select, alphasort);
349
350 if (n < 0)
351 plog(" scandir() error");
352 else
353 {
354 while (n--)
355 {
356 bool pgp = FALSE;
357 chunk_t blob = chunk_empty;
358 char *filename = filelist[n]->d_name;
359
360 if (load_coded_file(filename, NULL, "crl", &blob, &pgp))
361 {
362 chunk_t crl_uri;
363
364 crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename);
365 crl_uri.ptr = malloc(crl_uri.len + 1);
366
367 /* build CRL file URI */
368 snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s"
369 , CRL_PATH, filename);
370
371 insert_crl(blob, crl_uri, FALSE);
372 }
373 free(filelist[n]);
374 }
375 free(filelist);
376 }
377 }
378 /* restore directory path */
379 ignore_result(chdir(save_dir));
380 }
381
382 /**
383 * Parses a CRL revocation reason code
384 */
385 static crl_reason_t parse_crl_reasonCode(chunk_t object)
386 {
387 crl_reason_t reason = REASON_UNSPECIFIED;
388
389 if (*object.ptr == ASN1_ENUMERATED
390 && asn1_length(&object) == 1)
391 {
392 reason = *object.ptr;
393 }
394
395 DBG(DBG_PARSING,
396 DBG_log(" '%N'", crl_reason_names, reason)
397 )
398 return reason;
399 }
400
401 /*
402 * Parses an X.509 CRL
403 */
404 bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
405 {
406 u_char buf[BUF_LEN];
407 asn1_parser_t *parser;
408 chunk_t extnID;
409 chunk_t userCertificate = chunk_empty;
410 chunk_t object;
411 int objectID;
412 bool success = FALSE;
413 bool critical;
414
415 parser = asn1_parser_create(crlObjects, blob);
416
417 while (parser->iterate(parser, &objectID, &object))
418 {
419 u_int level = parser->get_level(parser)+1;
420
421 switch (objectID) {
422 case CRL_OBJ_CERTIFICATE_LIST:
423 crl->certificateList = object;
424 break;
425 case CRL_OBJ_TBS_CERT_LIST:
426 crl->tbsCertList = object;
427 break;
428 case CRL_OBJ_VERSION:
429 crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
430 DBG(DBG_PARSING,
431 DBG_log(" v%d", crl->version);
432 )
433 break;
434 case CRL_OBJ_SIG_ALG:
435 crl->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL);
436 break;
437 case CRL_OBJ_ISSUER:
438 crl->issuer = object;
439 DBG(DBG_PARSING,
440 dntoa(buf, BUF_LEN, object);
441 DBG_log(" '%s'",buf)
442 )
443 break;
444 case CRL_OBJ_THIS_UPDATE:
445 crl->thisUpdate = asn1_parse_time(object, level);
446 break;
447 case CRL_OBJ_NEXT_UPDATE:
448 crl->nextUpdate = asn1_parse_time(object, level);
449 break;
450 case CRL_OBJ_USER_CERTIFICATE:
451 userCertificate = object;
452 break;
453 case CRL_OBJ_REVOCATION_DATE:
454 {
455 /* put all the serial numbers and the revocation date in a chained list
456 with revocedCertificates pointing to the first revoked certificate */
457
458 revokedCert_t *revokedCert = malloc_thing(revokedCert_t);
459 revokedCert->userCertificate = userCertificate;
460 revokedCert->revocationDate = asn1_parse_time(object, level);
461 revokedCert->revocationReason = REASON_UNSPECIFIED;
462 revokedCert->next = crl->revokedCertificates;
463 crl->revokedCertificates = revokedCert;
464 }
465 break;
466 case CRL_OBJ_CRL_ENTRY_EXTN_ID:
467 case CRL_OBJ_EXTN_ID:
468 extnID = object;
469 break;
470 case CRL_OBJ_CRL_ENTRY_CRITICAL:
471 case CRL_OBJ_CRITICAL:
472 critical = object.len && *object.ptr;
473 DBG(DBG_PARSING,
474 DBG_log(" %s",(critical)?"TRUE":"FALSE");
475 )
476 break;
477 case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
478 case CRL_OBJ_EXTN_VALUE:
479 {
480 u_int extn_oid = asn1_known_oid(extnID);
481
482 if (extn_oid == OID_CRL_REASON_CODE)
483 {
484 crl->revokedCertificates->revocationReason =
485 parse_crl_reasonCode(object);
486 }
487 else if (extn_oid == OID_AUTHORITY_KEY_ID)
488 {
489 parse_authorityKeyIdentifier(object, level
490 , &crl->authKeyID, &crl->authKeySerialNumber);
491 }
492 else if (extn_oid == OID_CRL_NUMBER)
493 {
494 if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
495 level, "crlNumber"))
496 {
497 goto end;
498 }
499 crl->crlNumber = object;
500 }
501 }
502 break;
503 case CRL_OBJ_ALGORITHM:
504 crl->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
505 break;
506 case CRL_OBJ_SIGNATURE:
507 crl->signature = object;
508 break;
509 default:
510 break;
511 }
512 }
513 success = parser->success(parser);
514 time(&crl->installed);
515
516 end:
517 parser->destroy(parser);
518 return success;
519 }
520
521 /* Checks if the current certificate is revoked. It goes through the
522 * list of revoked certificates of the corresponding crl. Either the
523 * status CERT_GOOD or CERT_REVOKED is returned
524 */
525 static cert_status_t
526 check_revocation(const x509crl_t *crl, chunk_t serial
527 , time_t *revocationDate, crl_reason_t * revocationReason)
528 {
529 revokedCert_t *revokedCert = crl->revokedCertificates;
530
531 *revocationDate = UNDEFINED_TIME;
532 *revocationReason = REASON_UNSPECIFIED;
533
534 DBG(DBG_CONTROL,
535 DBG_dump_chunk("serial number:", serial)
536 )
537
538 while(revokedCert != NULL)
539 {
540 /* compare serial numbers */
541 if (revokedCert->userCertificate.len == serial.len &&
542 memeq(revokedCert->userCertificate.ptr, serial.ptr, serial.len))
543 {
544 *revocationDate = revokedCert->revocationDate;
545 *revocationReason = revokedCert->revocationReason;
546 return CERT_REVOKED;
547 }
548 revokedCert = revokedCert->next;
549 }
550 return CERT_GOOD;
551 }
552
553 /*
554 * check if any crls are about to expire
555 */
556 void
557 check_crls(void)
558 {
559 x509crl_t *crl;
560
561 lock_crl_list("check_crls");
562 crl = x509crls;
563
564 while (crl != NULL)
565 {
566 time_t time_left = crl->nextUpdate - time(NULL);
567 u_char buf[BUF_LEN];
568
569 DBG(DBG_CONTROL,
570 dntoa(buf, BUF_LEN, crl->issuer);
571 DBG_log("issuer: '%s'",buf);
572 if (crl->authKeyID.ptr != NULL)
573 {
574 datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
575 , buf, BUF_LEN);
576 DBG_log("authkey: %s", buf);
577 }
578 DBG_log("%ld seconds left", time_left)
579 )
580 if (time_left < 2*crl_check_interval)
581 {
582 fetch_req_t *req = build_crl_fetch_request(crl->issuer
583 , crl->authKeySerialNumber
584 , crl->authKeyID, crl->distributionPoints);
585 add_crl_fetch_request(req);
586 }
587 crl = crl->next;
588 }
589 unlock_crl_list("check_crls");
590 }
591
592 /*
593 * verify if a cert hasn't been revoked by a crl
594 */
595 cert_status_t
596 verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
597 , crl_reason_t *revocationReason)
598 {
599 x509crl_t *crl;
600
601 ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
602 , cert->authKeyID);
603
604 generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
605
606 *revocationDate = UNDEFINED_TIME;
607 *revocationReason = REASON_UNSPECIFIED;
608
609 lock_crl_list("verify_by_crl");
610 crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
611
612 if (crl == NULL)
613 {
614 unlock_crl_list("verify_by_crl");
615 plog("crl not found");
616
617 if (cert->crlDistributionPoints != NULL)
618 {
619 fetch_req_t *req = build_crl_fetch_request(cert->issuer
620 , cert->authKeySerialNumber
621 , cert->authKeyID, cert->crlDistributionPoints);
622 add_crl_fetch_request(req);
623 }
624
625 if (crluri != NULL)
626 {
627 fetch_req_t *req = build_crl_fetch_request(cert->issuer
628 , cert->authKeySerialNumber
629 , cert->authKeyID, crluri);
630 add_crl_fetch_request(req);
631 }
632
633 if (cert->crlDistributionPoints != 0 || crluri != NULL)
634 {
635 wake_fetch_thread("verify_by_crl");
636 return CERT_UNKNOWN;
637 }
638 else
639 return CERT_UNDEFINED;
640 }
641 else
642 {
643 x509cert_t *issuer_cert;
644 bool valid;
645
646 DBG(DBG_CONTROL,
647 DBG_log("crl found")
648 )
649
650 add_distribution_points(cert->crlDistributionPoints
651 , &crl->distributionPoints);
652
653 add_distribution_points(crluri
654 , &crl->distributionPoints);
655
656 lock_authcert_list("verify_by_crl");
657
658 issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
659 , crl->authKeyID, AUTH_CA);
660 valid = check_signature(crl->tbsCertList, crl->signature
661 , crl->algorithm, crl->algorithm, issuer_cert);
662
663 unlock_authcert_list("verify_by_crl");
664
665 if (valid)
666 {
667 cert_status_t status;
668
669 DBG(DBG_CONTROL,
670 DBG_log("crl signature is valid")
671 )
672 /* return the expiration date */
673 *until = crl->nextUpdate;
674
675 /* has the certificate been revoked? */
676 status = check_revocation(crl, cert->serialNumber, revocationDate
677 , revocationReason);
678
679 if (*until < time(NULL))
680 {
681 fetch_req_t *req;
682
683 plog("crl update is overdue since %T", until, TRUE);
684
685 /* try to fetch a crl update */
686 req = build_crl_fetch_request(crl->issuer
687 , crl->authKeySerialNumber
688 , crl->authKeyID, crl->distributionPoints);
689 unlock_crl_list("verify_by_crl");
690
691 add_crl_fetch_request(req);
692 wake_fetch_thread("verify_by_crl");
693 }
694 else
695 {
696 unlock_crl_list("verify_by_crl");
697 DBG(DBG_CONTROL,
698 DBG_log("crl is valid")
699 )
700 }
701 return status;
702 }
703 else
704 {
705 unlock_crl_list("verify_by_crl");
706 plog("crl signature is invalid");
707 return CERT_UNKNOWN;
708 }
709 }
710 }
711
712 /*
713 * list all X.509 crls in the chained list
714 */
715 void
716 list_crls(bool utc, bool strict)
717 {
718 x509crl_t *crl;
719
720 lock_crl_list("list_crls");
721 crl = x509crls;
722
723 if (crl != NULL)
724 {
725 whack_log(RC_COMMENT, " ");
726 whack_log(RC_COMMENT, "List of X.509 CRLs:");
727 whack_log(RC_COMMENT, " ");
728 }
729
730 while (crl != NULL)
731 {
732 u_char buf[BUF_LEN];
733 u_int revoked = 0;
734 revokedCert_t *revokedCert = crl->revokedCertificates;
735
736 /* count number of revoked certificates in CRL */
737 while (revokedCert != NULL)
738 {
739 revoked++;
740 revokedCert = revokedCert->next;
741 }
742
743 whack_log(RC_COMMENT, "%T, revoked certs: %d",
744 &crl->installed, utc, revoked);
745 dntoa(buf, BUF_LEN, crl->issuer);
746 whack_log(RC_COMMENT, " issuer: '%s'", buf);
747 if (crl->crlNumber.ptr != NULL)
748 {
749 datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':'
750 , buf, BUF_LEN);
751 whack_log(RC_COMMENT, " crlnumber: %s", buf);
752 }
753 list_distribution_points(crl->distributionPoints);
754
755 whack_log(RC_COMMENT, " updates: this %T",
756 &crl->thisUpdate, utc);
757 whack_log(RC_COMMENT, " next %T %s",
758 &crl->nextUpdate, utc,
759 check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict));
760 if (crl->authKeyID.ptr != NULL)
761 {
762 datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
763 , buf, BUF_LEN);
764 whack_log(RC_COMMENT, " authkey: %s", buf);
765 }
766 if (crl->authKeySerialNumber.ptr != NULL)
767 {
768 datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
769 , buf, BUF_LEN);
770 whack_log(RC_COMMENT, " aserial: %s", buf);
771 }
772
773 crl = crl->next;
774 }
775 unlock_crl_list("list_crls");
776 }
777