root/source4/heimdal/lib/hx509/revoke.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hx509_revoke_init
  2. _hx509_revoke_ref
  3. free_ocsp
  4. hx509_revoke_free
  5. verify_ocsp
  6. parse_ocsp_basic
  7. load_ocsp
  8. hx509_revoke_add_ocsp
  9. verify_crl
  10. load_crl
  11. hx509_revoke_add_crl
  12. hx509_revoke_verify
  13. add_to_req
  14. hx509_ocsp_request
  15. printable_time
  16. hx509_revoke_ocsp_print
  17. hx509_ocsp_verify
  18. hx509_crl_alloc
  19. hx509_crl_add_revoked_certs
  20. hx509_crl_lifetime
  21. hx509_crl_free
  22. add_revoked
  23. hx509_crl_sign

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

/* [<][>][^][v][top][bottom][index][help] */