Use CAs subjectKeyIdentifier as CRLs authorityKeyIdentifier
[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 if (revoked && extn_oid == OID_CRL_REASON_CODE)
265 {
266 if (*object.ptr == ASN1_ENUMERATED &&
267 asn1_length(&object) == 1)
268 {
269 revoked->reason = *object.ptr;
270 }
271 DBG2(DBG_LIB, " '%N'", crl_reason_names,
272 revoked->reason);
273 }
274 else if (extn_oid == OID_AUTHORITY_KEY_ID)
275 {
276 this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
277 level, &this->authKeySerialNumber);
278 }
279 else if (extn_oid == OID_CRL_NUMBER)
280 {
281 if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
282 level, "crlNumber"))
283 {
284 goto end;
285 }
286 this->crlNumber = object;
287 }
288 }
289 break;
290 case CRL_OBJ_ALGORITHM:
291 {
292 this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
293 if (this->algorithm != sig_alg)
294 {
295 DBG1(DBG_LIB, " signature algorithms do not agree");
296 goto end;
297 }
298 break;
299 }
300 case CRL_OBJ_SIGNATURE:
301 this->signature = object;
302 break;
303 default:
304 break;
305 }
306 }
307 success = parser->success(parser);
308
309 end:
310 parser->destroy(parser);
311 return success;
312 }
313
314 /**
315 * enumerator filter callback for create_enumerator
316 */
317 static bool filter(void *data, revoked_t **revoked, chunk_t *serial, void *p2,
318 time_t *date, void *p3, crl_reason_t *reason)
319 {
320 if (serial)
321 {
322 *serial = (*revoked)->serial;
323 }
324 if (date)
325 {
326 *date = (*revoked)->date;
327 }
328 if (reason)
329 {
330 *reason = (*revoked)->reason;
331 }
332 return TRUE;
333 }
334
335 METHOD(crl_t, get_serial, chunk_t,
336 private_x509_crl_t *this)
337 {
338 return this->crlNumber;
339 }
340
341 METHOD(crl_t, get_authKeyIdentifier, chunk_t,
342 private_x509_crl_t *this)
343 {
344 return this->authKeyIdentifier;
345 }
346
347 METHOD(crl_t, create_enumerator, enumerator_t*,
348 private_x509_crl_t *this)
349 {
350 return enumerator_create_filter(
351 this->revoked->create_enumerator(this->revoked),
352 (void*)filter, NULL, NULL);
353 }
354
355 METHOD(certificate_t, get_type, certificate_type_t,
356 private_x509_crl_t *this)
357 {
358 return CERT_X509_CRL;
359 }
360
361 METHOD(certificate_t, get_issuer, identification_t*,
362 private_x509_crl_t *this)
363 {
364 return this->issuer;
365 }
366
367 METHOD(certificate_t, has_issuer, id_match_t,
368 private_x509_crl_t *this, identification_t *issuer)
369 {
370 if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr &&
371 chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer)))
372 {
373 return ID_MATCH_PERFECT;
374 }
375 return this->issuer->matches(this->issuer, issuer);
376 }
377
378 METHOD(certificate_t, issued_by, bool,
379 private_x509_crl_t *this, certificate_t *issuer)
380 {
381 public_key_t *key;
382 signature_scheme_t scheme;
383 bool valid;
384 x509_t *x509 = (x509_t*)issuer;
385
386 /* check if issuer is an X.509 CA certificate */
387 if (issuer->get_type(issuer) != CERT_X509)
388 {
389 return FALSE;
390 }
391 if (!(x509->get_flags(x509) & X509_CA))
392 {
393 return FALSE;
394 }
395
396 /* get the public key of the issuer */
397 key = issuer->get_public_key(issuer);
398
399 /* compare keyIdentifiers if available, otherwise use DNs */
400 if (this->authKeyIdentifier.ptr && key)
401 {
402 chunk_t fingerprint;
403
404 if (!key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &fingerprint) ||
405 !chunk_equals(fingerprint, this->authKeyIdentifier))
406 {
407 return FALSE;
408 }
409 }
410 else
411 {
412 if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
413 {
414 return FALSE;
415 }
416 }
417
418 /* determine signature scheme */
419 scheme = signature_scheme_from_oid(this->algorithm);
420
421 if (scheme == SIGN_UNKNOWN || key == NULL)
422 {
423 return FALSE;
424 }
425 valid = key->verify(key, scheme, this->tbsCertList, this->signature);
426 key->destroy(key);
427 return valid;
428 }
429
430 METHOD(certificate_t, get_public_key, public_key_t*,
431 private_x509_crl_t *this)
432 {
433 return NULL;
434 }
435
436 METHOD(certificate_t, get_ref, certificate_t*,
437 private_x509_crl_t *this)
438 {
439 ref_get(&this->ref);
440 return &this->public.crl.certificate;
441 }
442
443 METHOD(certificate_t, get_validity, bool,
444 private_x509_crl_t *this, time_t *when,
445 time_t *not_before, time_t *not_after)
446 {
447 time_t t = when ? *when : time(NULL);
448
449 if (not_before)
450 {
451 *not_before = this->thisUpdate;
452 }
453 if (not_after)
454 {
455 *not_after = this->nextUpdate;
456 }
457 return (t <= this->nextUpdate);
458 }
459
460 METHOD(certificate_t, get_encoding, chunk_t,
461 private_x509_crl_t *this)
462 {
463 return chunk_clone(this->encoding);
464 }
465
466 METHOD(certificate_t, equals, bool,
467 private_x509_crl_t *this, certificate_t *other)
468 {
469 chunk_t encoding;
470 bool equal;
471
472 if ((certificate_t*)this == other)
473 {
474 return TRUE;
475 }
476 if (other->equals == (void*)equals)
477 { /* skip allocation if we have the same implementation */
478 return chunk_equals(this->encoding, ((private_x509_crl_t*)other)->encoding);
479 }
480 encoding = other->get_encoding(other);
481 equal = chunk_equals(this->encoding, encoding);
482 free(encoding.ptr);
483 return equal;
484 }
485
486 /**
487 * Destroy a revoked_t entry
488 */
489 static void revoked_destroy(revoked_t *revoked)
490 {
491 free(revoked->serial.ptr);
492 free(revoked);
493 }
494
495 METHOD(certificate_t, destroy, void,
496 private_x509_crl_t *this)
497 {
498 if (ref_put(&this->ref))
499 {
500 this->revoked->destroy_function(this->revoked, (void*)revoked_destroy);
501 DESTROY_IF(this->issuer);
502 free(this->authKeyIdentifier.ptr);
503 free(this->encoding.ptr);
504 if (this->generated)
505 {
506 free(this->crlNumber.ptr);
507 free(this->signature.ptr);
508 free(this->tbsCertList.ptr);
509 }
510 free(this);
511 }
512 }
513
514 /**
515 * create an empty but initialized X.509 crl
516 */
517 static private_x509_crl_t* create_empty(void)
518 {
519 private_x509_crl_t *this;
520
521 INIT(this,
522 .public = {
523 .crl = {
524 .certificate = {
525 .get_type = _get_type,
526 .get_subject = _get_issuer,
527 .get_issuer = _get_issuer,
528 .has_subject = _has_issuer,
529 .has_issuer = _has_issuer,
530 .issued_by = _issued_by,
531 .get_public_key = _get_public_key,
532 .get_validity = _get_validity,
533 .get_encoding = _get_encoding,
534 .equals = _equals,
535 .get_ref = _get_ref,
536 .destroy = _destroy,
537 },
538 .get_serial = _get_serial,
539 .get_authKeyIdentifier = _get_authKeyIdentifier,
540 .create_enumerator = _create_enumerator,
541 },
542 },
543 .revoked = linked_list_create(),
544 .ref = 1,
545 );
546 return this;
547 }
548
549 /**
550 * See header.
551 */
552 x509_crl_t *x509_crl_load(certificate_type_t type, va_list args)
553 {
554 chunk_t blob = chunk_empty;
555
556 while (TRUE)
557 {
558 switch (va_arg(args, builder_part_t))
559 {
560 case BUILD_BLOB_ASN1_DER:
561 blob = va_arg(args, chunk_t);
562 continue;
563 case BUILD_END:
564 break;
565 default:
566 return NULL;
567 }
568 break;
569 }
570 if (blob.ptr)
571 {
572 private_x509_crl_t *crl = create_empty();
573
574 crl->encoding = chunk_clone(blob);
575 if (parse(crl))
576 {
577 return &crl->public;
578 }
579 destroy(crl);
580 }
581 return NULL;
582 };
583
584 /**
585 * Read certificate status from enumerator, copy to crl
586 */
587 static void read_revoked(private_x509_crl_t *crl, enumerator_t *enumerator)
588 {
589 revoked_t *revoked;
590 chunk_t serial;
591 time_t date;
592 crl_reason_t reason;
593
594 while (enumerator->enumerate(enumerator, &serial, &date, &reason))
595 {
596 INIT(revoked,
597 .serial = chunk_clone(serial),
598 .date = date,
599 .reason = reason,
600 );
601 crl->revoked->insert_last(crl->revoked, revoked);
602 }
603 }
604
605 /**
606 * Generate CRL encoding, sign CRL
607 */
608 static bool generate(private_x509_crl_t *this, certificate_t *cert,
609 private_key_t *key, hash_algorithm_t digest_alg)
610 {
611 chunk_t extensions = chunk_empty, certList = chunk_empty, serial;
612 enumerator_t *enumerator;
613 crl_reason_t reason;
614 time_t date;
615 x509_t *x509;
616
617 x509 = (x509_t*)cert;
618
619 this->issuer = cert->get_issuer(cert);
620 this->issuer = this->issuer->clone(this->issuer);
621
622 this->authKeyIdentifier = chunk_clone(x509->get_subjectKeyIdentifier(x509));
623
624 /* select signature scheme */
625 this->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
626 key->get_type(key));
627 if (this->algorithm == OID_UNKNOWN)
628 {
629 return FALSE;
630 }
631
632 enumerator = create_enumerator(this);
633 while (enumerator->enumerate(enumerator, &serial, &date, &reason))
634 {
635 chunk_t revoked, entry_ext = chunk_empty;
636
637 if (reason != CRL_REASON_UNSPECIFIED)
638 {
639 entry_ext = asn1_wrap(ASN1_SEQUENCE, "m",
640 asn1_wrap(ASN1_SEQUENCE, "mm",
641 asn1_build_known_oid(OID_CRL_REASON_CODE),
642 asn1_wrap(ASN1_OCTET_STRING, "m",
643 asn1_wrap(ASN1_ENUMERATED, "c",
644 chunk_from_chars(reason)))));
645 }
646 revoked = asn1_wrap(ASN1_SEQUENCE, "mmm",
647 asn1_integer("c", serial),
648 asn1_from_time(&date, ASN1_UTCTIME),
649 entry_ext);
650 certList = chunk_cat("mm", certList, revoked);
651 }
652 enumerator->destroy(enumerator);
653
654 extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m",
655 asn1_wrap(ASN1_SEQUENCE, "mm",
656 asn1_wrap(ASN1_SEQUENCE, "mm",
657 asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
658 asn1_wrap(ASN1_OCTET_STRING, "m",
659 asn1_wrap(ASN1_SEQUENCE, "m",
660 asn1_wrap(ASN1_CONTEXT_S_0, "c",
661 this->authKeyIdentifier)))),
662 asn1_wrap(ASN1_SEQUENCE, "mm",
663 asn1_build_known_oid(OID_CRL_NUMBER),
664 asn1_wrap(ASN1_OCTET_STRING, "m",
665 asn1_integer("c", this->crlNumber))
666 )
667 ));
668
669 this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cmcmmmm",
670 ASN1_INTEGER_1,
671 asn1_algorithmIdentifier(this->algorithm),
672 this->issuer->get_encoding(this->issuer),
673 asn1_from_time(&this->thisUpdate, ASN1_UTCTIME),
674 asn1_from_time(&this->nextUpdate, ASN1_UTCTIME),
675 asn1_wrap(ASN1_SEQUENCE, "m", certList),
676 extensions);
677
678 if (!key->sign(key, signature_scheme_from_oid(this->algorithm),
679 this->tbsCertList, &this->signature))
680 {
681 return FALSE;
682 }
683 this->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
684 this->tbsCertList,
685 asn1_algorithmIdentifier(this->algorithm),
686 asn1_bitstring("c", this->signature));
687 return TRUE;
688 }
689
690 /**
691 * See header.
692 */
693 x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
694 {
695 hash_algorithm_t digest_alg = HASH_SHA1;
696 private_x509_crl_t *crl;
697 certificate_t *cert = NULL;
698 private_key_t *key = NULL;
699
700 crl = create_empty();
701 crl->generated = TRUE;
702 while (TRUE)
703 {
704 builder_part_t part = va_arg(args, builder_part_t);
705
706 switch (part)
707 {
708 case BUILD_SIGNING_KEY:
709 key = va_arg(args, private_key_t*);
710 continue;
711 case BUILD_SIGNING_CERT:
712 cert = va_arg(args, certificate_t*);
713 continue;
714 case BUILD_NOT_BEFORE_TIME:
715 crl->thisUpdate = va_arg(args, time_t);
716 continue;
717 case BUILD_NOT_AFTER_TIME:
718 crl->nextUpdate = va_arg(args, time_t);
719 continue;
720 case BUILD_SERIAL:
721 crl->crlNumber = va_arg(args, chunk_t);
722 crl->crlNumber = chunk_clone(crl->crlNumber);
723 continue;
724 case BUILD_DIGEST_ALG:
725 digest_alg = va_arg(args, int);
726 continue;
727 case BUILD_REVOKED_ENUMERATOR:
728 read_revoked(crl, va_arg(args, enumerator_t*));
729 continue;
730 case BUILD_END:
731 break;
732 default:
733 destroy(crl);
734 return NULL;
735 }
736 break;
737 }
738
739 if (key && cert && cert->get_type(cert) == CERT_X509 &&
740 generate(crl, cert, key, digest_alg))
741 {
742 return &crl->public;
743 }
744 destroy(crl);
745 return NULL;
746 }