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