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