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