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