2 * Copyright (C) 2008-2009 Martin Willi
3 * Copyright (C) 2017 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
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>.
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
19 typedef struct private_x509_crl_t private_x509_crl_t
;
20 typedef struct revoked_t revoked_t
;
24 #include <utils/debug.h>
27 #include <asn1/asn1.h>
28 #include <asn1/asn1_parser.h>
29 #include <credentials/certificates/x509.h>
30 #include <credentials/keys/private_key.h>
31 #include <collections/linked_list.h>
34 * entry for a revoked certificate
38 * serial of the revoked certificate
48 * reason for revocation
54 * private data of x509_crl
56 struct private_x509_crl_t
{
64 * X.509 crl encoding in ASN.1 DER format
69 * X.509 crl body over which signature is computed
74 * Version of the X.509 crl
79 * ID representing the crl issuer
81 identification_t
*issuer
;
89 * Time when the crl was generated
94 * Time when an update crl will be available
99 * list of revoked certificates as revoked_t
101 linked_list_t
*revoked
;
104 * List of Freshest CRL distribution points
106 linked_list_t
*crl_uris
;
109 * Authority Key Identifier
111 chunk_t authKeyIdentifier
;
114 * Authority Key Serial Number
116 chunk_t authKeySerialNumber
;
119 * Number of BaseCRL, if a delta CRL
121 chunk_t baseCrlNumber
;
124 * Signature algorithm
134 * has this CRL been generated
147 extern chunk_t
x509_parse_authorityKeyIdentifier(chunk_t blob
, int level0
,
148 chunk_t
*authKeySerialNumber
);
153 extern bool x509_parse_crlDistributionPoints(chunk_t blob
, int level0
,
154 linked_list_t
*list
);
159 extern chunk_t
x509_build_crlDistributionPoints(linked_list_t
*list
, int extn
);
162 * ASN.1 definition of an X.509 certificate revocation list
164 static const asn1Object_t crlObjects
[] = {
165 { 0, "certificateList", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 0 */
166 { 1, "tbsCertList", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 1 */
167 { 2, "version", ASN1_INTEGER
, ASN1_OPT
|
169 { 2, "end opt", ASN1_EOC
, ASN1_END
}, /* 3 */
170 { 2, "signature", ASN1_EOC
, ASN1_RAW
}, /* 4 */
171 { 2, "issuer", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 5 */
172 { 2, "thisUpdate", ASN1_EOC
, ASN1_RAW
}, /* 6 */
173 { 2, "nextUpdate", ASN1_EOC
, ASN1_RAW
}, /* 7 */
174 { 2, "revokedCertificates", ASN1_SEQUENCE
, ASN1_OPT
|
176 { 3, "certList", ASN1_SEQUENCE
, ASN1_NONE
}, /* 9 */
177 { 4, "userCertificate", ASN1_INTEGER
, ASN1_BODY
}, /* 10 */
178 { 4, "revocationDate", ASN1_EOC
, ASN1_RAW
}, /* 11 */
179 { 4, "crlEntryExtensions", ASN1_SEQUENCE
, ASN1_OPT
|
180 ASN1_LOOP
}, /* 12 */
181 { 5, "extension", ASN1_SEQUENCE
, ASN1_NONE
}, /* 13 */
182 { 6, "extnID", ASN1_OID
, ASN1_BODY
}, /* 14 */
183 { 6, "critical", ASN1_BOOLEAN
, ASN1_DEF
|
184 ASN1_BODY
}, /* 15 */
185 { 6, "extnValue", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 16 */
186 { 4, "end opt or loop", ASN1_EOC
, ASN1_END
}, /* 17 */
187 { 2, "end opt or loop", ASN1_EOC
, ASN1_END
}, /* 18 */
188 { 2, "optional extensions", ASN1_CONTEXT_C_0
, ASN1_OPT
}, /* 19 */
189 { 3, "crlExtensions", ASN1_SEQUENCE
, ASN1_LOOP
}, /* 20 */
190 { 4, "extension", ASN1_SEQUENCE
, ASN1_NONE
}, /* 21 */
191 { 5, "extnID", ASN1_OID
, ASN1_BODY
}, /* 22 */
192 { 5, "critical", ASN1_BOOLEAN
, ASN1_DEF
|
193 ASN1_BODY
}, /* 23 */
194 { 5, "extnValue", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 24 */
195 { 3, "end loop", ASN1_EOC
, ASN1_END
}, /* 25 */
196 { 2, "end opt", ASN1_EOC
, ASN1_END
}, /* 26 */
197 { 1, "signatureAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 27 */
198 { 1, "signatureValue", ASN1_BIT_STRING
, ASN1_BODY
}, /* 28 */
199 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
201 #define CRL_OBJ_TBS_CERT_LIST 1
202 #define CRL_OBJ_VERSION 2
203 #define CRL_OBJ_SIG_ALG 4
204 #define CRL_OBJ_ISSUER 5
205 #define CRL_OBJ_THIS_UPDATE 6
206 #define CRL_OBJ_NEXT_UPDATE 7
207 #define CRL_OBJ_USER_CERTIFICATE 10
208 #define CRL_OBJ_REVOCATION_DATE 11
209 #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
210 #define CRL_OBJ_CRL_ENTRY_CRITICAL 15
211 #define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
212 #define CRL_OBJ_EXTN_ID 22
213 #define CRL_OBJ_CRITICAL 23
214 #define CRL_OBJ_EXTN_VALUE 24
215 #define CRL_OBJ_ALGORITHM 27
216 #define CRL_OBJ_SIGNATURE 28
219 * Parses an X.509 Certificate Revocation List (CRL)
221 static bool parse(private_x509_crl_t
*this)
223 asn1_parser_t
*parser
;
225 chunk_t extnID
= chunk_empty
;
226 chunk_t userCertificate
= chunk_empty
;
228 int sig_alg
= OID_UNKNOWN
;
229 bool success
= FALSE
;
230 bool critical
= FALSE
;
231 revoked_t
*revoked
= NULL
;
233 parser
= asn1_parser_create(crlObjects
, this->encoding
);
235 while (parser
->iterate(parser
, &objectID
, &object
))
237 u_int level
= parser
->get_level(parser
)+1;
241 case CRL_OBJ_TBS_CERT_LIST
:
242 this->tbsCertList
= object
;
244 case CRL_OBJ_VERSION
:
245 this->version
= (object
.len
) ?
(1+(u_int
)*object
.ptr
) : 1;
246 DBG2(DBG_ASN
, " v%d", this->version
);
248 case CRL_OBJ_SIG_ALG
:
249 sig_alg
= asn1_parse_algorithmIdentifier(object
, level
, NULL
);
252 this->issuer
= identification_create_from_encoding(ID_DER_ASN1_DN
, object
);
253 DBG2(DBG_ASN
, " '%Y'", this->issuer
);
255 case CRL_OBJ_THIS_UPDATE
:
256 this->thisUpdate
= asn1_parse_time(object
, level
);
258 case CRL_OBJ_NEXT_UPDATE
:
259 this->nextUpdate
= asn1_parse_time(object
, level
);
261 case CRL_OBJ_USER_CERTIFICATE
:
262 userCertificate
= object
;
264 case CRL_OBJ_REVOCATION_DATE
:
265 revoked
= malloc_thing(revoked_t
);
266 revoked
->serial
= chunk_clone(userCertificate
);
267 revoked
->date
= asn1_parse_time(object
, level
);
268 revoked
->reason
= CRL_REASON_UNSPECIFIED
;
269 this->revoked
->insert_last(this->revoked
, (void *)revoked
);
271 case CRL_OBJ_CRL_ENTRY_EXTN_ID
:
272 case CRL_OBJ_EXTN_ID
:
275 case CRL_OBJ_CRL_ENTRY_CRITICAL
:
276 case CRL_OBJ_CRITICAL
:
277 critical
= object
.len
&& *object
.ptr
;
278 DBG2(DBG_ASN
, " %s", critical ?
"TRUE" : "FALSE");
280 case CRL_OBJ_CRL_ENTRY_EXTN_VALUE
:
281 case CRL_OBJ_EXTN_VALUE
:
283 int extn_oid
= asn1_known_oid(extnID
);
287 case OID_CRL_REASON_CODE
:
290 if (object
.len
&& *object
.ptr
== ASN1_ENUMERATED
&&
291 asn1_length(&object
) == 1)
293 revoked
->reason
= *object
.ptr
;
295 DBG2(DBG_ASN
, " '%N'", crl_reason_names
,
299 case OID_AUTHORITY_KEY_ID
:
300 this->authKeyIdentifier
=
301 x509_parse_authorityKeyIdentifier(
302 object
, level
, &this->authKeySerialNumber
);
305 if (!asn1_parse_simple_object(&object
, ASN1_INTEGER
,
310 this->crlNumber
= object
;
312 case OID_FRESHEST_CRL
:
313 if (!x509_parse_crlDistributionPoints(object
, level
,
319 case OID_DELTA_CRL_INDICATOR
:
320 if (!asn1_parse_simple_object(&object
, ASN1_INTEGER
,
321 level
, "deltaCrlIndicator"))
325 this->baseCrlNumber
= object
;
327 case OID_ISSUING_DIST_POINT
:
328 /* TODO support of IssuingDistributionPoints */
331 if (critical
&& lib
->settings
->get_bool(lib
->settings
,
332 "%s.x509.enforce_critical", TRUE
, lib
->ns
))
334 DBG1(DBG_ASN
, "critical '%s' extension not supported",
335 (extn_oid
== OID_UNKNOWN
) ?
"unknown" :
336 (char*)oid_names
[extn_oid
].name
);
343 case CRL_OBJ_ALGORITHM
:
345 this->algorithm
= asn1_parse_algorithmIdentifier(object
, level
, NULL
);
346 if (this->algorithm
!= sig_alg
)
348 DBG1(DBG_ASN
, " signature algorithms do not agree");
353 case CRL_OBJ_SIGNATURE
:
354 this->signature
= chunk_skip(object
, 1);
360 success
= parser
->success(parser
);
363 parser
->destroy(parser
);
368 * enumerator filter callback for create_enumerator
370 static bool filter(void *data
, revoked_t
**revoked
, chunk_t
*serial
, void *p2
,
371 time_t *date
, void *p3
, crl_reason_t
*reason
)
375 *serial
= (*revoked
)->serial
;
379 *date
= (*revoked
)->date
;
383 *reason
= (*revoked
)->reason
;
388 METHOD(crl_t
, get_serial
, chunk_t
,
389 private_x509_crl_t
*this)
391 return this->crlNumber
;
394 METHOD(crl_t
, get_authKeyIdentifier
, chunk_t
,
395 private_x509_crl_t
*this)
397 return this->authKeyIdentifier
;
400 METHOD(crl_t
, is_delta_crl
, bool,
401 private_x509_crl_t
*this, chunk_t
*base_crl
)
403 if (this->baseCrlNumber
.len
)
407 *base_crl
= this->baseCrlNumber
;
414 METHOD(crl_t
, create_delta_crl_uri_enumerator
, enumerator_t
*,
415 private_x509_crl_t
*this)
417 return this->crl_uris
->create_enumerator(this->crl_uris
);
420 METHOD(crl_t
, create_enumerator
, enumerator_t
*,
421 private_x509_crl_t
*this)
423 return enumerator_create_filter(
424 this->revoked
->create_enumerator(this->revoked
),
425 (void*)filter
, NULL
, NULL
);
428 METHOD(certificate_t
, get_type
, certificate_type_t
,
429 private_x509_crl_t
*this)
431 return CERT_X509_CRL
;
434 METHOD(certificate_t
, get_issuer
, identification_t
*,
435 private_x509_crl_t
*this)
440 METHOD(certificate_t
, has_issuer
, id_match_t
,
441 private_x509_crl_t
*this, identification_t
*issuer
)
443 if (issuer
->get_type(issuer
) == ID_KEY_ID
&& this->authKeyIdentifier
.ptr
&&
444 chunk_equals(this->authKeyIdentifier
, issuer
->get_encoding(issuer
)))
446 return ID_MATCH_PERFECT
;
448 return this->issuer
->matches(this->issuer
, issuer
);
451 METHOD(certificate_t
, issued_by
, bool,
452 private_x509_crl_t
*this, certificate_t
*issuer
, signature_scheme_t
*schemep
)
455 signature_scheme_t scheme
;
457 x509_t
*x509
= (x509_t
*)issuer
;
458 chunk_t keyid
= chunk_empty
;
460 /* check if issuer is an X.509 CA certificate */
461 if (issuer
->get_type(issuer
) != CERT_X509
)
465 if (!(x509
->get_flags(x509
) & (X509_CA
| X509_CRL_SIGN
)))
470 /* compare keyIdentifiers if available, otherwise use DNs */
471 if (this->authKeyIdentifier
.ptr
)
473 keyid
= x509
->get_subjectKeyIdentifier(x509
);
474 if (keyid
.len
&& !chunk_equals(keyid
, this->authKeyIdentifier
))
481 if (!this->issuer
->equals(this->issuer
, issuer
->get_subject(issuer
)))
487 scheme
= signature_scheme_from_oid(this->algorithm
);
488 if (scheme
== SIGN_UNKNOWN
)
492 key
= issuer
->get_public_key(issuer
);
497 valid
= key
->verify(key
, scheme
, this->tbsCertList
, this->signature
);
499 if (valid
&& schemep
)
506 METHOD(certificate_t
, get_public_key
, public_key_t
*,
507 private_x509_crl_t
*this)
512 METHOD(certificate_t
, get_ref
, certificate_t
*,
513 private_x509_crl_t
*this)
516 return &this->public.crl
.certificate
;
519 METHOD(certificate_t
, get_validity
, bool,
520 private_x509_crl_t
*this, time_t *when
,
521 time_t *not_before
, time_t *not_after
)
523 time_t t
= when ?
*when
: time(NULL
);
527 *not_before
= this->thisUpdate
;
531 *not_after
= this->nextUpdate
;
533 return (t
<= this->nextUpdate
);
536 METHOD(certificate_t
, get_encoding
, bool,
537 private_x509_crl_t
*this, cred_encoding_type_t type
, chunk_t
*encoding
)
539 if (type
== CERT_ASN1_DER
)
541 *encoding
= chunk_clone(this->encoding
);
544 return lib
->encoding
->encode(lib
->encoding
, type
, NULL
, encoding
,
545 CRED_PART_X509_CRL_ASN1_DER
, this->encoding
, CRED_PART_END
);
548 METHOD(certificate_t
, equals
, bool,
549 private_x509_crl_t
*this, certificate_t
*other
)
554 if ((certificate_t
*)this == other
)
558 if (other
->equals
== (void*)equals
)
559 { /* skip allocation if we have the same implementation */
560 return chunk_equals(this->encoding
, ((private_x509_crl_t
*)other
)->encoding
);
562 if (!other
->get_encoding(other
, CERT_ASN1_DER
, &encoding
))
566 equal
= chunk_equals(this->encoding
, encoding
);
572 * Destroy a revoked_t entry
574 static void revoked_destroy(revoked_t
*revoked
)
576 free(revoked
->serial
.ptr
);
581 * Destroy a CDP entry
583 static void cdp_destroy(x509_cdp_t
*this)
586 DESTROY_IF(this->issuer
);
590 METHOD(certificate_t
, destroy
, void,
591 private_x509_crl_t
*this)
593 if (ref_put(&this->ref
))
595 this->revoked
->destroy_function(this->revoked
, (void*)revoked_destroy
);
596 this->crl_uris
->destroy_function(this->crl_uris
, (void*)cdp_destroy
);
597 DESTROY_IF(this->issuer
);
598 free(this->authKeyIdentifier
.ptr
);
599 free(this->encoding
.ptr
);
602 free(this->crlNumber
.ptr
);
603 free(this->baseCrlNumber
.ptr
);
604 free(this->signature
.ptr
);
605 free(this->tbsCertList
.ptr
);
612 * create an empty but initialized X.509 crl
614 static private_x509_crl_t
* create_empty(void)
616 private_x509_crl_t
*this;
622 .get_type
= _get_type
,
623 .get_subject
= _get_issuer
,
624 .get_issuer
= _get_issuer
,
625 .has_subject
= _has_issuer
,
626 .has_issuer
= _has_issuer
,
627 .issued_by
= _issued_by
,
628 .get_public_key
= _get_public_key
,
629 .get_validity
= _get_validity
,
630 .get_encoding
= _get_encoding
,
635 .get_serial
= _get_serial
,
636 .get_authKeyIdentifier
= _get_authKeyIdentifier
,
637 .is_delta_crl
= _is_delta_crl
,
638 .create_delta_crl_uri_enumerator
= _create_delta_crl_uri_enumerator
,
639 .create_enumerator
= _create_enumerator
,
642 .revoked
= linked_list_create(),
643 .crl_uris
= linked_list_create(),
652 x509_crl_t
*x509_crl_load(certificate_type_t type
, va_list args
)
654 chunk_t blob
= chunk_empty
;
658 switch (va_arg(args
, builder_part_t
))
660 case BUILD_BLOB_ASN1_DER
:
661 blob
= va_arg(args
, chunk_t
);
672 private_x509_crl_t
*crl
= create_empty();
674 crl
->encoding
= chunk_clone(blob
);
685 * Read certificate status from enumerator, copy to crl
687 static void read_revoked(private_x509_crl_t
*crl
, enumerator_t
*enumerator
)
694 while (enumerator
->enumerate(enumerator
, &serial
, &date
, &reason
))
697 .serial
= chunk_clone(serial
),
701 crl
->revoked
->insert_last(crl
->revoked
, revoked
);
706 * Generate CRL encoding, sign CRL
708 static bool generate(private_x509_crl_t
*this, certificate_t
*cert
,
709 private_key_t
*key
, hash_algorithm_t digest_alg
)
711 chunk_t extensions
= chunk_empty
, certList
= chunk_empty
, serial
;
712 chunk_t crlDistributionPoints
= chunk_empty
, baseCrlNumber
= chunk_empty
;
713 enumerator_t
*enumerator
;
718 x509
= (x509_t
*)cert
;
720 this->issuer
= cert
->get_subject(cert
);
721 this->issuer
= this->issuer
->clone(this->issuer
);
723 this->authKeyIdentifier
= chunk_clone(x509
->get_subjectKeyIdentifier(x509
));
725 /* select signature scheme */
726 this->algorithm
= hasher_signature_algorithm_to_oid(digest_alg
,
728 if (this->algorithm
== OID_UNKNOWN
)
733 enumerator
= create_enumerator(this);
734 while (enumerator
->enumerate(enumerator
, &serial
, &date
, &reason
))
736 chunk_t revoked
, entry_ext
= chunk_empty
;
738 if (reason
!= CRL_REASON_UNSPECIFIED
)
740 entry_ext
= asn1_wrap(ASN1_SEQUENCE
, "m",
741 asn1_wrap(ASN1_SEQUENCE
, "mm",
742 asn1_build_known_oid(OID_CRL_REASON_CODE
),
743 asn1_wrap(ASN1_OCTET_STRING
, "m",
744 asn1_wrap(ASN1_ENUMERATED
, "c",
745 chunk_from_chars(reason
)))));
747 revoked
= asn1_wrap(ASN1_SEQUENCE
, "mmm",
748 asn1_integer("c", serial
),
749 asn1_from_time(&date
, ASN1_UTCTIME
),
751 certList
= chunk_cat("mm", certList
, revoked
);
753 enumerator
->destroy(enumerator
);
755 crlDistributionPoints
= x509_build_crlDistributionPoints(this->crl_uris
,
758 if (this->baseCrlNumber
.len
)
760 baseCrlNumber
= asn1_wrap(ASN1_SEQUENCE
, "mmm",
761 asn1_build_known_oid(OID_DELTA_CRL_INDICATOR
),
762 asn1_wrap(ASN1_BOOLEAN
, "c",
763 chunk_from_chars(0xFF)),
764 asn1_wrap(ASN1_OCTET_STRING
, "m",
765 asn1_integer("c", this->baseCrlNumber
)));
768 extensions
= asn1_wrap(ASN1_CONTEXT_C_0
, "m",
769 asn1_wrap(ASN1_SEQUENCE
, "mmmm",
770 asn1_wrap(ASN1_SEQUENCE
, "mm",
771 asn1_build_known_oid(OID_AUTHORITY_KEY_ID
),
772 asn1_wrap(ASN1_OCTET_STRING
, "m",
773 asn1_wrap(ASN1_SEQUENCE
, "m",
774 asn1_wrap(ASN1_CONTEXT_S_0
, "c",
775 this->authKeyIdentifier
)))),
776 asn1_wrap(ASN1_SEQUENCE
, "mm",
777 asn1_build_known_oid(OID_CRL_NUMBER
),
778 asn1_wrap(ASN1_OCTET_STRING
, "m",
779 asn1_integer("c", this->crlNumber
))),
780 crlDistributionPoints
, baseCrlNumber
));
782 this->tbsCertList
= asn1_wrap(ASN1_SEQUENCE
, "cmcmmmm",
784 asn1_algorithmIdentifier(this->algorithm
),
785 this->issuer
->get_encoding(this->issuer
),
786 asn1_from_time(&this->thisUpdate
, ASN1_UTCTIME
),
787 asn1_from_time(&this->nextUpdate
, ASN1_UTCTIME
),
788 asn1_wrap(ASN1_SEQUENCE
, "m", certList
),
791 if (!key
->sign(key
, signature_scheme_from_oid(this->algorithm
),
792 this->tbsCertList
, &this->signature
))
796 this->encoding
= asn1_wrap(ASN1_SEQUENCE
, "cmm",
798 asn1_algorithmIdentifier(this->algorithm
),
799 asn1_bitstring("c", this->signature
));
806 x509_crl_t
*x509_crl_gen(certificate_type_t type
, va_list args
)
808 hash_algorithm_t digest_alg
= HASH_SHA1
;
809 private_x509_crl_t
*crl
;
810 certificate_t
*cert
= NULL
;
811 private_key_t
*key
= NULL
;
813 crl
= create_empty();
814 crl
->generated
= TRUE
;
817 builder_part_t part
= va_arg(args
, builder_part_t
);
821 case BUILD_SIGNING_KEY
:
822 key
= va_arg(args
, private_key_t
*);
824 case BUILD_SIGNING_CERT
:
825 cert
= va_arg(args
, certificate_t
*);
827 case BUILD_NOT_BEFORE_TIME
:
828 crl
->thisUpdate
= va_arg(args
, time_t);
830 case BUILD_NOT_AFTER_TIME
:
831 crl
->nextUpdate
= va_arg(args
, time_t);
834 crl
->crlNumber
= va_arg(args
, chunk_t
);
835 crl
->crlNumber
= chunk_clone(crl
->crlNumber
);
837 case BUILD_DIGEST_ALG
:
838 digest_alg
= va_arg(args
, int);
840 case BUILD_REVOKED_ENUMERATOR
:
841 read_revoked(crl
, va_arg(args
, enumerator_t
*));
844 crl
->baseCrlNumber
= va_arg(args
, chunk_t
);
845 crl
->baseCrlNumber
= chunk_clone(crl
->baseCrlNumber
);
847 case BUILD_CRL_DISTRIBUTION_POINTS
:
849 enumerator_t
*enumerator
;
851 x509_cdp_t
*in
, *cdp
;
853 list
= va_arg(args
, linked_list_t
*);
854 enumerator
= list
->create_enumerator(list
);
855 while (enumerator
->enumerate(enumerator
, &in
))
858 .uri
= strdup(in
->uri
),
859 .issuer
= in
->issuer ? in
->issuer
->clone(in
->issuer
) : NULL
,
861 crl
->crl_uris
->insert_last(crl
->crl_uris
, cdp
);
863 enumerator
->destroy(enumerator
);
875 if (key
&& cert
&& cert
->get_type(cert
) == CERT_X509
&&
876 generate(crl
, cert
, key
, digest_alg
))