1248613Sdes/* 2248613Sdes * Copyright (c) 2012 Damien Miller <djm@mindrot.org> 3248613Sdes * 4248613Sdes * Permission to use, copy, modify, and distribute this software for any 5248613Sdes * purpose with or without fee is hereby granted, provided that the above 6248613Sdes * copyright notice and this permission notice appear in all copies. 7248613Sdes * 8248613Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9248613Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10248613Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11248613Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12248613Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13248613Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14248613Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15248613Sdes */ 16248613Sdes 17263970Sdes/* $OpenBSD: krl.c,v 1.14 2014/01/31 16:39:19 tedu Exp $ */ 18248613Sdes 19248613Sdes#include "includes.h" 20248613Sdes 21248613Sdes#include <sys/types.h> 22248613Sdes#include <sys/param.h> 23248613Sdes#include <openbsd-compat/sys-tree.h> 24248613Sdes#include <openbsd-compat/sys-queue.h> 25248613Sdes 26248613Sdes#include <errno.h> 27248613Sdes#include <fcntl.h> 28248613Sdes#include <limits.h> 29248613Sdes#include <string.h> 30248613Sdes#include <time.h> 31248613Sdes#include <unistd.h> 32248613Sdes 33248613Sdes#include "buffer.h" 34248613Sdes#include "key.h" 35248613Sdes#include "authfile.h" 36248613Sdes#include "misc.h" 37248613Sdes#include "log.h" 38248613Sdes#include "xmalloc.h" 39248613Sdes 40248613Sdes#include "krl.h" 41248613Sdes 42248613Sdes/* #define DEBUG_KRL */ 43248613Sdes#ifdef DEBUG_KRL 44248613Sdes# define KRL_DBG(x) debug3 x 45248613Sdes#else 46248613Sdes# define KRL_DBG(x) 47248613Sdes#endif 48248613Sdes 49248613Sdes/* 50248613Sdes * Trees of revoked serial numbers, key IDs and keys. This allows 51248613Sdes * quick searching, querying and producing lists in canonical order. 52248613Sdes */ 53248613Sdes 54248613Sdes/* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */ 55248613Sdesstruct revoked_serial { 56248613Sdes u_int64_t lo, hi; 57248613Sdes RB_ENTRY(revoked_serial) tree_entry; 58248613Sdes}; 59248613Sdesstatic int serial_cmp(struct revoked_serial *a, struct revoked_serial *b); 60248613SdesRB_HEAD(revoked_serial_tree, revoked_serial); 61248613SdesRB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp); 62248613Sdes 63248613Sdes/* Tree of key IDs */ 64248613Sdesstruct revoked_key_id { 65248613Sdes char *key_id; 66248613Sdes RB_ENTRY(revoked_key_id) tree_entry; 67248613Sdes}; 68248613Sdesstatic int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b); 69248613SdesRB_HEAD(revoked_key_id_tree, revoked_key_id); 70248613SdesRB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp); 71248613Sdes 72248613Sdes/* Tree of blobs (used for keys and fingerprints) */ 73248613Sdesstruct revoked_blob { 74248613Sdes u_char *blob; 75248613Sdes u_int len; 76248613Sdes RB_ENTRY(revoked_blob) tree_entry; 77248613Sdes}; 78248613Sdesstatic int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); 79248613SdesRB_HEAD(revoked_blob_tree, revoked_blob); 80248613SdesRB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp); 81248613Sdes 82248613Sdes/* Tracks revoked certs for a single CA */ 83248613Sdesstruct revoked_certs { 84248613Sdes Key *ca_key; 85248613Sdes struct revoked_serial_tree revoked_serials; 86248613Sdes struct revoked_key_id_tree revoked_key_ids; 87248613Sdes TAILQ_ENTRY(revoked_certs) entry; 88248613Sdes}; 89248613SdesTAILQ_HEAD(revoked_certs_list, revoked_certs); 90248613Sdes 91248613Sdesstruct ssh_krl { 92248613Sdes u_int64_t krl_version; 93248613Sdes u_int64_t generated_date; 94248613Sdes u_int64_t flags; 95248613Sdes char *comment; 96248613Sdes struct revoked_blob_tree revoked_keys; 97248613Sdes struct revoked_blob_tree revoked_sha1s; 98248613Sdes struct revoked_certs_list revoked_certs; 99248613Sdes}; 100248613Sdes 101248613Sdes/* Return equal if a and b overlap */ 102248613Sdesstatic int 103248613Sdesserial_cmp(struct revoked_serial *a, struct revoked_serial *b) 104248613Sdes{ 105248613Sdes if (a->hi >= b->lo && a->lo <= b->hi) 106248613Sdes return 0; 107248613Sdes return a->lo < b->lo ? -1 : 1; 108248613Sdes} 109248613Sdes 110248613Sdesstatic int 111248613Sdeskey_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b) 112248613Sdes{ 113248613Sdes return strcmp(a->key_id, b->key_id); 114248613Sdes} 115248613Sdes 116248613Sdesstatic int 117248613Sdesblob_cmp(struct revoked_blob *a, struct revoked_blob *b) 118248613Sdes{ 119248613Sdes int r; 120248613Sdes 121248613Sdes if (a->len != b->len) { 122248613Sdes if ((r = memcmp(a->blob, b->blob, MIN(a->len, b->len))) != 0) 123248613Sdes return r; 124248613Sdes return a->len > b->len ? 1 : -1; 125248613Sdes } else 126248613Sdes return memcmp(a->blob, b->blob, a->len); 127248613Sdes} 128248613Sdes 129248613Sdesstruct ssh_krl * 130248613Sdesssh_krl_init(void) 131248613Sdes{ 132248613Sdes struct ssh_krl *krl; 133248613Sdes 134248613Sdes if ((krl = calloc(1, sizeof(*krl))) == NULL) 135248613Sdes return NULL; 136248613Sdes RB_INIT(&krl->revoked_keys); 137248613Sdes RB_INIT(&krl->revoked_sha1s); 138248613Sdes TAILQ_INIT(&krl->revoked_certs); 139248613Sdes return krl; 140248613Sdes} 141248613Sdes 142248613Sdesstatic void 143248613Sdesrevoked_certs_free(struct revoked_certs *rc) 144248613Sdes{ 145248613Sdes struct revoked_serial *rs, *trs; 146248613Sdes struct revoked_key_id *rki, *trki; 147248613Sdes 148248613Sdes RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) { 149248613Sdes RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs); 150248613Sdes free(rs); 151248613Sdes } 152248613Sdes RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) { 153248613Sdes RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki); 154248613Sdes free(rki->key_id); 155248613Sdes free(rki); 156248613Sdes } 157248613Sdes if (rc->ca_key != NULL) 158248613Sdes key_free(rc->ca_key); 159248613Sdes} 160248613Sdes 161248613Sdesvoid 162248613Sdesssh_krl_free(struct ssh_krl *krl) 163248613Sdes{ 164248613Sdes struct revoked_blob *rb, *trb; 165248613Sdes struct revoked_certs *rc, *trc; 166248613Sdes 167248613Sdes if (krl == NULL) 168248613Sdes return; 169248613Sdes 170248613Sdes free(krl->comment); 171248613Sdes RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) { 172248613Sdes RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb); 173248613Sdes free(rb->blob); 174248613Sdes free(rb); 175248613Sdes } 176248613Sdes RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) { 177248613Sdes RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb); 178248613Sdes free(rb->blob); 179248613Sdes free(rb); 180248613Sdes } 181248613Sdes TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) { 182248613Sdes TAILQ_REMOVE(&krl->revoked_certs, rc, entry); 183248613Sdes revoked_certs_free(rc); 184248613Sdes } 185248613Sdes} 186248613Sdes 187248613Sdesvoid 188248613Sdesssh_krl_set_version(struct ssh_krl *krl, u_int64_t version) 189248613Sdes{ 190248613Sdes krl->krl_version = version; 191248613Sdes} 192248613Sdes 193248613Sdesvoid 194248613Sdesssh_krl_set_comment(struct ssh_krl *krl, const char *comment) 195248613Sdes{ 196248613Sdes free(krl->comment); 197248613Sdes if ((krl->comment = strdup(comment)) == NULL) 198248613Sdes fatal("%s: strdup", __func__); 199248613Sdes} 200248613Sdes 201248613Sdes/* 202248613Sdes * Find the revoked_certs struct for a CA key. If allow_create is set then 203248613Sdes * create a new one in the tree if one did not exist already. 204248613Sdes */ 205248613Sdesstatic int 206248613Sdesrevoked_certs_for_ca_key(struct ssh_krl *krl, const Key *ca_key, 207248613Sdes struct revoked_certs **rcp, int allow_create) 208248613Sdes{ 209248613Sdes struct revoked_certs *rc; 210248613Sdes 211248613Sdes *rcp = NULL; 212248613Sdes TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 213248613Sdes if (key_equal(rc->ca_key, ca_key)) { 214248613Sdes *rcp = rc; 215248613Sdes return 0; 216248613Sdes } 217248613Sdes } 218248613Sdes if (!allow_create) 219248613Sdes return 0; 220248613Sdes /* If this CA doesn't exist in the list then add it now */ 221248613Sdes if ((rc = calloc(1, sizeof(*rc))) == NULL) 222248613Sdes return -1; 223248613Sdes if ((rc->ca_key = key_from_private(ca_key)) == NULL) { 224248613Sdes free(rc); 225248613Sdes return -1; 226248613Sdes } 227248613Sdes RB_INIT(&rc->revoked_serials); 228248613Sdes RB_INIT(&rc->revoked_key_ids); 229248613Sdes TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); 230248613Sdes debug3("%s: new CA %s", __func__, key_type(ca_key)); 231248613Sdes *rcp = rc; 232248613Sdes return 0; 233248613Sdes} 234248613Sdes 235248613Sdesstatic int 236248613Sdesinsert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi) 237248613Sdes{ 238248613Sdes struct revoked_serial rs, *ers, *crs, *irs; 239248613Sdes 240248613Sdes KRL_DBG(("%s: insert %llu:%llu", __func__, lo, hi)); 241263970Sdes memset(&rs, 0, sizeof(rs)); 242248613Sdes rs.lo = lo; 243248613Sdes rs.hi = hi; 244248613Sdes ers = RB_NFIND(revoked_serial_tree, rt, &rs); 245248613Sdes if (ers == NULL || serial_cmp(ers, &rs) != 0) { 246248613Sdes /* No entry matches. Just insert */ 247248613Sdes if ((irs = malloc(sizeof(rs))) == NULL) 248248613Sdes return -1; 249248613Sdes memcpy(irs, &rs, sizeof(*irs)); 250248613Sdes ers = RB_INSERT(revoked_serial_tree, rt, irs); 251248613Sdes if (ers != NULL) { 252248613Sdes KRL_DBG(("%s: bad: ers != NULL", __func__)); 253248613Sdes /* Shouldn't happen */ 254248613Sdes free(irs); 255248613Sdes return -1; 256248613Sdes } 257248613Sdes ers = irs; 258248613Sdes } else { 259248613Sdes KRL_DBG(("%s: overlap found %llu:%llu", __func__, 260248613Sdes ers->lo, ers->hi)); 261248613Sdes /* 262248613Sdes * The inserted entry overlaps an existing one. Grow the 263248613Sdes * existing entry. 264248613Sdes */ 265248613Sdes if (ers->lo > lo) 266248613Sdes ers->lo = lo; 267248613Sdes if (ers->hi < hi) 268248613Sdes ers->hi = hi; 269248613Sdes } 270248613Sdes /* 271248613Sdes * The inserted or revised range might overlap or abut adjacent ones; 272248613Sdes * coalesce as necessary. 273248613Sdes */ 274248613Sdes 275248613Sdes /* Check predecessors */ 276248613Sdes while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) { 277248613Sdes KRL_DBG(("%s: pred %llu:%llu", __func__, crs->lo, crs->hi)); 278248613Sdes if (ers->lo != 0 && crs->hi < ers->lo - 1) 279248613Sdes break; 280248613Sdes /* This entry overlaps. */ 281248613Sdes if (crs->lo < ers->lo) { 282248613Sdes ers->lo = crs->lo; 283248613Sdes KRL_DBG(("%s: pred extend %llu:%llu", __func__, 284248613Sdes ers->lo, ers->hi)); 285248613Sdes } 286248613Sdes RB_REMOVE(revoked_serial_tree, rt, crs); 287248613Sdes free(crs); 288248613Sdes } 289248613Sdes /* Check successors */ 290248613Sdes while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) { 291248613Sdes KRL_DBG(("%s: succ %llu:%llu", __func__, crs->lo, crs->hi)); 292248613Sdes if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1) 293248613Sdes break; 294248613Sdes /* This entry overlaps. */ 295248613Sdes if (crs->hi > ers->hi) { 296248613Sdes ers->hi = crs->hi; 297248613Sdes KRL_DBG(("%s: succ extend %llu:%llu", __func__, 298248613Sdes ers->lo, ers->hi)); 299248613Sdes } 300248613Sdes RB_REMOVE(revoked_serial_tree, rt, crs); 301248613Sdes free(crs); 302248613Sdes } 303248613Sdes KRL_DBG(("%s: done, final %llu:%llu", __func__, ers->lo, ers->hi)); 304248613Sdes return 0; 305248613Sdes} 306248613Sdes 307248613Sdesint 308248613Sdesssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const Key *ca_key, 309248613Sdes u_int64_t serial) 310248613Sdes{ 311248613Sdes return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial); 312248613Sdes} 313248613Sdes 314248613Sdesint 315248613Sdesssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, const Key *ca_key, 316248613Sdes u_int64_t lo, u_int64_t hi) 317248613Sdes{ 318248613Sdes struct revoked_certs *rc; 319248613Sdes 320248613Sdes if (lo > hi || lo == 0) 321248613Sdes return -1; 322248613Sdes if (revoked_certs_for_ca_key(krl, ca_key, &rc, 1) != 0) 323248613Sdes return -1; 324248613Sdes return insert_serial_range(&rc->revoked_serials, lo, hi); 325248613Sdes} 326248613Sdes 327248613Sdesint 328248613Sdesssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const Key *ca_key, 329248613Sdes const char *key_id) 330248613Sdes{ 331248613Sdes struct revoked_key_id *rki, *erki; 332248613Sdes struct revoked_certs *rc; 333248613Sdes 334248613Sdes if (revoked_certs_for_ca_key(krl, ca_key, &rc, 1) != 0) 335248613Sdes return -1; 336248613Sdes 337248613Sdes debug3("%s: revoke %s", __func__, key_id); 338248613Sdes if ((rki = calloc(1, sizeof(*rki))) == NULL || 339248613Sdes (rki->key_id = strdup(key_id)) == NULL) { 340248613Sdes free(rki); 341248613Sdes fatal("%s: strdup", __func__); 342248613Sdes } 343248613Sdes erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki); 344248613Sdes if (erki != NULL) { 345248613Sdes free(rki->key_id); 346248613Sdes free(rki); 347248613Sdes } 348248613Sdes return 0; 349248613Sdes} 350248613Sdes 351248613Sdes/* Convert "key" to a public key blob without any certificate information */ 352248613Sdesstatic int 353248613Sdesplain_key_blob(const Key *key, u_char **blob, u_int *blen) 354248613Sdes{ 355248613Sdes Key *kcopy; 356248613Sdes int r; 357248613Sdes 358248613Sdes if ((kcopy = key_from_private(key)) == NULL) 359248613Sdes return -1; 360248613Sdes if (key_is_cert(kcopy)) { 361248613Sdes if (key_drop_cert(kcopy) != 0) { 362248613Sdes error("%s: key_drop_cert", __func__); 363248613Sdes key_free(kcopy); 364248613Sdes return -1; 365248613Sdes } 366248613Sdes } 367248613Sdes r = key_to_blob(kcopy, blob, blen); 368248613Sdes free(kcopy); 369248613Sdes return r == 0 ? -1 : 0; 370248613Sdes} 371248613Sdes 372248613Sdes/* Revoke a key blob. Ownership of blob is transferred to the tree */ 373248613Sdesstatic int 374248613Sdesrevoke_blob(struct revoked_blob_tree *rbt, u_char *blob, u_int len) 375248613Sdes{ 376248613Sdes struct revoked_blob *rb, *erb; 377248613Sdes 378248613Sdes if ((rb = calloc(1, sizeof(*rb))) == NULL) 379248613Sdes return -1; 380248613Sdes rb->blob = blob; 381248613Sdes rb->len = len; 382248613Sdes erb = RB_INSERT(revoked_blob_tree, rbt, rb); 383248613Sdes if (erb != NULL) { 384248613Sdes free(rb->blob); 385248613Sdes free(rb); 386248613Sdes } 387248613Sdes return 0; 388248613Sdes} 389248613Sdes 390248613Sdesint 391248613Sdesssh_krl_revoke_key_explicit(struct ssh_krl *krl, const Key *key) 392248613Sdes{ 393248613Sdes u_char *blob; 394248613Sdes u_int len; 395248613Sdes 396248613Sdes debug3("%s: revoke type %s", __func__, key_type(key)); 397248613Sdes if (plain_key_blob(key, &blob, &len) != 0) 398248613Sdes return -1; 399248613Sdes return revoke_blob(&krl->revoked_keys, blob, len); 400248613Sdes} 401248613Sdes 402248613Sdesint 403248613Sdesssh_krl_revoke_key_sha1(struct ssh_krl *krl, const Key *key) 404248613Sdes{ 405248613Sdes u_char *blob; 406248613Sdes u_int len; 407248613Sdes 408248613Sdes debug3("%s: revoke type %s by sha1", __func__, key_type(key)); 409248613Sdes if ((blob = key_fingerprint_raw(key, SSH_FP_SHA1, &len)) == NULL) 410248613Sdes return -1; 411248613Sdes return revoke_blob(&krl->revoked_sha1s, blob, len); 412248613Sdes} 413248613Sdes 414248613Sdesint 415248613Sdesssh_krl_revoke_key(struct ssh_krl *krl, const Key *key) 416248613Sdes{ 417248613Sdes if (!key_is_cert(key)) 418248613Sdes return ssh_krl_revoke_key_sha1(krl, key); 419248613Sdes 420248613Sdes if (key_cert_is_legacy(key) || key->cert->serial == 0) { 421248613Sdes return ssh_krl_revoke_cert_by_key_id(krl, 422248613Sdes key->cert->signature_key, 423248613Sdes key->cert->key_id); 424248613Sdes } else { 425248613Sdes return ssh_krl_revoke_cert_by_serial(krl, 426248613Sdes key->cert->signature_key, 427248613Sdes key->cert->serial); 428248613Sdes } 429248613Sdes} 430248613Sdes 431248613Sdes/* 432248613Sdes * Select a copact next section type to emit in a KRL based on the 433248613Sdes * current section type, the run length of contiguous revoked serial 434248613Sdes * numbers and the gaps from the last and to the next revoked serial. 435248613Sdes * Applies a mostly-accurate bit cost model to select the section type 436248613Sdes * that will minimise the size of the resultant KRL. 437248613Sdes */ 438248613Sdesstatic int 439248613Sdeschoose_next_state(int current_state, u_int64_t contig, int final, 440248613Sdes u_int64_t last_gap, u_int64_t next_gap, int *force_new_section) 441248613Sdes{ 442248613Sdes int new_state; 443248613Sdes u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart; 444248613Sdes 445248613Sdes /* 446248613Sdes * Avoid unsigned overflows. 447248613Sdes * The limits are high enough to avoid confusing the calculations. 448248613Sdes */ 449248613Sdes contig = MIN(contig, 1ULL<<31); 450248613Sdes last_gap = MIN(last_gap, 1ULL<<31); 451248613Sdes next_gap = MIN(next_gap, 1ULL<<31); 452248613Sdes 453248613Sdes /* 454248613Sdes * Calculate the cost to switch from the current state to candidates. 455248613Sdes * NB. range sections only ever contain a single range, so their 456248613Sdes * switching cost is independent of the current_state. 457248613Sdes */ 458248613Sdes cost_list = cost_bitmap = cost_bitmap_restart = 0; 459248613Sdes cost_range = 8; 460248613Sdes switch (current_state) { 461248613Sdes case KRL_SECTION_CERT_SERIAL_LIST: 462248613Sdes cost_bitmap_restart = cost_bitmap = 8 + 64; 463248613Sdes break; 464248613Sdes case KRL_SECTION_CERT_SERIAL_BITMAP: 465248613Sdes cost_list = 8; 466248613Sdes cost_bitmap_restart = 8 + 64; 467248613Sdes break; 468248613Sdes case KRL_SECTION_CERT_SERIAL_RANGE: 469248613Sdes case 0: 470248613Sdes cost_bitmap_restart = cost_bitmap = 8 + 64; 471248613Sdes cost_list = 8; 472248613Sdes } 473248613Sdes 474248613Sdes /* Estimate base cost in bits of each section type */ 475248613Sdes cost_list += 64 * contig + (final ? 0 : 8+64); 476248613Sdes cost_range += (2 * 64) + (final ? 0 : 8+64); 477248613Sdes cost_bitmap += last_gap + contig + (final ? 0 : MIN(next_gap, 8+64)); 478248613Sdes cost_bitmap_restart += contig + (final ? 0 : MIN(next_gap, 8+64)); 479248613Sdes 480248613Sdes /* Convert to byte costs for actual comparison */ 481248613Sdes cost_list = (cost_list + 7) / 8; 482248613Sdes cost_bitmap = (cost_bitmap + 7) / 8; 483248613Sdes cost_bitmap_restart = (cost_bitmap_restart + 7) / 8; 484248613Sdes cost_range = (cost_range + 7) / 8; 485248613Sdes 486248613Sdes /* Now pick the best choice */ 487248613Sdes *force_new_section = 0; 488248613Sdes new_state = KRL_SECTION_CERT_SERIAL_BITMAP; 489248613Sdes cost = cost_bitmap; 490248613Sdes if (cost_range < cost) { 491248613Sdes new_state = KRL_SECTION_CERT_SERIAL_RANGE; 492248613Sdes cost = cost_range; 493248613Sdes } 494248613Sdes if (cost_list < cost) { 495248613Sdes new_state = KRL_SECTION_CERT_SERIAL_LIST; 496248613Sdes cost = cost_list; 497248613Sdes } 498248613Sdes if (cost_bitmap_restart < cost) { 499248613Sdes new_state = KRL_SECTION_CERT_SERIAL_BITMAP; 500248613Sdes *force_new_section = 1; 501248613Sdes cost = cost_bitmap_restart; 502248613Sdes } 503248613Sdes debug3("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:" 504248613Sdes "list %llu range %llu bitmap %llu new bitmap %llu, " 505263970Sdes "selected 0x%02x%s", __func__, (long long unsigned)contig, 506263970Sdes (long long unsigned)last_gap, (long long unsigned)next_gap, final, 507263970Sdes (long long unsigned)cost_list, (long long unsigned)cost_range, 508263970Sdes (long long unsigned)cost_bitmap, 509263970Sdes (long long unsigned)cost_bitmap_restart, new_state, 510248613Sdes *force_new_section ? " restart" : ""); 511248613Sdes return new_state; 512248613Sdes} 513248613Sdes 514248613Sdes/* Generate a KRL_SECTION_CERTIFICATES KRL section */ 515248613Sdesstatic int 516248613Sdesrevoked_certs_generate(struct revoked_certs *rc, Buffer *buf) 517248613Sdes{ 518248613Sdes int final, force_new_sect, r = -1; 519248613Sdes u_int64_t i, contig, gap, last = 0, bitmap_start = 0; 520248613Sdes struct revoked_serial *rs, *nrs; 521248613Sdes struct revoked_key_id *rki; 522248613Sdes int next_state, state = 0; 523248613Sdes Buffer sect; 524248613Sdes u_char *kblob = NULL; 525248613Sdes u_int klen; 526248613Sdes BIGNUM *bitmap = NULL; 527248613Sdes 528248613Sdes /* Prepare CA scope key blob if we have one supplied */ 529248613Sdes if (key_to_blob(rc->ca_key, &kblob, &klen) == 0) 530248613Sdes return -1; 531248613Sdes 532248613Sdes buffer_init(§); 533248613Sdes 534248613Sdes /* Store the header */ 535248613Sdes buffer_put_string(buf, kblob, klen); 536248613Sdes buffer_put_string(buf, NULL, 0); /* Reserved */ 537248613Sdes 538248613Sdes free(kblob); 539248613Sdes 540248613Sdes /* Store the revoked serials. */ 541248613Sdes for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials); 542248613Sdes rs != NULL; 543248613Sdes rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) { 544248613Sdes debug3("%s: serial %llu:%llu state 0x%02x", __func__, 545263970Sdes (long long unsigned)rs->lo, (long long unsigned)rs->hi, 546251135Sdes state); 547248613Sdes 548248613Sdes /* Check contiguous length and gap to next section (if any) */ 549248613Sdes nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs); 550248613Sdes final = nrs == NULL; 551248613Sdes gap = nrs == NULL ? 0 : nrs->lo - rs->hi; 552248613Sdes contig = 1 + (rs->hi - rs->lo); 553248613Sdes 554248613Sdes /* Choose next state based on these */ 555248613Sdes next_state = choose_next_state(state, contig, final, 556248613Sdes state == 0 ? 0 : rs->lo - last, gap, &force_new_sect); 557248613Sdes 558248613Sdes /* 559248613Sdes * If the current section is a range section or has a different 560248613Sdes * type to the next section, then finish it off now. 561248613Sdes */ 562248613Sdes if (state != 0 && (force_new_sect || next_state != state || 563248613Sdes state == KRL_SECTION_CERT_SERIAL_RANGE)) { 564248613Sdes debug3("%s: finish state 0x%02x", __func__, state); 565248613Sdes switch (state) { 566248613Sdes case KRL_SECTION_CERT_SERIAL_LIST: 567248613Sdes case KRL_SECTION_CERT_SERIAL_RANGE: 568248613Sdes break; 569248613Sdes case KRL_SECTION_CERT_SERIAL_BITMAP: 570248613Sdes buffer_put_bignum2(§, bitmap); 571248613Sdes BN_free(bitmap); 572248613Sdes bitmap = NULL; 573248613Sdes break; 574248613Sdes } 575248613Sdes buffer_put_char(buf, state); 576248613Sdes buffer_put_string(buf, 577248613Sdes buffer_ptr(§), buffer_len(§)); 578248613Sdes } 579248613Sdes 580248613Sdes /* If we are starting a new section then prepare it now */ 581248613Sdes if (next_state != state || force_new_sect) { 582248613Sdes debug3("%s: start state 0x%02x", __func__, next_state); 583248613Sdes state = next_state; 584248613Sdes buffer_clear(§); 585248613Sdes switch (state) { 586248613Sdes case KRL_SECTION_CERT_SERIAL_LIST: 587248613Sdes case KRL_SECTION_CERT_SERIAL_RANGE: 588248613Sdes break; 589248613Sdes case KRL_SECTION_CERT_SERIAL_BITMAP: 590248613Sdes if ((bitmap = BN_new()) == NULL) 591248613Sdes goto out; 592248613Sdes bitmap_start = rs->lo; 593248613Sdes buffer_put_int64(§, bitmap_start); 594248613Sdes break; 595248613Sdes } 596248613Sdes } 597248613Sdes 598248613Sdes /* Perform section-specific processing */ 599248613Sdes switch (state) { 600248613Sdes case KRL_SECTION_CERT_SERIAL_LIST: 601248613Sdes for (i = 0; i < contig; i++) 602248613Sdes buffer_put_int64(§, rs->lo + i); 603248613Sdes break; 604248613Sdes case KRL_SECTION_CERT_SERIAL_RANGE: 605248613Sdes buffer_put_int64(§, rs->lo); 606248613Sdes buffer_put_int64(§, rs->hi); 607248613Sdes break; 608248613Sdes case KRL_SECTION_CERT_SERIAL_BITMAP: 609248613Sdes if (rs->lo - bitmap_start > INT_MAX) { 610248613Sdes error("%s: insane bitmap gap", __func__); 611248613Sdes goto out; 612248613Sdes } 613248613Sdes for (i = 0; i < contig; i++) { 614248613Sdes if (BN_set_bit(bitmap, 615248613Sdes rs->lo + i - bitmap_start) != 1) 616248613Sdes goto out; 617248613Sdes } 618248613Sdes break; 619248613Sdes } 620248613Sdes last = rs->hi; 621248613Sdes } 622248613Sdes /* Flush the remaining section, if any */ 623248613Sdes if (state != 0) { 624248613Sdes debug3("%s: serial final flush for state 0x%02x", 625248613Sdes __func__, state); 626248613Sdes switch (state) { 627248613Sdes case KRL_SECTION_CERT_SERIAL_LIST: 628248613Sdes case KRL_SECTION_CERT_SERIAL_RANGE: 629248613Sdes break; 630248613Sdes case KRL_SECTION_CERT_SERIAL_BITMAP: 631248613Sdes buffer_put_bignum2(§, bitmap); 632248613Sdes BN_free(bitmap); 633248613Sdes bitmap = NULL; 634248613Sdes break; 635248613Sdes } 636248613Sdes buffer_put_char(buf, state); 637248613Sdes buffer_put_string(buf, 638248613Sdes buffer_ptr(§), buffer_len(§)); 639248613Sdes } 640248613Sdes debug3("%s: serial done ", __func__); 641248613Sdes 642248613Sdes /* Now output a section for any revocations by key ID */ 643248613Sdes buffer_clear(§); 644248613Sdes RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) { 645248613Sdes debug3("%s: key ID %s", __func__, rki->key_id); 646248613Sdes buffer_put_cstring(§, rki->key_id); 647248613Sdes } 648248613Sdes if (buffer_len(§) != 0) { 649248613Sdes buffer_put_char(buf, KRL_SECTION_CERT_KEY_ID); 650248613Sdes buffer_put_string(buf, buffer_ptr(§), 651248613Sdes buffer_len(§)); 652248613Sdes } 653248613Sdes r = 0; 654248613Sdes out: 655248613Sdes if (bitmap != NULL) 656248613Sdes BN_free(bitmap); 657248613Sdes buffer_free(§); 658248613Sdes return r; 659248613Sdes} 660248613Sdes 661248613Sdesint 662248613Sdesssh_krl_to_blob(struct ssh_krl *krl, Buffer *buf, const Key **sign_keys, 663248613Sdes u_int nsign_keys) 664248613Sdes{ 665248613Sdes int r = -1; 666248613Sdes struct revoked_certs *rc; 667248613Sdes struct revoked_blob *rb; 668248613Sdes Buffer sect; 669248613Sdes u_char *kblob = NULL, *sblob = NULL; 670248613Sdes u_int klen, slen, i; 671248613Sdes 672248613Sdes if (krl->generated_date == 0) 673248613Sdes krl->generated_date = time(NULL); 674248613Sdes 675248613Sdes buffer_init(§); 676248613Sdes 677248613Sdes /* Store the header */ 678248613Sdes buffer_append(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1); 679248613Sdes buffer_put_int(buf, KRL_FORMAT_VERSION); 680248613Sdes buffer_put_int64(buf, krl->krl_version); 681248613Sdes buffer_put_int64(buf, krl->generated_date); 682248613Sdes buffer_put_int64(buf, krl->flags); 683248613Sdes buffer_put_string(buf, NULL, 0); 684248613Sdes buffer_put_cstring(buf, krl->comment ? krl->comment : ""); 685248613Sdes 686248613Sdes /* Store sections for revoked certificates */ 687248613Sdes TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 688248613Sdes if (revoked_certs_generate(rc, §) != 0) 689248613Sdes goto out; 690248613Sdes buffer_put_char(buf, KRL_SECTION_CERTIFICATES); 691248613Sdes buffer_put_string(buf, buffer_ptr(§), 692248613Sdes buffer_len(§)); 693248613Sdes } 694248613Sdes 695248613Sdes /* Finally, output sections for revocations by public key/hash */ 696248613Sdes buffer_clear(§); 697248613Sdes RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { 698248613Sdes debug3("%s: key len %u ", __func__, rb->len); 699248613Sdes buffer_put_string(§, rb->blob, rb->len); 700248613Sdes } 701248613Sdes if (buffer_len(§) != 0) { 702248613Sdes buffer_put_char(buf, KRL_SECTION_EXPLICIT_KEY); 703248613Sdes buffer_put_string(buf, buffer_ptr(§), 704248613Sdes buffer_len(§)); 705248613Sdes } 706248613Sdes buffer_clear(§); 707248613Sdes RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { 708248613Sdes debug3("%s: hash len %u ", __func__, rb->len); 709248613Sdes buffer_put_string(§, rb->blob, rb->len); 710248613Sdes } 711248613Sdes if (buffer_len(§) != 0) { 712248613Sdes buffer_put_char(buf, KRL_SECTION_FINGERPRINT_SHA1); 713248613Sdes buffer_put_string(buf, buffer_ptr(§), 714248613Sdes buffer_len(§)); 715248613Sdes } 716248613Sdes 717248613Sdes for (i = 0; i < nsign_keys; i++) { 718248613Sdes if (key_to_blob(sign_keys[i], &kblob, &klen) == 0) 719248613Sdes goto out; 720248613Sdes 721248613Sdes debug3("%s: signature key len %u", __func__, klen); 722248613Sdes buffer_put_char(buf, KRL_SECTION_SIGNATURE); 723248613Sdes buffer_put_string(buf, kblob, klen); 724248613Sdes 725248613Sdes if (key_sign(sign_keys[i], &sblob, &slen, 726248613Sdes buffer_ptr(buf), buffer_len(buf)) == -1) 727248613Sdes goto out; 728248613Sdes debug3("%s: signature sig len %u", __func__, slen); 729248613Sdes buffer_put_string(buf, sblob, slen); 730248613Sdes } 731248613Sdes 732248613Sdes r = 0; 733248613Sdes out: 734248613Sdes free(kblob); 735248613Sdes free(sblob); 736248613Sdes buffer_free(§); 737248613Sdes return r; 738248613Sdes} 739248613Sdes 740248613Sdesstatic void 741248613Sdesformat_timestamp(u_int64_t timestamp, char *ts, size_t nts) 742248613Sdes{ 743248613Sdes time_t t; 744248613Sdes struct tm *tm; 745248613Sdes 746248613Sdes t = timestamp; 747248613Sdes tm = localtime(&t); 748248613Sdes *ts = '\0'; 749248613Sdes strftime(ts, nts, "%Y%m%dT%H%M%S", tm); 750248613Sdes} 751248613Sdes 752248613Sdesstatic int 753248613Sdesparse_revoked_certs(Buffer *buf, struct ssh_krl *krl) 754248613Sdes{ 755248613Sdes int ret = -1, nbits; 756248613Sdes u_char type, *blob; 757248613Sdes u_int blen; 758248613Sdes Buffer subsect; 759248613Sdes u_int64_t serial, serial_lo, serial_hi; 760248613Sdes BIGNUM *bitmap = NULL; 761248613Sdes char *key_id = NULL; 762248613Sdes Key *ca_key = NULL; 763248613Sdes 764248613Sdes buffer_init(&subsect); 765248613Sdes 766248613Sdes if ((blob = buffer_get_string_ptr_ret(buf, &blen)) == NULL || 767248613Sdes buffer_get_string_ptr_ret(buf, NULL) == NULL) { /* reserved */ 768248613Sdes error("%s: buffer error", __func__); 769248613Sdes goto out; 770248613Sdes } 771248613Sdes if ((ca_key = key_from_blob(blob, blen)) == NULL) 772248613Sdes goto out; 773248613Sdes 774248613Sdes while (buffer_len(buf) > 0) { 775248613Sdes if (buffer_get_char_ret(&type, buf) != 0 || 776248613Sdes (blob = buffer_get_string_ptr_ret(buf, &blen)) == NULL) { 777248613Sdes error("%s: buffer error", __func__); 778248613Sdes goto out; 779248613Sdes } 780248613Sdes buffer_clear(&subsect); 781248613Sdes buffer_append(&subsect, blob, blen); 782248613Sdes debug3("%s: subsection type 0x%02x", __func__, type); 783248613Sdes /* buffer_dump(&subsect); */ 784248613Sdes 785248613Sdes switch (type) { 786248613Sdes case KRL_SECTION_CERT_SERIAL_LIST: 787248613Sdes while (buffer_len(&subsect) > 0) { 788248613Sdes if (buffer_get_int64_ret(&serial, 789248613Sdes &subsect) != 0) { 790248613Sdes error("%s: buffer error", __func__); 791248613Sdes goto out; 792248613Sdes } 793248613Sdes if (ssh_krl_revoke_cert_by_serial(krl, ca_key, 794248613Sdes serial) != 0) { 795248613Sdes error("%s: update failed", __func__); 796248613Sdes goto out; 797248613Sdes } 798248613Sdes } 799248613Sdes break; 800248613Sdes case KRL_SECTION_CERT_SERIAL_RANGE: 801248613Sdes if (buffer_get_int64_ret(&serial_lo, &subsect) != 0 || 802248613Sdes buffer_get_int64_ret(&serial_hi, &subsect) != 0) { 803248613Sdes error("%s: buffer error", __func__); 804248613Sdes goto out; 805248613Sdes } 806248613Sdes if (ssh_krl_revoke_cert_by_serial_range(krl, ca_key, 807248613Sdes serial_lo, serial_hi) != 0) { 808248613Sdes error("%s: update failed", __func__); 809248613Sdes goto out; 810248613Sdes } 811248613Sdes break; 812248613Sdes case KRL_SECTION_CERT_SERIAL_BITMAP: 813248613Sdes if ((bitmap = BN_new()) == NULL) { 814248613Sdes error("%s: BN_new", __func__); 815248613Sdes goto out; 816248613Sdes } 817248613Sdes if (buffer_get_int64_ret(&serial_lo, &subsect) != 0 || 818248613Sdes buffer_get_bignum2_ret(&subsect, bitmap) != 0) { 819248613Sdes error("%s: buffer error", __func__); 820248613Sdes goto out; 821248613Sdes } 822248613Sdes if ((nbits = BN_num_bits(bitmap)) < 0) { 823248613Sdes error("%s: bitmap bits < 0", __func__); 824248613Sdes goto out; 825248613Sdes } 826248613Sdes for (serial = 0; serial < (u_int)nbits; serial++) { 827248613Sdes if (serial > 0 && serial_lo + serial == 0) { 828248613Sdes error("%s: bitmap wraps u64", __func__); 829248613Sdes goto out; 830248613Sdes } 831248613Sdes if (!BN_is_bit_set(bitmap, serial)) 832248613Sdes continue; 833248613Sdes if (ssh_krl_revoke_cert_by_serial(krl, ca_key, 834248613Sdes serial_lo + serial) != 0) { 835248613Sdes error("%s: update failed", __func__); 836248613Sdes goto out; 837248613Sdes } 838248613Sdes } 839248613Sdes BN_free(bitmap); 840248613Sdes bitmap = NULL; 841248613Sdes break; 842248613Sdes case KRL_SECTION_CERT_KEY_ID: 843248613Sdes while (buffer_len(&subsect) > 0) { 844248613Sdes if ((key_id = buffer_get_cstring_ret(&subsect, 845248613Sdes NULL)) == NULL) { 846248613Sdes error("%s: buffer error", __func__); 847248613Sdes goto out; 848248613Sdes } 849248613Sdes if (ssh_krl_revoke_cert_by_key_id(krl, ca_key, 850248613Sdes key_id) != 0) { 851248613Sdes error("%s: update failed", __func__); 852248613Sdes goto out; 853248613Sdes } 854248613Sdes free(key_id); 855248613Sdes key_id = NULL; 856248613Sdes } 857248613Sdes break; 858248613Sdes default: 859248613Sdes error("Unsupported KRL certificate section %u", type); 860248613Sdes goto out; 861248613Sdes } 862248613Sdes if (buffer_len(&subsect) > 0) { 863248613Sdes error("KRL certificate section contains unparsed data"); 864248613Sdes goto out; 865248613Sdes } 866248613Sdes } 867248613Sdes 868248613Sdes ret = 0; 869248613Sdes out: 870248613Sdes if (ca_key != NULL) 871248613Sdes key_free(ca_key); 872248613Sdes if (bitmap != NULL) 873248613Sdes BN_free(bitmap); 874248613Sdes free(key_id); 875248613Sdes buffer_free(&subsect); 876248613Sdes return ret; 877248613Sdes} 878248613Sdes 879248613Sdes 880248613Sdes/* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ 881248613Sdesint 882248613Sdesssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp, 883248613Sdes const Key **sign_ca_keys, u_int nsign_ca_keys) 884248613Sdes{ 885248613Sdes Buffer copy, sect; 886248613Sdes struct ssh_krl *krl; 887248613Sdes char timestamp[64]; 888248613Sdes int ret = -1, r, sig_seen; 889248613Sdes Key *key = NULL, **ca_used = NULL; 890263970Sdes u_char type, *blob, *rdata = NULL; 891263970Sdes u_int i, j, sig_off, sects_off, rlen, blen, format_version, nca_used; 892248613Sdes 893263970Sdes nca_used = 0; 894248613Sdes *krlp = NULL; 895248613Sdes if (buffer_len(buf) < sizeof(KRL_MAGIC) - 1 || 896248613Sdes memcmp(buffer_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) { 897248613Sdes debug3("%s: not a KRL", __func__); 898248613Sdes /* 899248613Sdes * Return success but a NULL *krlp here to signal that the 900248613Sdes * file might be a simple list of keys. 901248613Sdes */ 902248613Sdes return 0; 903248613Sdes } 904248613Sdes 905248613Sdes /* Take a copy of the KRL buffer so we can verify its signature later */ 906248613Sdes buffer_init(©); 907248613Sdes buffer_append(©, buffer_ptr(buf), buffer_len(buf)); 908248613Sdes 909248613Sdes buffer_init(§); 910248613Sdes buffer_consume(©, sizeof(KRL_MAGIC) - 1); 911248613Sdes 912248613Sdes if ((krl = ssh_krl_init()) == NULL) { 913248613Sdes error("%s: alloc failed", __func__); 914248613Sdes goto out; 915248613Sdes } 916248613Sdes 917248613Sdes if (buffer_get_int_ret(&format_version, ©) != 0) { 918248613Sdes error("%s: KRL truncated", __func__); 919248613Sdes goto out; 920248613Sdes } 921248613Sdes if (format_version != KRL_FORMAT_VERSION) { 922248613Sdes error("%s: KRL unsupported format version %u", 923248613Sdes __func__, format_version); 924248613Sdes goto out; 925248613Sdes } 926248613Sdes if (buffer_get_int64_ret(&krl->krl_version, ©) != 0 || 927248613Sdes buffer_get_int64_ret(&krl->generated_date, ©) != 0 || 928248613Sdes buffer_get_int64_ret(&krl->flags, ©) != 0 || 929248613Sdes buffer_get_string_ptr_ret(©, NULL) == NULL || /* reserved */ 930248613Sdes (krl->comment = buffer_get_cstring_ret(©, NULL)) == NULL) { 931248613Sdes error("%s: buffer error", __func__); 932248613Sdes goto out; 933248613Sdes } 934248613Sdes 935248613Sdes format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); 936251135Sdes debug("KRL version %llu generated at %s%s%s", 937263970Sdes (long long unsigned)krl->krl_version, timestamp, 938251135Sdes *krl->comment ? ": " : "", krl->comment); 939248613Sdes 940248613Sdes /* 941248613Sdes * 1st pass: verify signatures, if any. This is done to avoid 942248613Sdes * detailed parsing of data whose provenance is unverified. 943248613Sdes */ 944248613Sdes sig_seen = 0; 945248613Sdes sects_off = buffer_len(buf) - buffer_len(©); 946248613Sdes while (buffer_len(©) > 0) { 947248613Sdes if (buffer_get_char_ret(&type, ©) != 0 || 948248613Sdes (blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) { 949248613Sdes error("%s: buffer error", __func__); 950248613Sdes goto out; 951248613Sdes } 952248613Sdes debug3("%s: first pass, section 0x%02x", __func__, type); 953248613Sdes if (type != KRL_SECTION_SIGNATURE) { 954248613Sdes if (sig_seen) { 955248613Sdes error("KRL contains non-signature section " 956248613Sdes "after signature"); 957248613Sdes goto out; 958248613Sdes } 959248613Sdes /* Not interested for now. */ 960248613Sdes continue; 961248613Sdes } 962248613Sdes sig_seen = 1; 963248613Sdes /* First string component is the signing key */ 964248613Sdes if ((key = key_from_blob(blob, blen)) == NULL) { 965248613Sdes error("%s: invalid signature key", __func__); 966248613Sdes goto out; 967248613Sdes } 968248613Sdes sig_off = buffer_len(buf) - buffer_len(©); 969248613Sdes /* Second string component is the signature itself */ 970248613Sdes if ((blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) { 971248613Sdes error("%s: buffer error", __func__); 972248613Sdes goto out; 973248613Sdes } 974248613Sdes /* Check signature over entire KRL up to this point */ 975248613Sdes if (key_verify(key, blob, blen, 976263970Sdes buffer_ptr(buf), buffer_len(buf) - sig_off) != 1) { 977248613Sdes error("bad signaure on KRL"); 978248613Sdes goto out; 979248613Sdes } 980248613Sdes /* Check if this key has already signed this KRL */ 981248613Sdes for (i = 0; i < nca_used; i++) { 982248613Sdes if (key_equal(ca_used[i], key)) { 983248613Sdes error("KRL signed more than once with " 984248613Sdes "the same key"); 985248613Sdes goto out; 986248613Sdes } 987248613Sdes } 988248613Sdes /* Record keys used to sign the KRL */ 989248613Sdes ca_used = xrealloc(ca_used, nca_used + 1, sizeof(*ca_used)); 990248613Sdes ca_used[nca_used++] = key; 991248613Sdes key = NULL; 992248613Sdes break; 993248613Sdes } 994248613Sdes 995248613Sdes /* 996248613Sdes * 2nd pass: parse and load the KRL, skipping the header to the point 997248613Sdes * where the section start. 998248613Sdes */ 999248613Sdes buffer_append(©, (u_char*)buffer_ptr(buf) + sects_off, 1000248613Sdes buffer_len(buf) - sects_off); 1001248613Sdes while (buffer_len(©) > 0) { 1002248613Sdes if (buffer_get_char_ret(&type, ©) != 0 || 1003248613Sdes (blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) { 1004248613Sdes error("%s: buffer error", __func__); 1005248613Sdes goto out; 1006248613Sdes } 1007248613Sdes debug3("%s: second pass, section 0x%02x", __func__, type); 1008248613Sdes buffer_clear(§); 1009248613Sdes buffer_append(§, blob, blen); 1010248613Sdes 1011248613Sdes switch (type) { 1012248613Sdes case KRL_SECTION_CERTIFICATES: 1013248613Sdes if ((r = parse_revoked_certs(§, krl)) != 0) 1014248613Sdes goto out; 1015248613Sdes break; 1016248613Sdes case KRL_SECTION_EXPLICIT_KEY: 1017248613Sdes case KRL_SECTION_FINGERPRINT_SHA1: 1018248613Sdes while (buffer_len(§) > 0) { 1019263970Sdes if ((rdata = buffer_get_string_ret(§, 1020263970Sdes &rlen)) == NULL) { 1021248613Sdes error("%s: buffer error", __func__); 1022248613Sdes goto out; 1023248613Sdes } 1024248613Sdes if (type == KRL_SECTION_FINGERPRINT_SHA1 && 1025263970Sdes rlen != 20) { 1026248613Sdes error("%s: bad SHA1 length", __func__); 1027248613Sdes goto out; 1028248613Sdes } 1029248613Sdes if (revoke_blob( 1030248613Sdes type == KRL_SECTION_EXPLICIT_KEY ? 1031248613Sdes &krl->revoked_keys : &krl->revoked_sha1s, 1032263970Sdes rdata, rlen) != 0) 1033263970Sdes goto out; 1034263970Sdes rdata = NULL; /* revoke_blob frees blob */ 1035248613Sdes } 1036248613Sdes break; 1037248613Sdes case KRL_SECTION_SIGNATURE: 1038248613Sdes /* Handled above, but still need to stay in synch */ 1039248613Sdes buffer_clear(§); 1040248613Sdes if ((blob = buffer_get_string_ptr_ret(©, 1041248613Sdes &blen)) == NULL) { 1042248613Sdes error("%s: buffer error", __func__); 1043248613Sdes goto out; 1044248613Sdes } 1045248613Sdes break; 1046248613Sdes default: 1047248613Sdes error("Unsupported KRL section %u", type); 1048248613Sdes goto out; 1049248613Sdes } 1050248613Sdes if (buffer_len(§) > 0) { 1051248613Sdes error("KRL section contains unparsed data"); 1052248613Sdes goto out; 1053248613Sdes } 1054248613Sdes } 1055248613Sdes 1056248613Sdes /* Check that the key(s) used to sign the KRL weren't revoked */ 1057248613Sdes sig_seen = 0; 1058248613Sdes for (i = 0; i < nca_used; i++) { 1059248613Sdes if (ssh_krl_check_key(krl, ca_used[i]) == 0) 1060248613Sdes sig_seen = 1; 1061248613Sdes else { 1062248613Sdes key_free(ca_used[i]); 1063248613Sdes ca_used[i] = NULL; 1064248613Sdes } 1065248613Sdes } 1066248613Sdes if (nca_used && !sig_seen) { 1067248613Sdes error("All keys used to sign KRL were revoked"); 1068248613Sdes goto out; 1069248613Sdes } 1070248613Sdes 1071248613Sdes /* If we have CA keys, then verify that one was used to sign the KRL */ 1072248613Sdes if (sig_seen && nsign_ca_keys != 0) { 1073248613Sdes sig_seen = 0; 1074248613Sdes for (i = 0; !sig_seen && i < nsign_ca_keys; i++) { 1075248613Sdes for (j = 0; j < nca_used; j++) { 1076248613Sdes if (ca_used[j] == NULL) 1077248613Sdes continue; 1078248613Sdes if (key_equal(ca_used[j], sign_ca_keys[i])) { 1079248613Sdes sig_seen = 1; 1080248613Sdes break; 1081248613Sdes } 1082248613Sdes } 1083248613Sdes } 1084248613Sdes if (!sig_seen) { 1085248613Sdes error("KRL not signed with any trusted key"); 1086248613Sdes goto out; 1087248613Sdes } 1088248613Sdes } 1089248613Sdes 1090248613Sdes *krlp = krl; 1091248613Sdes ret = 0; 1092248613Sdes out: 1093248613Sdes if (ret != 0) 1094248613Sdes ssh_krl_free(krl); 1095248613Sdes for (i = 0; i < nca_used; i++) { 1096248613Sdes if (ca_used[i] != NULL) 1097248613Sdes key_free(ca_used[i]); 1098248613Sdes } 1099248613Sdes free(ca_used); 1100263970Sdes free(rdata); 1101248613Sdes if (key != NULL) 1102248613Sdes key_free(key); 1103248613Sdes buffer_free(©); 1104248613Sdes buffer_free(§); 1105248613Sdes return ret; 1106248613Sdes} 1107248613Sdes 1108248613Sdes/* Checks whether a given key/cert is revoked. Does not check its CA */ 1109248613Sdesstatic int 1110248613Sdesis_key_revoked(struct ssh_krl *krl, const Key *key) 1111248613Sdes{ 1112248613Sdes struct revoked_blob rb, *erb; 1113248613Sdes struct revoked_serial rs, *ers; 1114248613Sdes struct revoked_key_id rki, *erki; 1115248613Sdes struct revoked_certs *rc; 1116248613Sdes 1117248613Sdes /* Check explicitly revoked hashes first */ 1118263970Sdes memset(&rb, 0, sizeof(rb)); 1119248613Sdes if ((rb.blob = key_fingerprint_raw(key, SSH_FP_SHA1, &rb.len)) == NULL) 1120248613Sdes return -1; 1121248613Sdes erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); 1122248613Sdes free(rb.blob); 1123248613Sdes if (erb != NULL) { 1124248613Sdes debug("%s: revoked by key SHA1", __func__); 1125248613Sdes return -1; 1126248613Sdes } 1127248613Sdes 1128248613Sdes /* Next, explicit keys */ 1129263970Sdes memset(&rb, 0, sizeof(rb)); 1130248613Sdes if (plain_key_blob(key, &rb.blob, &rb.len) != 0) 1131248613Sdes return -1; 1132248613Sdes erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); 1133248613Sdes free(rb.blob); 1134248613Sdes if (erb != NULL) { 1135248613Sdes debug("%s: revoked by explicit key", __func__); 1136248613Sdes return -1; 1137248613Sdes } 1138248613Sdes 1139248613Sdes if (!key_is_cert(key)) 1140248613Sdes return 0; 1141248613Sdes 1142248613Sdes /* Check cert revocation */ 1143248613Sdes if (revoked_certs_for_ca_key(krl, key->cert->signature_key, 1144248613Sdes &rc, 0) != 0) 1145248613Sdes return -1; 1146248613Sdes if (rc == NULL) 1147248613Sdes return 0; /* No entry for this CA */ 1148248613Sdes 1149248613Sdes /* Check revocation by cert key ID */ 1150263970Sdes memset(&rki, 0, sizeof(rki)); 1151248613Sdes rki.key_id = key->cert->key_id; 1152248613Sdes erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); 1153248613Sdes if (erki != NULL) { 1154248613Sdes debug("%s: revoked by key ID", __func__); 1155248613Sdes return -1; 1156248613Sdes } 1157248613Sdes 1158248613Sdes /* 1159248613Sdes * Legacy cert formats lack serial numbers. Zero serials numbers 1160248613Sdes * are ignored (it's the default when the CA doesn't specify one). 1161248613Sdes */ 1162248613Sdes if (key_cert_is_legacy(key) || key->cert->serial == 0) 1163248613Sdes return 0; 1164248613Sdes 1165263970Sdes memset(&rs, 0, sizeof(rs)); 1166248613Sdes rs.lo = rs.hi = key->cert->serial; 1167248613Sdes ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); 1168248613Sdes if (ers != NULL) { 1169248613Sdes KRL_DBG(("%s: %llu matched %llu:%llu", __func__, 1170248613Sdes key->cert->serial, ers->lo, ers->hi)); 1171248613Sdes debug("%s: revoked by serial", __func__); 1172248613Sdes return -1; 1173248613Sdes } 1174248613Sdes KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); 1175248613Sdes 1176248613Sdes return 0; 1177248613Sdes} 1178248613Sdes 1179248613Sdesint 1180248613Sdesssh_krl_check_key(struct ssh_krl *krl, const Key *key) 1181248613Sdes{ 1182248613Sdes int r; 1183248613Sdes 1184248613Sdes debug2("%s: checking key", __func__); 1185248613Sdes if ((r = is_key_revoked(krl, key)) != 0) 1186248613Sdes return r; 1187248613Sdes if (key_is_cert(key)) { 1188248613Sdes debug2("%s: checking CA key", __func__); 1189248613Sdes if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) 1190248613Sdes return r; 1191248613Sdes } 1192248613Sdes debug3("%s: key okay", __func__); 1193248613Sdes return 0; 1194248613Sdes} 1195248613Sdes 1196248613Sdes/* Returns 0 on success, -1 on error or key revoked, -2 if path is not a KRL */ 1197248613Sdesint 1198248613Sdesssh_krl_file_contains_key(const char *path, const Key *key) 1199248613Sdes{ 1200248613Sdes Buffer krlbuf; 1201248613Sdes struct ssh_krl *krl; 1202248613Sdes int revoked, fd; 1203248613Sdes 1204248613Sdes if (path == NULL) 1205248613Sdes return 0; 1206248613Sdes 1207248613Sdes if ((fd = open(path, O_RDONLY)) == -1) { 1208248613Sdes error("open %s: %s", path, strerror(errno)); 1209248613Sdes error("Revoked keys file not accessible - refusing public key " 1210248613Sdes "authentication"); 1211248613Sdes return -1; 1212248613Sdes } 1213248613Sdes buffer_init(&krlbuf); 1214248613Sdes if (!key_load_file(fd, path, &krlbuf)) { 1215248613Sdes close(fd); 1216248613Sdes buffer_free(&krlbuf); 1217248613Sdes error("Revoked keys file not readable - refusing public key " 1218248613Sdes "authentication"); 1219248613Sdes return -1; 1220248613Sdes } 1221248613Sdes close(fd); 1222248613Sdes if (ssh_krl_from_blob(&krlbuf, &krl, NULL, 0) != 0) { 1223248613Sdes buffer_free(&krlbuf); 1224248613Sdes error("Invalid KRL, refusing public key " 1225248613Sdes "authentication"); 1226248613Sdes return -1; 1227248613Sdes } 1228248613Sdes buffer_free(&krlbuf); 1229248613Sdes if (krl == NULL) { 1230248613Sdes debug3("%s: %s is not a KRL file", __func__, path); 1231248613Sdes return -2; 1232248613Sdes } 1233248613Sdes debug2("%s: checking KRL %s", __func__, path); 1234248613Sdes revoked = ssh_krl_check_key(krl, key) != 0; 1235248613Sdes ssh_krl_free(krl); 1236248613Sdes return revoked ? -1 : 0; 1237248613Sdes} 1238