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