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