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