1178825Sdfr/*
2178825Sdfr * Copyright (c) 2006 - 2007 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr/**
35178825Sdfr * @page page_revoke Revocation methods
36178825Sdfr *
37178825Sdfr * There are two revocation method for PKIX/X.509: CRL and OCSP.
38178825Sdfr * Revocation is needed if the private key is lost and
39178825Sdfr * stolen. Depending on how picky you are, you might want to make
40178825Sdfr * revocation for destroyed private keys too (smartcard broken), but
41178825Sdfr * that should not be a problem.
42178825Sdfr *
43178825Sdfr * CRL is a list of certifiates that have expired.
44178825Sdfr *
45178825Sdfr * OCSP is an online checking method where the requestor sends a list
46178825Sdfr * of certificates to the OCSP server to return a signed reply if they
47178825Sdfr * are valid or not. Some services sends a OCSP reply as part of the
48178825Sdfr * hand-shake to make the revoktion decision simpler/faster for the
49178825Sdfr * client.
50178825Sdfr */
51178825Sdfr
52178825Sdfr#include "hx_locl.h"
53178825SdfrRCSID("$Id: revoke.c 22275 2007-12-11 11:02:11Z lha $");
54178825Sdfr
55178825Sdfrstruct revoke_crl {
56178825Sdfr    char *path;
57178825Sdfr    time_t last_modfied;
58178825Sdfr    CRLCertificateList crl;
59178825Sdfr    int verified;
60178825Sdfr    int failed_verify;
61178825Sdfr};
62178825Sdfr
63178825Sdfrstruct revoke_ocsp {
64178825Sdfr    char *path;
65178825Sdfr    time_t last_modfied;
66178825Sdfr    OCSPBasicOCSPResponse ocsp;
67178825Sdfr    hx509_certs certs;
68178825Sdfr    hx509_cert signer;
69178825Sdfr};
70178825Sdfr
71178825Sdfr
72178825Sdfrstruct hx509_revoke_ctx_data {
73178825Sdfr    unsigned ref;
74178825Sdfr    struct {
75178825Sdfr	struct revoke_crl *val;
76178825Sdfr	size_t len;
77178825Sdfr    } crls;
78178825Sdfr    struct {
79178825Sdfr	struct revoke_ocsp *val;
80178825Sdfr	size_t len;
81178825Sdfr    } ocsps;
82178825Sdfr};
83178825Sdfr
84178825Sdfr/**
85178825Sdfr * Allocate a revokation context. Free with hx509_revoke_free().
86178825Sdfr *
87178825Sdfr * @param context A hx509 context.
88178825Sdfr * @param ctx returns a newly allocated revokation context.
89178825Sdfr *
90178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
91178825Sdfr *
92178825Sdfr * @ingroup hx509_revoke
93178825Sdfr */
94178825Sdfr
95178825Sdfrint
96178825Sdfrhx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
97178825Sdfr{
98178825Sdfr    *ctx = calloc(1, sizeof(**ctx));
99178825Sdfr    if (*ctx == NULL)
100178825Sdfr	return ENOMEM;
101178825Sdfr
102178825Sdfr    (*ctx)->ref = 1;
103178825Sdfr    (*ctx)->crls.len = 0;
104178825Sdfr    (*ctx)->crls.val = NULL;
105178825Sdfr    (*ctx)->ocsps.len = 0;
106178825Sdfr    (*ctx)->ocsps.val = NULL;
107178825Sdfr
108178825Sdfr    return 0;
109178825Sdfr}
110178825Sdfr
111178825Sdfrhx509_revoke_ctx
112178825Sdfr_hx509_revoke_ref(hx509_revoke_ctx ctx)
113178825Sdfr{
114178825Sdfr    if (ctx == NULL)
115178825Sdfr	return NULL;
116178825Sdfr    if (ctx->ref <= 0)
117178825Sdfr	_hx509_abort("revoke ctx refcount <= 0");
118178825Sdfr    ctx->ref++;
119178825Sdfr    if (ctx->ref == 0)
120178825Sdfr	_hx509_abort("revoke ctx refcount == 0");
121178825Sdfr    return ctx;
122178825Sdfr}
123178825Sdfr
124178825Sdfrstatic void
125178825Sdfrfree_ocsp(struct revoke_ocsp *ocsp)
126178825Sdfr{
127178825Sdfr    free(ocsp->path);
128178825Sdfr    free_OCSPBasicOCSPResponse(&ocsp->ocsp);
129178825Sdfr    hx509_certs_free(&ocsp->certs);
130178825Sdfr    hx509_cert_free(ocsp->signer);
131178825Sdfr}
132178825Sdfr
133178825Sdfr/**
134178825Sdfr * Free a hx509 revokation context.
135178825Sdfr *
136178825Sdfr * @param ctx context to be freed
137178825Sdfr *
138178825Sdfr * @ingroup hx509_revoke
139178825Sdfr */
140178825Sdfr
141178825Sdfrvoid
142178825Sdfrhx509_revoke_free(hx509_revoke_ctx *ctx)
143178825Sdfr{
144178825Sdfr    size_t i ;
145178825Sdfr
146178825Sdfr    if (ctx == NULL || *ctx == NULL)
147178825Sdfr	return;
148178825Sdfr
149178825Sdfr    if ((*ctx)->ref <= 0)
150178825Sdfr	_hx509_abort("revoke ctx refcount <= 0 on free");
151178825Sdfr    if (--(*ctx)->ref > 0)
152178825Sdfr	return;
153178825Sdfr
154178825Sdfr    for (i = 0; i < (*ctx)->crls.len; i++) {
155178825Sdfr	free((*ctx)->crls.val[i].path);
156178825Sdfr	free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
157178825Sdfr    }
158178825Sdfr
159178825Sdfr    for (i = 0; i < (*ctx)->ocsps.len; i++)
160178825Sdfr	free_ocsp(&(*ctx)->ocsps.val[i]);
161178825Sdfr    free((*ctx)->ocsps.val);
162178825Sdfr
163178825Sdfr    free((*ctx)->crls.val);
164178825Sdfr
165178825Sdfr    memset(*ctx, 0, sizeof(**ctx));
166178825Sdfr    free(*ctx);
167178825Sdfr    *ctx = NULL;
168178825Sdfr}
169178825Sdfr
170178825Sdfrstatic int
171178825Sdfrverify_ocsp(hx509_context context,
172178825Sdfr	    struct revoke_ocsp *ocsp,
173178825Sdfr	    time_t time_now,
174178825Sdfr	    hx509_certs certs,
175178825Sdfr	    hx509_cert parent)
176178825Sdfr{
177178825Sdfr    hx509_cert signer = NULL;
178178825Sdfr    hx509_query q;
179178825Sdfr    int ret;
180178825Sdfr
181178825Sdfr    _hx509_query_clear(&q);
182178825Sdfr
183178825Sdfr    /*
184178825Sdfr     * Need to match on issuer too in case there are two CA that have
185178825Sdfr     * issued the same name to a certificate. One example of this is
186178825Sdfr     * the www.openvalidation.org test's ocsp validator.
187178825Sdfr     */
188178825Sdfr
189178825Sdfr    q.match = HX509_QUERY_MATCH_ISSUER_NAME;
190178825Sdfr    q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
191178825Sdfr
192178825Sdfr    switch(ocsp->ocsp.tbsResponseData.responderID.element) {
193178825Sdfr    case choice_OCSPResponderID_byName:
194178825Sdfr	q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
195178825Sdfr	q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
196178825Sdfr	break;
197178825Sdfr    case choice_OCSPResponderID_byKey:
198178825Sdfr	q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
199178825Sdfr	q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
200178825Sdfr	break;
201178825Sdfr    }
202178825Sdfr
203178825Sdfr    ret = hx509_certs_find(context, certs, &q, &signer);
204178825Sdfr    if (ret && ocsp->certs)
205178825Sdfr	ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
206178825Sdfr    if (ret)
207178825Sdfr	goto out;
208178825Sdfr
209178825Sdfr    /*
210178825Sdfr     * If signer certificate isn't the CA certificate, lets check the
211178825Sdfr     * it is the CA that signed the signer certificate and the OCSP EKU
212178825Sdfr     * is set.
213178825Sdfr     */
214178825Sdfr    if (hx509_cert_cmp(signer, parent) != 0) {
215178825Sdfr	Certificate *p = _hx509_get_cert(parent);
216178825Sdfr	Certificate *s = _hx509_get_cert(signer);
217178825Sdfr
218178825Sdfr	ret = _hx509_cert_is_parent_cmp(s, p, 0);
219178825Sdfr	if (ret != 0) {
220178825Sdfr	    ret = HX509_PARENT_NOT_CA;
221178825Sdfr	    hx509_set_error_string(context, 0, ret, "Revoke OSCP signer is "
222178825Sdfr				   "doesn't have CA as signer certificate");
223178825Sdfr	    goto out;
224178825Sdfr	}
225178825Sdfr
226178825Sdfr	ret = _hx509_verify_signature_bitstring(context,
227178825Sdfr						p,
228178825Sdfr						&s->signatureAlgorithm,
229178825Sdfr						&s->tbsCertificate._save,
230178825Sdfr						&s->signatureValue);
231178825Sdfr	if (ret) {
232178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
233178825Sdfr				   "OSCP signer signature invalid");
234178825Sdfr	    goto out;
235178825Sdfr	}
236178825Sdfr
237178825Sdfr	ret = hx509_cert_check_eku(context, signer,
238178825Sdfr				   oid_id_pkix_kp_OCSPSigning(), 0);
239178825Sdfr	if (ret)
240178825Sdfr	    goto out;
241178825Sdfr    }
242178825Sdfr
243178825Sdfr    ret = _hx509_verify_signature_bitstring(context,
244178825Sdfr					    _hx509_get_cert(signer),
245178825Sdfr					    &ocsp->ocsp.signatureAlgorithm,
246178825Sdfr					    &ocsp->ocsp.tbsResponseData._save,
247178825Sdfr					    &ocsp->ocsp.signature);
248178825Sdfr    if (ret) {
249178825Sdfr	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
250178825Sdfr			       "OSCP signature invalid");
251178825Sdfr	goto out;
252178825Sdfr    }
253178825Sdfr
254178825Sdfr    ocsp->signer = signer;
255178825Sdfr    signer = NULL;
256178825Sdfrout:
257178825Sdfr    if (signer)
258178825Sdfr	hx509_cert_free(signer);
259178825Sdfr
260178825Sdfr    return ret;
261178825Sdfr}
262178825Sdfr
263178825Sdfr/*
264178825Sdfr *
265178825Sdfr */
266178825Sdfr
267178825Sdfrstatic int
268178825Sdfrparse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
269178825Sdfr{
270178825Sdfr    OCSPResponse resp;
271178825Sdfr    size_t size;
272178825Sdfr    int ret;
273178825Sdfr
274178825Sdfr    memset(basic, 0, sizeof(*basic));
275178825Sdfr
276178825Sdfr    ret = decode_OCSPResponse(data, length, &resp, &size);
277178825Sdfr    if (ret)
278178825Sdfr	return ret;
279178825Sdfr    if (length != size) {
280178825Sdfr	free_OCSPResponse(&resp);
281178825Sdfr	return ASN1_EXTRA_DATA;
282178825Sdfr    }
283178825Sdfr
284178825Sdfr    switch (resp.responseStatus) {
285178825Sdfr    case successful:
286178825Sdfr	break;
287178825Sdfr    default:
288178825Sdfr	free_OCSPResponse(&resp);
289178825Sdfr	return HX509_REVOKE_WRONG_DATA;
290178825Sdfr    }
291178825Sdfr
292178825Sdfr    if (resp.responseBytes == NULL) {
293178825Sdfr	free_OCSPResponse(&resp);
294178825Sdfr	return EINVAL;
295178825Sdfr    }
296178825Sdfr
297178825Sdfr    ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
298178825Sdfr			   oid_id_pkix_ocsp_basic());
299178825Sdfr    if (ret != 0) {
300178825Sdfr	free_OCSPResponse(&resp);
301178825Sdfr	return HX509_REVOKE_WRONG_DATA;
302178825Sdfr    }
303178825Sdfr
304178825Sdfr    ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
305178825Sdfr				       resp.responseBytes->response.length,
306178825Sdfr				       basic,
307178825Sdfr				       &size);
308178825Sdfr    if (ret) {
309178825Sdfr	free_OCSPResponse(&resp);
310178825Sdfr	return ret;
311178825Sdfr    }
312178825Sdfr    if (size != resp.responseBytes->response.length) {
313178825Sdfr	free_OCSPResponse(&resp);
314178825Sdfr	free_OCSPBasicOCSPResponse(basic);
315178825Sdfr	return ASN1_EXTRA_DATA;
316178825Sdfr    }
317178825Sdfr    free_OCSPResponse(&resp);
318178825Sdfr
319178825Sdfr    return 0;
320178825Sdfr}
321178825Sdfr
322178825Sdfr/*
323178825Sdfr *
324178825Sdfr */
325178825Sdfr
326178825Sdfrstatic int
327178825Sdfrload_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
328178825Sdfr{
329178825Sdfr    OCSPBasicOCSPResponse basic;
330178825Sdfr    hx509_certs certs = NULL;
331178825Sdfr    size_t length;
332178825Sdfr    struct stat sb;
333178825Sdfr    void *data;
334178825Sdfr    int ret;
335178825Sdfr
336178825Sdfr    ret = _hx509_map_file(ocsp->path, &data, &length, &sb);
337178825Sdfr    if (ret)
338178825Sdfr	return ret;
339178825Sdfr
340178825Sdfr    ret = parse_ocsp_basic(data, length, &basic);
341178825Sdfr    _hx509_unmap_file(data, length);
342178825Sdfr    if (ret) {
343178825Sdfr	hx509_set_error_string(context, 0, ret,
344178825Sdfr			       "Failed to parse OCSP response");
345178825Sdfr	return ret;
346178825Sdfr    }
347178825Sdfr
348178825Sdfr    if (basic.certs) {
349178825Sdfr	int i;
350178825Sdfr
351178825Sdfr	ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
352178825Sdfr			       NULL, &certs);
353178825Sdfr	if (ret) {
354178825Sdfr	    free_OCSPBasicOCSPResponse(&basic);
355178825Sdfr	    return ret;
356178825Sdfr	}
357178825Sdfr
358178825Sdfr	for (i = 0; i < basic.certs->len; i++) {
359178825Sdfr	    hx509_cert c;
360178825Sdfr
361178825Sdfr	    ret = hx509_cert_init(context, &basic.certs->val[i], &c);
362178825Sdfr	    if (ret)
363178825Sdfr		continue;
364178825Sdfr
365178825Sdfr	    ret = hx509_certs_add(context, certs, c);
366178825Sdfr	    hx509_cert_free(c);
367178825Sdfr	    if (ret)
368178825Sdfr		continue;
369178825Sdfr	}
370178825Sdfr    }
371178825Sdfr
372178825Sdfr    ocsp->last_modfied = sb.st_mtime;
373178825Sdfr
374178825Sdfr    free_OCSPBasicOCSPResponse(&ocsp->ocsp);
375178825Sdfr    hx509_certs_free(&ocsp->certs);
376178825Sdfr    hx509_cert_free(ocsp->signer);
377178825Sdfr
378178825Sdfr    ocsp->ocsp = basic;
379178825Sdfr    ocsp->certs = certs;
380178825Sdfr    ocsp->signer = NULL;
381178825Sdfr
382178825Sdfr    return 0;
383178825Sdfr}
384178825Sdfr
385178825Sdfr/**
386178825Sdfr * Add a OCSP file to the revokation context.
387178825Sdfr *
388178825Sdfr * @param context hx509 context
389178825Sdfr * @param ctx hx509 revokation context
390178825Sdfr * @param path path to file that is going to be added to the context.
391178825Sdfr *
392178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
393178825Sdfr *
394178825Sdfr * @ingroup hx509_revoke
395178825Sdfr */
396178825Sdfr
397178825Sdfrint
398178825Sdfrhx509_revoke_add_ocsp(hx509_context context,
399178825Sdfr		      hx509_revoke_ctx ctx,
400178825Sdfr		      const char *path)
401178825Sdfr{
402178825Sdfr    void *data;
403178825Sdfr    int ret;
404178825Sdfr    size_t i;
405178825Sdfr
406178825Sdfr    if (strncmp(path, "FILE:", 5) != 0) {
407178825Sdfr	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
408178825Sdfr			       "unsupport type in %s", path);
409178825Sdfr	return HX509_UNSUPPORTED_OPERATION;
410178825Sdfr    }
411178825Sdfr
412178825Sdfr    path += 5;
413178825Sdfr
414178825Sdfr    for (i = 0; i < ctx->ocsps.len; i++) {
415178825Sdfr	if (strcmp(ctx->ocsps.val[0].path, path) == 0)
416178825Sdfr	    return 0;
417178825Sdfr    }
418178825Sdfr
419178825Sdfr    data = realloc(ctx->ocsps.val,
420178825Sdfr		   (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
421178825Sdfr    if (data == NULL) {
422178825Sdfr	hx509_clear_error_string(context);
423178825Sdfr	return ENOMEM;
424178825Sdfr    }
425178825Sdfr
426178825Sdfr    ctx->ocsps.val = data;
427178825Sdfr
428178825Sdfr    memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
429178825Sdfr	   sizeof(ctx->ocsps.val[0]));
430178825Sdfr
431178825Sdfr    ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
432178825Sdfr    if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
433178825Sdfr	hx509_clear_error_string(context);
434178825Sdfr	return ENOMEM;
435178825Sdfr    }
436178825Sdfr
437178825Sdfr    ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
438178825Sdfr    if (ret) {
439178825Sdfr	free(ctx->ocsps.val[ctx->ocsps.len].path);
440178825Sdfr	return ret;
441178825Sdfr    }
442178825Sdfr    ctx->ocsps.len++;
443178825Sdfr
444178825Sdfr    return ret;
445178825Sdfr}
446178825Sdfr
447178825Sdfr/*
448178825Sdfr *
449178825Sdfr */
450178825Sdfr
451178825Sdfrstatic int
452178825Sdfrverify_crl(hx509_context context,
453178825Sdfr	   hx509_revoke_ctx ctx,
454178825Sdfr	   CRLCertificateList *crl,
455178825Sdfr	   time_t time_now,
456178825Sdfr	   hx509_certs certs,
457178825Sdfr	   hx509_cert parent)
458178825Sdfr{
459178825Sdfr    hx509_cert signer;
460178825Sdfr    hx509_query q;
461178825Sdfr    time_t t;
462178825Sdfr    int ret;
463178825Sdfr
464178825Sdfr    t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
465178825Sdfr    if (t > time_now) {
466178825Sdfr	hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
467178825Sdfr			       "CRL used before time");
468178825Sdfr	return HX509_CRL_USED_BEFORE_TIME;
469178825Sdfr    }
470178825Sdfr
471178825Sdfr    if (crl->tbsCertList.nextUpdate == NULL) {
472178825Sdfr	hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
473178825Sdfr			       "CRL missing nextUpdate");
474178825Sdfr	return HX509_CRL_INVALID_FORMAT;
475178825Sdfr    }
476178825Sdfr
477178825Sdfr    t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
478178825Sdfr    if (t < time_now) {
479178825Sdfr	hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
480178825Sdfr			       "CRL used after time");
481178825Sdfr	return HX509_CRL_USED_AFTER_TIME;
482178825Sdfr    }
483178825Sdfr
484178825Sdfr    _hx509_query_clear(&q);
485178825Sdfr
486178825Sdfr    /*
487178825Sdfr     * If it's the signer have CRLSIGN bit set, use that as the signer
488178825Sdfr     * cert for the certificate, otherwise, search for a certificate.
489178825Sdfr     */
490178825Sdfr    if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
491178825Sdfr	signer = hx509_cert_ref(parent);
492178825Sdfr    } else {
493178825Sdfr	q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
494178825Sdfr	q.match |= HX509_QUERY_KU_CRLSIGN;
495178825Sdfr	q.subject_name = &crl->tbsCertList.issuer;
496178825Sdfr
497178825Sdfr	ret = hx509_certs_find(context, certs, &q, &signer);
498178825Sdfr	if (ret) {
499178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
500178825Sdfr				   "Failed to find certificate for CRL");
501178825Sdfr	    return ret;
502178825Sdfr	}
503178825Sdfr    }
504178825Sdfr
505178825Sdfr    ret = _hx509_verify_signature_bitstring(context,
506178825Sdfr					    _hx509_get_cert(signer),
507178825Sdfr					    &crl->signatureAlgorithm,
508178825Sdfr					    &crl->tbsCertList._save,
509178825Sdfr					    &crl->signatureValue);
510178825Sdfr    if (ret) {
511178825Sdfr	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
512178825Sdfr			       "CRL signature invalid");
513178825Sdfr	goto out;
514178825Sdfr    }
515178825Sdfr
516178825Sdfr    /*
517178825Sdfr     * If signer is not CA cert, need to check revoke status of this
518178825Sdfr     * CRL signing cert too, this include all parent CRL signer cert
519178825Sdfr     * up to the root *sigh*, assume root at least hve CERTSIGN flag
520178825Sdfr     * set.
521178825Sdfr     */
522178825Sdfr    while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
523178825Sdfr	hx509_cert crl_parent;
524178825Sdfr
525178825Sdfr	_hx509_query_clear(&q);
526178825Sdfr
527178825Sdfr	q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
528178825Sdfr	q.match |= HX509_QUERY_KU_CRLSIGN;
529178825Sdfr	q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
530178825Sdfr
531178825Sdfr	ret = hx509_certs_find(context, certs, &q, &crl_parent);
532178825Sdfr	if (ret) {
533178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
534178825Sdfr				   "Failed to find parent of CRL signer");
535178825Sdfr	    goto out;
536178825Sdfr	}
537178825Sdfr
538178825Sdfr	ret = hx509_revoke_verify(context,
539178825Sdfr				  ctx,
540178825Sdfr				  certs,
541178825Sdfr				  time_now,
542178825Sdfr				  signer,
543178825Sdfr				  crl_parent);
544178825Sdfr	hx509_cert_free(signer);
545178825Sdfr	signer = crl_parent;
546178825Sdfr	if (ret) {
547178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
548178825Sdfr				   "Failed to verify revoke "
549178825Sdfr				   "status of CRL signer");
550178825Sdfr	    goto out;
551178825Sdfr	}
552178825Sdfr    }
553178825Sdfr
554178825Sdfrout:
555178825Sdfr    hx509_cert_free(signer);
556178825Sdfr
557178825Sdfr    return ret;
558178825Sdfr}
559178825Sdfr
560178825Sdfrstatic int
561178825Sdfrload_crl(const char *path, time_t *t, CRLCertificateList *crl)
562178825Sdfr{
563178825Sdfr    size_t length, size;
564178825Sdfr    struct stat sb;
565178825Sdfr    void *data;
566178825Sdfr    int ret;
567178825Sdfr
568178825Sdfr    memset(crl, 0, sizeof(*crl));
569178825Sdfr
570178825Sdfr    ret = _hx509_map_file(path, &data, &length, &sb);
571178825Sdfr    if (ret)
572178825Sdfr	return ret;
573178825Sdfr
574178825Sdfr    *t = sb.st_mtime;
575178825Sdfr
576178825Sdfr    ret = decode_CRLCertificateList(data, length, crl, &size);
577178825Sdfr    _hx509_unmap_file(data, length);
578178825Sdfr    if (ret)
579178825Sdfr	return ret;
580178825Sdfr
581178825Sdfr    /* check signature is aligned */
582178825Sdfr    if (crl->signatureValue.length & 7) {
583178825Sdfr	free_CRLCertificateList(crl);
584178825Sdfr	return HX509_CRYPTO_SIG_INVALID_FORMAT;
585178825Sdfr    }
586178825Sdfr    return 0;
587178825Sdfr}
588178825Sdfr
589178825Sdfr/**
590178825Sdfr * Add a CRL file to the revokation context.
591178825Sdfr *
592178825Sdfr * @param context hx509 context
593178825Sdfr * @param ctx hx509 revokation context
594178825Sdfr * @param path path to file that is going to be added to the context.
595178825Sdfr *
596178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
597178825Sdfr *
598178825Sdfr * @ingroup hx509_revoke
599178825Sdfr */
600178825Sdfr
601178825Sdfrint
602178825Sdfrhx509_revoke_add_crl(hx509_context context,
603178825Sdfr		     hx509_revoke_ctx ctx,
604178825Sdfr		     const char *path)
605178825Sdfr{
606178825Sdfr    void *data;
607178825Sdfr    size_t i;
608178825Sdfr    int ret;
609178825Sdfr
610178825Sdfr    if (strncmp(path, "FILE:", 5) != 0) {
611178825Sdfr	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
612178825Sdfr			       "unsupport type in %s", path);
613178825Sdfr	return HX509_UNSUPPORTED_OPERATION;
614178825Sdfr    }
615178825Sdfr
616178825Sdfr
617178825Sdfr    path += 5;
618178825Sdfr
619178825Sdfr    for (i = 0; i < ctx->crls.len; i++) {
620178825Sdfr	if (strcmp(ctx->crls.val[0].path, path) == 0)
621178825Sdfr	    return 0;
622178825Sdfr    }
623178825Sdfr
624178825Sdfr    data = realloc(ctx->crls.val,
625178825Sdfr		   (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
626178825Sdfr    if (data == NULL) {
627178825Sdfr	hx509_clear_error_string(context);
628178825Sdfr	return ENOMEM;
629178825Sdfr    }
630178825Sdfr    ctx->crls.val = data;
631178825Sdfr
632178825Sdfr    memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
633178825Sdfr
634178825Sdfr    ctx->crls.val[ctx->crls.len].path = strdup(path);
635178825Sdfr    if (ctx->crls.val[ctx->crls.len].path == NULL) {
636178825Sdfr	hx509_clear_error_string(context);
637178825Sdfr	return ENOMEM;
638178825Sdfr    }
639178825Sdfr
640178825Sdfr    ret = load_crl(path,
641178825Sdfr		   &ctx->crls.val[ctx->crls.len].last_modfied,
642178825Sdfr		   &ctx->crls.val[ctx->crls.len].crl);
643178825Sdfr    if (ret) {
644178825Sdfr	free(ctx->crls.val[ctx->crls.len].path);
645178825Sdfr	return ret;
646178825Sdfr    }
647178825Sdfr
648178825Sdfr    ctx->crls.len++;
649178825Sdfr
650178825Sdfr    return ret;
651178825Sdfr}
652178825Sdfr
653178825Sdfr/**
654178825Sdfr * Check that a certificate is not expired according to a revokation
655178825Sdfr * context. Also need the parent certificte to the check OCSP
656178825Sdfr * parent identifier.
657178825Sdfr *
658178825Sdfr * @param context hx509 context
659178825Sdfr * @param ctx hx509 revokation context
660178825Sdfr * @param certs
661178825Sdfr * @param now
662178825Sdfr * @param cert
663178825Sdfr * @param parent_cert
664178825Sdfr *
665178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
666178825Sdfr *
667178825Sdfr * @ingroup hx509_revoke
668178825Sdfr */
669178825Sdfr
670178825Sdfr
671178825Sdfrint
672178825Sdfrhx509_revoke_verify(hx509_context context,
673178825Sdfr		    hx509_revoke_ctx ctx,
674178825Sdfr		    hx509_certs certs,
675178825Sdfr		    time_t now,
676178825Sdfr		    hx509_cert cert,
677178825Sdfr		    hx509_cert parent_cert)
678178825Sdfr{
679178825Sdfr    const Certificate *c = _hx509_get_cert(cert);
680178825Sdfr    const Certificate *p = _hx509_get_cert(parent_cert);
681178825Sdfr    unsigned long i, j, k;
682178825Sdfr    int ret;
683178825Sdfr
684178825Sdfr    hx509_clear_error_string(context);
685178825Sdfr
686178825Sdfr    for (i = 0; i < ctx->ocsps.len; i++) {
687178825Sdfr	struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
688178825Sdfr	struct stat sb;
689178825Sdfr
690178825Sdfr	/* check this ocsp apply to this cert */
691178825Sdfr
692178825Sdfr	/* check if there is a newer version of the file */
693178825Sdfr	ret = stat(ocsp->path, &sb);
694178825Sdfr	if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
695178825Sdfr	    ret = load_ocsp(context, ocsp);
696178825Sdfr	    if (ret)
697178825Sdfr		continue;
698178825Sdfr	}
699178825Sdfr
700178825Sdfr	/* verify signature in ocsp if not already done */
701178825Sdfr	if (ocsp->signer == NULL) {
702178825Sdfr	    ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
703178825Sdfr	    if (ret)
704178825Sdfr		continue;
705178825Sdfr	}
706178825Sdfr
707178825Sdfr	for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
708178825Sdfr	    heim_octet_string os;
709178825Sdfr
710178825Sdfr	    ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
711178825Sdfr				   &c->tbsCertificate.serialNumber);
712178825Sdfr	    if (ret != 0)
713178825Sdfr		continue;
714178825Sdfr
715178825Sdfr	    /* verify issuer hashes hash */
716178825Sdfr	    ret = _hx509_verify_signature(context,
717178825Sdfr					  NULL,
718178825Sdfr					  &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
719178825Sdfr					  &c->tbsCertificate.issuer._save,
720178825Sdfr					  &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
721178825Sdfr	    if (ret != 0)
722178825Sdfr		continue;
723178825Sdfr
724178825Sdfr	    os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
725178825Sdfr	    os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
726178825Sdfr
727178825Sdfr	    ret = _hx509_verify_signature(context,
728178825Sdfr					  NULL,
729178825Sdfr					  &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
730178825Sdfr					  &os,
731178825Sdfr					  &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
732178825Sdfr	    if (ret != 0)
733178825Sdfr		continue;
734178825Sdfr
735178825Sdfr	    switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
736178825Sdfr	    case choice_OCSPCertStatus_good:
737178825Sdfr		break;
738178825Sdfr	    case choice_OCSPCertStatus_revoked:
739178825Sdfr		hx509_set_error_string(context, 0,
740178825Sdfr				       HX509_CERT_REVOKED,
741178825Sdfr				       "Certificate revoked by issuer in OCSP");
742178825Sdfr		return HX509_CERT_REVOKED;
743178825Sdfr	    case choice_OCSPCertStatus_unknown:
744178825Sdfr		continue;
745178825Sdfr	    }
746178825Sdfr
747178825Sdfr	    /* don't allow the update to be in the future */
748178825Sdfr	    if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
749178825Sdfr		now + context->ocsp_time_diff)
750178825Sdfr		continue;
751178825Sdfr
752178825Sdfr	    /* don't allow the next update to be in the past */
753178825Sdfr	    if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
754178825Sdfr		if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
755178825Sdfr		    continue;
756178825Sdfr	    } else
757178825Sdfr		/* Should force a refetch, but can we ? */;
758178825Sdfr
759178825Sdfr	    return 0;
760178825Sdfr	}
761178825Sdfr    }
762178825Sdfr
763178825Sdfr    for (i = 0; i < ctx->crls.len; i++) {
764178825Sdfr	struct revoke_crl *crl = &ctx->crls.val[i];
765178825Sdfr	struct stat sb;
766178825Sdfr
767178825Sdfr	/* check if cert.issuer == crls.val[i].crl.issuer */
768178825Sdfr	ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
769178825Sdfr			      &crl->crl.tbsCertList.issuer);
770178825Sdfr	if (ret)
771178825Sdfr	    continue;
772178825Sdfr
773178825Sdfr	ret = stat(crl->path, &sb);
774178825Sdfr	if (ret == 0 && crl->last_modfied != sb.st_mtime) {
775178825Sdfr	    CRLCertificateList cl;
776178825Sdfr
777178825Sdfr	    ret = load_crl(crl->path, &crl->last_modfied, &cl);
778178825Sdfr	    if (ret == 0) {
779178825Sdfr		free_CRLCertificateList(&crl->crl);
780178825Sdfr		crl->crl = cl;
781178825Sdfr		crl->verified = 0;
782178825Sdfr		crl->failed_verify = 0;
783178825Sdfr	    }
784178825Sdfr	}
785178825Sdfr	if (crl->failed_verify)
786178825Sdfr	    continue;
787178825Sdfr
788178825Sdfr	/* verify signature in crl if not already done */
789178825Sdfr	if (crl->verified == 0) {
790178825Sdfr	    ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
791178825Sdfr	    if (ret) {
792178825Sdfr		crl->failed_verify = 1;
793178825Sdfr		continue;
794178825Sdfr	    }
795178825Sdfr	    crl->verified = 1;
796178825Sdfr	}
797178825Sdfr
798178825Sdfr	if (crl->crl.tbsCertList.crlExtensions) {
799178825Sdfr	    for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
800178825Sdfr		if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
801178825Sdfr		    hx509_set_error_string(context, 0,
802178825Sdfr					   HX509_CRL_UNKNOWN_EXTENSION,
803178825Sdfr					   "Unknown CRL extension");
804178825Sdfr		    return HX509_CRL_UNKNOWN_EXTENSION;
805178825Sdfr		}
806178825Sdfr	    }
807178825Sdfr	}
808178825Sdfr
809178825Sdfr	if (crl->crl.tbsCertList.revokedCertificates == NULL)
810178825Sdfr	    return 0;
811178825Sdfr
812178825Sdfr	/* check if cert is in crl */
813178825Sdfr	for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
814178825Sdfr	    time_t t;
815178825Sdfr
816178825Sdfr	    ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
817178825Sdfr				       &c->tbsCertificate.serialNumber);
818178825Sdfr	    if (ret != 0)
819178825Sdfr		continue;
820178825Sdfr
821178825Sdfr	    t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
822178825Sdfr	    if (t > now)
823178825Sdfr		continue;
824178825Sdfr
825178825Sdfr	    if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
826178825Sdfr		for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
827178825Sdfr		    if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
828178825Sdfr			return HX509_CRL_UNKNOWN_EXTENSION;
829178825Sdfr
830178825Sdfr	    hx509_set_error_string(context, 0,
831178825Sdfr				   HX509_CERT_REVOKED,
832178825Sdfr				   "Certificate revoked by issuer in CRL");
833178825Sdfr	    return HX509_CERT_REVOKED;
834178825Sdfr	}
835178825Sdfr
836178825Sdfr	return 0;
837178825Sdfr    }
838178825Sdfr
839178825Sdfr
840178825Sdfr    if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
841178825Sdfr	return 0;
842178825Sdfr    hx509_set_error_string(context, HX509_ERROR_APPEND,
843178825Sdfr			   HX509_REVOKE_STATUS_MISSING,
844178825Sdfr			   "No revoke status found for "
845178825Sdfr			   "certificates");
846178825Sdfr    return HX509_REVOKE_STATUS_MISSING;
847178825Sdfr}
848178825Sdfr
849178825Sdfrstruct ocsp_add_ctx {
850178825Sdfr    OCSPTBSRequest *req;
851178825Sdfr    hx509_certs certs;
852178825Sdfr    const AlgorithmIdentifier *digest;
853178825Sdfr    hx509_cert parent;
854178825Sdfr};
855178825Sdfr
856178825Sdfrstatic int
857178825Sdfradd_to_req(hx509_context context, void *ptr, hx509_cert cert)
858178825Sdfr{
859178825Sdfr    struct ocsp_add_ctx *ctx = ptr;
860178825Sdfr    OCSPInnerRequest *one;
861178825Sdfr    hx509_cert parent = NULL;
862178825Sdfr    Certificate *p, *c = _hx509_get_cert(cert);
863178825Sdfr    heim_octet_string os;
864178825Sdfr    int ret;
865178825Sdfr    hx509_query q;
866178825Sdfr    void *d;
867178825Sdfr
868178825Sdfr    d = realloc(ctx->req->requestList.val,
869178825Sdfr		sizeof(ctx->req->requestList.val[0]) *
870178825Sdfr		(ctx->req->requestList.len + 1));
871178825Sdfr    if (d == NULL)
872178825Sdfr	return ENOMEM;
873178825Sdfr    ctx->req->requestList.val = d;
874178825Sdfr
875178825Sdfr    one = &ctx->req->requestList.val[ctx->req->requestList.len];
876178825Sdfr    memset(one, 0, sizeof(*one));
877178825Sdfr
878178825Sdfr    _hx509_query_clear(&q);
879178825Sdfr
880178825Sdfr    q.match |= HX509_QUERY_FIND_ISSUER_CERT;
881178825Sdfr    q.subject = c;
882178825Sdfr
883178825Sdfr    ret = hx509_certs_find(context, ctx->certs, &q, &parent);
884178825Sdfr    if (ret)
885178825Sdfr	goto out;
886178825Sdfr
887178825Sdfr    if (ctx->parent) {
888178825Sdfr	if (hx509_cert_cmp(ctx->parent, parent) != 0) {
889178825Sdfr	    ret = HX509_REVOKE_NOT_SAME_PARENT;
890178825Sdfr	    hx509_set_error_string(context, 0, ret,
891178825Sdfr				   "Not same parent certifate as "
892178825Sdfr				   "last certificate in request");
893178825Sdfr	    goto out;
894178825Sdfr	}
895178825Sdfr    } else
896178825Sdfr	ctx->parent = hx509_cert_ref(parent);
897178825Sdfr
898178825Sdfr    p = _hx509_get_cert(parent);
899178825Sdfr
900178825Sdfr    ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
901178825Sdfr    if (ret)
902178825Sdfr	goto out;
903178825Sdfr
904178825Sdfr    ret = _hx509_create_signature(context,
905178825Sdfr				  NULL,
906178825Sdfr				  &one->reqCert.hashAlgorithm,
907178825Sdfr				  &c->tbsCertificate.issuer._save,
908178825Sdfr				  NULL,
909178825Sdfr				  &one->reqCert.issuerNameHash);
910178825Sdfr    if (ret)
911178825Sdfr	goto out;
912178825Sdfr
913178825Sdfr    os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
914178825Sdfr    os.length =
915178825Sdfr	p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
916178825Sdfr
917178825Sdfr    ret = _hx509_create_signature(context,
918178825Sdfr				  NULL,
919178825Sdfr				  &one->reqCert.hashAlgorithm,
920178825Sdfr				  &os,
921178825Sdfr				  NULL,
922178825Sdfr				  &one->reqCert.issuerKeyHash);
923178825Sdfr    if (ret)
924178825Sdfr	goto out;
925178825Sdfr
926178825Sdfr    ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
927178825Sdfr				       &one->reqCert.serialNumber);
928178825Sdfr    if (ret)
929178825Sdfr	goto out;
930178825Sdfr
931178825Sdfr    ctx->req->requestList.len++;
932178825Sdfrout:
933178825Sdfr    hx509_cert_free(parent);
934178825Sdfr    if (ret) {
935178825Sdfr	free_OCSPInnerRequest(one);
936178825Sdfr	memset(one, 0, sizeof(*one));
937178825Sdfr    }
938178825Sdfr
939178825Sdfr    return ret;
940178825Sdfr}
941178825Sdfr
942178825Sdfr/**
943178825Sdfr * Create an OCSP request for a set of certificates.
944178825Sdfr *
945178825Sdfr * @param context a hx509 context
946178825Sdfr * @param reqcerts list of certificates to request ocsp data for
947178825Sdfr * @param pool certificate pool to use when signing
948178825Sdfr * @param signer certificate to use to sign the request
949178825Sdfr * @param digest the signing algorithm in the request, if NULL use the
950178825Sdfr * default signature algorithm,
951178825Sdfr * @param request the encoded request, free with free_heim_octet_string().
952178825Sdfr * @param nonce nonce in the request, free with free_heim_octet_string().
953178825Sdfr *
954178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
955178825Sdfr *
956178825Sdfr * @ingroup hx509_revoke
957178825Sdfr */
958178825Sdfr
959178825Sdfrint
960178825Sdfrhx509_ocsp_request(hx509_context context,
961178825Sdfr		   hx509_certs reqcerts,
962178825Sdfr		   hx509_certs pool,
963178825Sdfr		   hx509_cert signer,
964178825Sdfr		   const AlgorithmIdentifier *digest,
965178825Sdfr		   heim_octet_string *request,
966178825Sdfr		   heim_octet_string *nonce)
967178825Sdfr{
968178825Sdfr    OCSPRequest req;
969178825Sdfr    size_t size;
970178825Sdfr    int ret;
971178825Sdfr    struct ocsp_add_ctx ctx;
972178825Sdfr    Extensions *es;
973178825Sdfr
974178825Sdfr    memset(&req, 0, sizeof(req));
975178825Sdfr
976178825Sdfr    if (digest == NULL)
977178825Sdfr	digest = _hx509_crypto_default_digest_alg;
978178825Sdfr
979178825Sdfr    ctx.req = &req.tbsRequest;
980178825Sdfr    ctx.certs = pool;
981178825Sdfr    ctx.digest = digest;
982178825Sdfr    ctx.parent = NULL;
983178825Sdfr
984178825Sdfr    ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx);
985178825Sdfr    hx509_cert_free(ctx.parent);
986178825Sdfr    if (ret)
987178825Sdfr	goto out;
988178825Sdfr
989178825Sdfr    if (nonce) {
990178825Sdfr	req.tbsRequest.requestExtensions =
991178825Sdfr	    calloc(1, sizeof(*req.tbsRequest.requestExtensions));
992178825Sdfr	if (req.tbsRequest.requestExtensions == NULL) {
993178825Sdfr	    ret = ENOMEM;
994178825Sdfr	    goto out;
995178825Sdfr	}
996178825Sdfr
997178825Sdfr	es = req.tbsRequest.requestExtensions;
998178825Sdfr
999178825Sdfr	es->val = calloc(es->len, sizeof(es->val[0]));
1000178825Sdfr	if (es->val == NULL) {
1001178825Sdfr	    ret = ENOMEM;
1002178825Sdfr	    goto out;
1003178825Sdfr	}
1004178825Sdfr	es->len = 1;
1005178825Sdfr
1006178825Sdfr	ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID);
1007178825Sdfr	if (ret) {
1008178825Sdfr	    free_OCSPRequest(&req);
1009178825Sdfr	    return ret;
1010178825Sdfr	}
1011178825Sdfr
1012178825Sdfr	es->val[0].extnValue.data = malloc(10);
1013178825Sdfr	if (es->val[0].extnValue.data == NULL) {
1014178825Sdfr	    ret = ENOMEM;
1015178825Sdfr	    goto out;
1016178825Sdfr	}
1017178825Sdfr	es->val[0].extnValue.length = 10;
1018178825Sdfr
1019178825Sdfr	ret = RAND_bytes(es->val[0].extnValue.data,
1020178825Sdfr			 es->val[0].extnValue.length);
1021178825Sdfr	if (ret != 1) {
1022178825Sdfr	    ret = HX509_CRYPTO_INTERNAL_ERROR;
1023178825Sdfr	    goto out;
1024178825Sdfr	}
1025178825Sdfr	ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1026178825Sdfr	if (ret) {
1027178825Sdfr	    ret = ENOMEM;
1028178825Sdfr	    goto out;
1029178825Sdfr	}
1030178825Sdfr    }
1031178825Sdfr
1032178825Sdfr    ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1033178825Sdfr		       &req, &size, ret);
1034178825Sdfr    free_OCSPRequest(&req);
1035178825Sdfr    if (ret)
1036178825Sdfr	goto out;
1037178825Sdfr    if (size != request->length)
1038178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
1039178825Sdfr
1040178825Sdfr    return 0;
1041178825Sdfr
1042178825Sdfrout:
1043178825Sdfr    free_OCSPRequest(&req);
1044178825Sdfr    return ret;
1045178825Sdfr}
1046178825Sdfr
1047178825Sdfrstatic char *
1048178825Sdfrprintable_time(time_t t)
1049178825Sdfr{
1050178825Sdfr    static char s[128];
1051178825Sdfr    strlcpy(s, ctime(&t)+ 4, sizeof(s));
1052178825Sdfr    s[20] = 0;
1053178825Sdfr    return s;
1054178825Sdfr}
1055178825Sdfr
1056178825Sdfr/**
1057178825Sdfr * Print the OCSP reply stored in a file.
1058178825Sdfr *
1059178825Sdfr * @param context a hx509 context
1060178825Sdfr * @param path path to a file with a OCSP reply
1061178825Sdfr * @param out the out FILE descriptor to print the reply on
1062178825Sdfr *
1063178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1064178825Sdfr *
1065178825Sdfr * @ingroup hx509_revoke
1066178825Sdfr */
1067178825Sdfr
1068178825Sdfrint
1069178825Sdfrhx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
1070178825Sdfr{
1071178825Sdfr    struct revoke_ocsp ocsp;
1072178825Sdfr    int ret, i;
1073178825Sdfr
1074178825Sdfr    if (out == NULL)
1075178825Sdfr	out = stdout;
1076178825Sdfr
1077178825Sdfr    memset(&ocsp, 0, sizeof(ocsp));
1078178825Sdfr
1079178825Sdfr    ocsp.path = strdup(path);
1080178825Sdfr    if (ocsp.path == NULL)
1081178825Sdfr	return ENOMEM;
1082178825Sdfr
1083178825Sdfr    ret = load_ocsp(context, &ocsp);
1084178825Sdfr    if (ret) {
1085178825Sdfr	free_ocsp(&ocsp);
1086178825Sdfr	return ret;
1087178825Sdfr    }
1088178825Sdfr
1089178825Sdfr    fprintf(out, "signer: ");
1090178825Sdfr
1091178825Sdfr    switch(ocsp.ocsp.tbsResponseData.responderID.element) {
1092178825Sdfr    case choice_OCSPResponderID_byName: {
1093178825Sdfr	hx509_name n;
1094178825Sdfr	char *s;
1095178825Sdfr	_hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
1096178825Sdfr	hx509_name_to_string(n, &s);
1097178825Sdfr	hx509_name_free(&n);
1098178825Sdfr	fprintf(out, " byName: %s\n", s);
1099178825Sdfr	free(s);
1100178825Sdfr	break;
1101178825Sdfr    }
1102178825Sdfr    case choice_OCSPResponderID_byKey: {
1103178825Sdfr	char *s;
1104178825Sdfr	hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
1105178825Sdfr		   ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
1106178825Sdfr		   &s);
1107178825Sdfr	fprintf(out, " byKey: %s\n", s);
1108178825Sdfr	free(s);
1109178825Sdfr	break;
1110178825Sdfr    }
1111178825Sdfr    default:
1112178825Sdfr	_hx509_abort("choice_OCSPResponderID unknown");
1113178825Sdfr	break;
1114178825Sdfr    }
1115178825Sdfr
1116178825Sdfr    fprintf(out, "producedAt: %s\n",
1117178825Sdfr	    printable_time(ocsp.ocsp.tbsResponseData.producedAt));
1118178825Sdfr
1119178825Sdfr    fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
1120178825Sdfr
1121178825Sdfr    for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
1122178825Sdfr	const char *status;
1123178825Sdfr	switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1124178825Sdfr	case choice_OCSPCertStatus_good:
1125178825Sdfr	    status = "good";
1126178825Sdfr	    break;
1127178825Sdfr	case choice_OCSPCertStatus_revoked:
1128178825Sdfr	    status = "revoked";
1129178825Sdfr	    break;
1130178825Sdfr	case choice_OCSPCertStatus_unknown:
1131178825Sdfr	    status = "unknown";
1132178825Sdfr	    break;
1133178825Sdfr	default:
1134178825Sdfr	    status = "element unknown";
1135178825Sdfr	}
1136178825Sdfr
1137178825Sdfr	fprintf(out, "\t%d. status: %s\n", i, status);
1138178825Sdfr
1139178825Sdfr	fprintf(out, "\tthisUpdate: %s\n",
1140178825Sdfr		printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1141178825Sdfr	if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
1142178825Sdfr	    fprintf(out, "\tproducedAt: %s\n",
1143178825Sdfr		    printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1144178825Sdfr
1145178825Sdfr    }
1146178825Sdfr
1147178825Sdfr    fprintf(out, "appended certs:\n");
1148178825Sdfr    if (ocsp.certs)
1149178825Sdfr	ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out);
1150178825Sdfr
1151178825Sdfr    free_ocsp(&ocsp);
1152178825Sdfr    return ret;
1153178825Sdfr}
1154178825Sdfr
1155178825Sdfr/**
1156178825Sdfr * Verify that the certificate is part of the OCSP reply and it's not
1157178825Sdfr * expired. Doesn't verify signature the OCSP reply or it's done by a
1158178825Sdfr * authorized sender, that is assumed to be already done.
1159178825Sdfr *
1160178825Sdfr * @param context a hx509 context
1161178825Sdfr * @param now the time right now, if 0, use the current time.
1162178825Sdfr * @param cert the certificate to verify
1163178825Sdfr * @param flags flags control the behavior
1164178825Sdfr * @param data pointer to the encode ocsp reply
1165178825Sdfr * @param length the length of the encode ocsp reply
1166178825Sdfr * @param expiration return the time the OCSP will expire and need to
1167178825Sdfr * be rechecked.
1168178825Sdfr *
1169178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1170178825Sdfr *
1171178825Sdfr * @ingroup hx509_verify
1172178825Sdfr */
1173178825Sdfr
1174178825Sdfrint
1175178825Sdfrhx509_ocsp_verify(hx509_context context,
1176178825Sdfr		  time_t now,
1177178825Sdfr		  hx509_cert cert,
1178178825Sdfr		  int flags,
1179178825Sdfr		  const void *data, size_t length,
1180178825Sdfr		  time_t *expiration)
1181178825Sdfr{
1182178825Sdfr    const Certificate *c = _hx509_get_cert(cert);
1183178825Sdfr    OCSPBasicOCSPResponse basic;
1184178825Sdfr    int ret, i;
1185178825Sdfr
1186178825Sdfr    if (now == 0)
1187178825Sdfr	now = time(NULL);
1188178825Sdfr
1189178825Sdfr    *expiration = 0;
1190178825Sdfr
1191178825Sdfr    ret = parse_ocsp_basic(data, length, &basic);
1192178825Sdfr    if (ret) {
1193178825Sdfr	hx509_set_error_string(context, 0, ret,
1194178825Sdfr			       "Failed to parse OCSP response");
1195178825Sdfr	return ret;
1196178825Sdfr    }
1197178825Sdfr
1198178825Sdfr    for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1199178825Sdfr
1200178825Sdfr	ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1201178825Sdfr			       &c->tbsCertificate.serialNumber);
1202178825Sdfr	if (ret != 0)
1203178825Sdfr	    continue;
1204178825Sdfr
1205178825Sdfr	/* verify issuer hashes hash */
1206178825Sdfr	ret = _hx509_verify_signature(context,
1207178825Sdfr				      NULL,
1208178825Sdfr				      &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1209178825Sdfr				      &c->tbsCertificate.issuer._save,
1210178825Sdfr				      &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1211178825Sdfr	if (ret != 0)
1212178825Sdfr	    continue;
1213178825Sdfr
1214178825Sdfr	switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1215178825Sdfr	case choice_OCSPCertStatus_good:
1216178825Sdfr	    break;
1217178825Sdfr	case choice_OCSPCertStatus_revoked:
1218178825Sdfr	case choice_OCSPCertStatus_unknown:
1219178825Sdfr	    continue;
1220178825Sdfr	}
1221178825Sdfr
1222178825Sdfr	/* don't allow the update to be in the future */
1223178825Sdfr	if (basic.tbsResponseData.responses.val[i].thisUpdate >
1224178825Sdfr	    now + context->ocsp_time_diff)
1225178825Sdfr	    continue;
1226178825Sdfr
1227178825Sdfr	/* don't allow the next update to be in the past */
1228178825Sdfr	if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1229178825Sdfr	    if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1230178825Sdfr		continue;
1231178825Sdfr	    *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1232178825Sdfr	} else
1233178825Sdfr	    *expiration = now;
1234178825Sdfr
1235178825Sdfr	free_OCSPBasicOCSPResponse(&basic);
1236178825Sdfr	return 0;
1237178825Sdfr    }
1238178825Sdfr
1239178825Sdfr    free_OCSPBasicOCSPResponse(&basic);
1240178825Sdfr
1241178825Sdfr    {
1242178825Sdfr	hx509_name name;
1243178825Sdfr	char *subject;
1244178825Sdfr
1245178825Sdfr	ret = hx509_cert_get_subject(cert, &name);
1246178825Sdfr	if (ret) {
1247178825Sdfr	    hx509_clear_error_string(context);
1248178825Sdfr	    goto out;
1249178825Sdfr	}
1250178825Sdfr	ret = hx509_name_to_string(name, &subject);
1251178825Sdfr	hx509_name_free(&name);
1252178825Sdfr	if (ret) {
1253178825Sdfr	    hx509_clear_error_string(context);
1254178825Sdfr	    goto out;
1255178825Sdfr	}
1256178825Sdfr	hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
1257178825Sdfr			       "Certificate %s not in OCSP response "
1258178825Sdfr			       "or not good",
1259178825Sdfr			       subject);
1260178825Sdfr	free(subject);
1261178825Sdfr    }
1262178825Sdfrout:
1263178825Sdfr    return HX509_CERT_NOT_IN_OCSP;
1264178825Sdfr}
1265178825Sdfr
1266178825Sdfrstruct hx509_crl {
1267178825Sdfr    hx509_certs revoked;
1268178825Sdfr    time_t expire;
1269178825Sdfr};
1270178825Sdfr
1271178825Sdfr/**
1272178825Sdfr * Create a CRL context. Use hx509_crl_free() to free the CRL context.
1273178825Sdfr *
1274178825Sdfr * @param context a hx509 context.
1275178825Sdfr * @param crl return pointer to a newly allocated CRL context.
1276178825Sdfr *
1277178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1278178825Sdfr *
1279178825Sdfr * @ingroup hx509_verify
1280178825Sdfr */
1281178825Sdfr
1282178825Sdfrint
1283178825Sdfrhx509_crl_alloc(hx509_context context, hx509_crl *crl)
1284178825Sdfr{
1285178825Sdfr    int ret;
1286178825Sdfr
1287178825Sdfr    *crl = calloc(1, sizeof(**crl));
1288178825Sdfr    if (*crl == NULL) {
1289178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1290178825Sdfr	return ENOMEM;
1291178825Sdfr    }
1292178825Sdfr
1293178825Sdfr    ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1294178825Sdfr    if (ret) {
1295178825Sdfr	free(*crl);
1296178825Sdfr	*crl = NULL;
1297178825Sdfr	return ret;
1298178825Sdfr    }
1299178825Sdfr    (*crl)->expire = 0;
1300178825Sdfr    return ret;
1301178825Sdfr}
1302178825Sdfr
1303178825Sdfr/**
1304178825Sdfr * Add revoked certificate to an CRL context.
1305178825Sdfr *
1306178825Sdfr * @param context a hx509 context.
1307178825Sdfr * @param crl the CRL to add the revoked certificate to.
1308178825Sdfr * @param certs keyset of certificate to revoke.
1309178825Sdfr *
1310178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1311178825Sdfr *
1312178825Sdfr * @ingroup hx509_verify
1313178825Sdfr */
1314178825Sdfr
1315178825Sdfrint
1316178825Sdfrhx509_crl_add_revoked_certs(hx509_context context,
1317178825Sdfr			    hx509_crl crl,
1318178825Sdfr			    hx509_certs certs)
1319178825Sdfr{
1320178825Sdfr    return hx509_certs_merge(context, crl->revoked, certs);
1321178825Sdfr}
1322178825Sdfr
1323178825Sdfr/**
1324178825Sdfr * Set the lifetime of a CRL context.
1325178825Sdfr *
1326178825Sdfr * @param context a hx509 context.
1327178825Sdfr * @param crl a CRL context
1328178825Sdfr * @param delta delta time the certificate is valid, library adds the
1329178825Sdfr * current time to this.
1330178825Sdfr *
1331178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1332178825Sdfr *
1333178825Sdfr * @ingroup hx509_verify
1334178825Sdfr */
1335178825Sdfr
1336178825Sdfrint
1337178825Sdfrhx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1338178825Sdfr{
1339178825Sdfr    crl->expire = time(NULL) + delta;
1340178825Sdfr    return 0;
1341178825Sdfr}
1342178825Sdfr
1343178825Sdfr/**
1344178825Sdfr * Free a CRL context.
1345178825Sdfr *
1346178825Sdfr * @param context a hx509 context.
1347178825Sdfr * @param crl a CRL context to free.
1348178825Sdfr *
1349178825Sdfr * @ingroup hx509_verify
1350178825Sdfr */
1351178825Sdfr
1352178825Sdfrvoid
1353178825Sdfrhx509_crl_free(hx509_context context, hx509_crl *crl)
1354178825Sdfr{
1355178825Sdfr    if (*crl == NULL)
1356178825Sdfr	return;
1357178825Sdfr    hx509_certs_free(&(*crl)->revoked);
1358178825Sdfr    memset(*crl, 0, sizeof(**crl));
1359178825Sdfr    free(*crl);
1360178825Sdfr    *crl = NULL;
1361178825Sdfr}
1362178825Sdfr
1363178825Sdfrstatic int
1364178825Sdfradd_revoked(hx509_context context, void *ctx, hx509_cert cert)
1365178825Sdfr{
1366178825Sdfr    TBSCRLCertList *c = ctx;
1367178825Sdfr    unsigned int num;
1368178825Sdfr    void *ptr;
1369178825Sdfr    int ret;
1370178825Sdfr
1371178825Sdfr    num = c->revokedCertificates->len;
1372178825Sdfr    ptr = realloc(c->revokedCertificates->val,
1373178825Sdfr		  (num + 1) * sizeof(c->revokedCertificates->val[0]));
1374178825Sdfr    if (ptr == NULL) {
1375178825Sdfr	hx509_clear_error_string(context);
1376178825Sdfr	return ENOMEM;
1377178825Sdfr    }
1378178825Sdfr    c->revokedCertificates->val = ptr;
1379178825Sdfr
1380178825Sdfr    ret = hx509_cert_get_serialnumber(cert,
1381178825Sdfr				      &c->revokedCertificates->val[num].userCertificate);
1382178825Sdfr    if (ret) {
1383178825Sdfr	hx509_clear_error_string(context);
1384178825Sdfr	return ret;
1385178825Sdfr    }
1386178825Sdfr    c->revokedCertificates->val[num].revocationDate.element =
1387178825Sdfr	choice_Time_generalTime;
1388178825Sdfr    c->revokedCertificates->val[num].revocationDate.u.generalTime =
1389178825Sdfr	time(NULL) - 3600 * 24;
1390178825Sdfr    c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1391178825Sdfr
1392178825Sdfr    c->revokedCertificates->len++;
1393178825Sdfr
1394178825Sdfr    return 0;
1395178825Sdfr}
1396178825Sdfr
1397178825Sdfr/**
1398178825Sdfr * Sign a CRL and return an encode certificate.
1399178825Sdfr *
1400178825Sdfr * @param context a hx509 context.
1401178825Sdfr * @param signer certificate to sign the CRL with
1402178825Sdfr * @param crl the CRL to sign
1403178825Sdfr * @param os return the signed and encoded CRL, free with
1404178825Sdfr * free_heim_octet_string()
1405178825Sdfr *
1406178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1407178825Sdfr *
1408178825Sdfr * @ingroup hx509_verify
1409178825Sdfr */
1410178825Sdfr
1411178825Sdfrint
1412178825Sdfrhx509_crl_sign(hx509_context context,
1413178825Sdfr	       hx509_cert signer,
1414178825Sdfr	       hx509_crl crl,
1415178825Sdfr	       heim_octet_string *os)
1416178825Sdfr{
1417178825Sdfr    const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
1418178825Sdfr    CRLCertificateList c;
1419178825Sdfr    size_t size;
1420178825Sdfr    int ret;
1421178825Sdfr    hx509_private_key signerkey;
1422178825Sdfr
1423178825Sdfr    memset(&c, 0, sizeof(c));
1424178825Sdfr
1425178825Sdfr    signerkey = _hx509_cert_private_key(signer);
1426178825Sdfr    if (signerkey == NULL) {
1427178825Sdfr	ret = HX509_PRIVATE_KEY_MISSING;
1428178825Sdfr	hx509_set_error_string(context, 0, ret,
1429178825Sdfr			       "Private key missing for CRL signing");
1430178825Sdfr	return ret;
1431178825Sdfr    }
1432178825Sdfr
1433178825Sdfr    c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1434178825Sdfr    if (c.tbsCertList.version == NULL) {
1435178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1436178825Sdfr	return ENOMEM;
1437178825Sdfr    }
1438178825Sdfr
1439178825Sdfr    *c.tbsCertList.version = 1;
1440178825Sdfr
1441178825Sdfr    ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1442178825Sdfr    if (ret) {
1443178825Sdfr	hx509_clear_error_string(context);
1444178825Sdfr	goto out;
1445178825Sdfr    }
1446178825Sdfr
1447178825Sdfr    ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1448178825Sdfr		    &c.tbsCertList.issuer);
1449178825Sdfr    if (ret) {
1450178825Sdfr	hx509_clear_error_string(context);
1451178825Sdfr	goto out;
1452178825Sdfr    }
1453178825Sdfr
1454178825Sdfr    c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1455178825Sdfr    c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1456178825Sdfr
1457178825Sdfr    c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1458178825Sdfr    if (c.tbsCertList.nextUpdate == NULL) {
1459178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1460178825Sdfr	ret = ENOMEM;
1461178825Sdfr	goto out;
1462178825Sdfr    }
1463178825Sdfr
1464178825Sdfr    {
1465178825Sdfr	time_t next = crl->expire;
1466178825Sdfr	if (next == 0)
1467178825Sdfr	    next = time(NULL) + 24 * 3600 * 365;
1468178825Sdfr
1469178825Sdfr	c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1470178825Sdfr	c.tbsCertList.nextUpdate->u.generalTime = next;
1471178825Sdfr    }
1472178825Sdfr
1473178825Sdfr    c.tbsCertList.revokedCertificates =
1474178825Sdfr	calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1475178825Sdfr    if (c.tbsCertList.revokedCertificates == NULL) {
1476178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1477178825Sdfr	ret = ENOMEM;
1478178825Sdfr	goto out;
1479178825Sdfr    }
1480178825Sdfr    c.tbsCertList.crlExtensions = NULL;
1481178825Sdfr
1482178825Sdfr    ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList);
1483178825Sdfr    if (ret)
1484178825Sdfr	goto out;
1485178825Sdfr
1486178825Sdfr    /* if not revoked certs, remove OPTIONAL entry */
1487178825Sdfr    if (c.tbsCertList.revokedCertificates->len == 0) {
1488178825Sdfr	free(c.tbsCertList.revokedCertificates);
1489178825Sdfr	c.tbsCertList.revokedCertificates = NULL;
1490178825Sdfr    }
1491178825Sdfr
1492178825Sdfr    ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1493178825Sdfr		       &c.tbsCertList, &size, ret);
1494178825Sdfr    if (ret) {
1495178825Sdfr	hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1496178825Sdfr	goto out;
1497178825Sdfr    }
1498178825Sdfr    if (size != os->length)
1499178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
1500178825Sdfr
1501178825Sdfr
1502178825Sdfr    ret = _hx509_create_signature_bitstring(context,
1503178825Sdfr					    signerkey,
1504178825Sdfr					    sigalg,
1505178825Sdfr					    os,
1506178825Sdfr					    &c.signatureAlgorithm,
1507178825Sdfr					    &c.signatureValue);
1508178825Sdfr    free(os->data);
1509178825Sdfr
1510178825Sdfr    ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1511178825Sdfr		       &c, &size, ret);
1512178825Sdfr    free_CRLCertificateList(&c);
1513178825Sdfr    if (ret) {
1514178825Sdfr	hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1515178825Sdfr	goto out;
1516178825Sdfr    }
1517178825Sdfr    if (size != os->length)
1518178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
1519178825Sdfr
1520178825Sdfr    return 0;
1521178825Sdfr
1522178825Sdfrout:
1523178825Sdfr    free_CRLCertificateList(&c);
1524178825Sdfr    return ret;
1525178825Sdfr}
1526