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