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