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 revokation context. Free with hx509_revoke_free().
85 : *
86 : * @param context A hx509 context.
87 : * @param ctx returns a newly allocated revokation context.
88 : *
89 : * @return An hx509 error code, see hx509_get_error_string().
90 : *
91 : * @ingroup hx509_revoke
92 : */
93 :
94 : HX509_LIB_FUNCTION int HX509_LIB_CALL
95 0 : hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
96 : {
97 0 : *ctx = calloc(1, sizeof(**ctx));
98 0 : if (*ctx == NULL)
99 0 : return ENOMEM;
100 :
101 0 : (*ctx)->ref = 1;
102 0 : (*ctx)->crls.len = 0;
103 0 : (*ctx)->crls.val = NULL;
104 0 : (*ctx)->ocsps.len = 0;
105 0 : (*ctx)->ocsps.val = NULL;
106 :
107 0 : return 0;
108 : }
109 :
110 : HX509_LIB_FUNCTION hx509_revoke_ctx HX509_LIB_CALL
111 115 : _hx509_revoke_ref(hx509_revoke_ctx ctx)
112 : {
113 115 : if (ctx == NULL)
114 115 : return NULL;
115 0 : if (ctx->ref == 0)
116 0 : _hx509_abort("revoke ctx refcount == 0 on ref");
117 0 : ctx->ref++;
118 0 : if (ctx->ref == UINT_MAX)
119 0 : _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
120 0 : 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 revokation 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 110 : hx509_revoke_free(hx509_revoke_ctx *ctx)
142 : {
143 : size_t i ;
144 :
145 110 : if (ctx == NULL || *ctx == NULL)
146 110 : return;
147 :
148 0 : if ((*ctx)->ref == 0)
149 0 : _hx509_abort("revoke ctx refcount == 0 on free");
150 0 : if (--(*ctx)->ref > 0)
151 0 : 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 : hx509_query q;
178 : 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, lets check the
212 : * it is the CA that signed the signer certificate and 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 : OCSPResponse resp;
272 : size_t size;
273 : 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 : OCSPBasicOCSPResponse basic;
331 0 : hx509_certs certs = NULL;
332 : size_t length;
333 : struct stat sb;
334 : void *data;
335 : 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 : 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 : 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 revokation context.
394 : *
395 : * @param context hx509 context
396 : * @param ctx hx509 revokation 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 : void *data;
410 : int ret;
411 : size_t i;
412 :
413 0 : if (strncmp(path, "FILE:", 5) != 0) {
414 0 : hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
415 : "unsupport 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 0 : 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 : hx509_cert signer;
467 : hx509_query q;
468 : time_t t;
469 : int ret;
470 :
471 0 : t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
472 0 : 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 0 : 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 0 : t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
485 0 : 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 0 : _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 0 : if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
498 0 : 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 0 : ret = _hx509_verify_signature_bitstring(context,
515 : signer,
516 0 : &crl->signatureAlgorithm,
517 0 : &crl->tbsCertList._save,
518 0 : &crl->signatureValue);
519 0 : 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 hve CERTSIGN flag
529 : * set.
530 : */
531 0 : while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
532 : 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 0 : out:
564 0 : hx509_cert_free(signer);
565 :
566 0 : return ret;
567 : }
568 :
569 : static int
570 0 : 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 0 : CRLCertificateList *crl = (CRLCertificateList *)ctx;
575 : size_t size;
576 : int ret;
577 :
578 0 : if (strcasecmp("X509 CRL", type) != 0)
579 0 : return HX509_CRYPTO_SIG_INVALID_FORMAT;
580 :
581 0 : ret = decode_CRLCertificateList(data, len, crl, &size);
582 0 : if (ret)
583 0 : return ret;
584 :
585 : /* check signature is aligned */
586 0 : if (crl->signatureValue.length & 7) {
587 0 : free_CRLCertificateList(crl);
588 0 : return HX509_CRYPTO_SIG_INVALID_FORMAT;
589 : }
590 :
591 0 : return 0;
592 : }
593 :
594 : static int
595 0 : load_crl(hx509_context context, const char *path, time_t *t, CRLCertificateList *crl)
596 : {
597 : struct stat sb;
598 : size_t length;
599 : void *data;
600 : FILE *f;
601 : int ret;
602 :
603 0 : memset(crl, 0, sizeof(*crl));
604 :
605 0 : ret = stat(path, &sb);
606 0 : if (ret)
607 0 : return errno;
608 :
609 0 : *t = sb.st_mtime;
610 :
611 0 : if ((f = fopen(path, "r")) == NULL)
612 0 : return errno;
613 :
614 0 : rk_cloexec_file(f);
615 :
616 0 : ret = hx509_pem_read(context, f, crl_parser, crl);
617 0 : fclose(f);
618 :
619 0 : if (ret == HX509_PARSING_KEY_FAILED) {
620 :
621 0 : ret = rk_undumpdata(path, &data, &length);
622 0 : if (ret)
623 0 : return ret;
624 :
625 0 : ret = crl_parser(context, "X509 CRL", NULL, data, length, crl);
626 0 : rk_xfree(data);
627 : }
628 0 : return ret;
629 : }
630 :
631 : /**
632 : * Add a CRL file to the revokation context.
633 : *
634 : * @param context hx509 context
635 : * @param ctx hx509 revokation context
636 : * @param path path to file that is going to be added to the context.
637 : *
638 : * @return An hx509 error code, see hx509_get_error_string().
639 : *
640 : * @ingroup hx509_revoke
641 : */
642 :
643 : HX509_LIB_FUNCTION int HX509_LIB_CALL
644 0 : hx509_revoke_add_crl(hx509_context context,
645 : hx509_revoke_ctx ctx,
646 : const char *path)
647 : {
648 : void *data;
649 : size_t i;
650 : int ret;
651 :
652 0 : if (strncmp(path, "FILE:", 5) != 0) {
653 0 : hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
654 : "unsupported type in %s", path);
655 0 : return HX509_UNSUPPORTED_OPERATION;
656 : }
657 :
658 :
659 0 : path += 5;
660 :
661 0 : for (i = 0; i < ctx->crls.len; i++) {
662 0 : if (strcmp(ctx->crls.val[i].path, path) == 0)
663 0 : return 0;
664 : }
665 :
666 0 : data = realloc(ctx->crls.val,
667 0 : (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
668 0 : if (data == NULL) {
669 0 : hx509_clear_error_string(context);
670 0 : return ENOMEM;
671 : }
672 0 : ctx->crls.val = data;
673 :
674 0 : memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
675 :
676 0 : ctx->crls.val[ctx->crls.len].path = strdup(path);
677 0 : if (ctx->crls.val[ctx->crls.len].path == NULL) {
678 0 : hx509_clear_error_string(context);
679 0 : return ENOMEM;
680 : }
681 :
682 0 : ret = load_crl(context,
683 : path,
684 0 : &ctx->crls.val[ctx->crls.len].last_modfied,
685 0 : &ctx->crls.val[ctx->crls.len].crl);
686 0 : if (ret) {
687 0 : free(ctx->crls.val[ctx->crls.len].path);
688 0 : return ret;
689 : }
690 :
691 0 : ctx->crls.len++;
692 :
693 0 : return ret;
694 : }
695 :
696 : /**
697 : * Check that a certificate is not expired according to a revokation
698 : * context. Also need the parent certificte to the check OCSP
699 : * parent identifier.
700 : *
701 : * @param context hx509 context
702 : * @param ctx hx509 revokation context
703 : * @param certs
704 : * @param now
705 : * @param cert
706 : * @param parent_cert
707 : *
708 : * @return An hx509 error code, see hx509_get_error_string().
709 : *
710 : * @ingroup hx509_revoke
711 : */
712 :
713 : HX509_LIB_FUNCTION int HX509_LIB_CALL
714 0 : hx509_revoke_verify(hx509_context context,
715 : hx509_revoke_ctx ctx,
716 : hx509_certs certs,
717 : time_t now,
718 : hx509_cert cert,
719 : hx509_cert parent_cert)
720 : {
721 0 : const Certificate *c = _hx509_get_cert(cert);
722 0 : const Certificate *p = _hx509_get_cert(parent_cert);
723 : unsigned long i, j, k;
724 : int ret;
725 :
726 0 : hx509_clear_error_string(context);
727 :
728 0 : for (i = 0; i < ctx->ocsps.len; i++) {
729 0 : struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
730 : struct stat sb;
731 :
732 : /* check this ocsp apply to this cert */
733 :
734 : /* check if there is a newer version of the file */
735 0 : ret = stat(ocsp->path, &sb);
736 0 : if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
737 0 : ret = load_ocsp(context, ocsp);
738 0 : if (ret)
739 0 : continue;
740 : }
741 :
742 : /* verify signature in ocsp if not already done */
743 0 : if (ocsp->signer == NULL) {
744 0 : ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
745 0 : if (ret)
746 0 : continue;
747 : }
748 :
749 0 : for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
750 : heim_octet_string os;
751 :
752 0 : ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
753 0 : &c->tbsCertificate.serialNumber);
754 0 : if (ret != 0)
755 0 : continue;
756 :
757 : /* verify issuer hashes hash */
758 0 : ret = _hx509_verify_signature(context,
759 : NULL,
760 0 : &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
761 : &c->tbsCertificate.issuer._save,
762 0 : &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
763 0 : if (ret != 0)
764 0 : continue;
765 :
766 0 : os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
767 0 : os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
768 :
769 0 : ret = _hx509_verify_signature(context,
770 : NULL,
771 0 : &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
772 : &os,
773 0 : &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
774 0 : if (ret != 0)
775 0 : continue;
776 :
777 0 : switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
778 0 : case choice_OCSPCertStatus_good:
779 0 : break;
780 0 : case choice_OCSPCertStatus_revoked:
781 0 : hx509_set_error_string(context, 0,
782 : HX509_CERT_REVOKED,
783 : "Certificate revoked by issuer in OCSP");
784 0 : return HX509_CERT_REVOKED;
785 0 : case choice_OCSPCertStatus_unknown:
786 0 : continue;
787 : }
788 :
789 : /* don't allow the update to be in the future */
790 0 : if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
791 0 : now + context->ocsp_time_diff)
792 0 : continue;
793 :
794 : /* don't allow the next update to be in the past */
795 0 : if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
796 0 : if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
797 0 : continue;
798 : } /* else should force a refetch, but can we ? */
799 :
800 0 : return 0;
801 : }
802 : }
803 :
804 0 : for (i = 0; i < ctx->crls.len; i++) {
805 0 : struct revoke_crl *crl = &ctx->crls.val[i];
806 : struct stat sb;
807 : int diff;
808 :
809 : /* check if cert.issuer == crls.val[i].crl.issuer */
810 0 : ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
811 0 : &crl->crl.tbsCertList.issuer, &diff);
812 0 : if (ret || diff)
813 0 : continue;
814 :
815 0 : ret = stat(crl->path, &sb);
816 0 : if (ret == 0 && crl->last_modfied != sb.st_mtime) {
817 : CRLCertificateList cl;
818 :
819 0 : ret = load_crl(context, crl->path, &crl->last_modfied, &cl);
820 0 : if (ret == 0) {
821 0 : free_CRLCertificateList(&crl->crl);
822 0 : crl->crl = cl;
823 0 : crl->verified = 0;
824 0 : crl->failed_verify = 0;
825 : }
826 : }
827 0 : if (crl->failed_verify)
828 0 : continue;
829 :
830 : /* verify signature in crl if not already done */
831 0 : if (crl->verified == 0) {
832 0 : ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
833 0 : if (ret) {
834 0 : crl->failed_verify = 1;
835 0 : continue;
836 : }
837 0 : crl->verified = 1;
838 : }
839 :
840 0 : if (crl->crl.tbsCertList.crlExtensions) {
841 0 : for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
842 0 : if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
843 0 : hx509_set_error_string(context, 0,
844 : HX509_CRL_UNKNOWN_EXTENSION,
845 : "Unknown CRL extension");
846 0 : return HX509_CRL_UNKNOWN_EXTENSION;
847 : }
848 : }
849 : }
850 :
851 0 : if (crl->crl.tbsCertList.revokedCertificates == NULL)
852 0 : return 0;
853 :
854 : /* check if cert is in crl */
855 0 : for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
856 : time_t t;
857 :
858 0 : ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
859 0 : &c->tbsCertificate.serialNumber);
860 0 : if (ret != 0)
861 0 : continue;
862 :
863 0 : t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
864 0 : if (t > now)
865 0 : continue;
866 :
867 0 : if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
868 0 : for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
869 0 : if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
870 0 : return HX509_CRL_UNKNOWN_EXTENSION;
871 :
872 0 : hx509_set_error_string(context, 0,
873 : HX509_CERT_REVOKED,
874 : "Certificate revoked by issuer in CRL");
875 0 : return HX509_CERT_REVOKED;
876 : }
877 :
878 0 : return 0;
879 : }
880 :
881 :
882 0 : if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
883 0 : return 0;
884 0 : hx509_set_error_string(context, HX509_ERROR_APPEND,
885 : HX509_REVOKE_STATUS_MISSING,
886 : "No revocation status found for certificates");
887 0 : return HX509_REVOKE_STATUS_MISSING;
888 : }
889 :
890 : struct ocsp_add_ctx {
891 : OCSPTBSRequest *req;
892 : hx509_certs certs;
893 : const AlgorithmIdentifier *digest;
894 : hx509_cert parent;
895 : };
896 :
897 : static int HX509_LIB_CALL
898 0 : add_to_req(hx509_context context, void *ptr, hx509_cert cert)
899 : {
900 0 : struct ocsp_add_ctx *ctx = ptr;
901 : OCSPInnerRequest *one;
902 0 : hx509_cert parent = NULL;
903 0 : Certificate *p, *c = _hx509_get_cert(cert);
904 : heim_octet_string os;
905 : int ret;
906 : hx509_query q;
907 : void *d;
908 :
909 0 : d = realloc(ctx->req->requestList.val,
910 : sizeof(ctx->req->requestList.val[0]) *
911 0 : (ctx->req->requestList.len + 1));
912 0 : if (d == NULL)
913 0 : return ENOMEM;
914 0 : ctx->req->requestList.val = d;
915 :
916 0 : one = &ctx->req->requestList.val[ctx->req->requestList.len];
917 0 : memset(one, 0, sizeof(*one));
918 :
919 0 : _hx509_query_clear(&q);
920 :
921 0 : q.match |= HX509_QUERY_FIND_ISSUER_CERT;
922 0 : q.subject = c;
923 :
924 0 : ret = hx509_certs_find(context, ctx->certs, &q, &parent);
925 0 : if (ret)
926 0 : goto out;
927 :
928 0 : if (ctx->parent) {
929 0 : if (hx509_cert_cmp(ctx->parent, parent) != 0) {
930 0 : ret = HX509_REVOKE_NOT_SAME_PARENT;
931 0 : hx509_set_error_string(context, 0, ret,
932 : "Not same parent certifate as "
933 : "last certificate in request");
934 0 : goto out;
935 : }
936 : } else
937 0 : ctx->parent = hx509_cert_ref(parent);
938 :
939 0 : p = _hx509_get_cert(parent);
940 :
941 0 : ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
942 0 : if (ret)
943 0 : goto out;
944 :
945 0 : ret = _hx509_create_signature(context,
946 : NULL,
947 0 : &one->reqCert.hashAlgorithm,
948 0 : &c->tbsCertificate.issuer._save,
949 : NULL,
950 : &one->reqCert.issuerNameHash);
951 0 : if (ret)
952 0 : goto out;
953 :
954 0 : os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
955 0 : os.length =
956 0 : p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
957 :
958 0 : ret = _hx509_create_signature(context,
959 : NULL,
960 0 : &one->reqCert.hashAlgorithm,
961 : &os,
962 : NULL,
963 : &one->reqCert.issuerKeyHash);
964 0 : if (ret)
965 0 : goto out;
966 :
967 0 : ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
968 : &one->reqCert.serialNumber);
969 0 : if (ret)
970 0 : goto out;
971 :
972 0 : ctx->req->requestList.len++;
973 0 : out:
974 0 : hx509_cert_free(parent);
975 0 : if (ret) {
976 0 : free_OCSPInnerRequest(one);
977 0 : memset(one, 0, sizeof(*one));
978 : }
979 :
980 0 : return ret;
981 : }
982 :
983 : /**
984 : * Create an OCSP request for a set of certificates.
985 : *
986 : * @param context a hx509 context
987 : * @param reqcerts list of certificates to request ocsp data for
988 : * @param pool certificate pool to use when signing
989 : * @param signer certificate to use to sign the request
990 : * @param digest the signing algorithm in the request, if NULL use the
991 : * default signature algorithm,
992 : * @param request the encoded request, free with free_heim_octet_string().
993 : * @param nonce nonce in the request, free with free_heim_octet_string().
994 : *
995 : * @return An hx509 error code, see hx509_get_error_string().
996 : *
997 : * @ingroup hx509_revoke
998 : */
999 :
1000 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1001 0 : hx509_ocsp_request(hx509_context context,
1002 : hx509_certs reqcerts,
1003 : hx509_certs pool,
1004 : hx509_cert signer,
1005 : const AlgorithmIdentifier *digest,
1006 : heim_octet_string *request,
1007 : heim_octet_string *nonce)
1008 : {
1009 : OCSPRequest req;
1010 : size_t size;
1011 : int ret;
1012 : struct ocsp_add_ctx ctx;
1013 : Extensions *es;
1014 :
1015 0 : memset(&req, 0, sizeof(req));
1016 :
1017 0 : if (digest == NULL)
1018 0 : digest = _hx509_crypto_default_digest_alg;
1019 :
1020 0 : ctx.req = &req.tbsRequest;
1021 0 : ctx.certs = pool;
1022 0 : ctx.digest = digest;
1023 0 : ctx.parent = NULL;
1024 :
1025 0 : ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx);
1026 0 : hx509_cert_free(ctx.parent);
1027 0 : if (ret)
1028 0 : goto out;
1029 :
1030 0 : if (nonce) {
1031 0 : req.tbsRequest.requestExtensions =
1032 0 : calloc(1, sizeof(*req.tbsRequest.requestExtensions));
1033 0 : if (req.tbsRequest.requestExtensions == NULL) {
1034 0 : ret = ENOMEM;
1035 0 : goto out;
1036 : }
1037 :
1038 0 : es = req.tbsRequest.requestExtensions;
1039 :
1040 0 : es->val = calloc(es->len, sizeof(es->val[0]));
1041 0 : if (es->val == NULL) {
1042 0 : ret = ENOMEM;
1043 0 : goto out;
1044 : }
1045 0 : es->len = 1;
1046 0 : ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
1047 0 : if (ret) {
1048 0 : free_OCSPRequest(&req);
1049 0 : return ret;
1050 : }
1051 :
1052 0 : es->val[0].extnValue.data = malloc(10);
1053 0 : if (es->val[0].extnValue.data == NULL) {
1054 0 : ret = ENOMEM;
1055 0 : goto out;
1056 : }
1057 0 : es->val[0].extnValue.length = 10;
1058 :
1059 0 : ret = RAND_bytes(es->val[0].extnValue.data,
1060 0 : es->val[0].extnValue.length);
1061 0 : if (ret != 1) {
1062 0 : ret = HX509_CRYPTO_INTERNAL_ERROR;
1063 0 : goto out;
1064 : }
1065 0 : ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1066 0 : if (ret) {
1067 0 : ret = ENOMEM;
1068 0 : goto out;
1069 : }
1070 : }
1071 :
1072 0 : ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1073 : &req, &size, ret);
1074 0 : free_OCSPRequest(&req);
1075 0 : if (ret)
1076 0 : goto out;
1077 0 : if (size != request->length)
1078 0 : _hx509_abort("internal ASN.1 encoder error");
1079 :
1080 0 : return 0;
1081 :
1082 0 : out:
1083 0 : free_OCSPRequest(&req);
1084 0 : return ret;
1085 : }
1086 :
1087 : static char *
1088 0 : printable_time(time_t t)
1089 : {
1090 : static char s[128];
1091 : char *p;
1092 0 : if ((p = ctime(&t)) == NULL)
1093 0 : strlcpy(s, "?", sizeof(s));
1094 : else {
1095 0 : strlcpy(s, p + 4, sizeof(s));
1096 0 : s[20] = 0;
1097 : }
1098 0 : return s;
1099 : }
1100 :
1101 : /*
1102 : *
1103 : */
1104 :
1105 : static int
1106 0 : print_ocsp(hx509_context context, struct revoke_ocsp *ocsp, FILE *out)
1107 : {
1108 0 : int ret = 0;
1109 : size_t i;
1110 :
1111 0 : fprintf(out, "signer: ");
1112 :
1113 0 : switch(ocsp->ocsp.tbsResponseData.responderID.element) {
1114 0 : case choice_OCSPResponderID_byName: {
1115 : hx509_name n;
1116 : char *s;
1117 0 : _hx509_name_from_Name(&ocsp->ocsp.tbsResponseData.responderID.u.byName, &n);
1118 0 : hx509_name_to_string(n, &s);
1119 0 : hx509_name_free(&n);
1120 0 : fprintf(out, " byName: %s\n", s);
1121 0 : free(s);
1122 0 : break;
1123 : }
1124 0 : case choice_OCSPResponderID_byKey: {
1125 : char *s;
1126 0 : hex_encode(ocsp->ocsp.tbsResponseData.responderID.u.byKey.data,
1127 : ocsp->ocsp.tbsResponseData.responderID.u.byKey.length,
1128 : &s);
1129 0 : fprintf(out, " byKey: %s\n", s);
1130 0 : free(s);
1131 0 : break;
1132 : }
1133 0 : default:
1134 0 : _hx509_abort("choice_OCSPResponderID unknown");
1135 : break;
1136 : }
1137 :
1138 0 : fprintf(out, "producedAt: %s\n",
1139 : printable_time(ocsp->ocsp.tbsResponseData.producedAt));
1140 :
1141 0 : fprintf(out, "replies: %d\n", ocsp->ocsp.tbsResponseData.responses.len);
1142 :
1143 0 : for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) {
1144 : const char *status;
1145 0 : switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1146 0 : case choice_OCSPCertStatus_good:
1147 0 : status = "good";
1148 0 : break;
1149 0 : case choice_OCSPCertStatus_revoked:
1150 0 : status = "revoked";
1151 0 : break;
1152 0 : case choice_OCSPCertStatus_unknown:
1153 0 : status = "unknown";
1154 0 : break;
1155 0 : default:
1156 0 : status = "element unknown";
1157 : }
1158 :
1159 0 : fprintf(out, "\t%llu. status: %s\n", (unsigned long long)i, status);
1160 :
1161 0 : fprintf(out, "\tthisUpdate: %s\n",
1162 0 : printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate));
1163 0 : if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate)
1164 0 : fprintf(out, "\tproducedAt: %s\n",
1165 0 : printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate));
1166 :
1167 : }
1168 :
1169 0 : fprintf(out, "appended certs:\n");
1170 0 : if (ocsp->certs)
1171 0 : ret = hx509_certs_iter_f(context, ocsp->certs, hx509_ci_print_names, out);
1172 :
1173 0 : return ret;
1174 : }
1175 :
1176 : static int
1177 0 : print_crl(hx509_context context, struct revoke_crl *crl, FILE *out)
1178 : {
1179 : {
1180 : hx509_name n;
1181 : char *s;
1182 0 : _hx509_name_from_Name(&crl->crl.tbsCertList.issuer, &n);
1183 0 : hx509_name_to_string(n, &s);
1184 0 : hx509_name_free(&n);
1185 0 : fprintf(out, " issuer: %s\n", s);
1186 0 : free(s);
1187 : }
1188 :
1189 0 : fprintf(out, " thisUpdate: %s\n",
1190 0 : printable_time(_hx509_Time2time_t(&crl->crl.tbsCertList.thisUpdate)));
1191 :
1192 0 : return 0;
1193 : }
1194 :
1195 :
1196 : /*
1197 : *
1198 : */
1199 :
1200 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1201 0 : hx509_revoke_print(hx509_context context,
1202 : hx509_revoke_ctx ctx,
1203 : FILE *out)
1204 : {
1205 0 : int saved_ret = 0, ret;
1206 : size_t n;
1207 :
1208 0 : for (n = 0; n < ctx->ocsps.len; n++) {
1209 0 : struct revoke_ocsp *ocsp = &ctx->ocsps.val[n];
1210 :
1211 0 : fprintf(out, "OCSP %s\n", ocsp->path);
1212 :
1213 0 : ret = print_ocsp(context, ocsp, out);
1214 0 : if (ret) {
1215 0 : fprintf(out, "failure printing OCSP: %d\n", ret);
1216 0 : saved_ret = ret;
1217 : }
1218 : }
1219 :
1220 0 : for (n = 0; n < ctx->crls.len; n++) {
1221 0 : struct revoke_crl *crl = &ctx->crls.val[n];
1222 :
1223 0 : fprintf(out, "CRL %s\n", crl->path);
1224 :
1225 0 : ret = print_crl(context, crl, out);
1226 0 : if (ret) {
1227 0 : fprintf(out, "failure printing CRL: %d\n", ret);
1228 0 : saved_ret = ret;
1229 : }
1230 : }
1231 0 : return saved_ret;
1232 :
1233 : }
1234 :
1235 : /**
1236 : * Print the OCSP reply stored in a file.
1237 : *
1238 : * @param context a hx509 context
1239 : * @param path path to a file with a OCSP reply
1240 : * @param out the out FILE descriptor to print the reply on
1241 : *
1242 : * @return An hx509 error code, see hx509_get_error_string().
1243 : *
1244 : * @ingroup hx509_revoke
1245 : */
1246 :
1247 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1248 0 : hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
1249 : {
1250 : struct revoke_ocsp ocsp;
1251 : int ret;
1252 :
1253 0 : if (out == NULL)
1254 0 : out = stdout;
1255 :
1256 0 : memset(&ocsp, 0, sizeof(ocsp));
1257 :
1258 0 : ocsp.path = strdup(path);
1259 0 : if (ocsp.path == NULL)
1260 0 : return ENOMEM;
1261 :
1262 0 : ret = load_ocsp(context, &ocsp);
1263 0 : if (ret) {
1264 0 : free_ocsp(&ocsp);
1265 0 : return ret;
1266 : }
1267 :
1268 0 : ret = print_ocsp(context, &ocsp, out);
1269 :
1270 0 : free_ocsp(&ocsp);
1271 0 : return ret;
1272 : }
1273 :
1274 : /**
1275 : * Verify that the certificate is part of the OCSP reply and it's not
1276 : * expired. Doesn't verify signature the OCSP reply or it's done by a
1277 : * authorized sender, that is assumed to be already done.
1278 : *
1279 : * @param context a hx509 context
1280 : * @param now the time right now, if 0, use the current time.
1281 : * @param cert the certificate to verify
1282 : * @param flags flags control the behavior
1283 : * @param data pointer to the encode ocsp reply
1284 : * @param length the length of the encode ocsp reply
1285 : * @param expiration return the time the OCSP will expire and need to
1286 : * be rechecked.
1287 : *
1288 : * @return An hx509 error code, see hx509_get_error_string().
1289 : *
1290 : * @ingroup hx509_verify
1291 : */
1292 :
1293 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1294 0 : hx509_ocsp_verify(hx509_context context,
1295 : time_t now,
1296 : hx509_cert cert,
1297 : int flags,
1298 : const void *data, size_t length,
1299 : time_t *expiration)
1300 : {
1301 0 : const Certificate *c = _hx509_get_cert(cert);
1302 : OCSPBasicOCSPResponse basic;
1303 : int ret;
1304 : size_t i;
1305 :
1306 0 : if (now == 0)
1307 0 : now = time(NULL);
1308 :
1309 0 : *expiration = 0;
1310 :
1311 0 : ret = parse_ocsp_basic(data, length, &basic);
1312 0 : if (ret) {
1313 0 : hx509_set_error_string(context, 0, ret,
1314 : "Failed to parse OCSP response");
1315 0 : return ret;
1316 : }
1317 :
1318 0 : for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1319 :
1320 0 : ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1321 0 : &c->tbsCertificate.serialNumber);
1322 0 : if (ret != 0)
1323 0 : continue;
1324 :
1325 : /* verify issuer hashes hash */
1326 0 : ret = _hx509_verify_signature(context,
1327 : NULL,
1328 0 : &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1329 : &c->tbsCertificate.issuer._save,
1330 0 : &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1331 0 : if (ret != 0)
1332 0 : continue;
1333 :
1334 0 : switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1335 0 : case choice_OCSPCertStatus_good:
1336 0 : break;
1337 0 : case choice_OCSPCertStatus_revoked:
1338 : case choice_OCSPCertStatus_unknown:
1339 0 : continue;
1340 : }
1341 :
1342 : /* don't allow the update to be in the future */
1343 0 : if (basic.tbsResponseData.responses.val[i].thisUpdate >
1344 0 : now + context->ocsp_time_diff)
1345 0 : continue;
1346 :
1347 : /* don't allow the next update to be in the past */
1348 0 : if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1349 0 : if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1350 0 : continue;
1351 0 : *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1352 : } else
1353 0 : *expiration = now;
1354 :
1355 0 : free_OCSPBasicOCSPResponse(&basic);
1356 0 : return 0;
1357 : }
1358 :
1359 0 : free_OCSPBasicOCSPResponse(&basic);
1360 :
1361 : {
1362 : hx509_name name;
1363 : char *subject;
1364 :
1365 0 : ret = hx509_cert_get_subject(cert, &name);
1366 0 : if (ret) {
1367 0 : hx509_clear_error_string(context);
1368 0 : goto out;
1369 : }
1370 0 : ret = hx509_name_to_string(name, &subject);
1371 0 : hx509_name_free(&name);
1372 0 : if (ret) {
1373 0 : hx509_clear_error_string(context);
1374 0 : goto out;
1375 : }
1376 0 : hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
1377 : "Certificate %s not in OCSP response "
1378 : "or not good",
1379 : subject);
1380 0 : free(subject);
1381 : }
1382 0 : out:
1383 0 : return HX509_CERT_NOT_IN_OCSP;
1384 : }
1385 :
1386 : struct hx509_crl {
1387 : hx509_certs revoked;
1388 : time_t expire;
1389 : };
1390 :
1391 : /**
1392 : * Create a CRL context. Use hx509_crl_free() to free the CRL context.
1393 : *
1394 : * @param context a hx509 context.
1395 : * @param crl return pointer to a newly allocated CRL context.
1396 : *
1397 : * @return An hx509 error code, see hx509_get_error_string().
1398 : *
1399 : * @ingroup hx509_verify
1400 : */
1401 :
1402 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1403 0 : hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1404 : {
1405 : int ret;
1406 :
1407 0 : *crl = calloc(1, sizeof(**crl));
1408 0 : if (*crl == NULL) {
1409 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1410 0 : return ENOMEM;
1411 : }
1412 :
1413 0 : ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1414 0 : if (ret) {
1415 0 : free(*crl);
1416 0 : *crl = NULL;
1417 0 : return ret;
1418 : }
1419 0 : (*crl)->expire = 0;
1420 0 : return ret;
1421 : }
1422 :
1423 : /**
1424 : * Add revoked certificate to an CRL context.
1425 : *
1426 : * @param context a hx509 context.
1427 : * @param crl the CRL to add the revoked certificate to.
1428 : * @param certs keyset of certificate to revoke.
1429 : *
1430 : * @return An hx509 error code, see hx509_get_error_string().
1431 : *
1432 : * @ingroup hx509_verify
1433 : */
1434 :
1435 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1436 0 : hx509_crl_add_revoked_certs(hx509_context context,
1437 : hx509_crl crl,
1438 : hx509_certs certs)
1439 : {
1440 0 : return hx509_certs_merge(context, crl->revoked, certs);
1441 : }
1442 :
1443 : /**
1444 : * Set the lifetime of a CRL context.
1445 : *
1446 : * @param context a hx509 context.
1447 : * @param crl a CRL context
1448 : * @param delta delta time the certificate is valid, library adds the
1449 : * current time to this.
1450 : *
1451 : * @return An hx509 error code, see hx509_get_error_string().
1452 : *
1453 : * @ingroup hx509_verify
1454 : */
1455 :
1456 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1457 0 : hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1458 : {
1459 0 : crl->expire = time(NULL) + delta;
1460 0 : return 0;
1461 : }
1462 :
1463 : /**
1464 : * Free a CRL context.
1465 : *
1466 : * @param context a hx509 context.
1467 : * @param crl a CRL context to free.
1468 : *
1469 : * @ingroup hx509_verify
1470 : */
1471 :
1472 : HX509_LIB_FUNCTION void HX509_LIB_CALL
1473 0 : hx509_crl_free(hx509_context context, hx509_crl *crl)
1474 : {
1475 0 : if (*crl == NULL)
1476 0 : return;
1477 0 : hx509_certs_free(&(*crl)->revoked);
1478 0 : memset(*crl, 0, sizeof(**crl));
1479 0 : free(*crl);
1480 0 : *crl = NULL;
1481 : }
1482 :
1483 : static int HX509_LIB_CALL
1484 0 : add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1485 : {
1486 0 : TBSCRLCertList *c = ctx;
1487 : unsigned int num;
1488 : void *ptr;
1489 : int ret;
1490 :
1491 0 : num = c->revokedCertificates->len;
1492 0 : ptr = realloc(c->revokedCertificates->val,
1493 0 : (num + 1) * sizeof(c->revokedCertificates->val[0]));
1494 0 : if (ptr == NULL) {
1495 0 : hx509_clear_error_string(context);
1496 0 : return ENOMEM;
1497 : }
1498 0 : c->revokedCertificates->val = ptr;
1499 :
1500 0 : ret = hx509_cert_get_serialnumber(cert,
1501 0 : &c->revokedCertificates->val[num].userCertificate);
1502 0 : if (ret) {
1503 0 : hx509_clear_error_string(context);
1504 0 : return ret;
1505 : }
1506 0 : c->revokedCertificates->val[num].revocationDate.element =
1507 : choice_Time_generalTime;
1508 0 : c->revokedCertificates->val[num].revocationDate.u.generalTime =
1509 0 : time(NULL) - 3600 * 24;
1510 0 : c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1511 :
1512 0 : c->revokedCertificates->len++;
1513 :
1514 0 : return 0;
1515 : }
1516 :
1517 : /**
1518 : * Sign a CRL and return an encode certificate.
1519 : *
1520 : * @param context a hx509 context.
1521 : * @param signer certificate to sign the CRL with
1522 : * @param crl the CRL to sign
1523 : * @param os return the signed and encoded CRL, free with
1524 : * free_heim_octet_string()
1525 : *
1526 : * @return An hx509 error code, see hx509_get_error_string().
1527 : *
1528 : * @ingroup hx509_verify
1529 : */
1530 :
1531 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1532 0 : hx509_crl_sign(hx509_context context,
1533 : hx509_cert signer,
1534 : hx509_crl crl,
1535 : heim_octet_string *os)
1536 : {
1537 0 : const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
1538 : CRLCertificateList c;
1539 : size_t size;
1540 : int ret;
1541 : hx509_private_key signerkey;
1542 :
1543 0 : memset(&c, 0, sizeof(c));
1544 :
1545 0 : signerkey = _hx509_cert_private_key(signer);
1546 0 : if (signerkey == NULL) {
1547 0 : ret = HX509_PRIVATE_KEY_MISSING;
1548 0 : hx509_set_error_string(context, 0, ret,
1549 : "Private key missing for CRL signing");
1550 0 : return ret;
1551 : }
1552 :
1553 0 : c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1554 0 : if (c.tbsCertList.version == NULL) {
1555 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1556 0 : return ENOMEM;
1557 : }
1558 :
1559 0 : *c.tbsCertList.version = 1;
1560 :
1561 0 : ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1562 0 : if (ret) {
1563 0 : hx509_clear_error_string(context);
1564 0 : goto out;
1565 : }
1566 :
1567 0 : ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1568 : &c.tbsCertList.issuer);
1569 0 : if (ret) {
1570 0 : hx509_clear_error_string(context);
1571 0 : goto out;
1572 : }
1573 :
1574 0 : c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1575 0 : c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1576 :
1577 0 : c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1578 0 : if (c.tbsCertList.nextUpdate == NULL) {
1579 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1580 0 : ret = ENOMEM;
1581 0 : goto out;
1582 : }
1583 :
1584 : {
1585 0 : time_t next = crl->expire;
1586 0 : if (next == 0)
1587 0 : next = time(NULL) + 24 * 3600 * 365;
1588 :
1589 0 : c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1590 0 : c.tbsCertList.nextUpdate->u.generalTime = next;
1591 : }
1592 :
1593 0 : c.tbsCertList.revokedCertificates =
1594 0 : calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1595 0 : if (c.tbsCertList.revokedCertificates == NULL) {
1596 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1597 0 : ret = ENOMEM;
1598 0 : goto out;
1599 : }
1600 0 : c.tbsCertList.crlExtensions = NULL;
1601 :
1602 0 : ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList);
1603 0 : if (ret)
1604 0 : goto out;
1605 :
1606 : /* if not revoked certs, remove OPTIONAL entry */
1607 0 : if (c.tbsCertList.revokedCertificates->len == 0) {
1608 0 : free(c.tbsCertList.revokedCertificates);
1609 0 : c.tbsCertList.revokedCertificates = NULL;
1610 : }
1611 :
1612 0 : ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1613 : &c.tbsCertList, &size, ret);
1614 0 : if (ret) {
1615 0 : hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1616 0 : goto out;
1617 : }
1618 0 : if (size != os->length)
1619 0 : _hx509_abort("internal ASN.1 encoder error");
1620 :
1621 :
1622 0 : ret = _hx509_create_signature_bitstring(context,
1623 : signerkey,
1624 : sigalg,
1625 : os,
1626 : &c.signatureAlgorithm,
1627 : &c.signatureValue);
1628 0 : free(os->data);
1629 0 : if (ret) {
1630 0 : hx509_set_error_string(context, 0, ret, "Failed to sign CRL");
1631 0 : goto out;
1632 : }
1633 :
1634 0 : ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1635 : &c, &size, ret);
1636 0 : if (ret) {
1637 0 : hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1638 0 : goto out;
1639 : }
1640 0 : if (size != os->length)
1641 0 : _hx509_abort("internal ASN.1 encoder error");
1642 :
1643 0 : free_CRLCertificateList(&c);
1644 :
1645 0 : return 0;
1646 :
1647 0 : out:
1648 0 : free_CRLCertificateList(&c);
1649 0 : return ret;
1650 : }
|