]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/hx509/revoke.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / hx509 / revoke.c
1 /*
2  * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 /**
35  * @page page_revoke Revocation methods
36  *
37  * There are two revocation method for PKIX/X.509: CRL and OCSP.
38  * Revocation is needed if the private key is lost and
39  * stolen. Depending on how picky you are, you might want to make
40  * revocation for destroyed private keys too (smartcard broken), but
41  * that should not be a problem.
42  *
43  * CRL is a list of certifiates that have expired.
44  *
45  * OCSP is an online checking method where the requestor sends a list
46  * of certificates to the OCSP server to return a signed reply if they
47  * are valid or not. Some services sends a OCSP reply as part of the
48  * hand-shake to make the revoktion decision simpler/faster for the
49  * client.
50  */
51
52 #include "hx_locl.h"
53 RCSID("$Id: revoke.c 22275 2007-12-11 11:02:11Z lha $");
54
55 struct revoke_crl {
56     char *path;
57     time_t last_modfied;
58     CRLCertificateList crl;
59     int verified;
60     int failed_verify;
61 };
62
63 struct revoke_ocsp {
64     char *path;
65     time_t last_modfied;
66     OCSPBasicOCSPResponse ocsp;
67     hx509_certs certs;
68     hx509_cert signer;
69 };
70
71
72 struct hx509_revoke_ctx_data {
73     unsigned ref;
74     struct {
75         struct revoke_crl *val;
76         size_t len;
77     } crls;
78     struct {
79         struct revoke_ocsp *val;
80         size_t len;
81     } ocsps;
82 };
83
84 /**
85  * Allocate a revokation context. Free with hx509_revoke_free().
86  *
87  * @param context A hx509 context.
88  * @param ctx returns a newly allocated revokation context.
89  *
90  * @return An hx509 error code, see hx509_get_error_string().
91  *
92  * @ingroup hx509_revoke
93  */
94
95 int
96 hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
97 {
98     *ctx = calloc(1, sizeof(**ctx));
99     if (*ctx == NULL)
100         return ENOMEM;
101
102     (*ctx)->ref = 1;
103     (*ctx)->crls.len = 0;
104     (*ctx)->crls.val = NULL;
105     (*ctx)->ocsps.len = 0;
106     (*ctx)->ocsps.val = NULL;
107
108     return 0;
109 }
110
111 hx509_revoke_ctx
112 _hx509_revoke_ref(hx509_revoke_ctx ctx)
113 {
114     if (ctx == NULL)
115         return NULL;
116     if (ctx->ref <= 0)
117         _hx509_abort("revoke ctx refcount <= 0");
118     ctx->ref++;
119     if (ctx->ref == 0)
120         _hx509_abort("revoke ctx refcount == 0");
121     return ctx;
122 }
123
124 static void
125 free_ocsp(struct revoke_ocsp *ocsp)
126 {
127     free(ocsp->path);
128     free_OCSPBasicOCSPResponse(&ocsp->ocsp);
129     hx509_certs_free(&ocsp->certs);
130     hx509_cert_free(ocsp->signer);
131 }
132
133 /**
134  * Free a hx509 revokation context.
135  *
136  * @param ctx context to be freed
137  *
138  * @ingroup hx509_revoke
139  */
140
141 void
142 hx509_revoke_free(hx509_revoke_ctx *ctx)
143 {
144     size_t i ;
145
146     if (ctx == NULL || *ctx == NULL)
147         return;
148
149     if ((*ctx)->ref <= 0)
150         _hx509_abort("revoke ctx refcount <= 0 on free");
151     if (--(*ctx)->ref > 0)
152         return;
153
154     for (i = 0; i < (*ctx)->crls.len; i++) {
155         free((*ctx)->crls.val[i].path);
156         free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
157     }
158
159     for (i = 0; i < (*ctx)->ocsps.len; i++)
160         free_ocsp(&(*ctx)->ocsps.val[i]);
161     free((*ctx)->ocsps.val);
162
163     free((*ctx)->crls.val);
164
165     memset(*ctx, 0, sizeof(**ctx));
166     free(*ctx);
167     *ctx = NULL;
168 }
169
170 static int
171 verify_ocsp(hx509_context context,
172             struct revoke_ocsp *ocsp,
173             time_t time_now,
174             hx509_certs certs,
175             hx509_cert parent)
176 {
177     hx509_cert signer = NULL;
178     hx509_query q;
179     int ret;
180         
181     _hx509_query_clear(&q);
182         
183     /*
184      * Need to match on issuer too in case there are two CA that have
185      * issued the same name to a certificate. One example of this is
186      * the www.openvalidation.org test's ocsp validator.
187      */
188
189     q.match = HX509_QUERY_MATCH_ISSUER_NAME;
190     q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
191
192     switch(ocsp->ocsp.tbsResponseData.responderID.element) {
193     case choice_OCSPResponderID_byName:
194         q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
195         q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
196         break;
197     case choice_OCSPResponderID_byKey:
198         q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
199         q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
200         break;
201     }
202         
203     ret = hx509_certs_find(context, certs, &q, &signer);
204     if (ret && ocsp->certs)
205         ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
206     if (ret)
207         goto out;
208
209     /*
210      * If signer certificate isn't the CA certificate, lets check the
211      * it is the CA that signed the signer certificate and the OCSP EKU
212      * is set.
213      */
214     if (hx509_cert_cmp(signer, parent) != 0) {
215         Certificate *p = _hx509_get_cert(parent);
216         Certificate *s = _hx509_get_cert(signer);
217
218         ret = _hx509_cert_is_parent_cmp(s, p, 0);
219         if (ret != 0) {
220             ret = HX509_PARENT_NOT_CA;
221             hx509_set_error_string(context, 0, ret, "Revoke OSCP signer is "
222                                    "doesn't have CA as signer certificate");
223             goto out;
224         }
225
226         ret = _hx509_verify_signature_bitstring(context,
227                                                 p,
228                                                 &s->signatureAlgorithm,
229                                                 &s->tbsCertificate._save,
230                                                 &s->signatureValue);
231         if (ret) {
232             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
233                                    "OSCP signer signature invalid");
234             goto out;
235         }
236
237         ret = hx509_cert_check_eku(context, signer, 
238                                    oid_id_pkix_kp_OCSPSigning(), 0);
239         if (ret)
240             goto out;
241     }
242
243     ret = _hx509_verify_signature_bitstring(context,
244                                             _hx509_get_cert(signer), 
245                                             &ocsp->ocsp.signatureAlgorithm,
246                                             &ocsp->ocsp.tbsResponseData._save,
247                                             &ocsp->ocsp.signature);
248     if (ret) {
249         hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 
250                                "OSCP signature invalid");
251         goto out;
252     }
253
254     ocsp->signer = signer;
255     signer = NULL;
256 out:
257     if (signer)
258         hx509_cert_free(signer);
259
260     return ret;
261 }
262
263 /*
264  *
265  */
266
267 static int
268 parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
269 {
270     OCSPResponse resp;
271     size_t size;
272     int ret;
273
274     memset(basic, 0, sizeof(*basic));
275
276     ret = decode_OCSPResponse(data, length, &resp, &size);
277     if (ret)
278         return ret;
279     if (length != size) {
280         free_OCSPResponse(&resp);
281         return ASN1_EXTRA_DATA;
282     }
283
284     switch (resp.responseStatus) {
285     case successful:
286         break;
287     default:
288         free_OCSPResponse(&resp);
289         return HX509_REVOKE_WRONG_DATA;
290     }
291
292     if (resp.responseBytes == NULL) {
293         free_OCSPResponse(&resp);
294         return EINVAL;
295     }
296
297     ret = der_heim_oid_cmp(&resp.responseBytes->responseType, 
298                            oid_id_pkix_ocsp_basic());
299     if (ret != 0) {
300         free_OCSPResponse(&resp);
301         return HX509_REVOKE_WRONG_DATA;
302     }
303
304     ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
305                                        resp.responseBytes->response.length,
306                                        basic,
307                                        &size);
308     if (ret) {
309         free_OCSPResponse(&resp);
310         return ret;
311     }
312     if (size != resp.responseBytes->response.length) {
313         free_OCSPResponse(&resp);
314         free_OCSPBasicOCSPResponse(basic);
315         return ASN1_EXTRA_DATA;
316     }
317     free_OCSPResponse(&resp);
318
319     return 0;
320 }
321
322 /*
323  *
324  */
325
326 static int
327 load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
328 {
329     OCSPBasicOCSPResponse basic;
330     hx509_certs certs = NULL;
331     size_t length;
332     struct stat sb;
333     void *data;
334     int ret;
335
336     ret = _hx509_map_file(ocsp->path, &data, &length, &sb);
337     if (ret)
338         return ret;
339
340     ret = parse_ocsp_basic(data, length, &basic);
341     _hx509_unmap_file(data, length);
342     if (ret) {
343         hx509_set_error_string(context, 0, ret,
344                                "Failed to parse OCSP response");
345         return ret;
346     }
347
348     if (basic.certs) {
349         int i;
350
351         ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, 
352                                NULL, &certs);
353         if (ret) {
354             free_OCSPBasicOCSPResponse(&basic);
355             return ret;
356         }
357
358         for (i = 0; i < basic.certs->len; i++) {
359             hx509_cert c;
360             
361             ret = hx509_cert_init(context, &basic.certs->val[i], &c);
362             if (ret)
363                 continue;
364             
365             ret = hx509_certs_add(context, certs, c);
366             hx509_cert_free(c);
367             if (ret)
368                 continue;
369         }
370     }
371
372     ocsp->last_modfied = sb.st_mtime;
373
374     free_OCSPBasicOCSPResponse(&ocsp->ocsp);
375     hx509_certs_free(&ocsp->certs);
376     hx509_cert_free(ocsp->signer);
377
378     ocsp->ocsp = basic;
379     ocsp->certs = certs;
380     ocsp->signer = NULL;
381
382     return 0;
383 }
384
385 /**
386  * Add a OCSP file to the revokation context.
387  *
388  * @param context hx509 context
389  * @param ctx hx509 revokation context
390  * @param path path to file that is going to be added to the context.
391  *
392  * @return An hx509 error code, see hx509_get_error_string().
393  *
394  * @ingroup hx509_revoke
395  */
396
397 int
398 hx509_revoke_add_ocsp(hx509_context context,
399                       hx509_revoke_ctx ctx,
400                       const char *path)
401 {
402     void *data;
403     int ret;
404     size_t i;
405
406     if (strncmp(path, "FILE:", 5) != 0) {
407         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
408                                "unsupport type in %s", path);
409         return HX509_UNSUPPORTED_OPERATION;
410     }
411
412     path += 5;
413
414     for (i = 0; i < ctx->ocsps.len; i++) {
415         if (strcmp(ctx->ocsps.val[0].path, path) == 0)
416             return 0;
417     }
418
419     data = realloc(ctx->ocsps.val, 
420                    (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
421     if (data == NULL) {
422         hx509_clear_error_string(context);
423         return ENOMEM;
424     }
425
426     ctx->ocsps.val = data;
427
428     memset(&ctx->ocsps.val[ctx->ocsps.len], 0, 
429            sizeof(ctx->ocsps.val[0]));
430
431     ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
432     if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
433         hx509_clear_error_string(context);
434         return ENOMEM;
435     }
436
437     ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
438     if (ret) {
439         free(ctx->ocsps.val[ctx->ocsps.len].path);
440         return ret;
441     }
442     ctx->ocsps.len++;
443
444     return ret;
445 }
446
447 /*
448  *
449  */
450
451 static int
452 verify_crl(hx509_context context,
453            hx509_revoke_ctx ctx,
454            CRLCertificateList *crl,
455            time_t time_now,
456            hx509_certs certs,
457            hx509_cert parent)
458 {
459     hx509_cert signer;
460     hx509_query q;
461     time_t t;
462     int ret;
463         
464     t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
465     if (t > time_now) {
466         hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
467                                "CRL used before time");
468         return HX509_CRL_USED_BEFORE_TIME;
469     }
470
471     if (crl->tbsCertList.nextUpdate == NULL) {
472         hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
473                                "CRL missing nextUpdate");
474         return HX509_CRL_INVALID_FORMAT;
475     }
476
477     t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
478     if (t < time_now) {
479         hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
480                                "CRL used after time");
481         return HX509_CRL_USED_AFTER_TIME;
482     }
483
484     _hx509_query_clear(&q);
485         
486     /*
487      * If it's the signer have CRLSIGN bit set, use that as the signer
488      * cert for the certificate, otherwise, search for a certificate.
489      */
490     if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
491         signer = hx509_cert_ref(parent);
492     } else {
493         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
494         q.match |= HX509_QUERY_KU_CRLSIGN;
495         q.subject_name = &crl->tbsCertList.issuer;
496         
497         ret = hx509_certs_find(context, certs, &q, &signer);
498         if (ret) {
499             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
500                                    "Failed to find certificate for CRL");
501             return ret;
502         }
503     }
504
505     ret = _hx509_verify_signature_bitstring(context,
506                                             _hx509_get_cert(signer), 
507                                             &crl->signatureAlgorithm,
508                                             &crl->tbsCertList._save,
509                                             &crl->signatureValue);
510     if (ret) {
511         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
512                                "CRL signature invalid");
513         goto out;
514     }
515
516     /* 
517      * If signer is not CA cert, need to check revoke status of this
518      * CRL signing cert too, this include all parent CRL signer cert
519      * up to the root *sigh*, assume root at least hve CERTSIGN flag
520      * set.
521      */
522     while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
523         hx509_cert crl_parent;
524
525         _hx509_query_clear(&q);
526         
527         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
528         q.match |= HX509_QUERY_KU_CRLSIGN;
529         q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
530         
531         ret = hx509_certs_find(context, certs, &q, &crl_parent);
532         if (ret) {
533             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
534                                    "Failed to find parent of CRL signer");
535             goto out;
536         }
537
538         ret = hx509_revoke_verify(context,
539                                   ctx, 
540                                   certs,
541                                   time_now,
542                                   signer,
543                                   crl_parent);
544         hx509_cert_free(signer);
545         signer = crl_parent;
546         if (ret) {
547             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
548                                    "Failed to verify revoke "
549                                    "status of CRL signer");
550             goto out;
551         }
552     }
553
554 out:
555     hx509_cert_free(signer);
556
557     return ret;
558 }
559
560 static int
561 load_crl(const char *path, time_t *t, CRLCertificateList *crl)
562 {
563     size_t length, size;
564     struct stat sb;
565     void *data;
566     int ret;
567
568     memset(crl, 0, sizeof(*crl));
569
570     ret = _hx509_map_file(path, &data, &length, &sb);
571     if (ret)
572         return ret;
573
574     *t = sb.st_mtime;
575
576     ret = decode_CRLCertificateList(data, length, crl, &size);
577     _hx509_unmap_file(data, length);
578     if (ret)
579         return ret;
580
581     /* check signature is aligned */
582     if (crl->signatureValue.length & 7) {
583         free_CRLCertificateList(crl);
584         return HX509_CRYPTO_SIG_INVALID_FORMAT;
585     }
586     return 0;
587 }
588
589 /**
590  * Add a CRL file to the revokation context.
591  *
592  * @param context hx509 context
593  * @param ctx hx509 revokation context
594  * @param path path to file that is going to be added to the context.
595  *
596  * @return An hx509 error code, see hx509_get_error_string().
597  *
598  * @ingroup hx509_revoke
599  */
600
601 int
602 hx509_revoke_add_crl(hx509_context context,
603                      hx509_revoke_ctx ctx,
604                      const char *path)
605 {
606     void *data;
607     size_t i;
608     int ret;
609
610     if (strncmp(path, "FILE:", 5) != 0) {
611         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
612                                "unsupport type in %s", path);
613         return HX509_UNSUPPORTED_OPERATION;
614     }
615
616     
617     path += 5;
618
619     for (i = 0; i < ctx->crls.len; i++) {
620         if (strcmp(ctx->crls.val[0].path, path) == 0)
621             return 0;
622     }
623
624     data = realloc(ctx->crls.val, 
625                    (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
626     if (data == NULL) {
627         hx509_clear_error_string(context);
628         return ENOMEM;
629     }
630     ctx->crls.val = data;
631
632     memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
633
634     ctx->crls.val[ctx->crls.len].path = strdup(path);
635     if (ctx->crls.val[ctx->crls.len].path == NULL) {
636         hx509_clear_error_string(context);
637         return ENOMEM;
638     }
639
640     ret = load_crl(path, 
641                    &ctx->crls.val[ctx->crls.len].last_modfied,
642                    &ctx->crls.val[ctx->crls.len].crl);
643     if (ret) {
644         free(ctx->crls.val[ctx->crls.len].path);
645         return ret;
646     }
647
648     ctx->crls.len++;
649
650     return ret;
651 }
652
653 /**
654  * Check that a certificate is not expired according to a revokation
655  * context. Also need the parent certificte to the check OCSP
656  * parent identifier.
657  *
658  * @param context hx509 context
659  * @param ctx hx509 revokation context
660  * @param certs
661  * @param now
662  * @param cert
663  * @param parent_cert
664  *
665  * @return An hx509 error code, see hx509_get_error_string().
666  *
667  * @ingroup hx509_revoke
668  */
669
670
671 int
672 hx509_revoke_verify(hx509_context context,
673                     hx509_revoke_ctx ctx,
674                     hx509_certs certs,
675                     time_t now,
676                     hx509_cert cert,
677                     hx509_cert parent_cert)
678 {
679     const Certificate *c = _hx509_get_cert(cert);
680     const Certificate *p = _hx509_get_cert(parent_cert);
681     unsigned long i, j, k;
682     int ret;
683
684     hx509_clear_error_string(context);
685
686     for (i = 0; i < ctx->ocsps.len; i++) {
687         struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
688         struct stat sb;
689
690         /* check this ocsp apply to this cert */
691
692         /* check if there is a newer version of the file */
693         ret = stat(ocsp->path, &sb);
694         if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
695             ret = load_ocsp(context, ocsp);
696             if (ret)
697                 continue;
698         }
699
700         /* verify signature in ocsp if not already done */
701         if (ocsp->signer == NULL) {
702             ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
703             if (ret)
704                 continue;
705         }
706
707         for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
708             heim_octet_string os;
709
710             ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
711                                    &c->tbsCertificate.serialNumber);
712             if (ret != 0)
713                 continue;
714             
715             /* verify issuer hashes hash */
716             ret = _hx509_verify_signature(context,
717                                           NULL,
718                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
719                                           &c->tbsCertificate.issuer._save,
720                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
721             if (ret != 0)
722                 continue;
723
724             os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
725             os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
726
727             ret = _hx509_verify_signature(context,
728                                           NULL,
729                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
730                                           &os,
731                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
732             if (ret != 0)
733                 continue;
734
735             switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
736             case choice_OCSPCertStatus_good:
737                 break;
738             case choice_OCSPCertStatus_revoked:
739                 hx509_set_error_string(context, 0, 
740                                        HX509_CERT_REVOKED,
741                                        "Certificate revoked by issuer in OCSP");
742                 return HX509_CERT_REVOKED;
743             case choice_OCSPCertStatus_unknown:
744                 continue;
745             }
746
747             /* don't allow the update to be in the future */
748             if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > 
749                 now + context->ocsp_time_diff)
750                 continue;
751
752             /* don't allow the next update to be in the past */
753             if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
754                 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
755                     continue;
756             } else
757                 /* Should force a refetch, but can we ? */;
758
759             return 0;
760         }
761     }
762
763     for (i = 0; i < ctx->crls.len; i++) {
764         struct revoke_crl *crl = &ctx->crls.val[i];
765         struct stat sb;
766
767         /* check if cert.issuer == crls.val[i].crl.issuer */
768         ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 
769                               &crl->crl.tbsCertList.issuer);
770         if (ret)
771             continue;
772
773         ret = stat(crl->path, &sb);
774         if (ret == 0 && crl->last_modfied != sb.st_mtime) {
775             CRLCertificateList cl;
776
777             ret = load_crl(crl->path, &crl->last_modfied, &cl);
778             if (ret == 0) {
779                 free_CRLCertificateList(&crl->crl);
780                 crl->crl = cl;
781                 crl->verified = 0;
782                 crl->failed_verify = 0;
783             }
784         }
785         if (crl->failed_verify)
786             continue;
787
788         /* verify signature in crl if not already done */
789         if (crl->verified == 0) {
790             ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
791             if (ret) {
792                 crl->failed_verify = 1;
793                 continue;
794             }
795             crl->verified = 1;
796         }
797
798         if (crl->crl.tbsCertList.crlExtensions) {
799             for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
800                 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
801                     hx509_set_error_string(context, 0, 
802                                            HX509_CRL_UNKNOWN_EXTENSION,
803                                            "Unknown CRL extension");
804                     return HX509_CRL_UNKNOWN_EXTENSION;
805                 }
806             }
807         }
808
809         if (crl->crl.tbsCertList.revokedCertificates == NULL)
810             return 0;
811
812         /* check if cert is in crl */
813         for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
814             time_t t;
815
816             ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
817                                        &c->tbsCertificate.serialNumber);
818             if (ret != 0)
819                 continue;
820
821             t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
822             if (t > now)
823                 continue;
824             
825             if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
826                 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
827                     if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
828                         return HX509_CRL_UNKNOWN_EXTENSION;
829             
830             hx509_set_error_string(context, 0, 
831                                    HX509_CERT_REVOKED,
832                                    "Certificate revoked by issuer in CRL");
833             return HX509_CERT_REVOKED;
834         }
835
836         return 0;
837     }
838
839
840     if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
841         return 0;
842     hx509_set_error_string(context, HX509_ERROR_APPEND, 
843                            HX509_REVOKE_STATUS_MISSING,
844                            "No revoke status found for "
845                            "certificates");
846     return HX509_REVOKE_STATUS_MISSING;
847 }
848
849 struct ocsp_add_ctx {
850     OCSPTBSRequest *req;
851     hx509_certs certs;
852     const AlgorithmIdentifier *digest;
853     hx509_cert parent;
854 };
855
856 static int
857 add_to_req(hx509_context context, void *ptr, hx509_cert cert)
858 {
859     struct ocsp_add_ctx *ctx = ptr;
860     OCSPInnerRequest *one;
861     hx509_cert parent = NULL;
862     Certificate *p, *c = _hx509_get_cert(cert);
863     heim_octet_string os;
864     int ret;
865     hx509_query q;
866     void *d;
867
868     d = realloc(ctx->req->requestList.val, 
869                 sizeof(ctx->req->requestList.val[0]) *
870                 (ctx->req->requestList.len + 1));
871     if (d == NULL)
872         return ENOMEM;
873     ctx->req->requestList.val = d;
874     
875     one = &ctx->req->requestList.val[ctx->req->requestList.len];
876     memset(one, 0, sizeof(*one));
877
878     _hx509_query_clear(&q);
879
880     q.match |= HX509_QUERY_FIND_ISSUER_CERT;
881     q.subject = c;
882
883     ret = hx509_certs_find(context, ctx->certs, &q, &parent);
884     if (ret)
885         goto out;
886
887     if (ctx->parent) {
888         if (hx509_cert_cmp(ctx->parent, parent) != 0) {
889             ret = HX509_REVOKE_NOT_SAME_PARENT;
890             hx509_set_error_string(context, 0, ret,
891                                    "Not same parent certifate as "
892                                    "last certificate in request");
893             goto out;
894         }
895     } else
896         ctx->parent = hx509_cert_ref(parent);
897
898     p = _hx509_get_cert(parent);
899
900     ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
901     if (ret)
902         goto out;
903
904     ret = _hx509_create_signature(context,
905                                   NULL,
906                                   &one->reqCert.hashAlgorithm,
907                                   &c->tbsCertificate.issuer._save,
908                                   NULL,
909                                   &one->reqCert.issuerNameHash);
910     if (ret)
911         goto out;
912
913     os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
914     os.length = 
915         p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
916
917     ret = _hx509_create_signature(context,
918                                   NULL,
919                                   &one->reqCert.hashAlgorithm,
920                                   &os,
921                                   NULL,
922                                   &one->reqCert.issuerKeyHash);
923     if (ret)
924         goto out;
925
926     ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
927                                        &one->reqCert.serialNumber);
928     if (ret)
929         goto out;
930
931     ctx->req->requestList.len++;
932 out:
933     hx509_cert_free(parent);
934     if (ret) {
935         free_OCSPInnerRequest(one);
936         memset(one, 0, sizeof(*one));
937     }
938
939     return ret;
940 }
941
942 /**
943  * Create an OCSP request for a set of certificates.
944  *
945  * @param context a hx509 context
946  * @param reqcerts list of certificates to request ocsp data for
947  * @param pool certificate pool to use when signing
948  * @param signer certificate to use to sign the request
949  * @param digest the signing algorithm in the request, if NULL use the
950  * default signature algorithm,
951  * @param request the encoded request, free with free_heim_octet_string().
952  * @param nonce nonce in the request, free with free_heim_octet_string().
953  *
954  * @return An hx509 error code, see hx509_get_error_string().
955  *
956  * @ingroup hx509_revoke
957  */
958
959 int
960 hx509_ocsp_request(hx509_context context,
961                    hx509_certs reqcerts,
962                    hx509_certs pool,
963                    hx509_cert signer,
964                    const AlgorithmIdentifier *digest,
965                    heim_octet_string *request,
966                    heim_octet_string *nonce)
967 {
968     OCSPRequest req;
969     size_t size;
970     int ret;
971     struct ocsp_add_ctx ctx;
972     Extensions *es;
973
974     memset(&req, 0, sizeof(req));
975
976     if (digest == NULL)
977         digest = _hx509_crypto_default_digest_alg;
978
979     ctx.req = &req.tbsRequest;
980     ctx.certs = pool;
981     ctx.digest = digest;
982     ctx.parent = NULL;
983
984     ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx);
985     hx509_cert_free(ctx.parent);
986     if (ret)
987         goto out;
988     
989     if (nonce) {
990         req.tbsRequest.requestExtensions = 
991             calloc(1, sizeof(*req.tbsRequest.requestExtensions));
992         if (req.tbsRequest.requestExtensions == NULL) {
993             ret = ENOMEM;
994             goto out;
995         }
996
997         es = req.tbsRequest.requestExtensions;
998         
999         es->val = calloc(es->len, sizeof(es->val[0]));
1000         if (es->val == NULL) {
1001             ret = ENOMEM;
1002             goto out;
1003         }
1004         es->len = 1;
1005         
1006         ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID);
1007         if (ret) {
1008             free_OCSPRequest(&req);
1009             return ret;
1010         }
1011
1012         es->val[0].extnValue.data = malloc(10);
1013         if (es->val[0].extnValue.data == NULL) {
1014             ret = ENOMEM;
1015             goto out;
1016         }
1017         es->val[0].extnValue.length = 10;
1018         
1019         ret = RAND_bytes(es->val[0].extnValue.data,
1020                          es->val[0].extnValue.length);
1021         if (ret != 1) {
1022             ret = HX509_CRYPTO_INTERNAL_ERROR;
1023             goto out;
1024         }
1025         ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1026         if (ret) {
1027             ret = ENOMEM;
1028             goto out;
1029         }
1030     }
1031
1032     ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1033                        &req, &size, ret);
1034     free_OCSPRequest(&req);
1035     if (ret)
1036         goto out;
1037     if (size != request->length)
1038         _hx509_abort("internal ASN.1 encoder error");
1039
1040     return 0;
1041
1042 out:
1043     free_OCSPRequest(&req);
1044     return ret;
1045 }
1046
1047 static char *
1048 printable_time(time_t t)
1049 {
1050     static char s[128];
1051     strlcpy(s, ctime(&t)+ 4, sizeof(s));
1052     s[20] = 0;
1053     return s;
1054 }
1055
1056 /**
1057  * Print the OCSP reply stored in a file.
1058  *
1059  * @param context a hx509 context
1060  * @param path path to a file with a OCSP reply
1061  * @param out the out FILE descriptor to print the reply on
1062  *
1063  * @return An hx509 error code, see hx509_get_error_string().
1064  *
1065  * @ingroup hx509_revoke
1066  */
1067
1068 int
1069 hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
1070 {
1071     struct revoke_ocsp ocsp;
1072     int ret, i;
1073     
1074     if (out == NULL)
1075         out = stdout;
1076
1077     memset(&ocsp, 0, sizeof(ocsp));
1078
1079     ocsp.path = strdup(path);
1080     if (ocsp.path == NULL)
1081         return ENOMEM;
1082
1083     ret = load_ocsp(context, &ocsp);
1084     if (ret) {
1085         free_ocsp(&ocsp);
1086         return ret;
1087     }
1088
1089     fprintf(out, "signer: ");
1090
1091     switch(ocsp.ocsp.tbsResponseData.responderID.element) {
1092     case choice_OCSPResponderID_byName: {
1093         hx509_name n;
1094         char *s;
1095         _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
1096         hx509_name_to_string(n, &s);
1097         hx509_name_free(&n);
1098         fprintf(out, " byName: %s\n", s);
1099         free(s);
1100         break;
1101     }
1102     case choice_OCSPResponderID_byKey: {
1103         char *s;
1104         hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
1105                    ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
1106                    &s);
1107         fprintf(out, " byKey: %s\n", s);
1108         free(s);
1109         break;
1110     }
1111     default:
1112         _hx509_abort("choice_OCSPResponderID unknown");
1113         break;
1114     }
1115
1116     fprintf(out, "producedAt: %s\n", 
1117             printable_time(ocsp.ocsp.tbsResponseData.producedAt));
1118
1119     fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
1120
1121     for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
1122         const char *status;
1123         switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1124         case choice_OCSPCertStatus_good:
1125             status = "good";
1126             break;
1127         case choice_OCSPCertStatus_revoked:
1128             status = "revoked";
1129             break;
1130         case choice_OCSPCertStatus_unknown:
1131             status = "unknown";
1132             break;
1133         default:
1134             status = "element unknown";
1135         }
1136
1137         fprintf(out, "\t%d. status: %s\n", i, status);
1138
1139         fprintf(out, "\tthisUpdate: %s\n", 
1140                 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1141         if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
1142             fprintf(out, "\tproducedAt: %s\n", 
1143                     printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1144
1145     }
1146
1147     fprintf(out, "appended certs:\n");
1148     if (ocsp.certs)
1149         ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out);
1150
1151     free_ocsp(&ocsp);
1152     return ret;
1153 }
1154
1155 /**
1156  * Verify that the certificate is part of the OCSP reply and it's not
1157  * expired. Doesn't verify signature the OCSP reply or it's done by a
1158  * authorized sender, that is assumed to be already done.
1159  *
1160  * @param context a hx509 context
1161  * @param now the time right now, if 0, use the current time.
1162  * @param cert the certificate to verify
1163  * @param flags flags control the behavior
1164  * @param data pointer to the encode ocsp reply
1165  * @param length the length of the encode ocsp reply
1166  * @param expiration return the time the OCSP will expire and need to
1167  * be rechecked.
1168  *
1169  * @return An hx509 error code, see hx509_get_error_string().
1170  *
1171  * @ingroup hx509_verify
1172  */
1173
1174 int
1175 hx509_ocsp_verify(hx509_context context,
1176                   time_t now,
1177                   hx509_cert cert,
1178                   int flags,
1179                   const void *data, size_t length,
1180                   time_t *expiration)
1181 {
1182     const Certificate *c = _hx509_get_cert(cert);
1183     OCSPBasicOCSPResponse basic;
1184     int ret, i;
1185
1186     if (now == 0)
1187         now = time(NULL);
1188
1189     *expiration = 0;
1190
1191     ret = parse_ocsp_basic(data, length, &basic);
1192     if (ret) {
1193         hx509_set_error_string(context, 0, ret,
1194                                "Failed to parse OCSP response");
1195         return ret;
1196     }
1197
1198     for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1199
1200         ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1201                                &c->tbsCertificate.serialNumber);
1202         if (ret != 0)
1203             continue;
1204             
1205         /* verify issuer hashes hash */
1206         ret = _hx509_verify_signature(context,
1207                                       NULL,
1208                                       &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1209                                       &c->tbsCertificate.issuer._save,
1210                                       &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1211         if (ret != 0)
1212             continue;
1213
1214         switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1215         case choice_OCSPCertStatus_good:
1216             break;
1217         case choice_OCSPCertStatus_revoked:
1218         case choice_OCSPCertStatus_unknown:
1219             continue;
1220         }
1221
1222         /* don't allow the update to be in the future */
1223         if (basic.tbsResponseData.responses.val[i].thisUpdate > 
1224             now + context->ocsp_time_diff)
1225             continue;
1226
1227         /* don't allow the next update to be in the past */
1228         if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1229             if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1230                 continue;
1231             *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1232         } else
1233             *expiration = now;
1234
1235         free_OCSPBasicOCSPResponse(&basic);
1236         return 0;
1237     }
1238
1239     free_OCSPBasicOCSPResponse(&basic);
1240
1241     {
1242         hx509_name name;
1243         char *subject;
1244         
1245         ret = hx509_cert_get_subject(cert, &name);
1246         if (ret) {
1247             hx509_clear_error_string(context);
1248             goto out;
1249         }
1250         ret = hx509_name_to_string(name, &subject);
1251         hx509_name_free(&name);
1252         if (ret) {
1253             hx509_clear_error_string(context);
1254             goto out;
1255         }
1256         hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
1257                                "Certificate %s not in OCSP response "
1258                                "or not good",
1259                                subject);
1260         free(subject);
1261     }
1262 out:
1263     return HX509_CERT_NOT_IN_OCSP;
1264 }
1265
1266 struct hx509_crl {
1267     hx509_certs revoked;
1268     time_t expire;
1269 };
1270
1271 /**
1272  * Create a CRL context. Use hx509_crl_free() to free the CRL context.
1273  *
1274  * @param context a hx509 context.
1275  * @param crl return pointer to a newly allocated CRL context.
1276  *
1277  * @return An hx509 error code, see hx509_get_error_string().
1278  *
1279  * @ingroup hx509_verify
1280  */
1281
1282 int
1283 hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1284 {
1285     int ret;
1286
1287     *crl = calloc(1, sizeof(**crl));
1288     if (*crl == NULL) {
1289         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1290         return ENOMEM;
1291     }
1292
1293     ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1294     if (ret) {
1295         free(*crl);
1296         *crl = NULL;
1297         return ret;
1298     }
1299     (*crl)->expire = 0;
1300     return ret;
1301 }
1302
1303 /**
1304  * Add revoked certificate to an CRL context.
1305  *
1306  * @param context a hx509 context.
1307  * @param crl the CRL to add the revoked certificate to.
1308  * @param certs keyset of certificate to revoke.
1309  *
1310  * @return An hx509 error code, see hx509_get_error_string().
1311  *
1312  * @ingroup hx509_verify
1313  */
1314
1315 int
1316 hx509_crl_add_revoked_certs(hx509_context context,
1317                             hx509_crl crl, 
1318                             hx509_certs certs)
1319 {
1320     return hx509_certs_merge(context, crl->revoked, certs);
1321 }
1322
1323 /**
1324  * Set the lifetime of a CRL context.
1325  *
1326  * @param context a hx509 context.
1327  * @param crl a CRL context
1328  * @param delta delta time the certificate is valid, library adds the
1329  * current time to this.
1330  *
1331  * @return An hx509 error code, see hx509_get_error_string().
1332  *
1333  * @ingroup hx509_verify
1334  */
1335
1336 int
1337 hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1338 {
1339     crl->expire = time(NULL) + delta;
1340     return 0;
1341 }
1342
1343 /**
1344  * Free a CRL context.
1345  *
1346  * @param context a hx509 context.
1347  * @param crl a CRL context to free.
1348  *
1349  * @ingroup hx509_verify
1350  */
1351
1352 void
1353 hx509_crl_free(hx509_context context, hx509_crl *crl)
1354 {
1355     if (*crl == NULL)
1356         return;
1357     hx509_certs_free(&(*crl)->revoked);
1358     memset(*crl, 0, sizeof(**crl));
1359     free(*crl);
1360     *crl = NULL;
1361 }
1362
1363 static int
1364 add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1365 {
1366     TBSCRLCertList *c = ctx;
1367     unsigned int num;
1368     void *ptr;
1369     int ret;
1370
1371     num = c->revokedCertificates->len;
1372     ptr = realloc(c->revokedCertificates->val,
1373                   (num + 1) * sizeof(c->revokedCertificates->val[0]));
1374     if (ptr == NULL) {
1375         hx509_clear_error_string(context);
1376         return ENOMEM;
1377     }
1378     c->revokedCertificates->val = ptr;
1379
1380     ret = hx509_cert_get_serialnumber(cert, 
1381                                       &c->revokedCertificates->val[num].userCertificate);
1382     if (ret) {
1383         hx509_clear_error_string(context);
1384         return ret;
1385     }
1386     c->revokedCertificates->val[num].revocationDate.element = 
1387         choice_Time_generalTime;
1388     c->revokedCertificates->val[num].revocationDate.u.generalTime =
1389         time(NULL) - 3600 * 24;
1390     c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1391
1392     c->revokedCertificates->len++;
1393
1394     return 0;
1395 }    
1396
1397 /**
1398  * Sign a CRL and return an encode certificate.
1399  *
1400  * @param context a hx509 context.
1401  * @param signer certificate to sign the CRL with
1402  * @param crl the CRL to sign
1403  * @param os return the signed and encoded CRL, free with
1404  * free_heim_octet_string()
1405  *
1406  * @return An hx509 error code, see hx509_get_error_string().
1407  *
1408  * @ingroup hx509_verify
1409  */
1410
1411 int
1412 hx509_crl_sign(hx509_context context,
1413                hx509_cert signer,
1414                hx509_crl crl,
1415                heim_octet_string *os)
1416 {
1417     const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
1418     CRLCertificateList c;
1419     size_t size;
1420     int ret;
1421     hx509_private_key signerkey;
1422
1423     memset(&c, 0, sizeof(c));
1424
1425     signerkey = _hx509_cert_private_key(signer);
1426     if (signerkey == NULL) {
1427         ret = HX509_PRIVATE_KEY_MISSING;
1428         hx509_set_error_string(context, 0, ret,
1429                                "Private key missing for CRL signing");
1430         return ret;
1431     }
1432
1433     c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1434     if (c.tbsCertList.version == NULL) {
1435         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1436         return ENOMEM;
1437     }
1438
1439     *c.tbsCertList.version = 1;
1440
1441     ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1442     if (ret) {
1443         hx509_clear_error_string(context);
1444         goto out;
1445     }
1446
1447     ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1448                     &c.tbsCertList.issuer);
1449     if (ret) {
1450         hx509_clear_error_string(context);
1451         goto out;
1452     }
1453
1454     c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1455     c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1456
1457     c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1458     if (c.tbsCertList.nextUpdate == NULL) {
1459         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1460         ret = ENOMEM;
1461         goto out;
1462     }
1463
1464     {
1465         time_t next = crl->expire;
1466         if (next == 0)
1467             next = time(NULL) + 24 * 3600 * 365;
1468
1469         c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1470         c.tbsCertList.nextUpdate->u.generalTime = next;
1471     }
1472
1473     c.tbsCertList.revokedCertificates = 
1474         calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1475     if (c.tbsCertList.revokedCertificates == NULL) {
1476         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1477         ret = ENOMEM;
1478         goto out;
1479     }
1480     c.tbsCertList.crlExtensions = NULL;
1481
1482     ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList);
1483     if (ret)
1484         goto out;
1485
1486     /* if not revoked certs, remove OPTIONAL entry */
1487     if (c.tbsCertList.revokedCertificates->len == 0) {
1488         free(c.tbsCertList.revokedCertificates);
1489         c.tbsCertList.revokedCertificates = NULL;
1490     }
1491
1492     ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1493                        &c.tbsCertList, &size, ret);
1494     if (ret) {
1495         hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1496         goto out;
1497     }
1498     if (size != os->length)
1499         _hx509_abort("internal ASN.1 encoder error");
1500
1501
1502     ret = _hx509_create_signature_bitstring(context,
1503                                             signerkey,
1504                                             sigalg,
1505                                             os,
1506                                             &c.signatureAlgorithm,
1507                                             &c.signatureValue);
1508     free(os->data);
1509
1510     ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1511                        &c, &size, ret);
1512     free_CRLCertificateList(&c);
1513     if (ret) {
1514         hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1515         goto out;
1516     }
1517     if (size != os->length)
1518         _hx509_abort("internal ASN.1 encoder error");
1519
1520     return 0;
1521
1522 out:
1523     free_CRLCertificateList(&c);
1524     return ret;
1525 }