Home | History | Annotate | Line # | Download | only in hx509
      1 /*	$NetBSD: revoke.c,v 1.5 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006 - 2007 Kungliga Tekniska Hgskolan
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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 *
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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