8325c4723d7e26d307bd6b4ac539f1cfdad455f5
[metze/samba/wip.git] / source / 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 23413 2008-07-26 18:34:53Z 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 int 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 on ref");
118     ctx->ref++;
119     if (ctx->ref == UINT_MAX)
120         _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
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 OCSP 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                                    "OCSP 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                                "OCSP 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 = rk_undumpdata(ocsp->path, &data, &length);
337     if (ret)
338         return ret;
339
340     ret = stat(ocsp->path, &sb);
341     if (ret)
342         return errno;
343
344     ret = parse_ocsp_basic(data, length, &basic);
345     rk_xfree(data);
346     if (ret) {
347         hx509_set_error_string(context, 0, ret,
348                                "Failed to parse OCSP response");
349         return ret;
350     }
351
352     if (basic.certs) {
353         int i;
354
355         ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, 
356                                NULL, &certs);
357         if (ret) {
358             free_OCSPBasicOCSPResponse(&basic);
359             return ret;
360         }
361
362         for (i = 0; i < basic.certs->len; i++) {
363             hx509_cert c;
364             
365             ret = hx509_cert_init(context, &basic.certs->val[i], &c);
366             if (ret)
367                 continue;
368             
369             ret = hx509_certs_add(context, certs, c);
370             hx509_cert_free(c);
371             if (ret)
372                 continue;
373         }
374     }
375
376     ocsp->last_modfied = sb.st_mtime;
377
378     free_OCSPBasicOCSPResponse(&ocsp->ocsp);
379     hx509_certs_free(&ocsp->certs);
380     hx509_cert_free(ocsp->signer);
381
382     ocsp->ocsp = basic;
383     ocsp->certs = certs;
384     ocsp->signer = NULL;
385
386     return 0;
387 }
388
389 /**
390  * Add a OCSP file to the revokation context.
391  *
392  * @param context hx509 context
393  * @param ctx hx509 revokation context
394  * @param path path to file that is going to be added to the context.
395  *
396  * @return An hx509 error code, see hx509_get_error_string().
397  *
398  * @ingroup hx509_revoke
399  */
400
401 int
402 hx509_revoke_add_ocsp(hx509_context context,
403                       hx509_revoke_ctx ctx,
404                       const char *path)
405 {
406     void *data;
407     int ret;
408     size_t i;
409
410     if (strncmp(path, "FILE:", 5) != 0) {
411         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
412                                "unsupport type in %s", path);
413         return HX509_UNSUPPORTED_OPERATION;
414     }
415
416     path += 5;
417
418     for (i = 0; i < ctx->ocsps.len; i++) {
419         if (strcmp(ctx->ocsps.val[0].path, path) == 0)
420             return 0;
421     }
422
423     data = realloc(ctx->ocsps.val, 
424                    (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
425     if (data == NULL) {
426         hx509_clear_error_string(context);
427         return ENOMEM;
428     }
429
430     ctx->ocsps.val = data;
431
432     memset(&ctx->ocsps.val[ctx->ocsps.len], 0, 
433            sizeof(ctx->ocsps.val[0]));
434
435     ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
436     if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
437         hx509_clear_error_string(context);
438         return ENOMEM;
439     }
440
441     ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
442     if (ret) {
443         free(ctx->ocsps.val[ctx->ocsps.len].path);
444         return ret;
445     }
446     ctx->ocsps.len++;
447
448     return ret;
449 }
450
451 /*
452  *
453  */
454
455 static int
456 verify_crl(hx509_context context,
457            hx509_revoke_ctx ctx,
458            CRLCertificateList *crl,
459            time_t time_now,
460            hx509_certs certs,
461            hx509_cert parent)
462 {
463     hx509_cert signer;
464     hx509_query q;
465     time_t t;
466     int ret;
467         
468     t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
469     if (t > time_now) {
470         hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
471                                "CRL used before time");
472         return HX509_CRL_USED_BEFORE_TIME;
473     }
474
475     if (crl->tbsCertList.nextUpdate == NULL) {
476         hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
477                                "CRL missing nextUpdate");
478         return HX509_CRL_INVALID_FORMAT;
479     }
480
481     t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
482     if (t < time_now) {
483         hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
484                                "CRL used after time");
485         return HX509_CRL_USED_AFTER_TIME;
486     }
487
488     _hx509_query_clear(&q);
489         
490     /*
491      * If it's the signer have CRLSIGN bit set, use that as the signer
492      * cert for the certificate, otherwise, search for a certificate.
493      */
494     if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
495         signer = hx509_cert_ref(parent);
496     } else {
497         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
498         q.match |= HX509_QUERY_KU_CRLSIGN;
499         q.subject_name = &crl->tbsCertList.issuer;
500         
501         ret = hx509_certs_find(context, certs, &q, &signer);
502         if (ret) {
503             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
504                                    "Failed to find certificate for CRL");
505             return ret;
506         }
507     }
508
509     ret = _hx509_verify_signature_bitstring(context,
510                                             _hx509_get_cert(signer), 
511                                             &crl->signatureAlgorithm,
512                                             &crl->tbsCertList._save,
513                                             &crl->signatureValue);
514     if (ret) {
515         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
516                                "CRL signature invalid");
517         goto out;
518     }
519
520     /* 
521      * If signer is not CA cert, need to check revoke status of this
522      * CRL signing cert too, this include all parent CRL signer cert
523      * up to the root *sigh*, assume root at least hve CERTSIGN flag
524      * set.
525      */
526     while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
527         hx509_cert crl_parent;
528
529         _hx509_query_clear(&q);
530         
531         q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
532         q.match |= HX509_QUERY_KU_CRLSIGN;
533         q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
534         
535         ret = hx509_certs_find(context, certs, &q, &crl_parent);
536         if (ret) {
537             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
538                                    "Failed to find parent of CRL signer");
539             goto out;
540         }
541
542         ret = hx509_revoke_verify(context,
543                                   ctx, 
544                                   certs,
545                                   time_now,
546                                   signer,
547                                   crl_parent);
548         hx509_cert_free(signer);
549         signer = crl_parent;
550         if (ret) {
551             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
552                                    "Failed to verify revoke "
553                                    "status of CRL signer");
554             goto out;
555         }
556     }
557
558 out:
559     hx509_cert_free(signer);
560
561     return ret;
562 }
563
564 static int
565 load_crl(const char *path, time_t *t, CRLCertificateList *crl)
566 {
567     size_t length, size;
568     struct stat sb;
569     void *data;
570     int ret;
571
572     memset(crl, 0, sizeof(*crl));
573
574     ret = rk_undumpdata(path, &data, &length);
575     if (ret)
576         return ret;
577
578     ret = stat(path, &sb);
579     if (ret)
580         return errno;
581
582     *t = sb.st_mtime;
583
584     ret = decode_CRLCertificateList(data, length, crl, &size);
585     rk_xfree(data);
586     if (ret)
587         return ret;
588
589     /* check signature is aligned */
590     if (crl->signatureValue.length & 7) {
591         free_CRLCertificateList(crl);
592         return HX509_CRYPTO_SIG_INVALID_FORMAT;
593     }
594     return 0;
595 }
596
597 /**
598  * Add a CRL file to the revokation context.
599  *
600  * @param context hx509 context
601  * @param ctx hx509 revokation context
602  * @param path path to file that is going to be added to the context.
603  *
604  * @return An hx509 error code, see hx509_get_error_string().
605  *
606  * @ingroup hx509_revoke
607  */
608
609 int
610 hx509_revoke_add_crl(hx509_context context,
611                      hx509_revoke_ctx ctx,
612                      const char *path)
613 {
614     void *data;
615     size_t i;
616     int ret;
617
618     if (strncmp(path, "FILE:", 5) != 0) {
619         hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
620                                "unsupport type in %s", path);
621         return HX509_UNSUPPORTED_OPERATION;
622     }
623
624     
625     path += 5;
626
627     for (i = 0; i < ctx->crls.len; i++) {
628         if (strcmp(ctx->crls.val[0].path, path) == 0)
629             return 0;
630     }
631
632     data = realloc(ctx->crls.val, 
633                    (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
634     if (data == NULL) {
635         hx509_clear_error_string(context);
636         return ENOMEM;
637     }
638     ctx->crls.val = data;
639
640     memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
641
642     ctx->crls.val[ctx->crls.len].path = strdup(path);
643     if (ctx->crls.val[ctx->crls.len].path == NULL) {
644         hx509_clear_error_string(context);
645         return ENOMEM;
646     }
647
648     ret = load_crl(path, 
649                    &ctx->crls.val[ctx->crls.len].last_modfied,
650                    &ctx->crls.val[ctx->crls.len].crl);
651     if (ret) {
652         free(ctx->crls.val[ctx->crls.len].path);
653         return ret;
654     }
655
656     ctx->crls.len++;
657
658     return ret;
659 }
660
661 /**
662  * Check that a certificate is not expired according to a revokation
663  * context. Also need the parent certificte to the check OCSP
664  * parent identifier.
665  *
666  * @param context hx509 context
667  * @param ctx hx509 revokation context
668  * @param certs
669  * @param now
670  * @param cert
671  * @param parent_cert
672  *
673  * @return An hx509 error code, see hx509_get_error_string().
674  *
675  * @ingroup hx509_revoke
676  */
677
678
679 int
680 hx509_revoke_verify(hx509_context context,
681                     hx509_revoke_ctx ctx,
682                     hx509_certs certs,
683                     time_t now,
684                     hx509_cert cert,
685                     hx509_cert parent_cert)
686 {
687     const Certificate *c = _hx509_get_cert(cert);
688     const Certificate *p = _hx509_get_cert(parent_cert);
689     unsigned long i, j, k;
690     int ret;
691
692     hx509_clear_error_string(context);
693
694     for (i = 0; i < ctx->ocsps.len; i++) {
695         struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
696         struct stat sb;
697
698         /* check this ocsp apply to this cert */
699
700         /* check if there is a newer version of the file */
701         ret = stat(ocsp->path, &sb);
702         if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
703             ret = load_ocsp(context, ocsp);
704             if (ret)
705                 continue;
706         }
707
708         /* verify signature in ocsp if not already done */
709         if (ocsp->signer == NULL) {
710             ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
711             if (ret)
712                 continue;
713         }
714
715         for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
716             heim_octet_string os;
717
718             ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
719                                    &c->tbsCertificate.serialNumber);
720             if (ret != 0)
721                 continue;
722             
723             /* verify issuer hashes hash */
724             ret = _hx509_verify_signature(context,
725                                           NULL,
726                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
727                                           &c->tbsCertificate.issuer._save,
728                                           &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
729             if (ret != 0)
730                 continue;
731
732             os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
733             os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
734
735             ret = _hx509_verify_signature(context,
736                                           NULL,
737                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
738                                           &os,
739                                           &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
740             if (ret != 0)
741                 continue;
742
743             switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
744             case choice_OCSPCertStatus_good:
745                 break;
746             case choice_OCSPCertStatus_revoked:
747                 hx509_set_error_string(context, 0, 
748                                        HX509_CERT_REVOKED,
749                                        "Certificate revoked by issuer in OCSP");
750                 return HX509_CERT_REVOKED;
751             case choice_OCSPCertStatus_unknown:
752                 continue;
753             }
754
755             /* don't allow the update to be in the future */
756             if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > 
757                 now + context->ocsp_time_diff)
758                 continue;
759
760             /* don't allow the next update to be in the past */
761             if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
762                 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
763                     continue;
764             } else
765                 /* Should force a refetch, but can we ? */;
766
767             return 0;
768         }
769     }
770
771     for (i = 0; i < ctx->crls.len; i++) {
772         struct revoke_crl *crl = &ctx->crls.val[i];
773         struct stat sb;
774         int diff;
775
776         /* check if cert.issuer == crls.val[i].crl.issuer */
777         ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 
778                               &crl->crl.tbsCertList.issuer, &diff);
779         if (ret || diff)
780             continue;
781
782         ret = stat(crl->path, &sb);
783         if (ret == 0 && crl->last_modfied != sb.st_mtime) {
784             CRLCertificateList cl;
785
786             ret = load_crl(crl->path, &crl->last_modfied, &cl);
787             if (ret == 0) {
788                 free_CRLCertificateList(&crl->crl);
789                 crl->crl = cl;
790                 crl->verified = 0;
791                 crl->failed_verify = 0;
792             }
793         }
794         if (crl->failed_verify)
795             continue;
796
797         /* verify signature in crl if not already done */
798         if (crl->verified == 0) {
799             ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
800             if (ret) {
801                 crl->failed_verify = 1;
802                 continue;
803             }
804             crl->verified = 1;
805         }
806
807         if (crl->crl.tbsCertList.crlExtensions) {
808             for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
809                 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
810                     hx509_set_error_string(context, 0, 
811                                            HX509_CRL_UNKNOWN_EXTENSION,
812                                            "Unknown CRL extension");
813                     return HX509_CRL_UNKNOWN_EXTENSION;
814                 }
815             }
816         }
817
818         if (crl->crl.tbsCertList.revokedCertificates == NULL)
819             return 0;
820
821         /* check if cert is in crl */
822         for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
823             time_t t;
824
825             ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
826                                        &c->tbsCertificate.serialNumber);
827             if (ret != 0)
828                 continue;
829
830             t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
831             if (t > now)
832                 continue;
833             
834             if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
835                 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
836                     if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
837                         return HX509_CRL_UNKNOWN_EXTENSION;
838             
839             hx509_set_error_string(context, 0, 
840                                    HX509_CERT_REVOKED,
841                                    "Certificate revoked by issuer in CRL");
842             return HX509_CERT_REVOKED;
843         }
844
845         return 0;
846     }
847
848
849     if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
850         return 0;
851     hx509_set_error_string(context, HX509_ERROR_APPEND, 
852                            HX509_REVOKE_STATUS_MISSING,
853                            "No revoke status found for "
854                            "certificates");
855     return HX509_REVOKE_STATUS_MISSING;
856 }
857
858 struct ocsp_add_ctx {
859     OCSPTBSRequest *req;
860     hx509_certs certs;
861     const AlgorithmIdentifier *digest;
862     hx509_cert parent;
863 };
864
865 static int
866 add_to_req(hx509_context context, void *ptr, hx509_cert cert)
867 {
868     struct ocsp_add_ctx *ctx = ptr;
869     OCSPInnerRequest *one;
870     hx509_cert parent = NULL;
871     Certificate *p, *c = _hx509_get_cert(cert);
872     heim_octet_string os;
873     int ret;
874     hx509_query q;
875     void *d;
876
877     d = realloc(ctx->req->requestList.val, 
878                 sizeof(ctx->req->requestList.val[0]) *
879                 (ctx->req->requestList.len + 1));
880     if (d == NULL)
881         return ENOMEM;
882     ctx->req->requestList.val = d;
883     
884     one = &ctx->req->requestList.val[ctx->req->requestList.len];
885     memset(one, 0, sizeof(*one));
886
887     _hx509_query_clear(&q);
888
889     q.match |= HX509_QUERY_FIND_ISSUER_CERT;
890     q.subject = c;
891
892     ret = hx509_certs_find(context, ctx->certs, &q, &parent);
893     if (ret)
894         goto out;
895
896     if (ctx->parent) {
897         if (hx509_cert_cmp(ctx->parent, parent) != 0) {
898             ret = HX509_REVOKE_NOT_SAME_PARENT;
899             hx509_set_error_string(context, 0, ret,
900                                    "Not same parent certifate as "
901                                    "last certificate in request");
902             goto out;
903         }
904     } else
905         ctx->parent = hx509_cert_ref(parent);
906
907     p = _hx509_get_cert(parent);
908
909     ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
910     if (ret)
911         goto out;
912
913     ret = _hx509_create_signature(context,
914                                   NULL,
915                                   &one->reqCert.hashAlgorithm,
916                                   &c->tbsCertificate.issuer._save,
917                                   NULL,
918                                   &one->reqCert.issuerNameHash);
919     if (ret)
920         goto out;
921
922     os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
923     os.length = 
924         p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
925
926     ret = _hx509_create_signature(context,
927                                   NULL,
928                                   &one->reqCert.hashAlgorithm,
929                                   &os,
930                                   NULL,
931                                   &one->reqCert.issuerKeyHash);
932     if (ret)
933         goto out;
934
935     ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
936                                        &one->reqCert.serialNumber);
937     if (ret)
938         goto out;
939
940     ctx->req->requestList.len++;
941 out:
942     hx509_cert_free(parent);
943     if (ret) {
944         free_OCSPInnerRequest(one);
945         memset(one, 0, sizeof(*one));
946     }
947
948     return ret;
949 }
950
951 /**
952  * Create an OCSP request for a set of certificates.
953  *
954  * @param context a hx509 context
955  * @param reqcerts list of certificates to request ocsp data for
956  * @param pool certificate pool to use when signing
957  * @param signer certificate to use to sign the request
958  * @param digest the signing algorithm in the request, if NULL use the
959  * default signature algorithm,
960  * @param request the encoded request, free with free_heim_octet_string().
961  * @param nonce nonce in the request, free with free_heim_octet_string().
962  *
963  * @return An hx509 error code, see hx509_get_error_string().
964  *
965  * @ingroup hx509_revoke
966  */
967
968 int
969 hx509_ocsp_request(hx509_context context,
970                    hx509_certs reqcerts,
971                    hx509_certs pool,
972                    hx509_cert signer,
973                    const AlgorithmIdentifier *digest,
974                    heim_octet_string *request,
975                    heim_octet_string *nonce)
976 {
977     OCSPRequest req;
978     size_t size;
979     int ret;
980     struct ocsp_add_ctx ctx;
981     Extensions *es;
982
983     memset(&req, 0, sizeof(req));
984
985     if (digest == NULL)
986         digest = _hx509_crypto_default_digest_alg;
987
988     ctx.req = &req.tbsRequest;
989     ctx.certs = pool;
990     ctx.digest = digest;
991     ctx.parent = NULL;
992
993     ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx);
994     hx509_cert_free(ctx.parent);
995     if (ret)
996         goto out;
997     
998     if (nonce) {
999         req.tbsRequest.requestExtensions = 
1000             calloc(1, sizeof(*req.tbsRequest.requestExtensions));
1001         if (req.tbsRequest.requestExtensions == NULL) {
1002             ret = ENOMEM;
1003             goto out;
1004         }
1005
1006         es = req.tbsRequest.requestExtensions;
1007         
1008         es->val = calloc(es->len, sizeof(es->val[0]));
1009         if (es->val == NULL) {
1010             ret = ENOMEM;
1011             goto out;
1012         }
1013         es->len = 1;
1014         
1015         ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID);
1016         if (ret) {
1017             free_OCSPRequest(&req);
1018             return ret;
1019         }
1020
1021         es->val[0].extnValue.data = malloc(10);
1022         if (es->val[0].extnValue.data == NULL) {
1023             ret = ENOMEM;
1024             goto out;
1025         }
1026         es->val[0].extnValue.length = 10;
1027         
1028         ret = RAND_bytes(es->val[0].extnValue.data,
1029                          es->val[0].extnValue.length);
1030         if (ret != 1) {
1031             ret = HX509_CRYPTO_INTERNAL_ERROR;
1032             goto out;
1033         }
1034         ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1035         if (ret) {
1036             ret = ENOMEM;
1037             goto out;
1038         }
1039     }
1040
1041     ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1042                        &req, &size, ret);
1043     free_OCSPRequest(&req);
1044     if (ret)
1045         goto out;
1046     if (size != request->length)
1047         _hx509_abort("internal ASN.1 encoder error");
1048
1049     return 0;
1050
1051 out:
1052     free_OCSPRequest(&req);
1053     return ret;
1054 }
1055
1056 static char *
1057 printable_time(time_t t)
1058 {
1059     static char s[128];
1060     strlcpy(s, ctime(&t)+ 4, sizeof(s));
1061     s[20] = 0;
1062     return s;
1063 }
1064
1065 /**
1066  * Print the OCSP reply stored in a file.
1067  *
1068  * @param context a hx509 context
1069  * @param path path to a file with a OCSP reply
1070  * @param out the out FILE descriptor to print the reply on
1071  *
1072  * @return An hx509 error code, see hx509_get_error_string().
1073  *
1074  * @ingroup hx509_revoke
1075  */
1076
1077 int
1078 hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
1079 {
1080     struct revoke_ocsp ocsp;
1081     int ret, i;
1082     
1083     if (out == NULL)
1084         out = stdout;
1085
1086     memset(&ocsp, 0, sizeof(ocsp));
1087
1088     ocsp.path = strdup(path);
1089     if (ocsp.path == NULL)
1090         return ENOMEM;
1091
1092     ret = load_ocsp(context, &ocsp);
1093     if (ret) {
1094         free_ocsp(&ocsp);
1095         return ret;
1096     }
1097
1098     fprintf(out, "signer: ");
1099
1100     switch(ocsp.ocsp.tbsResponseData.responderID.element) {
1101     case choice_OCSPResponderID_byName: {
1102         hx509_name n;
1103         char *s;
1104         _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
1105         hx509_name_to_string(n, &s);
1106         hx509_name_free(&n);
1107         fprintf(out, " byName: %s\n", s);
1108         free(s);
1109         break;
1110     }
1111     case choice_OCSPResponderID_byKey: {
1112         char *s;
1113         hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
1114                    ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
1115                    &s);
1116         fprintf(out, " byKey: %s\n", s);
1117         free(s);
1118         break;
1119     }
1120     default:
1121         _hx509_abort("choice_OCSPResponderID unknown");
1122         break;
1123     }
1124
1125     fprintf(out, "producedAt: %s\n", 
1126             printable_time(ocsp.ocsp.tbsResponseData.producedAt));
1127
1128     fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
1129
1130     for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
1131         const char *status;
1132         switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1133         case choice_OCSPCertStatus_good:
1134             status = "good";
1135             break;
1136         case choice_OCSPCertStatus_revoked:
1137             status = "revoked";
1138             break;
1139         case choice_OCSPCertStatus_unknown:
1140             status = "unknown";
1141             break;
1142         default:
1143             status = "element unknown";
1144         }
1145
1146         fprintf(out, "\t%d. status: %s\n", i, status);
1147
1148         fprintf(out, "\tthisUpdate: %s\n", 
1149                 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1150         if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
1151             fprintf(out, "\tproducedAt: %s\n", 
1152                     printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1153
1154     }
1155
1156     fprintf(out, "appended certs:\n");
1157     if (ocsp.certs)
1158         ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out);
1159
1160     free_ocsp(&ocsp);
1161     return ret;
1162 }
1163
1164 /**
1165  * Verify that the certificate is part of the OCSP reply and it's not
1166  * expired. Doesn't verify signature the OCSP reply or it's done by a
1167  * authorized sender, that is assumed to be already done.
1168  *
1169  * @param context a hx509 context
1170  * @param now the time right now, if 0, use the current time.
1171  * @param cert the certificate to verify
1172  * @param flags flags control the behavior
1173  * @param data pointer to the encode ocsp reply
1174  * @param length the length of the encode ocsp reply
1175  * @param expiration return the time the OCSP will expire and need to
1176  * be rechecked.
1177  *
1178  * @return An hx509 error code, see hx509_get_error_string().
1179  *
1180  * @ingroup hx509_verify
1181  */
1182
1183 int
1184 hx509_ocsp_verify(hx509_context context,
1185                   time_t now,
1186                   hx509_cert cert,
1187                   int flags,
1188                   const void *data, size_t length,
1189                   time_t *expiration)
1190 {
1191     const Certificate *c = _hx509_get_cert(cert);
1192     OCSPBasicOCSPResponse basic;
1193     int ret, i;
1194
1195     if (now == 0)
1196         now = time(NULL);
1197
1198     *expiration = 0;
1199
1200     ret = parse_ocsp_basic(data, length, &basic);
1201     if (ret) {
1202         hx509_set_error_string(context, 0, ret,
1203                                "Failed to parse OCSP response");
1204         return ret;
1205     }
1206
1207     for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1208
1209         ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1210                                &c->tbsCertificate.serialNumber);
1211         if (ret != 0)
1212             continue;
1213             
1214         /* verify issuer hashes hash */
1215         ret = _hx509_verify_signature(context,
1216                                       NULL,
1217                                       &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1218                                       &c->tbsCertificate.issuer._save,
1219                                       &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1220         if (ret != 0)
1221             continue;
1222
1223         switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1224         case choice_OCSPCertStatus_good:
1225             break;
1226         case choice_OCSPCertStatus_revoked:
1227         case choice_OCSPCertStatus_unknown:
1228             continue;
1229         }
1230
1231         /* don't allow the update to be in the future */
1232         if (basic.tbsResponseData.responses.val[i].thisUpdate > 
1233             now + context->ocsp_time_diff)
1234             continue;
1235
1236         /* don't allow the next update to be in the past */
1237         if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1238             if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1239                 continue;
1240             *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1241         } else
1242             *expiration = now;
1243
1244         free_OCSPBasicOCSPResponse(&basic);
1245         return 0;
1246     }
1247
1248     free_OCSPBasicOCSPResponse(&basic);
1249
1250     {
1251         hx509_name name;
1252         char *subject;
1253         
1254         ret = hx509_cert_get_subject(cert, &name);
1255         if (ret) {
1256             hx509_clear_error_string(context);
1257             goto out;
1258         }
1259         ret = hx509_name_to_string(name, &subject);
1260         hx509_name_free(&name);
1261         if (ret) {
1262             hx509_clear_error_string(context);
1263             goto out;
1264         }
1265         hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
1266                                "Certificate %s not in OCSP response "
1267                                "or not good",
1268                                subject);
1269         free(subject);
1270     }
1271 out:
1272     return HX509_CERT_NOT_IN_OCSP;
1273 }
1274
1275 struct hx509_crl {
1276     hx509_certs revoked;
1277     time_t expire;
1278 };
1279
1280 /**
1281  * Create a CRL context. Use hx509_crl_free() to free the CRL context.
1282  *
1283  * @param context a hx509 context.
1284  * @param crl return pointer to a newly allocated CRL context.
1285  *
1286  * @return An hx509 error code, see hx509_get_error_string().
1287  *
1288  * @ingroup hx509_verify
1289  */
1290
1291 int
1292 hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1293 {
1294     int ret;
1295
1296     *crl = calloc(1, sizeof(**crl));
1297     if (*crl == NULL) {
1298         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1299         return ENOMEM;
1300     }
1301
1302     ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1303     if (ret) {
1304         free(*crl);
1305         *crl = NULL;
1306         return ret;
1307     }
1308     (*crl)->expire = 0;
1309     return ret;
1310 }
1311
1312 /**
1313  * Add revoked certificate to an CRL context.
1314  *
1315  * @param context a hx509 context.
1316  * @param crl the CRL to add the revoked certificate to.
1317  * @param certs keyset of certificate to revoke.
1318  *
1319  * @return An hx509 error code, see hx509_get_error_string().
1320  *
1321  * @ingroup hx509_verify
1322  */
1323
1324 int
1325 hx509_crl_add_revoked_certs(hx509_context context,
1326                             hx509_crl crl, 
1327                             hx509_certs certs)
1328 {
1329     return hx509_certs_merge(context, crl->revoked, certs);
1330 }
1331
1332 /**
1333  * Set the lifetime of a CRL context.
1334  *
1335  * @param context a hx509 context.
1336  * @param crl a CRL context
1337  * @param delta delta time the certificate is valid, library adds the
1338  * current time to this.
1339  *
1340  * @return An hx509 error code, see hx509_get_error_string().
1341  *
1342  * @ingroup hx509_verify
1343  */
1344
1345 int
1346 hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1347 {
1348     crl->expire = time(NULL) + delta;
1349     return 0;
1350 }
1351
1352 /**
1353  * Free a CRL context.
1354  *
1355  * @param context a hx509 context.
1356  * @param crl a CRL context to free.
1357  *
1358  * @ingroup hx509_verify
1359  */
1360
1361 void
1362 hx509_crl_free(hx509_context context, hx509_crl *crl)
1363 {
1364     if (*crl == NULL)
1365         return;
1366     hx509_certs_free(&(*crl)->revoked);
1367     memset(*crl, 0, sizeof(**crl));
1368     free(*crl);
1369     *crl = NULL;
1370 }
1371
1372 static int
1373 add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1374 {
1375     TBSCRLCertList *c = ctx;
1376     unsigned int num;
1377     void *ptr;
1378     int ret;
1379
1380     num = c->revokedCertificates->len;
1381     ptr = realloc(c->revokedCertificates->val,
1382                   (num + 1) * sizeof(c->revokedCertificates->val[0]));
1383     if (ptr == NULL) {
1384         hx509_clear_error_string(context);
1385         return ENOMEM;
1386     }
1387     c->revokedCertificates->val = ptr;
1388
1389     ret = hx509_cert_get_serialnumber(cert, 
1390                                       &c->revokedCertificates->val[num].userCertificate);
1391     if (ret) {
1392         hx509_clear_error_string(context);
1393         return ret;
1394     }
1395     c->revokedCertificates->val[num].revocationDate.element = 
1396         choice_Time_generalTime;
1397     c->revokedCertificates->val[num].revocationDate.u.generalTime =
1398         time(NULL) - 3600 * 24;
1399     c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1400
1401     c->revokedCertificates->len++;
1402
1403     return 0;
1404 }    
1405
1406 /**
1407  * Sign a CRL and return an encode certificate.
1408  *
1409  * @param context a hx509 context.
1410  * @param signer certificate to sign the CRL with
1411  * @param crl the CRL to sign
1412  * @param os return the signed and encoded CRL, free with
1413  * free_heim_octet_string()
1414  *
1415  * @return An hx509 error code, see hx509_get_error_string().
1416  *
1417  * @ingroup hx509_verify
1418  */
1419
1420 int
1421 hx509_crl_sign(hx509_context context,
1422                hx509_cert signer,
1423                hx509_crl crl,
1424                heim_octet_string *os)
1425 {
1426     const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
1427     CRLCertificateList c;
1428     size_t size;
1429     int ret;
1430     hx509_private_key signerkey;
1431
1432     memset(&c, 0, sizeof(c));
1433
1434     signerkey = _hx509_cert_private_key(signer);
1435     if (signerkey == NULL) {
1436         ret = HX509_PRIVATE_KEY_MISSING;
1437         hx509_set_error_string(context, 0, ret,
1438                                "Private key missing for CRL signing");
1439         return ret;
1440     }
1441
1442     c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1443     if (c.tbsCertList.version == NULL) {
1444         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1445         return ENOMEM;
1446     }
1447
1448     *c.tbsCertList.version = 1;
1449
1450     ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1451     if (ret) {
1452         hx509_clear_error_string(context);
1453         goto out;
1454     }
1455
1456     ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1457                     &c.tbsCertList.issuer);
1458     if (ret) {
1459         hx509_clear_error_string(context);
1460         goto out;
1461     }
1462
1463     c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1464     c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1465
1466     c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1467     if (c.tbsCertList.nextUpdate == NULL) {
1468         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1469         ret = ENOMEM;
1470         goto out;
1471     }
1472
1473     {
1474         time_t next = crl->expire;
1475         if (next == 0)
1476             next = time(NULL) + 24 * 3600 * 365;
1477
1478         c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1479         c.tbsCertList.nextUpdate->u.generalTime = next;
1480     }
1481
1482     c.tbsCertList.revokedCertificates = 
1483         calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1484     if (c.tbsCertList.revokedCertificates == NULL) {
1485         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1486         ret = ENOMEM;
1487         goto out;
1488     }
1489     c.tbsCertList.crlExtensions = NULL;
1490
1491     ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList);
1492     if (ret)
1493         goto out;
1494
1495     /* if not revoked certs, remove OPTIONAL entry */
1496     if (c.tbsCertList.revokedCertificates->len == 0) {
1497         free(c.tbsCertList.revokedCertificates);
1498         c.tbsCertList.revokedCertificates = NULL;
1499     }
1500
1501     ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1502                        &c.tbsCertList, &size, ret);
1503     if (ret) {
1504         hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1505         goto out;
1506     }
1507     if (size != os->length)
1508         _hx509_abort("internal ASN.1 encoder error");
1509
1510
1511     ret = _hx509_create_signature_bitstring(context,
1512                                             signerkey,
1513                                             sigalg,
1514                                             os,
1515                                             &c.signatureAlgorithm,
1516                                             &c.signatureValue);
1517     free(os->data);
1518
1519     ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1520                        &c, &size, ret);
1521     free_CRLCertificateList(&c);
1522     if (ret) {
1523         hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1524         goto out;
1525     }
1526     if (size != os->length)
1527         _hx509_abort("internal ASN.1 encoder error");
1528
1529     return 0;
1530
1531 out:
1532     free_CRLCertificateList(&c);
1533     return ret;
1534 }