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
hx509_revoke_init(hx509_context context,hx509_revoke_ctx * ctx)95 hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
96 {
97 *ctx = calloc(1, sizeof(**ctx));
98 if (*ctx == NULL)
99 return ENOMEM;
100
101 (*ctx)->ref = 1;
102 (*ctx)->crls.len = 0;
103 (*ctx)->crls.val = NULL;
104 (*ctx)->ocsps.len = 0;
105 (*ctx)->ocsps.val = NULL;
106
107 return 0;
108 }
109
110 hx509_revoke_ctx
_hx509_revoke_ref(hx509_revoke_ctx ctx)111 _hx509_revoke_ref(hx509_revoke_ctx ctx)
112 {
113 if (ctx == NULL)
114 return NULL;
115 if (ctx->ref == 0)
116 _hx509_abort("revoke ctx refcount == 0 on ref");
117 ctx->ref++;
118 if (ctx->ref == UINT_MAX)
119 _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
120 return ctx;
121 }
122
123 static void
free_ocsp(struct revoke_ocsp * ocsp)124 free_ocsp(struct revoke_ocsp *ocsp)
125 {
126 free(ocsp->path);
127 free_OCSPBasicOCSPResponse(&ocsp->ocsp);
128 hx509_certs_free(&ocsp->certs);
129 hx509_cert_free(ocsp->signer);
130 }
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
hx509_revoke_free(hx509_revoke_ctx * ctx)141 hx509_revoke_free(hx509_revoke_ctx *ctx)
142 {
143 size_t i ;
144
145 if (ctx == NULL || *ctx == NULL)
146 return;
147
148 if ((*ctx)->ref == 0)
149 _hx509_abort("revoke ctx refcount == 0 on free");
150 if (--(*ctx)->ref > 0)
151 return;
152
153 for (i = 0; i < (*ctx)->crls.len; i++) {
154 free((*ctx)->crls.val[i].path);
155 free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
156 }
157
158 for (i = 0; i < (*ctx)->ocsps.len; i++)
159 free_ocsp(&(*ctx)->ocsps.val[i]);
160 free((*ctx)->ocsps.val);
161
162 free((*ctx)->crls.val);
163
164 memset(*ctx, 0, sizeof(**ctx));
165 free(*ctx);
166 *ctx = NULL;
167 }
168
169 static int
verify_ocsp(hx509_context context,struct revoke_ocsp * ocsp,time_t time_now,hx509_certs certs,hx509_cert parent)170 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 hx509_cert signer = NULL;
177 hx509_query q;
178 int ret;
179
180 _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 q.match = HX509_QUERY_MATCH_ISSUER_NAME;
189 q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
190
191 switch(ocsp->ocsp.tbsResponseData.responderID.element) {
192 case choice_OCSPResponderID_byName:
193 q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
194 q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
195 break;
196 case choice_OCSPResponderID_byKey:
197 q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
198 q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
199 break;
200 }
201
202 ret = hx509_certs_find(context, certs, &q, &signer);
203 if (ret && ocsp->certs)
204 ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
205 if (ret)
206 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 if (hx509_cert_cmp(signer, parent) != 0) {
214 Certificate *p = _hx509_get_cert(parent);
215 Certificate *s = _hx509_get_cert(signer);
216
217 ret = _hx509_cert_is_parent_cmp(s, p, 0);
218 if (ret != 0) {
219 ret = HX509_PARENT_NOT_CA;
220 hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is "
221 "doesn't have CA as signer certificate");
222 goto out;
223 }
224
225 ret = _hx509_verify_signature_bitstring(context,
226 parent,
227 &s->signatureAlgorithm,
228 &s->tbsCertificate._save,
229 &s->signatureValue);
230 if (ret) {
231 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
232 "OCSP signer signature invalid");
233 goto out;
234 }
235
236 ret = hx509_cert_check_eku(context, signer,
237 &asn1_oid_id_pkix_kp_OCSPSigning, 0);
238 if (ret)
239 goto out;
240 }
241
242 ret = _hx509_verify_signature_bitstring(context,
243 signer,
244 &ocsp->ocsp.signatureAlgorithm,
245 &ocsp->ocsp.tbsResponseData._save,
246 &ocsp->ocsp.signature);
247 if (ret) {
248 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
249 "OCSP signature invalid");
250 goto out;
251 }
252
253 ocsp->signer = signer;
254 signer = NULL;
255 out:
256 if (signer)
257 hx509_cert_free(signer);
258
259 return ret;
260 }
261
262 /*
263 *
264 */
265
266 static int
parse_ocsp_basic(const void * data,size_t length,OCSPBasicOCSPResponse * basic)267 parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
268 {
269 OCSPResponse resp;
270 size_t size;
271 int ret;
272
273 memset(basic, 0, sizeof(*basic));
274
275 ret = decode_OCSPResponse(data, length, &resp, &size);
276 if (ret)
277 return ret;
278 if (length != size) {
279 free_OCSPResponse(&resp);
280 return ASN1_EXTRA_DATA;
281 }
282
283 switch (resp.responseStatus) {
284 case successful:
285 break;
286 default:
287 free_OCSPResponse(&resp);
288 return HX509_REVOKE_WRONG_DATA;
289 }
290
291 if (resp.responseBytes == NULL) {
292 free_OCSPResponse(&resp);
293 return EINVAL;
294 }
295
296 ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
297 &asn1_oid_id_pkix_ocsp_basic);
298 if (ret != 0) {
299 free_OCSPResponse(&resp);
300 return HX509_REVOKE_WRONG_DATA;
301 }
302
303 ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
304 resp.responseBytes->response.length,
305 basic,
306 &size);
307 if (ret) {
308 free_OCSPResponse(&resp);
309 return ret;
310 }
311 if (size != resp.responseBytes->response.length) {
312 free_OCSPResponse(&resp);
313 free_OCSPBasicOCSPResponse(basic);
314 return ASN1_EXTRA_DATA;
315 }
316 free_OCSPResponse(&resp);
317
318 return 0;
319 }
320
321 /*
322 *
323 */
324
325 static int
load_ocsp(hx509_context context,struct revoke_ocsp * ocsp)326 load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
327 {
328 OCSPBasicOCSPResponse basic;
329 hx509_certs certs = NULL;
330 size_t length;
331 struct stat sb;
332 void *data;
333 int ret;
334
335 ret = rk_undumpdata(ocsp->path, &data, &length);
336 if (ret)
337 return ret;
338
339 ret = stat(ocsp->path, &sb);
340 if (ret)
341 return errno;
342
343 ret = parse_ocsp_basic(data, length, &basic);
344 rk_xfree(data);
345 if (ret) {
346 hx509_set_error_string(context, 0, ret,
347 "Failed to parse OCSP response");
348 return ret;
349 }
350
351 if (basic.certs) {
352 size_t i;
353
354 ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
355 NULL, &certs);
356 if (ret) {
357 free_OCSPBasicOCSPResponse(&basic);
358 return ret;
359 }
360
361 for (i = 0; i < basic.certs->len; i++) {
362 hx509_cert c;
363
364 ret = hx509_cert_init(context, &basic.certs->val[i], &c);
365 if (ret)
366 continue;
367
368 ret = hx509_certs_add(context, certs, c);
369 hx509_cert_free(c);
370 if (ret)
371 continue;
372 }
373 }
374
375 ocsp->last_modfied = sb.st_mtime;
376
377 free_OCSPBasicOCSPResponse(&ocsp->ocsp);
378 hx509_certs_free(&ocsp->certs);
379 hx509_cert_free(ocsp->signer);
380
381 ocsp->ocsp = basic;
382 ocsp->certs = certs;
383 ocsp->signer = NULL;
384
385 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
hx509_revoke_add_ocsp(hx509_context context,hx509_revoke_ctx ctx,const char * path)401 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 if (strncmp(path, "FILE:", 5) != 0) {
410 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
411 "unsupport type in %s", path);
412 return HX509_UNSUPPORTED_OPERATION;
413 }
414
415 path += 5;
416
417 for (i = 0; i < ctx->ocsps.len; i++) {
418 if (strcmp(ctx->ocsps.val[0].path, path) == 0)
419 return 0;
420 }
421
422 data = realloc(ctx->ocsps.val,
423 (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
424 if (data == NULL) {
425 hx509_clear_error_string(context);
426 return ENOMEM;
427 }
428
429 ctx->ocsps.val = data;
430
431 memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
432 sizeof(ctx->ocsps.val[0]));
433
434 ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
435 if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
436 hx509_clear_error_string(context);
437 return ENOMEM;
438 }
439
440 ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
441 if (ret) {
442 free(ctx->ocsps.val[ctx->ocsps.len].path);
443 return ret;
444 }
445 ctx->ocsps.len++;
446
447 return ret;
448 }
449
450 /*
451 *
452 */
453
454 static int
verify_crl(hx509_context context,hx509_revoke_ctx ctx,CRLCertificateList * crl,time_t time_now,hx509_certs certs,hx509_cert parent)455 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 t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
468 if (t > time_now) {
469 hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
470 "CRL used before time");
471 return HX509_CRL_USED_BEFORE_TIME;
472 }
473
474 if (crl->tbsCertList.nextUpdate == NULL) {
475 hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
476 "CRL missing nextUpdate");
477 return HX509_CRL_INVALID_FORMAT;
478 }
479
480 t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
481 if (t < time_now) {
482 hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
483 "CRL used after time");
484 return HX509_CRL_USED_AFTER_TIME;
485 }
486
487 _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 if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
494 signer = hx509_cert_ref(parent);
495 } else {
496 q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
497 q.match |= HX509_QUERY_KU_CRLSIGN;
498 q.subject_name = &crl->tbsCertList.issuer;
499
500 ret = hx509_certs_find(context, certs, &q, &signer);
501 if (ret) {
502 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
503 "Failed to find certificate for CRL");
504 return ret;
505 }
506 }
507
508 ret = _hx509_verify_signature_bitstring(context,
509 signer,
510 &crl->signatureAlgorithm,
511 &crl->tbsCertList._save,
512 &crl->signatureValue);
513 if (ret) {
514 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
515 "CRL signature invalid");
516 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 while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
526 hx509_cert crl_parent;
527
528 _hx509_query_clear(&q);
529
530 q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
531 q.match |= HX509_QUERY_KU_CRLSIGN;
532 q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
533
534 ret = hx509_certs_find(context, certs, &q, &crl_parent);
535 if (ret) {
536 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
537 "Failed to find parent of CRL signer");
538 goto out;
539 }
540
541 ret = hx509_revoke_verify(context,
542 ctx,
543 certs,
544 time_now,
545 signer,
546 crl_parent);
547 hx509_cert_free(signer);
548 signer = crl_parent;
549 if (ret) {
550 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
551 "Failed to verify revoke "
552 "status of CRL signer");
553 goto out;
554 }
555 }
556
557 out:
558 hx509_cert_free(signer);
559
560 return ret;
561 }
562
563 static int
load_crl(const char * path,time_t * t,CRLCertificateList * crl)564 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 memset(crl, 0, sizeof(*crl));
572
573 ret = rk_undumpdata(path, &data, &length);
574 if (ret)
575 return ret;
576
577 ret = stat(path, &sb);
578 if (ret)
579 return errno;
580
581 *t = sb.st_mtime;
582
583 ret = decode_CRLCertificateList(data, length, crl, &size);
584 rk_xfree(data);
585 if (ret)
586 return ret;
587
588 /* check signature is aligned */
589 if (crl->signatureValue.length & 7) {
590 free_CRLCertificateList(crl);
591 return HX509_CRYPTO_SIG_INVALID_FORMAT;
592 }
593 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
hx509_revoke_add_crl(hx509_context context,hx509_revoke_ctx ctx,const char * path)609 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 if (strncmp(path, "FILE:", 5) != 0) {
618 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
619 "unsupport type in %s", path);
620 return HX509_UNSUPPORTED_OPERATION;
621 }
622
623
624 path += 5;
625
626 for (i = 0; i < ctx->crls.len; i++) {
627 if (strcmp(ctx->crls.val[0].path, path) == 0)
628 return 0;
629 }
630
631 data = realloc(ctx->crls.val,
632 (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
633 if (data == NULL) {
634 hx509_clear_error_string(context);
635 return ENOMEM;
636 }
637 ctx->crls.val = data;
638
639 memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
640
641 ctx->crls.val[ctx->crls.len].path = strdup(path);
642 if (ctx->crls.val[ctx->crls.len].path == NULL) {
643 hx509_clear_error_string(context);
644 return ENOMEM;
645 }
646
647 ret = load_crl(path,
648 &ctx->crls.val[ctx->crls.len].last_modfied,
649 &ctx->crls.val[ctx->crls.len].crl);
650 if (ret) {
651 free(ctx->crls.val[ctx->crls.len].path);
652 return ret;
653 }
654
655 ctx->crls.len++;
656
657 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
hx509_revoke_verify(hx509_context context,hx509_revoke_ctx ctx,hx509_certs certs,time_t now,hx509_cert cert,hx509_cert parent_cert)679 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 const Certificate *c = _hx509_get_cert(cert);
687 const Certificate *p = _hx509_get_cert(parent_cert);
688 unsigned long i, j, k;
689 int ret;
690
691 hx509_clear_error_string(context);
692
693 for (i = 0; i < ctx->ocsps.len; i++) {
694 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 ret = stat(ocsp->path, &sb);
701 if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
702 ret = load_ocsp(context, ocsp);
703 if (ret)
704 continue;
705 }
706
707 /* verify signature in ocsp if not already done */
708 if (ocsp->signer == NULL) {
709 ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
710 if (ret)
711 continue;
712 }
713
714 for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
715 heim_octet_string os;
716
717 ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
718 &c->tbsCertificate.serialNumber);
719 if (ret != 0)
720 continue;
721
722 /* verify issuer hashes hash */
723 ret = _hx509_verify_signature(context,
724 NULL,
725 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
726 &c->tbsCertificate.issuer._save,
727 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
728 if (ret != 0)
729 continue;
730
731 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
732 os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
733
734 ret = _hx509_verify_signature(context,
735 NULL,
736 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
737 &os,
738 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
739 if (ret != 0)
740 continue;
741
742 switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
743 case choice_OCSPCertStatus_good:
744 break;
745 case choice_OCSPCertStatus_revoked:
746 hx509_set_error_string(context, 0,
747 HX509_CERT_REVOKED,
748 "Certificate revoked by issuer in OCSP");
749 return HX509_CERT_REVOKED;
750 case choice_OCSPCertStatus_unknown:
751 continue;
752 }
753
754 /* don't allow the update to be in the future */
755 if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
756 now + context->ocsp_time_diff)
757 continue;
758
759 /* don't allow the next update to be in the past */
760 if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
761 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
762 continue;
763 } /* else should force a refetch, but can we ? */
764
765 return 0;
766 }
767 }
768
769 for (i = 0; i < ctx->crls.len; i++) {
770 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 ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
776 &crl->crl.tbsCertList.issuer, &diff);
777 if (ret || diff)
778 continue;
779
780 ret = stat(crl->path, &sb);
781 if (ret == 0 && crl->last_modfied != sb.st_mtime) {
782 CRLCertificateList cl;
783
784 ret = load_crl(crl->path, &crl->last_modfied, &cl);
785 if (ret == 0) {
786 free_CRLCertificateList(&crl->crl);
787 crl->crl = cl;
788 crl->verified = 0;
789 crl->failed_verify = 0;
790 }
791 }
792 if (crl->failed_verify)
793 continue;
794
795 /* verify signature in crl if not already done */
796 if (crl->verified == 0) {
797 ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
798 if (ret) {
799 crl->failed_verify = 1;
800 continue;
801 }
802 crl->verified = 1;
803 }
804
805 if (crl->crl.tbsCertList.crlExtensions) {
806 for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
807 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
808 hx509_set_error_string(context, 0,
809 HX509_CRL_UNKNOWN_EXTENSION,
810 "Unknown CRL extension");
811 return HX509_CRL_UNKNOWN_EXTENSION;
812 }
813 }
814 }
815
816 if (crl->crl.tbsCertList.revokedCertificates == NULL)
817 return 0;
818
819 /* check if cert is in crl */
820 for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
821 time_t t;
822
823 ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
824 &c->tbsCertificate.serialNumber);
825 if (ret != 0)
826 continue;
827
828 t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
829 if (t > now)
830 continue;
831
832 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
833 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
834 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
835 return HX509_CRL_UNKNOWN_EXTENSION;
836
837 hx509_set_error_string(context, 0,
838 HX509_CERT_REVOKED,
839 "Certificate revoked by issuer in CRL");
840 return HX509_CERT_REVOKED;
841 }
842
843 return 0;
844 }
845
846
847 if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
848 return 0;
849 hx509_set_error_string(context, HX509_ERROR_APPEND,
850 HX509_REVOKE_STATUS_MISSING,
851 "No revoke status found for "
852 "certificates");
853 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
add_to_req(hx509_context context,void * ptr,hx509_cert cert)864 add_to_req(hx509_context context, void *ptr, hx509_cert cert)
865 {
866 struct ocsp_add_ctx *ctx = ptr;
867 OCSPInnerRequest *one;
868 hx509_cert parent = NULL;
869 Certificate *p, *c = _hx509_get_cert(cert);
870 heim_octet_string os;
871 int ret;
872 hx509_query q;
873 void *d;
874
875 d = realloc(ctx->req->requestList.val,
876 sizeof(ctx->req->requestList.val[0]) *
877 (ctx->req->requestList.len + 1));
878 if (d == NULL)
879 return ENOMEM;
880 ctx->req->requestList.val = d;
881
882 one = &ctx->req->requestList.val[ctx->req->requestList.len];
883 memset(one, 0, sizeof(*one));
884
885 _hx509_query_clear(&q);
886
887 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
888 q.subject = c;
889
890 ret = hx509_certs_find(context, ctx->certs, &q, &parent);
891 if (ret)
892 goto out;
893
894 if (ctx->parent) {
895 if (hx509_cert_cmp(ctx->parent, parent) != 0) {
896 ret = HX509_REVOKE_NOT_SAME_PARENT;
897 hx509_set_error_string(context, 0, ret,
898 "Not same parent certifate as "
899 "last certificate in request");
900 goto out;
901 }
902 } else
903 ctx->parent = hx509_cert_ref(parent);
904
905 p = _hx509_get_cert(parent);
906
907 ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
908 if (ret)
909 goto out;
910
911 ret = _hx509_create_signature(context,
912 NULL,
913 &one->reqCert.hashAlgorithm,
914 &c->tbsCertificate.issuer._save,
915 NULL,
916 &one->reqCert.issuerNameHash);
917 if (ret)
918 goto out;
919
920 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
921 os.length =
922 p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
923
924 ret = _hx509_create_signature(context,
925 NULL,
926 &one->reqCert.hashAlgorithm,
927 &os,
928 NULL,
929 &one->reqCert.issuerKeyHash);
930 if (ret)
931 goto out;
932
933 ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
934 &one->reqCert.serialNumber);
935 if (ret)
936 goto out;
937
938 ctx->req->requestList.len++;
939 out:
940 hx509_cert_free(parent);
941 if (ret) {
942 free_OCSPInnerRequest(one);
943 memset(one, 0, sizeof(*one));
944 }
945
946 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
hx509_ocsp_request(hx509_context context,hx509_certs reqcerts,hx509_certs pool,hx509_cert signer,const AlgorithmIdentifier * digest,heim_octet_string * request,heim_octet_string * nonce)967 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 memset(&req, 0, sizeof(req));
982
983 if (digest == NULL)
984 digest = _hx509_crypto_default_digest_alg;
985
986 ctx.req = &req.tbsRequest;
987 ctx.certs = pool;
988 ctx.digest = digest;
989 ctx.parent = NULL;
990
991 ret = hx509_certs_iter_f(context, reqcerts, add_to_req, &ctx);
992 hx509_cert_free(ctx.parent);
993 if (ret)
994 goto out;
995
996 if (nonce) {
997 req.tbsRequest.requestExtensions =
998 calloc(1, sizeof(*req.tbsRequest.requestExtensions));
999 if (req.tbsRequest.requestExtensions == NULL) {
1000 ret = ENOMEM;
1001 goto out;
1002 }
1003
1004 es = req.tbsRequest.requestExtensions;
1005
1006 es->val = calloc(es->len, sizeof(es->val[0]));
1007 if (es->val == NULL) {
1008 ret = ENOMEM;
1009 goto out;
1010 }
1011 es->len = 1;
1012 ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
1013 if (ret) {
1014 free_OCSPRequest(&req);
1015 return ret;
1016 }
1017
1018 es->val[0].extnValue.data = malloc(10);
1019 if (es->val[0].extnValue.data == NULL) {
1020 ret = ENOMEM;
1021 goto out;
1022 }
1023 es->val[0].extnValue.length = 10;
1024
1025 ret = RAND_bytes(es->val[0].extnValue.data,
1026 es->val[0].extnValue.length);
1027 if (ret != 1) {
1028 ret = HX509_CRYPTO_INTERNAL_ERROR;
1029 goto out;
1030 }
1031 ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1032 if (ret) {
1033 ret = ENOMEM;
1034 goto out;
1035 }
1036 }
1037
1038 ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1039 &req, &size, ret);
1040 free_OCSPRequest(&req);
1041 if (ret)
1042 goto out;
1043 if (size != request->length)
1044 _hx509_abort("internal ASN.1 encoder error");
1045
1046 return 0;
1047
1048 out:
1049 free_OCSPRequest(&req);
1050 return ret;
1051 }
1052
1053 static char *
printable_time(time_t t)1054 printable_time(time_t t)
1055 {
1056 static char s[128];
1057 char *p;
1058 if ((p = ctime(&t)) == NULL)
1059 strlcpy(s, "?", sizeof(s));
1060 else {
1061 strlcpy(s, p + 4, sizeof(s));
1062 s[20] = 0;
1063 }
1064 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
hx509_revoke_ocsp_print(hx509_context context,const char * path,FILE * out)1080 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 if (out == NULL)
1087 out = stdout;
1088
1089 memset(&ocsp, 0, sizeof(ocsp));
1090
1091 ocsp.path = strdup(path);
1092 if (ocsp.path == NULL)
1093 return ENOMEM;
1094
1095 ret = load_ocsp(context, &ocsp);
1096 if (ret) {
1097 free_ocsp(&ocsp);
1098 return ret;
1099 }
1100
1101 fprintf(out, "signer: ");
1102
1103 switch(ocsp.ocsp.tbsResponseData.responderID.element) {
1104 case choice_OCSPResponderID_byName: {
1105 hx509_name n;
1106 char *s;
1107 _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
1108 hx509_name_to_string(n, &s);
1109 hx509_name_free(&n);
1110 fprintf(out, " byName: %s\n", s);
1111 free(s);
1112 break;
1113 }
1114 case choice_OCSPResponderID_byKey: {
1115 char *s;
1116 hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
1117 ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
1118 &s);
1119 fprintf(out, " byKey: %s\n", s);
1120 free(s);
1121 break;
1122 }
1123 default:
1124 _hx509_abort("choice_OCSPResponderID unknown");
1125 break;
1126 }
1127
1128 fprintf(out, "producedAt: %s\n",
1129 printable_time(ocsp.ocsp.tbsResponseData.producedAt));
1130
1131 fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
1132
1133 for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
1134 const char *status;
1135 switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1136 case choice_OCSPCertStatus_good:
1137 status = "good";
1138 break;
1139 case choice_OCSPCertStatus_revoked:
1140 status = "revoked";
1141 break;
1142 case choice_OCSPCertStatus_unknown:
1143 status = "unknown";
1144 break;
1145 default:
1146 status = "element unknown";
1147 }
1148
1149 fprintf(out, "\t%zu. status: %s\n", i, status);
1150
1151 fprintf(out, "\tthisUpdate: %s\n",
1152 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1153 if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
1154 fprintf(out, "\tproducedAt: %s\n",
1155 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1156
1157 }
1158
1159 fprintf(out, "appended certs:\n");
1160 if (ocsp.certs)
1161 ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out);
1162
1163 free_ocsp(&ocsp);
1164 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
hx509_ocsp_verify(hx509_context context,time_t now,hx509_cert cert,int flags,const void * data,size_t length,time_t * expiration)1187 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 const Certificate *c = _hx509_get_cert(cert);
1195 OCSPBasicOCSPResponse basic;
1196 int ret;
1197 size_t i;
1198
1199 if (now == 0)
1200 now = time(NULL);
1201
1202 *expiration = 0;
1203
1204 ret = parse_ocsp_basic(data, length, &basic);
1205 if (ret) {
1206 hx509_set_error_string(context, 0, ret,
1207 "Failed to parse OCSP response");
1208 return ret;
1209 }
1210
1211 for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1212
1213 ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1214 &c->tbsCertificate.serialNumber);
1215 if (ret != 0)
1216 continue;
1217
1218 /* verify issuer hashes hash */
1219 ret = _hx509_verify_signature(context,
1220 NULL,
1221 &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1222 &c->tbsCertificate.issuer._save,
1223 &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1224 if (ret != 0)
1225 continue;
1226
1227 switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1228 case choice_OCSPCertStatus_good:
1229 break;
1230 case choice_OCSPCertStatus_revoked:
1231 case choice_OCSPCertStatus_unknown:
1232 continue;
1233 }
1234
1235 /* don't allow the update to be in the future */
1236 if (basic.tbsResponseData.responses.val[i].thisUpdate >
1237 now + context->ocsp_time_diff)
1238 continue;
1239
1240 /* don't allow the next update to be in the past */
1241 if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1242 if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1243 continue;
1244 *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1245 } else
1246 *expiration = now;
1247
1248 free_OCSPBasicOCSPResponse(&basic);
1249 return 0;
1250 }
1251
1252 free_OCSPBasicOCSPResponse(&basic);
1253
1254 {
1255 hx509_name name;
1256 char *subject;
1257
1258 ret = hx509_cert_get_subject(cert, &name);
1259 if (ret) {
1260 hx509_clear_error_string(context);
1261 goto out;
1262 }
1263 ret = hx509_name_to_string(name, &subject);
1264 hx509_name_free(&name);
1265 if (ret) {
1266 hx509_clear_error_string(context);
1267 goto out;
1268 }
1269 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 free(subject);
1274 }
1275 out:
1276 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
hx509_crl_alloc(hx509_context context,hx509_crl * crl)1296 hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1297 {
1298 int ret;
1299
1300 *crl = calloc(1, sizeof(**crl));
1301 if (*crl == NULL) {
1302 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1303 return ENOMEM;
1304 }
1305
1306 ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1307 if (ret) {
1308 free(*crl);
1309 *crl = NULL;
1310 return ret;
1311 }
1312 (*crl)->expire = 0;
1313 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
hx509_crl_add_revoked_certs(hx509_context context,hx509_crl crl,hx509_certs certs)1329 hx509_crl_add_revoked_certs(hx509_context context,
1330 hx509_crl crl,
1331 hx509_certs certs)
1332 {
1333 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
hx509_crl_lifetime(hx509_context context,hx509_crl crl,int delta)1350 hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1351 {
1352 crl->expire = time(NULL) + delta;
1353 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
hx509_crl_free(hx509_context context,hx509_crl * crl)1366 hx509_crl_free(hx509_context context, hx509_crl *crl)
1367 {
1368 if (*crl == NULL)
1369 return;
1370 hx509_certs_free(&(*crl)->revoked);
1371 memset(*crl, 0, sizeof(**crl));
1372 free(*crl);
1373 *crl = NULL;
1374 }
1375
1376 static int
add_revoked(hx509_context context,void * ctx,hx509_cert cert)1377 add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1378 {
1379 TBSCRLCertList *c = ctx;
1380 unsigned int num;
1381 void *ptr;
1382 int ret;
1383
1384 num = c->revokedCertificates->len;
1385 ptr = realloc(c->revokedCertificates->val,
1386 (num + 1) * sizeof(c->revokedCertificates->val[0]));
1387 if (ptr == NULL) {
1388 hx509_clear_error_string(context);
1389 return ENOMEM;
1390 }
1391 c->revokedCertificates->val = ptr;
1392
1393 ret = hx509_cert_get_serialnumber(cert,
1394 &c->revokedCertificates->val[num].userCertificate);
1395 if (ret) {
1396 hx509_clear_error_string(context);
1397 return ret;
1398 }
1399 c->revokedCertificates->val[num].revocationDate.element =
1400 choice_Time_generalTime;
1401 c->revokedCertificates->val[num].revocationDate.u.generalTime =
1402 time(NULL) - 3600 * 24;
1403 c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1404
1405 c->revokedCertificates->len++;
1406
1407 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
hx509_crl_sign(hx509_context context,hx509_cert signer,hx509_crl crl,heim_octet_string * os)1425 hx509_crl_sign(hx509_context context,
1426 hx509_cert signer,
1427 hx509_crl crl,
1428 heim_octet_string *os)
1429 {
1430 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 memset(&c, 0, sizeof(c));
1437
1438 signerkey = _hx509_cert_private_key(signer);
1439 if (signerkey == NULL) {
1440 ret = HX509_PRIVATE_KEY_MISSING;
1441 hx509_set_error_string(context, 0, ret,
1442 "Private key missing for CRL signing");
1443 return ret;
1444 }
1445
1446 c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1447 if (c.tbsCertList.version == NULL) {
1448 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1449 return ENOMEM;
1450 }
1451
1452 *c.tbsCertList.version = 1;
1453
1454 ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1455 if (ret) {
1456 hx509_clear_error_string(context);
1457 goto out;
1458 }
1459
1460 ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1461 &c.tbsCertList.issuer);
1462 if (ret) {
1463 hx509_clear_error_string(context);
1464 goto out;
1465 }
1466
1467 c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1468 c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1469
1470 c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1471 if (c.tbsCertList.nextUpdate == NULL) {
1472 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1473 ret = ENOMEM;
1474 goto out;
1475 }
1476
1477 {
1478 time_t next = crl->expire;
1479 if (next == 0)
1480 next = time(NULL) + 24 * 3600 * 365;
1481
1482 c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1483 c.tbsCertList.nextUpdate->u.generalTime = next;
1484 }
1485
1486 c.tbsCertList.revokedCertificates =
1487 calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1488 if (c.tbsCertList.revokedCertificates == NULL) {
1489 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1490 ret = ENOMEM;
1491 goto out;
1492 }
1493 c.tbsCertList.crlExtensions = NULL;
1494
1495 ret = hx509_certs_iter_f(context, crl->revoked, add_revoked, &c.tbsCertList);
1496 if (ret)
1497 goto out;
1498
1499 /* if not revoked certs, remove OPTIONAL entry */
1500 if (c.tbsCertList.revokedCertificates->len == 0) {
1501 free(c.tbsCertList.revokedCertificates);
1502 c.tbsCertList.revokedCertificates = NULL;
1503 }
1504
1505 ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1506 &c.tbsCertList, &size, ret);
1507 if (ret) {
1508 hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1509 goto out;
1510 }
1511 if (size != os->length)
1512 _hx509_abort("internal ASN.1 encoder error");
1513
1514
1515 ret = _hx509_create_signature_bitstring(context,
1516 signerkey,
1517 sigalg,
1518 os,
1519 &c.signatureAlgorithm,
1520 &c.signatureValue);
1521 free(os->data);
1522 if (ret) {
1523 hx509_set_error_string(context, 0, ret, "Failed to sign CRL");
1524 goto out;
1525 }
1526
1527 ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1528 &c, &size, ret);
1529 if (ret) {
1530 hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1531 goto out;
1532 }
1533 if (size != os->length)
1534 _hx509_abort("internal ASN.1 encoder error");
1535
1536 free_CRLCertificateList(&c);
1537
1538 return 0;
1539
1540 out:
1541 free_CRLCertificateList(&c);
1542 return ret;
1543 }
1544