Respect enforce_critical setting in x509 plugin CRLs
[strongswan.git] / src / libstrongswan / plugins / x509 / x509_crl.c
1 /*
2 * Copyright (C) 2008-2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "x509_crl.h"
17
18 typedef struct private_x509_crl_t private_x509_crl_t;
19 typedef struct revoked_t revoked_t;
20
21 #include <time.h>
22
23 #include <debug.h>
24 #include <library.h>
25 #include <asn1/oid.h>
26 #include <asn1/asn1.h>
27 #include <asn1/asn1_parser.h>
28 #include <credentials/certificates/x509.h>
29 #include <credentials/keys/private_key.h>
30 #include <utils/linked_list.h>
31
32 /**
33 * entry for a revoked certificate
34 */
35 struct revoked_t {
36 /**
37 * serial of the revoked certificate
38 */
39 chunk_t serial;
40
41 /**
42 * date of revocation
43 */
44 time_t date;
45
46 /**
47 * reason for revocation
48 */
49 crl_reason_t reason;
50 };
51
52 /**
53 * private data of x509_crl
54 */
55 struct private_x509_crl_t {
56
57 /**
58 * public functions
59 */
60 x509_crl_t public;
61
62 /**
63 * X.509 crl encoding in ASN.1 DER format
64 */
65 chunk_t encoding;
66
67 /**
68 * X.509 crl body over which signature is computed
69 */
70 chunk_t tbsCertList;
71
72 /**
73 * Version of the X.509 crl
74 */
75 u_int version;
76
77 /**
78 * ID representing the crl issuer
79 */
80 identification_t *issuer;
81
82 /**
83 * CRL number
84 */
85 chunk_t crlNumber;
86
87 /**
88 * Time when the crl was generated
89 */
90 time_t thisUpdate;
91
92 /**
93 * Time when an update crl will be available
94 */
95 time_t nextUpdate;
96
97 /**
98 * list of revoked certificates as revoked_t
99 */
100 linked_list_t *revoked;
101
102 /**
103 * Authority Key Identifier
104 */
105 chunk_t authKeyIdentifier;
106
107 /**
108 * Authority Key Serial Number
109 */
110 chunk_t authKeySerialNumber;
111
112 /**
113 * Signature algorithm
114 */
115 int algorithm;
116
117 /**
118 * Signature
119 */
120 chunk_t signature;
121
122 /**
123 * has this CRL been generated
124 */
125 bool generated;
126
127 /**
128 * reference counter
129 */
130 refcount_t ref;
131 };
132
133 /**
134 * from x509_cert
135 */
136 extern chunk_t x509_parse_authorityKeyIdentifier(
137 chunk_t blob, int level0,
138 chunk_t *authKeySerialNumber);
139
140 /**
141 * ASN.1 definition of an X.509 certificate revocation list
142 */
143 static const asn1Object_t crlObjects[] = {
144 { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
145 { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
146 { 2, "version", ASN1_INTEGER, ASN1_OPT |
147 ASN1_BODY }, /* 2 */
148 { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
149 { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
150 { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
151 { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
152 { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
153 { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
154 ASN1_LOOP }, /* 8 */
155 { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
156 { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
157 { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
158 { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
159 ASN1_LOOP }, /* 12 */
160 { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
161 { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
162 { 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
163 ASN1_BODY }, /* 15 */
164 { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
165 { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
166 { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
167 { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
168 { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
169 { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
170 { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
171 { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
172 ASN1_BODY }, /* 23 */
173 { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
174 { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
175 { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
176 { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
177 { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */
178 { 0, "exit", ASN1_EOC, ASN1_EXIT }
179 };
180 #define CRL_OBJ_TBS_CERT_LIST 1
181 #define CRL_OBJ_VERSION 2
182 #define CRL_OBJ_SIG_ALG 4
183 #define CRL_OBJ_ISSUER 5
184 #define CRL_OBJ_THIS_UPDATE 6
185 #define CRL_OBJ_NEXT_UPDATE 7
186 #define CRL_OBJ_USER_CERTIFICATE 10
187 #define CRL_OBJ_REVOCATION_DATE 11
188 #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
189 #define CRL_OBJ_CRL_ENTRY_CRITICAL 15
190 #define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
191 #define CRL_OBJ_EXTN_ID 22
192 #define CRL_OBJ_CRITICAL 23
193 #define CRL_OBJ_EXTN_VALUE 24
194 #define CRL_OBJ_ALGORITHM 27
195 #define CRL_OBJ_SIGNATURE 28
196
197 /**
198 * Parses an X.509 Certificate Revocation List (CRL)
199 */
200 static bool parse(private_x509_crl_t *this)
201 {
202 asn1_parser_t *parser;
203 chunk_t object;
204 chunk_t extnID;
205 chunk_t userCertificate = chunk_empty;
206 int objectID;
207 int sig_alg = OID_UNKNOWN;
208 bool success = FALSE;
209 bool critical;
210 revoked_t *revoked = NULL;
211
212 parser = asn1_parser_create(crlObjects, this->encoding);
213
214 while (parser->iterate(parser, &objectID, &object))
215 {
216 u_int level = parser->get_level(parser)+1;
217
218 switch (objectID)
219 {
220 case CRL_OBJ_TBS_CERT_LIST:
221 this->tbsCertList = object;
222 break;
223 case CRL_OBJ_VERSION:
224 this->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
225 DBG2(DBG_LIB, " v%d", this->version);
226 break;
227 case CRL_OBJ_SIG_ALG:
228 sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
229 break;
230 case CRL_OBJ_ISSUER:
231 this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
232 DBG2(DBG_LIB, " '%Y'", this->issuer);
233 break;
234 case CRL_OBJ_THIS_UPDATE:
235 this->thisUpdate = asn1_parse_time(object, level);
236 break;
237 case CRL_OBJ_NEXT_UPDATE:
238 this->nextUpdate = asn1_parse_time(object, level);
239 break;
240 case CRL_OBJ_USER_CERTIFICATE:
241 userCertificate = object;
242 break;
243 case CRL_OBJ_REVOCATION_DATE:
244 revoked = malloc_thing(revoked_t);
245 revoked->serial = chunk_clone(userCertificate);
246 revoked->date = asn1_parse_time(object, level);
247 revoked->reason = CRL_REASON_UNSPECIFIED;
248 this->revoked->insert_last(this->revoked, (void *)revoked);
249 break;
250 case CRL_OBJ_CRL_ENTRY_EXTN_ID:
251 case CRL_OBJ_EXTN_ID:
252 extnID = object;
253 break;
254 case CRL_OBJ_CRL_ENTRY_CRITICAL:
255 case CRL_OBJ_CRITICAL:
256 critical = object.len && *object.ptr;
257 DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE");
258 break;
259 case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
260 case CRL_OBJ_EXTN_VALUE:
261 {
262 int extn_oid = asn1_known_oid(extnID);
263
264 switch (extn_oid)
265 {
266 case OID_CRL_REASON_CODE:
267 if (revoked)
268 {
269 if (object.len && *object.ptr == ASN1_ENUMERATED &&
270 asn1_length(&object) == 1)
271 {
272 revoked->reason = *object.ptr;
273 }
274 DBG2(DBG_LIB, " '%N'", crl_reason_names,
275 revoked->reason);
276 }
277 break;
278 case OID_AUTHORITY_KEY_ID:
279 this->authKeyIdentifier =
280 x509_parse_authorityKeyIdentifier(
281 object, level, &this->authKeySerialNumber);
282 break;
283 case OID_CRL_NUMBER:
284 if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
285 level, "crlNumber"))
286 {
287 goto end;
288 }
289 this->crlNumber = object;
290 break;
291 default:
292 if (critical && lib->settings->get_bool(lib->settings,
293 "libstrongswan.plugins.x509.enforce_critical", FALSE))
294 {
295 DBG1(DBG_LIB, "critical %s extension not supported",
296 (extn_oid == OID_UNKNOWN) ? "unknown" :
297 (char*)oid_names[extn_oid].name);
298 goto end;
299 }
300 break;
301 }
302 break;
303 }
304 case CRL_OBJ_ALGORITHM:
305 {
306 this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
307 if (this->algorithm != sig_alg)
308 {
309 DBG1(DBG_LIB, " signature algorithms do not agree");
310 goto end;
311 }
312 break;
313 }
314 case CRL_OBJ_SIGNATURE:
315 this->signature = object;
316 break;
317 default:
318 break;
319 }
320 }
321 success = parser->success(parser);
322
323 end:
324 parser->destroy(parser);
325 return success;
326 }
327
328 /**
329 * enumerator filter callback for create_enumerator
330 */
331 static bool filter(void *data, revoked_t **revoked, chunk_t *serial, void *p2,
332 time_t *date, void *p3, crl_reason_t *reason)
333 {
334 if (serial)
335 {
336 *serial = (*revoked)->serial;
337 }
338 if (date)
339 {
340 *date = (*revoked)->date;
341 }
342 if (reason)
343 {
344 *reason = (*revoked)->reason;
345 }
346 return TRUE;
347 }
348
349 METHOD(crl_t, get_serial, chunk_t,
350 private_x509_crl_t *this)
351 {
352 return this->crlNumber;
353 }
354
355 METHOD(crl_t, get_authKeyIdentifier, chunk_t,
356 private_x509_crl_t *this)
357 {
358 return this->authKeyIdentifier;
359 }
360
361 METHOD(crl_t, create_enumerator, enumerator_t*,
362 private_x509_crl_t *this)
363 {
364 return enumerator_create_filter(
365 this->revoked->create_enumerator(this->revoked),
366 (void*)filter, NULL, NULL);
367 }
368
369 METHOD(certificate_t, get_type, certificate_type_t,
370 private_x509_crl_t *this)
371 {
372 return CERT_X509_CRL;
373 }
374
375 METHOD(certificate_t, get_issuer, identification_t*,
376 private_x509_crl_t *this)
377 {
378 return this->issuer;
379 }
380
381 METHOD(certificate_t, has_issuer, id_match_t,
382 private_x509_crl_t *this, identification_t *issuer)
383 {
384 if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr &&
385 chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer)))
386 {
387 return ID_MATCH_PERFECT;
388 }
389 return this->issuer->matches(this->issuer, issuer);
390 }
391
392 METHOD(certificate_t, issued_by, bool,
393 private_x509_crl_t *this, certificate_t *issuer)
394 {
395 public_key_t *key;
396 signature_scheme_t scheme;
397 bool valid;
398 x509_t *x509 = (x509_t*)issuer;
399
400 /* check if issuer is an X.509 CA certificate */
401 if (issuer->get_type(issuer) != CERT_X509)
402 {
403 return FALSE;
404 }
405 if (!(x509->get_flags(x509) & (X509_CA | X509_CRL_SIGN)))
406 {
407 return FALSE;
408 }
409
410 /* get the public key of the issuer */
411 key = issuer->get_public_key(issuer);
412
413 /* compare keyIdentifiers if available, otherwise use DNs */
414 if (this->authKeyIdentifier.ptr && key)
415 {
416 chunk_t fingerprint;
417
418 if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) ||
419 !chunk_equals(fingerprint, this->authKeyIdentifier))
420 {
421 return FALSE;
422 }
423 }
424 else
425 {
426 if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
427 {
428 return FALSE;
429 }
430 }
431
432 /* determine signature scheme */
433 scheme = signature_scheme_from_oid(this->algorithm);
434
435 if (scheme == SIGN_UNKNOWN || key == NULL)
436 {
437 return FALSE;
438 }
439 valid = key->verify(key, scheme, this->tbsCertList, this->signature);
440 key->destroy(key);
441 return valid;
442 }
443
444 METHOD(certificate_t, get_public_key, public_key_t*,
445 private_x509_crl_t *this)
446 {
447 return NULL;
448 }
449
450 METHOD(certificate_t, get_ref, certificate_t*,
451 private_x509_crl_t *this)
452 {
453 ref_get(&this->ref);
454 return &this->public.crl.certificate;
455 }
456
457 METHOD(certificate_t, get_validity, bool,
458 private_x509_crl_t *this, time_t *when,
459 time_t *not_before, time_t *not_after)
460 {
461 time_t t = when ? *when : time(NULL);
462
463 if (not_before)
464 {
465 *not_before = this->thisUpdate;
466 }
467 if (not_after)
468 {
469 *not_after = this->nextUpdate;
470 }
471 return (t <= this->nextUpdate);
472 }
473
474 METHOD(certificate_t, get_encoding, bool,
475 private_x509_crl_t *this, cred_encoding_type_t type, chunk_t *encoding)
476 {
477 if (type == CERT_ASN1_DER)
478 {
479 *encoding = chunk_clone(this->encoding);
480 return TRUE;
481 }
482 return lib->encoding->encode(lib->encoding, type, NULL, encoding,
483 CRED_PART_X509_CRL_ASN1_DER, this->encoding, CRED_PART_END);
484 }
485
486 METHOD(certificate_t, equals, bool,
487 private_x509_crl_t *this, certificate_t *other)
488 {
489 chunk_t encoding;
490 bool equal;
491
492 if ((certificate_t*)this == other)
493 {
494 return TRUE;
495 }
496 if (other->equals == (void*)equals)
497 { /* skip allocation if we have the same implementation */
498 return chunk_equals(this->encoding, ((private_x509_crl_t*)other)->encoding);
499 }
500 if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
501 {
502 return FALSE;
503 }
504 equal = chunk_equals(this->encoding, encoding);
505 free(encoding.ptr);
506 return equal;
507 }
508
509 /**
510 * Destroy a revoked_t entry
511 */
512 static void revoked_destroy(revoked_t *revoked)
513 {
514 free(revoked->serial.ptr);
515 free(revoked);
516 }
517
518 METHOD(certificate_t, destroy, void,
519 private_x509_crl_t *this)
520 {
521 if (ref_put(&this->ref))
522 {
523 this->revoked->destroy_function(this->revoked, (void*)revoked_destroy);
524 DESTROY_IF(this->issuer);
525 free(this->authKeyIdentifier.ptr);
526 free(this->encoding.ptr);
527 if (this->generated)
528 {
529 free(this->crlNumber.ptr);
530 free(this->signature.ptr);
531 free(this->tbsCertList.ptr);
532 }
533 free(this);
534 }
535 }
536
537 /**
538 * create an empty but initialized X.509 crl
539 */
540 static private_x509_crl_t* create_empty(void)
541 {
542 private_x509_crl_t *this;
543
544 INIT(this,
545 .public = {
546 .crl = {
547 .certificate = {
548 .get_type = _get_type,
549 .get_subject = _get_issuer,
550 .get_issuer = _get_issuer,
551 .has_subject = _has_issuer,
552 .has_issuer = _has_issuer,
553 .issued_by = _issued_by,
554 .get_public_key = _get_public_key,
555 .get_validity = _get_validity,
556 .get_encoding = _get_encoding,
557 .equals = _equals,
558 .get_ref = _get_ref,
559 .destroy = _destroy,
560 },
561 .get_serial = _get_serial,
562 .get_authKeyIdentifier = _get_authKeyIdentifier,
563 .create_enumerator = _create_enumerator,
564 },
565 },
566 .revoked = linked_list_create(),
567 .ref = 1,
568 );
569 return this;
570 }
571
572 /**
573 * See header.
574 */
575 x509_crl_t *x509_crl_load(certificate_type_t type, va_list args)
576 {
577 chunk_t blob = chunk_empty;
578
579 while (TRUE)
580 {
581 switch (va_arg(args, builder_part_t))
582 {
583 case BUILD_BLOB_ASN1_DER:
584 blob = va_arg(args, chunk_t);
585 continue;
586 case BUILD_END:
587 break;
588 default:
589 return NULL;
590 }
591 break;
592 }
593 if (blob.ptr)
594 {
595 private_x509_crl_t *crl = create_empty();
596
597 crl->encoding = chunk_clone(blob);
598 if (parse(crl))
599 {
600 return &crl->public;
601 }
602 destroy(crl);
603 }
604 return NULL;
605 };
606
607 /**
608 * Read certificate status from enumerator, copy to crl
609 */
610 static void read_revoked(private_x509_crl_t *crl, enumerator_t *enumerator)
611 {
612 revoked_t *revoked;
613 chunk_t serial;
614 time_t date;
615 crl_reason_t reason;
616
617 while (enumerator->enumerate(enumerator, &serial, &date, &reason))
618 {
619 INIT(revoked,
620 .serial = chunk_clone(serial),
621 .date = date,
622 .reason = reason,
623 );
624 crl->revoked->insert_last(crl->revoked, revoked);
625 }
626 }
627
628 /**
629 * Generate CRL encoding, sign CRL
630 */
631 static bool generate(private_x509_crl_t *this, certificate_t *cert,
632 private_key_t *key, hash_algorithm_t digest_alg)
633 {
634 chunk_t extensions = chunk_empty, certList = chunk_empty, serial;
635 enumerator_t *enumerator;
636 crl_reason_t reason;
637 time_t date;
638 x509_t *x509;
639
640 x509 = (x509_t*)cert;
641
642 this->issuer = cert->get_subject(cert);
643 this->issuer = this->issuer->clone(this->issuer);
644
645 this->authKeyIdentifier = chunk_clone(x509->get_subjectKeyIdentifier(x509));
646
647 /* select signature scheme */
648 this->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
649 key->get_type(key));
650 if (this->algorithm == OID_UNKNOWN)
651 {
652 return FALSE;
653 }
654
655 enumerator = create_enumerator(this);
656 while (enumerator->enumerate(enumerator, &serial, &date, &reason))
657 {
658 chunk_t revoked, entry_ext = chunk_empty;
659
660 if (reason != CRL_REASON_UNSPECIFIED)
661 {
662 entry_ext = asn1_wrap(ASN1_SEQUENCE, "m",
663 asn1_wrap(ASN1_SEQUENCE, "mm",
664 asn1_build_known_oid(OID_CRL_REASON_CODE),
665 asn1_wrap(ASN1_OCTET_STRING, "m",
666 asn1_wrap(ASN1_ENUMERATED, "c",
667 chunk_from_chars(reason)))));
668 }
669 revoked = asn1_wrap(ASN1_SEQUENCE, "mmm",
670 asn1_integer("c", serial),
671 asn1_from_time(&date, ASN1_UTCTIME),
672 entry_ext);
673 certList = chunk_cat("mm", certList, revoked);
674 }
675 enumerator->destroy(enumerator);
676
677 extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m",
678 asn1_wrap(ASN1_SEQUENCE, "mm",
679 asn1_wrap(ASN1_SEQUENCE, "mm",
680 asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
681 asn1_wrap(ASN1_OCTET_STRING, "m",
682 asn1_wrap(ASN1_SEQUENCE, "m",
683 asn1_wrap(ASN1_CONTEXT_S_0, "c",
684 this->authKeyIdentifier)))),
685 asn1_wrap(ASN1_SEQUENCE, "mm",
686 asn1_build_known_oid(OID_CRL_NUMBER),
687 asn1_wrap(ASN1_OCTET_STRING, "m",
688 asn1_integer("c", this->crlNumber))
689 )
690 ));
691
692 this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cmcmmmm",
693 ASN1_INTEGER_1,
694 asn1_algorithmIdentifier(this->algorithm),
695 this->issuer->get_encoding(this->issuer),
696 asn1_from_time(&this->thisUpdate, ASN1_UTCTIME),
697 asn1_from_time(&this->nextUpdate, ASN1_UTCTIME),
698 asn1_wrap(ASN1_SEQUENCE, "m", certList),
699 extensions);
700
701 if (!key->sign(key, signature_scheme_from_oid(this->algorithm),
702 this->tbsCertList, &this->signature))
703 {
704 return FALSE;
705 }
706 this->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
707 this->tbsCertList,
708 asn1_algorithmIdentifier(this->algorithm),
709 asn1_bitstring("c", this->signature));
710 return TRUE;
711 }
712
713 /**
714 * See header.
715 */
716 x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
717 {
718 hash_algorithm_t digest_alg = HASH_SHA1;
719 private_x509_crl_t *crl;
720 certificate_t *cert = NULL;
721 private_key_t *key = NULL;
722
723 crl = create_empty();
724 crl->generated = TRUE;
725 while (TRUE)
726 {
727 builder_part_t part = va_arg(args, builder_part_t);
728
729 switch (part)
730 {
731 case BUILD_SIGNING_KEY:
732 key = va_arg(args, private_key_t*);
733 continue;
734 case BUILD_SIGNING_CERT:
735 cert = va_arg(args, certificate_t*);
736 continue;
737 case BUILD_NOT_BEFORE_TIME:
738 crl->thisUpdate = va_arg(args, time_t);
739 continue;
740 case BUILD_NOT_AFTER_TIME:
741 crl->nextUpdate = va_arg(args, time_t);
742 continue;
743 case BUILD_SERIAL:
744 crl->crlNumber = va_arg(args, chunk_t);
745 crl->crlNumber = chunk_clone(crl->crlNumber);
746 continue;
747 case BUILD_DIGEST_ALG:
748 digest_alg = va_arg(args, int);
749 continue;
750 case BUILD_REVOKED_ENUMERATOR:
751 read_revoked(crl, va_arg(args, enumerator_t*));
752 continue;
753 case BUILD_END:
754 break;
755 default:
756 destroy(crl);
757 return NULL;
758 }
759 break;
760 }
761
762 if (key && cert && cert->get_type(cert) == CERT_X509 &&
763 generate(crl, cert, key, digest_alg))
764 {
765 return &crl->public;
766 }
767 destroy(crl);
768 return NULL;
769 }