1178825Sdfr/* 2178825Sdfr * Copyright (c) 2006 - 2007 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr/** 35178825Sdfr * @page page_revoke Revocation methods 36178825Sdfr * 37178825Sdfr * There are two revocation method for PKIX/X.509: CRL and OCSP. 38178825Sdfr * Revocation is needed if the private key is lost and 39178825Sdfr * stolen. Depending on how picky you are, you might want to make 40178825Sdfr * revocation for destroyed private keys too (smartcard broken), but 41178825Sdfr * that should not be a problem. 42178825Sdfr * 43178825Sdfr * CRL is a list of certifiates that have expired. 44178825Sdfr * 45178825Sdfr * OCSP is an online checking method where the requestor sends a list 46178825Sdfr * of certificates to the OCSP server to return a signed reply if they 47178825Sdfr * are valid or not. Some services sends a OCSP reply as part of the 48178825Sdfr * hand-shake to make the revoktion decision simpler/faster for the 49178825Sdfr * client. 50178825Sdfr */ 51178825Sdfr 52178825Sdfr#include "hx_locl.h" 53178825SdfrRCSID("$Id: revoke.c 22275 2007-12-11 11:02:11Z lha $"); 54178825Sdfr 55178825Sdfrstruct revoke_crl { 56178825Sdfr char *path; 57178825Sdfr time_t last_modfied; 58178825Sdfr CRLCertificateList crl; 59178825Sdfr int verified; 60178825Sdfr int failed_verify; 61178825Sdfr}; 62178825Sdfr 63178825Sdfrstruct revoke_ocsp { 64178825Sdfr char *path; 65178825Sdfr time_t last_modfied; 66178825Sdfr OCSPBasicOCSPResponse ocsp; 67178825Sdfr hx509_certs certs; 68178825Sdfr hx509_cert signer; 69178825Sdfr}; 70178825Sdfr 71178825Sdfr 72178825Sdfrstruct hx509_revoke_ctx_data { 73178825Sdfr unsigned ref; 74178825Sdfr struct { 75178825Sdfr struct revoke_crl *val; 76178825Sdfr size_t len; 77178825Sdfr } crls; 78178825Sdfr struct { 79178825Sdfr struct revoke_ocsp *val; 80178825Sdfr size_t len; 81178825Sdfr } ocsps; 82178825Sdfr}; 83178825Sdfr 84178825Sdfr/** 85178825Sdfr * Allocate a revokation context. Free with hx509_revoke_free(). 86178825Sdfr * 87178825Sdfr * @param context A hx509 context. 88178825Sdfr * @param ctx returns a newly allocated revokation context. 89178825Sdfr * 90178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 91178825Sdfr * 92178825Sdfr * @ingroup hx509_revoke 93178825Sdfr */ 94178825Sdfr 95178825Sdfrint 96178825Sdfrhx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx) 97178825Sdfr{ 98178825Sdfr *ctx = calloc(1, sizeof(**ctx)); 99178825Sdfr if (*ctx == NULL) 100178825Sdfr return ENOMEM; 101178825Sdfr 102178825Sdfr (*ctx)->ref = 1; 103178825Sdfr (*ctx)->crls.len = 0; 104178825Sdfr (*ctx)->crls.val = NULL; 105178825Sdfr (*ctx)->ocsps.len = 0; 106178825Sdfr (*ctx)->ocsps.val = NULL; 107178825Sdfr 108178825Sdfr return 0; 109178825Sdfr} 110178825Sdfr 111178825Sdfrhx509_revoke_ctx 112178825Sdfr_hx509_revoke_ref(hx509_revoke_ctx ctx) 113178825Sdfr{ 114178825Sdfr if (ctx == NULL) 115178825Sdfr return NULL; 116178825Sdfr if (ctx->ref <= 0) 117178825Sdfr _hx509_abort("revoke ctx refcount <= 0"); 118178825Sdfr ctx->ref++; 119178825Sdfr if (ctx->ref == 0) 120178825Sdfr _hx509_abort("revoke ctx refcount == 0"); 121178825Sdfr return ctx; 122178825Sdfr} 123178825Sdfr 124178825Sdfrstatic void 125178825Sdfrfree_ocsp(struct revoke_ocsp *ocsp) 126178825Sdfr{ 127178825Sdfr free(ocsp->path); 128178825Sdfr free_OCSPBasicOCSPResponse(&ocsp->ocsp); 129178825Sdfr hx509_certs_free(&ocsp->certs); 130178825Sdfr hx509_cert_free(ocsp->signer); 131178825Sdfr} 132178825Sdfr 133178825Sdfr/** 134178825Sdfr * Free a hx509 revokation context. 135178825Sdfr * 136178825Sdfr * @param ctx context to be freed 137178825Sdfr * 138178825Sdfr * @ingroup hx509_revoke 139178825Sdfr */ 140178825Sdfr 141178825Sdfrvoid 142178825Sdfrhx509_revoke_free(hx509_revoke_ctx *ctx) 143178825Sdfr{ 144178825Sdfr size_t i ; 145178825Sdfr 146178825Sdfr if (ctx == NULL || *ctx == NULL) 147178825Sdfr return; 148178825Sdfr 149178825Sdfr if ((*ctx)->ref <= 0) 150178825Sdfr _hx509_abort("revoke ctx refcount <= 0 on free"); 151178825Sdfr if (--(*ctx)->ref > 0) 152178825Sdfr return; 153178825Sdfr 154178825Sdfr for (i = 0; i < (*ctx)->crls.len; i++) { 155178825Sdfr free((*ctx)->crls.val[i].path); 156178825Sdfr free_CRLCertificateList(&(*ctx)->crls.val[i].crl); 157178825Sdfr } 158178825Sdfr 159178825Sdfr for (i = 0; i < (*ctx)->ocsps.len; i++) 160178825Sdfr free_ocsp(&(*ctx)->ocsps.val[i]); 161178825Sdfr free((*ctx)->ocsps.val); 162178825Sdfr 163178825Sdfr free((*ctx)->crls.val); 164178825Sdfr 165178825Sdfr memset(*ctx, 0, sizeof(**ctx)); 166178825Sdfr free(*ctx); 167178825Sdfr *ctx = NULL; 168178825Sdfr} 169178825Sdfr 170178825Sdfrstatic int 171178825Sdfrverify_ocsp(hx509_context context, 172178825Sdfr struct revoke_ocsp *ocsp, 173178825Sdfr time_t time_now, 174178825Sdfr hx509_certs certs, 175178825Sdfr hx509_cert parent) 176178825Sdfr{ 177178825Sdfr hx509_cert signer = NULL; 178178825Sdfr hx509_query q; 179178825Sdfr int ret; 180178825Sdfr 181178825Sdfr _hx509_query_clear(&q); 182178825Sdfr 183178825Sdfr /* 184178825Sdfr * Need to match on issuer too in case there are two CA that have 185178825Sdfr * issued the same name to a certificate. One example of this is 186178825Sdfr * the www.openvalidation.org test's ocsp validator. 187178825Sdfr */ 188178825Sdfr 189178825Sdfr q.match = HX509_QUERY_MATCH_ISSUER_NAME; 190178825Sdfr q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer; 191178825Sdfr 192178825Sdfr switch(ocsp->ocsp.tbsResponseData.responderID.element) { 193178825Sdfr case choice_OCSPResponderID_byName: 194178825Sdfr q.match |= HX509_QUERY_MATCH_SUBJECT_NAME; 195178825Sdfr q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName; 196178825Sdfr break; 197178825Sdfr case choice_OCSPResponderID_byKey: 198178825Sdfr q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1; 199178825Sdfr q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey; 200178825Sdfr break; 201178825Sdfr } 202178825Sdfr 203178825Sdfr ret = hx509_certs_find(context, certs, &q, &signer); 204178825Sdfr if (ret && ocsp->certs) 205178825Sdfr ret = hx509_certs_find(context, ocsp->certs, &q, &signer); 206178825Sdfr if (ret) 207178825Sdfr goto out; 208178825Sdfr 209178825Sdfr /* 210178825Sdfr * If signer certificate isn't the CA certificate, lets check the 211178825Sdfr * it is the CA that signed the signer certificate and the OCSP EKU 212178825Sdfr * is set. 213178825Sdfr */ 214178825Sdfr if (hx509_cert_cmp(signer, parent) != 0) { 215178825Sdfr Certificate *p = _hx509_get_cert(parent); 216178825Sdfr Certificate *s = _hx509_get_cert(signer); 217178825Sdfr 218178825Sdfr ret = _hx509_cert_is_parent_cmp(s, p, 0); 219178825Sdfr if (ret != 0) { 220178825Sdfr ret = HX509_PARENT_NOT_CA; 221178825Sdfr hx509_set_error_string(context, 0, ret, "Revoke OSCP signer is " 222178825Sdfr "doesn't have CA as signer certificate"); 223178825Sdfr goto out; 224178825Sdfr } 225178825Sdfr 226178825Sdfr ret = _hx509_verify_signature_bitstring(context, 227178825Sdfr p, 228178825Sdfr &s->signatureAlgorithm, 229178825Sdfr &s->tbsCertificate._save, 230178825Sdfr &s->signatureValue); 231178825Sdfr if (ret) { 232178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 233178825Sdfr "OSCP signer signature invalid"); 234178825Sdfr goto out; 235178825Sdfr } 236178825Sdfr 237178825Sdfr ret = hx509_cert_check_eku(context, signer, 238178825Sdfr oid_id_pkix_kp_OCSPSigning(), 0); 239178825Sdfr if (ret) 240178825Sdfr goto out; 241178825Sdfr } 242178825Sdfr 243178825Sdfr ret = _hx509_verify_signature_bitstring(context, 244178825Sdfr _hx509_get_cert(signer), 245178825Sdfr &ocsp->ocsp.signatureAlgorithm, 246178825Sdfr &ocsp->ocsp.tbsResponseData._save, 247178825Sdfr &ocsp->ocsp.signature); 248178825Sdfr if (ret) { 249178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 250178825Sdfr "OSCP signature invalid"); 251178825Sdfr goto out; 252178825Sdfr } 253178825Sdfr 254178825Sdfr ocsp->signer = signer; 255178825Sdfr signer = NULL; 256178825Sdfrout: 257178825Sdfr if (signer) 258178825Sdfr hx509_cert_free(signer); 259178825Sdfr 260178825Sdfr return ret; 261178825Sdfr} 262178825Sdfr 263178825Sdfr/* 264178825Sdfr * 265178825Sdfr */ 266178825Sdfr 267178825Sdfrstatic int 268178825Sdfrparse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic) 269178825Sdfr{ 270178825Sdfr OCSPResponse resp; 271178825Sdfr size_t size; 272178825Sdfr int ret; 273178825Sdfr 274178825Sdfr memset(basic, 0, sizeof(*basic)); 275178825Sdfr 276178825Sdfr ret = decode_OCSPResponse(data, length, &resp, &size); 277178825Sdfr if (ret) 278178825Sdfr return ret; 279178825Sdfr if (length != size) { 280178825Sdfr free_OCSPResponse(&resp); 281178825Sdfr return ASN1_EXTRA_DATA; 282178825Sdfr } 283178825Sdfr 284178825Sdfr switch (resp.responseStatus) { 285178825Sdfr case successful: 286178825Sdfr break; 287178825Sdfr default: 288178825Sdfr free_OCSPResponse(&resp); 289178825Sdfr return HX509_REVOKE_WRONG_DATA; 290178825Sdfr } 291178825Sdfr 292178825Sdfr if (resp.responseBytes == NULL) { 293178825Sdfr free_OCSPResponse(&resp); 294178825Sdfr return EINVAL; 295178825Sdfr } 296178825Sdfr 297178825Sdfr ret = der_heim_oid_cmp(&resp.responseBytes->responseType, 298178825Sdfr oid_id_pkix_ocsp_basic()); 299178825Sdfr if (ret != 0) { 300178825Sdfr free_OCSPResponse(&resp); 301178825Sdfr return HX509_REVOKE_WRONG_DATA; 302178825Sdfr } 303178825Sdfr 304178825Sdfr ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data, 305178825Sdfr resp.responseBytes->response.length, 306178825Sdfr basic, 307178825Sdfr &size); 308178825Sdfr if (ret) { 309178825Sdfr free_OCSPResponse(&resp); 310178825Sdfr return ret; 311178825Sdfr } 312178825Sdfr if (size != resp.responseBytes->response.length) { 313178825Sdfr free_OCSPResponse(&resp); 314178825Sdfr free_OCSPBasicOCSPResponse(basic); 315178825Sdfr return ASN1_EXTRA_DATA; 316178825Sdfr } 317178825Sdfr free_OCSPResponse(&resp); 318178825Sdfr 319178825Sdfr return 0; 320178825Sdfr} 321178825Sdfr 322178825Sdfr/* 323178825Sdfr * 324178825Sdfr */ 325178825Sdfr 326178825Sdfrstatic int 327178825Sdfrload_ocsp(hx509_context context, struct revoke_ocsp *ocsp) 328178825Sdfr{ 329178825Sdfr OCSPBasicOCSPResponse basic; 330178825Sdfr hx509_certs certs = NULL; 331178825Sdfr size_t length; 332178825Sdfr struct stat sb; 333178825Sdfr void *data; 334178825Sdfr int ret; 335178825Sdfr 336178825Sdfr ret = _hx509_map_file(ocsp->path, &data, &length, &sb); 337178825Sdfr if (ret) 338178825Sdfr return ret; 339178825Sdfr 340178825Sdfr ret = parse_ocsp_basic(data, length, &basic); 341178825Sdfr _hx509_unmap_file(data, length); 342178825Sdfr if (ret) { 343178825Sdfr hx509_set_error_string(context, 0, ret, 344178825Sdfr "Failed to parse OCSP response"); 345178825Sdfr return ret; 346178825Sdfr } 347178825Sdfr 348178825Sdfr if (basic.certs) { 349178825Sdfr int i; 350178825Sdfr 351178825Sdfr ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0, 352178825Sdfr NULL, &certs); 353178825Sdfr if (ret) { 354178825Sdfr free_OCSPBasicOCSPResponse(&basic); 355178825Sdfr return ret; 356178825Sdfr } 357178825Sdfr 358178825Sdfr for (i = 0; i < basic.certs->len; i++) { 359178825Sdfr hx509_cert c; 360178825Sdfr 361178825Sdfr ret = hx509_cert_init(context, &basic.certs->val[i], &c); 362178825Sdfr if (ret) 363178825Sdfr continue; 364178825Sdfr 365178825Sdfr ret = hx509_certs_add(context, certs, c); 366178825Sdfr hx509_cert_free(c); 367178825Sdfr if (ret) 368178825Sdfr continue; 369178825Sdfr } 370178825Sdfr } 371178825Sdfr 372178825Sdfr ocsp->last_modfied = sb.st_mtime; 373178825Sdfr 374178825Sdfr free_OCSPBasicOCSPResponse(&ocsp->ocsp); 375178825Sdfr hx509_certs_free(&ocsp->certs); 376178825Sdfr hx509_cert_free(ocsp->signer); 377178825Sdfr 378178825Sdfr ocsp->ocsp = basic; 379178825Sdfr ocsp->certs = certs; 380178825Sdfr ocsp->signer = NULL; 381178825Sdfr 382178825Sdfr return 0; 383178825Sdfr} 384178825Sdfr 385178825Sdfr/** 386178825Sdfr * Add a OCSP file to the revokation context. 387178825Sdfr * 388178825Sdfr * @param context hx509 context 389178825Sdfr * @param ctx hx509 revokation context 390178825Sdfr * @param path path to file that is going to be added to the context. 391178825Sdfr * 392178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 393178825Sdfr * 394178825Sdfr * @ingroup hx509_revoke 395178825Sdfr */ 396178825Sdfr 397178825Sdfrint 398178825Sdfrhx509_revoke_add_ocsp(hx509_context context, 399178825Sdfr hx509_revoke_ctx ctx, 400178825Sdfr const char *path) 401178825Sdfr{ 402178825Sdfr void *data; 403178825Sdfr int ret; 404178825Sdfr size_t i; 405178825Sdfr 406178825Sdfr if (strncmp(path, "FILE:", 5) != 0) { 407178825Sdfr hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 408178825Sdfr "unsupport type in %s", path); 409178825Sdfr return HX509_UNSUPPORTED_OPERATION; 410178825Sdfr } 411178825Sdfr 412178825Sdfr path += 5; 413178825Sdfr 414178825Sdfr for (i = 0; i < ctx->ocsps.len; i++) { 415178825Sdfr if (strcmp(ctx->ocsps.val[0].path, path) == 0) 416178825Sdfr return 0; 417178825Sdfr } 418178825Sdfr 419178825Sdfr data = realloc(ctx->ocsps.val, 420178825Sdfr (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0])); 421178825Sdfr if (data == NULL) { 422178825Sdfr hx509_clear_error_string(context); 423178825Sdfr return ENOMEM; 424178825Sdfr } 425178825Sdfr 426178825Sdfr ctx->ocsps.val = data; 427178825Sdfr 428178825Sdfr memset(&ctx->ocsps.val[ctx->ocsps.len], 0, 429178825Sdfr sizeof(ctx->ocsps.val[0])); 430178825Sdfr 431178825Sdfr ctx->ocsps.val[ctx->ocsps.len].path = strdup(path); 432178825Sdfr if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) { 433178825Sdfr hx509_clear_error_string(context); 434178825Sdfr return ENOMEM; 435178825Sdfr } 436178825Sdfr 437178825Sdfr ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]); 438178825Sdfr if (ret) { 439178825Sdfr free(ctx->ocsps.val[ctx->ocsps.len].path); 440178825Sdfr return ret; 441178825Sdfr } 442178825Sdfr ctx->ocsps.len++; 443178825Sdfr 444178825Sdfr return ret; 445178825Sdfr} 446178825Sdfr 447178825Sdfr/* 448178825Sdfr * 449178825Sdfr */ 450178825Sdfr 451178825Sdfrstatic int 452178825Sdfrverify_crl(hx509_context context, 453178825Sdfr hx509_revoke_ctx ctx, 454178825Sdfr CRLCertificateList *crl, 455178825Sdfr time_t time_now, 456178825Sdfr hx509_certs certs, 457178825Sdfr hx509_cert parent) 458178825Sdfr{ 459178825Sdfr hx509_cert signer; 460178825Sdfr hx509_query q; 461178825Sdfr time_t t; 462178825Sdfr int ret; 463178825Sdfr 464178825Sdfr t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate); 465178825Sdfr if (t > time_now) { 466178825Sdfr hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME, 467178825Sdfr "CRL used before time"); 468178825Sdfr return HX509_CRL_USED_BEFORE_TIME; 469178825Sdfr } 470178825Sdfr 471178825Sdfr if (crl->tbsCertList.nextUpdate == NULL) { 472178825Sdfr hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT, 473178825Sdfr "CRL missing nextUpdate"); 474178825Sdfr return HX509_CRL_INVALID_FORMAT; 475178825Sdfr } 476178825Sdfr 477178825Sdfr t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate); 478178825Sdfr if (t < time_now) { 479178825Sdfr hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME, 480178825Sdfr "CRL used after time"); 481178825Sdfr return HX509_CRL_USED_AFTER_TIME; 482178825Sdfr } 483178825Sdfr 484178825Sdfr _hx509_query_clear(&q); 485178825Sdfr 486178825Sdfr /* 487178825Sdfr * If it's the signer have CRLSIGN bit set, use that as the signer 488178825Sdfr * cert for the certificate, otherwise, search for a certificate. 489178825Sdfr */ 490178825Sdfr if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) { 491178825Sdfr signer = hx509_cert_ref(parent); 492178825Sdfr } else { 493178825Sdfr q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 494178825Sdfr q.match |= HX509_QUERY_KU_CRLSIGN; 495178825Sdfr q.subject_name = &crl->tbsCertList.issuer; 496178825Sdfr 497178825Sdfr ret = hx509_certs_find(context, certs, &q, &signer); 498178825Sdfr if (ret) { 499178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 500178825Sdfr "Failed to find certificate for CRL"); 501178825Sdfr return ret; 502178825Sdfr } 503178825Sdfr } 504178825Sdfr 505178825Sdfr ret = _hx509_verify_signature_bitstring(context, 506178825Sdfr _hx509_get_cert(signer), 507178825Sdfr &crl->signatureAlgorithm, 508178825Sdfr &crl->tbsCertList._save, 509178825Sdfr &crl->signatureValue); 510178825Sdfr if (ret) { 511178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 512178825Sdfr "CRL signature invalid"); 513178825Sdfr goto out; 514178825Sdfr } 515178825Sdfr 516178825Sdfr /* 517178825Sdfr * If signer is not CA cert, need to check revoke status of this 518178825Sdfr * CRL signing cert too, this include all parent CRL signer cert 519178825Sdfr * up to the root *sigh*, assume root at least hve CERTSIGN flag 520178825Sdfr * set. 521178825Sdfr */ 522178825Sdfr while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) { 523178825Sdfr hx509_cert crl_parent; 524178825Sdfr 525178825Sdfr _hx509_query_clear(&q); 526178825Sdfr 527178825Sdfr q.match = HX509_QUERY_MATCH_SUBJECT_NAME; 528178825Sdfr q.match |= HX509_QUERY_KU_CRLSIGN; 529178825Sdfr q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer; 530178825Sdfr 531178825Sdfr ret = hx509_certs_find(context, certs, &q, &crl_parent); 532178825Sdfr if (ret) { 533178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 534178825Sdfr "Failed to find parent of CRL signer"); 535178825Sdfr goto out; 536178825Sdfr } 537178825Sdfr 538178825Sdfr ret = hx509_revoke_verify(context, 539178825Sdfr ctx, 540178825Sdfr certs, 541178825Sdfr time_now, 542178825Sdfr signer, 543178825Sdfr crl_parent); 544178825Sdfr hx509_cert_free(signer); 545178825Sdfr signer = crl_parent; 546178825Sdfr if (ret) { 547178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 548178825Sdfr "Failed to verify revoke " 549178825Sdfr "status of CRL signer"); 550178825Sdfr goto out; 551178825Sdfr } 552178825Sdfr } 553178825Sdfr 554178825Sdfrout: 555178825Sdfr hx509_cert_free(signer); 556178825Sdfr 557178825Sdfr return ret; 558178825Sdfr} 559178825Sdfr 560178825Sdfrstatic int 561178825Sdfrload_crl(const char *path, time_t *t, CRLCertificateList *crl) 562178825Sdfr{ 563178825Sdfr size_t length, size; 564178825Sdfr struct stat sb; 565178825Sdfr void *data; 566178825Sdfr int ret; 567178825Sdfr 568178825Sdfr memset(crl, 0, sizeof(*crl)); 569178825Sdfr 570178825Sdfr ret = _hx509_map_file(path, &data, &length, &sb); 571178825Sdfr if (ret) 572178825Sdfr return ret; 573178825Sdfr 574178825Sdfr *t = sb.st_mtime; 575178825Sdfr 576178825Sdfr ret = decode_CRLCertificateList(data, length, crl, &size); 577178825Sdfr _hx509_unmap_file(data, length); 578178825Sdfr if (ret) 579178825Sdfr return ret; 580178825Sdfr 581178825Sdfr /* check signature is aligned */ 582178825Sdfr if (crl->signatureValue.length & 7) { 583178825Sdfr free_CRLCertificateList(crl); 584178825Sdfr return HX509_CRYPTO_SIG_INVALID_FORMAT; 585178825Sdfr } 586178825Sdfr return 0; 587178825Sdfr} 588178825Sdfr 589178825Sdfr/** 590178825Sdfr * Add a CRL file to the revokation context. 591178825Sdfr * 592178825Sdfr * @param context hx509 context 593178825Sdfr * @param ctx hx509 revokation context 594178825Sdfr * @param path path to file that is going to be added to the context. 595178825Sdfr * 596178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 597178825Sdfr * 598178825Sdfr * @ingroup hx509_revoke 599178825Sdfr */ 600178825Sdfr 601178825Sdfrint 602178825Sdfrhx509_revoke_add_crl(hx509_context context, 603178825Sdfr hx509_revoke_ctx ctx, 604178825Sdfr const char *path) 605178825Sdfr{ 606178825Sdfr void *data; 607178825Sdfr size_t i; 608178825Sdfr int ret; 609178825Sdfr 610178825Sdfr if (strncmp(path, "FILE:", 5) != 0) { 611178825Sdfr hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, 612178825Sdfr "unsupport type in %s", path); 613178825Sdfr return HX509_UNSUPPORTED_OPERATION; 614178825Sdfr } 615178825Sdfr 616178825Sdfr 617178825Sdfr path += 5; 618178825Sdfr 619178825Sdfr for (i = 0; i < ctx->crls.len; i++) { 620178825Sdfr if (strcmp(ctx->crls.val[0].path, path) == 0) 621178825Sdfr return 0; 622178825Sdfr } 623178825Sdfr 624178825Sdfr data = realloc(ctx->crls.val, 625178825Sdfr (ctx->crls.len + 1) * sizeof(ctx->crls.val[0])); 626178825Sdfr if (data == NULL) { 627178825Sdfr hx509_clear_error_string(context); 628178825Sdfr return ENOMEM; 629178825Sdfr } 630178825Sdfr ctx->crls.val = data; 631178825Sdfr 632178825Sdfr memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0])); 633178825Sdfr 634178825Sdfr ctx->crls.val[ctx->crls.len].path = strdup(path); 635178825Sdfr if (ctx->crls.val[ctx->crls.len].path == NULL) { 636178825Sdfr hx509_clear_error_string(context); 637178825Sdfr return ENOMEM; 638178825Sdfr } 639178825Sdfr 640178825Sdfr ret = load_crl(path, 641178825Sdfr &ctx->crls.val[ctx->crls.len].last_modfied, 642178825Sdfr &ctx->crls.val[ctx->crls.len].crl); 643178825Sdfr if (ret) { 644178825Sdfr free(ctx->crls.val[ctx->crls.len].path); 645178825Sdfr return ret; 646178825Sdfr } 647178825Sdfr 648178825Sdfr ctx->crls.len++; 649178825Sdfr 650178825Sdfr return ret; 651178825Sdfr} 652178825Sdfr 653178825Sdfr/** 654178825Sdfr * Check that a certificate is not expired according to a revokation 655178825Sdfr * context. Also need the parent certificte to the check OCSP 656178825Sdfr * parent identifier. 657178825Sdfr * 658178825Sdfr * @param context hx509 context 659178825Sdfr * @param ctx hx509 revokation context 660178825Sdfr * @param certs 661178825Sdfr * @param now 662178825Sdfr * @param cert 663178825Sdfr * @param parent_cert 664178825Sdfr * 665178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 666178825Sdfr * 667178825Sdfr * @ingroup hx509_revoke 668178825Sdfr */ 669178825Sdfr 670178825Sdfr 671178825Sdfrint 672178825Sdfrhx509_revoke_verify(hx509_context context, 673178825Sdfr hx509_revoke_ctx ctx, 674178825Sdfr hx509_certs certs, 675178825Sdfr time_t now, 676178825Sdfr hx509_cert cert, 677178825Sdfr hx509_cert parent_cert) 678178825Sdfr{ 679178825Sdfr const Certificate *c = _hx509_get_cert(cert); 680178825Sdfr const Certificate *p = _hx509_get_cert(parent_cert); 681178825Sdfr unsigned long i, j, k; 682178825Sdfr int ret; 683178825Sdfr 684178825Sdfr hx509_clear_error_string(context); 685178825Sdfr 686178825Sdfr for (i = 0; i < ctx->ocsps.len; i++) { 687178825Sdfr struct revoke_ocsp *ocsp = &ctx->ocsps.val[i]; 688178825Sdfr struct stat sb; 689178825Sdfr 690178825Sdfr /* check this ocsp apply to this cert */ 691178825Sdfr 692178825Sdfr /* check if there is a newer version of the file */ 693178825Sdfr ret = stat(ocsp->path, &sb); 694178825Sdfr if (ret == 0 && ocsp->last_modfied != sb.st_mtime) { 695178825Sdfr ret = load_ocsp(context, ocsp); 696178825Sdfr if (ret) 697178825Sdfr continue; 698178825Sdfr } 699178825Sdfr 700178825Sdfr /* verify signature in ocsp if not already done */ 701178825Sdfr if (ocsp->signer == NULL) { 702178825Sdfr ret = verify_ocsp(context, ocsp, now, certs, parent_cert); 703178825Sdfr if (ret) 704178825Sdfr continue; 705178825Sdfr } 706178825Sdfr 707178825Sdfr for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) { 708178825Sdfr heim_octet_string os; 709178825Sdfr 710178825Sdfr ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber, 711178825Sdfr &c->tbsCertificate.serialNumber); 712178825Sdfr if (ret != 0) 713178825Sdfr continue; 714178825Sdfr 715178825Sdfr /* verify issuer hashes hash */ 716178825Sdfr ret = _hx509_verify_signature(context, 717178825Sdfr NULL, 718178825Sdfr &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, 719178825Sdfr &c->tbsCertificate.issuer._save, 720178825Sdfr &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash); 721178825Sdfr if (ret != 0) 722178825Sdfr continue; 723178825Sdfr 724178825Sdfr os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 725178825Sdfr os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 726178825Sdfr 727178825Sdfr ret = _hx509_verify_signature(context, 728178825Sdfr NULL, 729178825Sdfr &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm, 730178825Sdfr &os, 731178825Sdfr &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash); 732178825Sdfr if (ret != 0) 733178825Sdfr continue; 734178825Sdfr 735178825Sdfr switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) { 736178825Sdfr case choice_OCSPCertStatus_good: 737178825Sdfr break; 738178825Sdfr case choice_OCSPCertStatus_revoked: 739178825Sdfr hx509_set_error_string(context, 0, 740178825Sdfr HX509_CERT_REVOKED, 741178825Sdfr "Certificate revoked by issuer in OCSP"); 742178825Sdfr return HX509_CERT_REVOKED; 743178825Sdfr case choice_OCSPCertStatus_unknown: 744178825Sdfr continue; 745178825Sdfr } 746178825Sdfr 747178825Sdfr /* don't allow the update to be in the future */ 748178825Sdfr if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > 749178825Sdfr now + context->ocsp_time_diff) 750178825Sdfr continue; 751178825Sdfr 752178825Sdfr /* don't allow the next update to be in the past */ 753178825Sdfr if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) { 754178825Sdfr if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now) 755178825Sdfr continue; 756178825Sdfr } else 757178825Sdfr /* Should force a refetch, but can we ? */; 758178825Sdfr 759178825Sdfr return 0; 760178825Sdfr } 761178825Sdfr } 762178825Sdfr 763178825Sdfr for (i = 0; i < ctx->crls.len; i++) { 764178825Sdfr struct revoke_crl *crl = &ctx->crls.val[i]; 765178825Sdfr struct stat sb; 766178825Sdfr 767178825Sdfr /* check if cert.issuer == crls.val[i].crl.issuer */ 768178825Sdfr ret = _hx509_name_cmp(&c->tbsCertificate.issuer, 769178825Sdfr &crl->crl.tbsCertList.issuer); 770178825Sdfr if (ret) 771178825Sdfr continue; 772178825Sdfr 773178825Sdfr ret = stat(crl->path, &sb); 774178825Sdfr if (ret == 0 && crl->last_modfied != sb.st_mtime) { 775178825Sdfr CRLCertificateList cl; 776178825Sdfr 777178825Sdfr ret = load_crl(crl->path, &crl->last_modfied, &cl); 778178825Sdfr if (ret == 0) { 779178825Sdfr free_CRLCertificateList(&crl->crl); 780178825Sdfr crl->crl = cl; 781178825Sdfr crl->verified = 0; 782178825Sdfr crl->failed_verify = 0; 783178825Sdfr } 784178825Sdfr } 785178825Sdfr if (crl->failed_verify) 786178825Sdfr continue; 787178825Sdfr 788178825Sdfr /* verify signature in crl if not already done */ 789178825Sdfr if (crl->verified == 0) { 790178825Sdfr ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert); 791178825Sdfr if (ret) { 792178825Sdfr crl->failed_verify = 1; 793178825Sdfr continue; 794178825Sdfr } 795178825Sdfr crl->verified = 1; 796178825Sdfr } 797178825Sdfr 798178825Sdfr if (crl->crl.tbsCertList.crlExtensions) { 799178825Sdfr for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) { 800178825Sdfr if (crl->crl.tbsCertList.crlExtensions->val[j].critical) { 801178825Sdfr hx509_set_error_string(context, 0, 802178825Sdfr HX509_CRL_UNKNOWN_EXTENSION, 803178825Sdfr "Unknown CRL extension"); 804178825Sdfr return HX509_CRL_UNKNOWN_EXTENSION; 805178825Sdfr } 806178825Sdfr } 807178825Sdfr } 808178825Sdfr 809178825Sdfr if (crl->crl.tbsCertList.revokedCertificates == NULL) 810178825Sdfr return 0; 811178825Sdfr 812178825Sdfr /* check if cert is in crl */ 813178825Sdfr for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) { 814178825Sdfr time_t t; 815178825Sdfr 816178825Sdfr ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate, 817178825Sdfr &c->tbsCertificate.serialNumber); 818178825Sdfr if (ret != 0) 819178825Sdfr continue; 820178825Sdfr 821178825Sdfr t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate); 822178825Sdfr if (t > now) 823178825Sdfr continue; 824178825Sdfr 825178825Sdfr if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions) 826178825Sdfr for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++) 827178825Sdfr if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical) 828178825Sdfr return HX509_CRL_UNKNOWN_EXTENSION; 829178825Sdfr 830178825Sdfr hx509_set_error_string(context, 0, 831178825Sdfr HX509_CERT_REVOKED, 832178825Sdfr "Certificate revoked by issuer in CRL"); 833178825Sdfr return HX509_CERT_REVOKED; 834178825Sdfr } 835178825Sdfr 836178825Sdfr return 0; 837178825Sdfr } 838178825Sdfr 839178825Sdfr 840178825Sdfr if (context->flags & HX509_CTX_VERIFY_MISSING_OK) 841178825Sdfr return 0; 842178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, 843178825Sdfr HX509_REVOKE_STATUS_MISSING, 844178825Sdfr "No revoke status found for " 845178825Sdfr "certificates"); 846178825Sdfr return HX509_REVOKE_STATUS_MISSING; 847178825Sdfr} 848178825Sdfr 849178825Sdfrstruct ocsp_add_ctx { 850178825Sdfr OCSPTBSRequest *req; 851178825Sdfr hx509_certs certs; 852178825Sdfr const AlgorithmIdentifier *digest; 853178825Sdfr hx509_cert parent; 854178825Sdfr}; 855178825Sdfr 856178825Sdfrstatic int 857178825Sdfradd_to_req(hx509_context context, void *ptr, hx509_cert cert) 858178825Sdfr{ 859178825Sdfr struct ocsp_add_ctx *ctx = ptr; 860178825Sdfr OCSPInnerRequest *one; 861178825Sdfr hx509_cert parent = NULL; 862178825Sdfr Certificate *p, *c = _hx509_get_cert(cert); 863178825Sdfr heim_octet_string os; 864178825Sdfr int ret; 865178825Sdfr hx509_query q; 866178825Sdfr void *d; 867178825Sdfr 868178825Sdfr d = realloc(ctx->req->requestList.val, 869178825Sdfr sizeof(ctx->req->requestList.val[0]) * 870178825Sdfr (ctx->req->requestList.len + 1)); 871178825Sdfr if (d == NULL) 872178825Sdfr return ENOMEM; 873178825Sdfr ctx->req->requestList.val = d; 874178825Sdfr 875178825Sdfr one = &ctx->req->requestList.val[ctx->req->requestList.len]; 876178825Sdfr memset(one, 0, sizeof(*one)); 877178825Sdfr 878178825Sdfr _hx509_query_clear(&q); 879178825Sdfr 880178825Sdfr q.match |= HX509_QUERY_FIND_ISSUER_CERT; 881178825Sdfr q.subject = c; 882178825Sdfr 883178825Sdfr ret = hx509_certs_find(context, ctx->certs, &q, &parent); 884178825Sdfr if (ret) 885178825Sdfr goto out; 886178825Sdfr 887178825Sdfr if (ctx->parent) { 888178825Sdfr if (hx509_cert_cmp(ctx->parent, parent) != 0) { 889178825Sdfr ret = HX509_REVOKE_NOT_SAME_PARENT; 890178825Sdfr hx509_set_error_string(context, 0, ret, 891178825Sdfr "Not same parent certifate as " 892178825Sdfr "last certificate in request"); 893178825Sdfr goto out; 894178825Sdfr } 895178825Sdfr } else 896178825Sdfr ctx->parent = hx509_cert_ref(parent); 897178825Sdfr 898178825Sdfr p = _hx509_get_cert(parent); 899178825Sdfr 900178825Sdfr ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm); 901178825Sdfr if (ret) 902178825Sdfr goto out; 903178825Sdfr 904178825Sdfr ret = _hx509_create_signature(context, 905178825Sdfr NULL, 906178825Sdfr &one->reqCert.hashAlgorithm, 907178825Sdfr &c->tbsCertificate.issuer._save, 908178825Sdfr NULL, 909178825Sdfr &one->reqCert.issuerNameHash); 910178825Sdfr if (ret) 911178825Sdfr goto out; 912178825Sdfr 913178825Sdfr os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 914178825Sdfr os.length = 915178825Sdfr p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 916178825Sdfr 917178825Sdfr ret = _hx509_create_signature(context, 918178825Sdfr NULL, 919178825Sdfr &one->reqCert.hashAlgorithm, 920178825Sdfr &os, 921178825Sdfr NULL, 922178825Sdfr &one->reqCert.issuerKeyHash); 923178825Sdfr if (ret) 924178825Sdfr goto out; 925178825Sdfr 926178825Sdfr ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber, 927178825Sdfr &one->reqCert.serialNumber); 928178825Sdfr if (ret) 929178825Sdfr goto out; 930178825Sdfr 931178825Sdfr ctx->req->requestList.len++; 932178825Sdfrout: 933178825Sdfr hx509_cert_free(parent); 934178825Sdfr if (ret) { 935178825Sdfr free_OCSPInnerRequest(one); 936178825Sdfr memset(one, 0, sizeof(*one)); 937178825Sdfr } 938178825Sdfr 939178825Sdfr return ret; 940178825Sdfr} 941178825Sdfr 942178825Sdfr/** 943178825Sdfr * Create an OCSP request for a set of certificates. 944178825Sdfr * 945178825Sdfr * @param context a hx509 context 946178825Sdfr * @param reqcerts list of certificates to request ocsp data for 947178825Sdfr * @param pool certificate pool to use when signing 948178825Sdfr * @param signer certificate to use to sign the request 949178825Sdfr * @param digest the signing algorithm in the request, if NULL use the 950178825Sdfr * default signature algorithm, 951178825Sdfr * @param request the encoded request, free with free_heim_octet_string(). 952178825Sdfr * @param nonce nonce in the request, free with free_heim_octet_string(). 953178825Sdfr * 954178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 955178825Sdfr * 956178825Sdfr * @ingroup hx509_revoke 957178825Sdfr */ 958178825Sdfr 959178825Sdfrint 960178825Sdfrhx509_ocsp_request(hx509_context context, 961178825Sdfr hx509_certs reqcerts, 962178825Sdfr hx509_certs pool, 963178825Sdfr hx509_cert signer, 964178825Sdfr const AlgorithmIdentifier *digest, 965178825Sdfr heim_octet_string *request, 966178825Sdfr heim_octet_string *nonce) 967178825Sdfr{ 968178825Sdfr OCSPRequest req; 969178825Sdfr size_t size; 970178825Sdfr int ret; 971178825Sdfr struct ocsp_add_ctx ctx; 972178825Sdfr Extensions *es; 973178825Sdfr 974178825Sdfr memset(&req, 0, sizeof(req)); 975178825Sdfr 976178825Sdfr if (digest == NULL) 977178825Sdfr digest = _hx509_crypto_default_digest_alg; 978178825Sdfr 979178825Sdfr ctx.req = &req.tbsRequest; 980178825Sdfr ctx.certs = pool; 981178825Sdfr ctx.digest = digest; 982178825Sdfr ctx.parent = NULL; 983178825Sdfr 984178825Sdfr ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx); 985178825Sdfr hx509_cert_free(ctx.parent); 986178825Sdfr if (ret) 987178825Sdfr goto out; 988178825Sdfr 989178825Sdfr if (nonce) { 990178825Sdfr req.tbsRequest.requestExtensions = 991178825Sdfr calloc(1, sizeof(*req.tbsRequest.requestExtensions)); 992178825Sdfr if (req.tbsRequest.requestExtensions == NULL) { 993178825Sdfr ret = ENOMEM; 994178825Sdfr goto out; 995178825Sdfr } 996178825Sdfr 997178825Sdfr es = req.tbsRequest.requestExtensions; 998178825Sdfr 999178825Sdfr es->val = calloc(es->len, sizeof(es->val[0])); 1000178825Sdfr if (es->val == NULL) { 1001178825Sdfr ret = ENOMEM; 1002178825Sdfr goto out; 1003178825Sdfr } 1004178825Sdfr es->len = 1; 1005178825Sdfr 1006178825Sdfr ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID); 1007178825Sdfr if (ret) { 1008178825Sdfr free_OCSPRequest(&req); 1009178825Sdfr return ret; 1010178825Sdfr } 1011178825Sdfr 1012178825Sdfr es->val[0].extnValue.data = malloc(10); 1013178825Sdfr if (es->val[0].extnValue.data == NULL) { 1014178825Sdfr ret = ENOMEM; 1015178825Sdfr goto out; 1016178825Sdfr } 1017178825Sdfr es->val[0].extnValue.length = 10; 1018178825Sdfr 1019178825Sdfr ret = RAND_bytes(es->val[0].extnValue.data, 1020178825Sdfr es->val[0].extnValue.length); 1021178825Sdfr if (ret != 1) { 1022178825Sdfr ret = HX509_CRYPTO_INTERNAL_ERROR; 1023178825Sdfr goto out; 1024178825Sdfr } 1025178825Sdfr ret = der_copy_octet_string(nonce, &es->val[0].extnValue); 1026178825Sdfr if (ret) { 1027178825Sdfr ret = ENOMEM; 1028178825Sdfr goto out; 1029178825Sdfr } 1030178825Sdfr } 1031178825Sdfr 1032178825Sdfr ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length, 1033178825Sdfr &req, &size, ret); 1034178825Sdfr free_OCSPRequest(&req); 1035178825Sdfr if (ret) 1036178825Sdfr goto out; 1037178825Sdfr if (size != request->length) 1038178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1039178825Sdfr 1040178825Sdfr return 0; 1041178825Sdfr 1042178825Sdfrout: 1043178825Sdfr free_OCSPRequest(&req); 1044178825Sdfr return ret; 1045178825Sdfr} 1046178825Sdfr 1047178825Sdfrstatic char * 1048178825Sdfrprintable_time(time_t t) 1049178825Sdfr{ 1050178825Sdfr static char s[128]; 1051178825Sdfr strlcpy(s, ctime(&t)+ 4, sizeof(s)); 1052178825Sdfr s[20] = 0; 1053178825Sdfr return s; 1054178825Sdfr} 1055178825Sdfr 1056178825Sdfr/** 1057178825Sdfr * Print the OCSP reply stored in a file. 1058178825Sdfr * 1059178825Sdfr * @param context a hx509 context 1060178825Sdfr * @param path path to a file with a OCSP reply 1061178825Sdfr * @param out the out FILE descriptor to print the reply on 1062178825Sdfr * 1063178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1064178825Sdfr * 1065178825Sdfr * @ingroup hx509_revoke 1066178825Sdfr */ 1067178825Sdfr 1068178825Sdfrint 1069178825Sdfrhx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) 1070178825Sdfr{ 1071178825Sdfr struct revoke_ocsp ocsp; 1072178825Sdfr int ret, i; 1073178825Sdfr 1074178825Sdfr if (out == NULL) 1075178825Sdfr out = stdout; 1076178825Sdfr 1077178825Sdfr memset(&ocsp, 0, sizeof(ocsp)); 1078178825Sdfr 1079178825Sdfr ocsp.path = strdup(path); 1080178825Sdfr if (ocsp.path == NULL) 1081178825Sdfr return ENOMEM; 1082178825Sdfr 1083178825Sdfr ret = load_ocsp(context, &ocsp); 1084178825Sdfr if (ret) { 1085178825Sdfr free_ocsp(&ocsp); 1086178825Sdfr return ret; 1087178825Sdfr } 1088178825Sdfr 1089178825Sdfr fprintf(out, "signer: "); 1090178825Sdfr 1091178825Sdfr switch(ocsp.ocsp.tbsResponseData.responderID.element) { 1092178825Sdfr case choice_OCSPResponderID_byName: { 1093178825Sdfr hx509_name n; 1094178825Sdfr char *s; 1095178825Sdfr _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); 1096178825Sdfr hx509_name_to_string(n, &s); 1097178825Sdfr hx509_name_free(&n); 1098178825Sdfr fprintf(out, " byName: %s\n", s); 1099178825Sdfr free(s); 1100178825Sdfr break; 1101178825Sdfr } 1102178825Sdfr case choice_OCSPResponderID_byKey: { 1103178825Sdfr char *s; 1104178825Sdfr hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, 1105178825Sdfr ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, 1106178825Sdfr &s); 1107178825Sdfr fprintf(out, " byKey: %s\n", s); 1108178825Sdfr free(s); 1109178825Sdfr break; 1110178825Sdfr } 1111178825Sdfr default: 1112178825Sdfr _hx509_abort("choice_OCSPResponderID unknown"); 1113178825Sdfr break; 1114178825Sdfr } 1115178825Sdfr 1116178825Sdfr fprintf(out, "producedAt: %s\n", 1117178825Sdfr printable_time(ocsp.ocsp.tbsResponseData.producedAt)); 1118178825Sdfr 1119178825Sdfr fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); 1120178825Sdfr 1121178825Sdfr for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { 1122178825Sdfr const char *status; 1123178825Sdfr switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { 1124178825Sdfr case choice_OCSPCertStatus_good: 1125178825Sdfr status = "good"; 1126178825Sdfr break; 1127178825Sdfr case choice_OCSPCertStatus_revoked: 1128178825Sdfr status = "revoked"; 1129178825Sdfr break; 1130178825Sdfr case choice_OCSPCertStatus_unknown: 1131178825Sdfr status = "unknown"; 1132178825Sdfr break; 1133178825Sdfr default: 1134178825Sdfr status = "element unknown"; 1135178825Sdfr } 1136178825Sdfr 1137178825Sdfr fprintf(out, "\t%d. status: %s\n", i, status); 1138178825Sdfr 1139178825Sdfr fprintf(out, "\tthisUpdate: %s\n", 1140178825Sdfr printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); 1141178825Sdfr if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) 1142178825Sdfr fprintf(out, "\tproducedAt: %s\n", 1143178825Sdfr printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); 1144178825Sdfr 1145178825Sdfr } 1146178825Sdfr 1147178825Sdfr fprintf(out, "appended certs:\n"); 1148178825Sdfr if (ocsp.certs) 1149178825Sdfr ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out); 1150178825Sdfr 1151178825Sdfr free_ocsp(&ocsp); 1152178825Sdfr return ret; 1153178825Sdfr} 1154178825Sdfr 1155178825Sdfr/** 1156178825Sdfr * Verify that the certificate is part of the OCSP reply and it's not 1157178825Sdfr * expired. Doesn't verify signature the OCSP reply or it's done by a 1158178825Sdfr * authorized sender, that is assumed to be already done. 1159178825Sdfr * 1160178825Sdfr * @param context a hx509 context 1161178825Sdfr * @param now the time right now, if 0, use the current time. 1162178825Sdfr * @param cert the certificate to verify 1163178825Sdfr * @param flags flags control the behavior 1164178825Sdfr * @param data pointer to the encode ocsp reply 1165178825Sdfr * @param length the length of the encode ocsp reply 1166178825Sdfr * @param expiration return the time the OCSP will expire and need to 1167178825Sdfr * be rechecked. 1168178825Sdfr * 1169178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1170178825Sdfr * 1171178825Sdfr * @ingroup hx509_verify 1172178825Sdfr */ 1173178825Sdfr 1174178825Sdfrint 1175178825Sdfrhx509_ocsp_verify(hx509_context context, 1176178825Sdfr time_t now, 1177178825Sdfr hx509_cert cert, 1178178825Sdfr int flags, 1179178825Sdfr const void *data, size_t length, 1180178825Sdfr time_t *expiration) 1181178825Sdfr{ 1182178825Sdfr const Certificate *c = _hx509_get_cert(cert); 1183178825Sdfr OCSPBasicOCSPResponse basic; 1184178825Sdfr int ret, i; 1185178825Sdfr 1186178825Sdfr if (now == 0) 1187178825Sdfr now = time(NULL); 1188178825Sdfr 1189178825Sdfr *expiration = 0; 1190178825Sdfr 1191178825Sdfr ret = parse_ocsp_basic(data, length, &basic); 1192178825Sdfr if (ret) { 1193178825Sdfr hx509_set_error_string(context, 0, ret, 1194178825Sdfr "Failed to parse OCSP response"); 1195178825Sdfr return ret; 1196178825Sdfr } 1197178825Sdfr 1198178825Sdfr for (i = 0; i < basic.tbsResponseData.responses.len; i++) { 1199178825Sdfr 1200178825Sdfr ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber, 1201178825Sdfr &c->tbsCertificate.serialNumber); 1202178825Sdfr if (ret != 0) 1203178825Sdfr continue; 1204178825Sdfr 1205178825Sdfr /* verify issuer hashes hash */ 1206178825Sdfr ret = _hx509_verify_signature(context, 1207178825Sdfr NULL, 1208178825Sdfr &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm, 1209178825Sdfr &c->tbsCertificate.issuer._save, 1210178825Sdfr &basic.tbsResponseData.responses.val[i].certID.issuerNameHash); 1211178825Sdfr if (ret != 0) 1212178825Sdfr continue; 1213178825Sdfr 1214178825Sdfr switch (basic.tbsResponseData.responses.val[i].certStatus.element) { 1215178825Sdfr case choice_OCSPCertStatus_good: 1216178825Sdfr break; 1217178825Sdfr case choice_OCSPCertStatus_revoked: 1218178825Sdfr case choice_OCSPCertStatus_unknown: 1219178825Sdfr continue; 1220178825Sdfr } 1221178825Sdfr 1222178825Sdfr /* don't allow the update to be in the future */ 1223178825Sdfr if (basic.tbsResponseData.responses.val[i].thisUpdate > 1224178825Sdfr now + context->ocsp_time_diff) 1225178825Sdfr continue; 1226178825Sdfr 1227178825Sdfr /* don't allow the next update to be in the past */ 1228178825Sdfr if (basic.tbsResponseData.responses.val[i].nextUpdate) { 1229178825Sdfr if (*basic.tbsResponseData.responses.val[i].nextUpdate < now) 1230178825Sdfr continue; 1231178825Sdfr *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate; 1232178825Sdfr } else 1233178825Sdfr *expiration = now; 1234178825Sdfr 1235178825Sdfr free_OCSPBasicOCSPResponse(&basic); 1236178825Sdfr return 0; 1237178825Sdfr } 1238178825Sdfr 1239178825Sdfr free_OCSPBasicOCSPResponse(&basic); 1240178825Sdfr 1241178825Sdfr { 1242178825Sdfr hx509_name name; 1243178825Sdfr char *subject; 1244178825Sdfr 1245178825Sdfr ret = hx509_cert_get_subject(cert, &name); 1246178825Sdfr if (ret) { 1247178825Sdfr hx509_clear_error_string(context); 1248178825Sdfr goto out; 1249178825Sdfr } 1250178825Sdfr ret = hx509_name_to_string(name, &subject); 1251178825Sdfr hx509_name_free(&name); 1252178825Sdfr if (ret) { 1253178825Sdfr hx509_clear_error_string(context); 1254178825Sdfr goto out; 1255178825Sdfr } 1256178825Sdfr hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP, 1257178825Sdfr "Certificate %s not in OCSP response " 1258178825Sdfr "or not good", 1259178825Sdfr subject); 1260178825Sdfr free(subject); 1261178825Sdfr } 1262178825Sdfrout: 1263178825Sdfr return HX509_CERT_NOT_IN_OCSP; 1264178825Sdfr} 1265178825Sdfr 1266178825Sdfrstruct hx509_crl { 1267178825Sdfr hx509_certs revoked; 1268178825Sdfr time_t expire; 1269178825Sdfr}; 1270178825Sdfr 1271178825Sdfr/** 1272178825Sdfr * Create a CRL context. Use hx509_crl_free() to free the CRL context. 1273178825Sdfr * 1274178825Sdfr * @param context a hx509 context. 1275178825Sdfr * @param crl return pointer to a newly allocated CRL context. 1276178825Sdfr * 1277178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1278178825Sdfr * 1279178825Sdfr * @ingroup hx509_verify 1280178825Sdfr */ 1281178825Sdfr 1282178825Sdfrint 1283178825Sdfrhx509_crl_alloc(hx509_context context, hx509_crl *crl) 1284178825Sdfr{ 1285178825Sdfr int ret; 1286178825Sdfr 1287178825Sdfr *crl = calloc(1, sizeof(**crl)); 1288178825Sdfr if (*crl == NULL) { 1289178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1290178825Sdfr return ENOMEM; 1291178825Sdfr } 1292178825Sdfr 1293178825Sdfr ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked); 1294178825Sdfr if (ret) { 1295178825Sdfr free(*crl); 1296178825Sdfr *crl = NULL; 1297178825Sdfr return ret; 1298178825Sdfr } 1299178825Sdfr (*crl)->expire = 0; 1300178825Sdfr return ret; 1301178825Sdfr} 1302178825Sdfr 1303178825Sdfr/** 1304178825Sdfr * Add revoked certificate to an CRL context. 1305178825Sdfr * 1306178825Sdfr * @param context a hx509 context. 1307178825Sdfr * @param crl the CRL to add the revoked certificate to. 1308178825Sdfr * @param certs keyset of certificate to revoke. 1309178825Sdfr * 1310178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1311178825Sdfr * 1312178825Sdfr * @ingroup hx509_verify 1313178825Sdfr */ 1314178825Sdfr 1315178825Sdfrint 1316178825Sdfrhx509_crl_add_revoked_certs(hx509_context context, 1317178825Sdfr hx509_crl crl, 1318178825Sdfr hx509_certs certs) 1319178825Sdfr{ 1320178825Sdfr return hx509_certs_merge(context, crl->revoked, certs); 1321178825Sdfr} 1322178825Sdfr 1323178825Sdfr/** 1324178825Sdfr * Set the lifetime of a CRL context. 1325178825Sdfr * 1326178825Sdfr * @param context a hx509 context. 1327178825Sdfr * @param crl a CRL context 1328178825Sdfr * @param delta delta time the certificate is valid, library adds the 1329178825Sdfr * current time to this. 1330178825Sdfr * 1331178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1332178825Sdfr * 1333178825Sdfr * @ingroup hx509_verify 1334178825Sdfr */ 1335178825Sdfr 1336178825Sdfrint 1337178825Sdfrhx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta) 1338178825Sdfr{ 1339178825Sdfr crl->expire = time(NULL) + delta; 1340178825Sdfr return 0; 1341178825Sdfr} 1342178825Sdfr 1343178825Sdfr/** 1344178825Sdfr * Free a CRL context. 1345178825Sdfr * 1346178825Sdfr * @param context a hx509 context. 1347178825Sdfr * @param crl a CRL context to free. 1348178825Sdfr * 1349178825Sdfr * @ingroup hx509_verify 1350178825Sdfr */ 1351178825Sdfr 1352178825Sdfrvoid 1353178825Sdfrhx509_crl_free(hx509_context context, hx509_crl *crl) 1354178825Sdfr{ 1355178825Sdfr if (*crl == NULL) 1356178825Sdfr return; 1357178825Sdfr hx509_certs_free(&(*crl)->revoked); 1358178825Sdfr memset(*crl, 0, sizeof(**crl)); 1359178825Sdfr free(*crl); 1360178825Sdfr *crl = NULL; 1361178825Sdfr} 1362178825Sdfr 1363178825Sdfrstatic int 1364178825Sdfradd_revoked(hx509_context context, void *ctx, hx509_cert cert) 1365178825Sdfr{ 1366178825Sdfr TBSCRLCertList *c = ctx; 1367178825Sdfr unsigned int num; 1368178825Sdfr void *ptr; 1369178825Sdfr int ret; 1370178825Sdfr 1371178825Sdfr num = c->revokedCertificates->len; 1372178825Sdfr ptr = realloc(c->revokedCertificates->val, 1373178825Sdfr (num + 1) * sizeof(c->revokedCertificates->val[0])); 1374178825Sdfr if (ptr == NULL) { 1375178825Sdfr hx509_clear_error_string(context); 1376178825Sdfr return ENOMEM; 1377178825Sdfr } 1378178825Sdfr c->revokedCertificates->val = ptr; 1379178825Sdfr 1380178825Sdfr ret = hx509_cert_get_serialnumber(cert, 1381178825Sdfr &c->revokedCertificates->val[num].userCertificate); 1382178825Sdfr if (ret) { 1383178825Sdfr hx509_clear_error_string(context); 1384178825Sdfr return ret; 1385178825Sdfr } 1386178825Sdfr c->revokedCertificates->val[num].revocationDate.element = 1387178825Sdfr choice_Time_generalTime; 1388178825Sdfr c->revokedCertificates->val[num].revocationDate.u.generalTime = 1389178825Sdfr time(NULL) - 3600 * 24; 1390178825Sdfr c->revokedCertificates->val[num].crlEntryExtensions = NULL; 1391178825Sdfr 1392178825Sdfr c->revokedCertificates->len++; 1393178825Sdfr 1394178825Sdfr return 0; 1395178825Sdfr} 1396178825Sdfr 1397178825Sdfr/** 1398178825Sdfr * Sign a CRL and return an encode certificate. 1399178825Sdfr * 1400178825Sdfr * @param context a hx509 context. 1401178825Sdfr * @param signer certificate to sign the CRL with 1402178825Sdfr * @param crl the CRL to sign 1403178825Sdfr * @param os return the signed and encoded CRL, free with 1404178825Sdfr * free_heim_octet_string() 1405178825Sdfr * 1406178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1407178825Sdfr * 1408178825Sdfr * @ingroup hx509_verify 1409178825Sdfr */ 1410178825Sdfr 1411178825Sdfrint 1412178825Sdfrhx509_crl_sign(hx509_context context, 1413178825Sdfr hx509_cert signer, 1414178825Sdfr hx509_crl crl, 1415178825Sdfr heim_octet_string *os) 1416178825Sdfr{ 1417178825Sdfr const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg; 1418178825Sdfr CRLCertificateList c; 1419178825Sdfr size_t size; 1420178825Sdfr int ret; 1421178825Sdfr hx509_private_key signerkey; 1422178825Sdfr 1423178825Sdfr memset(&c, 0, sizeof(c)); 1424178825Sdfr 1425178825Sdfr signerkey = _hx509_cert_private_key(signer); 1426178825Sdfr if (signerkey == NULL) { 1427178825Sdfr ret = HX509_PRIVATE_KEY_MISSING; 1428178825Sdfr hx509_set_error_string(context, 0, ret, 1429178825Sdfr "Private key missing for CRL signing"); 1430178825Sdfr return ret; 1431178825Sdfr } 1432178825Sdfr 1433178825Sdfr c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version)); 1434178825Sdfr if (c.tbsCertList.version == NULL) { 1435178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1436178825Sdfr return ENOMEM; 1437178825Sdfr } 1438178825Sdfr 1439178825Sdfr *c.tbsCertList.version = 1; 1440178825Sdfr 1441178825Sdfr ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature); 1442178825Sdfr if (ret) { 1443178825Sdfr hx509_clear_error_string(context); 1444178825Sdfr goto out; 1445178825Sdfr } 1446178825Sdfr 1447178825Sdfr ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer, 1448178825Sdfr &c.tbsCertList.issuer); 1449178825Sdfr if (ret) { 1450178825Sdfr hx509_clear_error_string(context); 1451178825Sdfr goto out; 1452178825Sdfr } 1453178825Sdfr 1454178825Sdfr c.tbsCertList.thisUpdate.element = choice_Time_generalTime; 1455178825Sdfr c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600; 1456178825Sdfr 1457178825Sdfr c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate)); 1458178825Sdfr if (c.tbsCertList.nextUpdate == NULL) { 1459178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1460178825Sdfr ret = ENOMEM; 1461178825Sdfr goto out; 1462178825Sdfr } 1463178825Sdfr 1464178825Sdfr { 1465178825Sdfr time_t next = crl->expire; 1466178825Sdfr if (next == 0) 1467178825Sdfr next = time(NULL) + 24 * 3600 * 365; 1468178825Sdfr 1469178825Sdfr c.tbsCertList.nextUpdate->element = choice_Time_generalTime; 1470178825Sdfr c.tbsCertList.nextUpdate->u.generalTime = next; 1471178825Sdfr } 1472178825Sdfr 1473178825Sdfr c.tbsCertList.revokedCertificates = 1474178825Sdfr calloc(1, sizeof(*c.tbsCertList.revokedCertificates)); 1475178825Sdfr if (c.tbsCertList.revokedCertificates == NULL) { 1476178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1477178825Sdfr ret = ENOMEM; 1478178825Sdfr goto out; 1479178825Sdfr } 1480178825Sdfr c.tbsCertList.crlExtensions = NULL; 1481178825Sdfr 1482178825Sdfr ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList); 1483178825Sdfr if (ret) 1484178825Sdfr goto out; 1485178825Sdfr 1486178825Sdfr /* if not revoked certs, remove OPTIONAL entry */ 1487178825Sdfr if (c.tbsCertList.revokedCertificates->len == 0) { 1488178825Sdfr free(c.tbsCertList.revokedCertificates); 1489178825Sdfr c.tbsCertList.revokedCertificates = NULL; 1490178825Sdfr } 1491178825Sdfr 1492178825Sdfr ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length, 1493178825Sdfr &c.tbsCertList, &size, ret); 1494178825Sdfr if (ret) { 1495178825Sdfr hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL"); 1496178825Sdfr goto out; 1497178825Sdfr } 1498178825Sdfr if (size != os->length) 1499178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1500178825Sdfr 1501178825Sdfr 1502178825Sdfr ret = _hx509_create_signature_bitstring(context, 1503178825Sdfr signerkey, 1504178825Sdfr sigalg, 1505178825Sdfr os, 1506178825Sdfr &c.signatureAlgorithm, 1507178825Sdfr &c.signatureValue); 1508178825Sdfr free(os->data); 1509178825Sdfr 1510178825Sdfr ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length, 1511178825Sdfr &c, &size, ret); 1512178825Sdfr free_CRLCertificateList(&c); 1513178825Sdfr if (ret) { 1514178825Sdfr hx509_set_error_string(context, 0, ret, "failed to encode CRL"); 1515178825Sdfr goto out; 1516178825Sdfr } 1517178825Sdfr if (size != os->length) 1518178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 1519178825Sdfr 1520178825Sdfr return 0; 1521178825Sdfr 1522178825Sdfrout: 1523178825Sdfr free_CRLCertificateList(&c); 1524178825Sdfr return ret; 1525178825Sdfr} 1526