Home | History | Annotate | Download | only in openssh
      1 /*
      2  * Copyright (c) 2012 Damien Miller <djm (at) mindrot.org>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 /* $OpenBSD: krl.c,v 1.31 2015/01/30 01:10:33 djm Exp $ */
     18 
     19 #include "includes.h"
     20 
     21 #include <sys/param.h>	/* MIN */
     22 #include <sys/types.h>
     23 #include <openbsd-compat/sys-tree.h>
     24 #include <openbsd-compat/sys-queue.h>
     25 
     26 #include <errno.h>
     27 #include <fcntl.h>
     28 #include <limits.h>
     29 #include <string.h>
     30 #include <time.h>
     31 #include <unistd.h>
     32 
     33 #include "sshbuf.h"
     34 #include "ssherr.h"
     35 #include "sshkey.h"
     36 #include "authfile.h"
     37 #include "misc.h"
     38 #include "log.h"
     39 #include "digest.h"
     40 #include "bitmap.h"
     41 
     42 #include "krl.h"
     43 
     44 /* #define DEBUG_KRL */
     45 #ifdef DEBUG_KRL
     46 # define KRL_DBG(x) debug3 x
     47 #else
     48 # define KRL_DBG(x)
     49 #endif
     50 
     51 /*
     52  * Trees of revoked serial numbers, key IDs and keys. This allows
     53  * quick searching, querying and producing lists in canonical order.
     54  */
     55 
     56 /* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */
     57 struct revoked_serial {
     58 	u_int64_t lo, hi;
     59 	RB_ENTRY(revoked_serial) tree_entry;
     60 };
     61 static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b);
     62 RB_HEAD(revoked_serial_tree, revoked_serial);
     63 RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp);
     64 
     65 /* Tree of key IDs */
     66 struct revoked_key_id {
     67 	char *key_id;
     68 	RB_ENTRY(revoked_key_id) tree_entry;
     69 };
     70 static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b);
     71 RB_HEAD(revoked_key_id_tree, revoked_key_id);
     72 RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp);
     73 
     74 /* Tree of blobs (used for keys and fingerprints) */
     75 struct revoked_blob {
     76 	u_char *blob;
     77 	size_t len;
     78 	RB_ENTRY(revoked_blob) tree_entry;
     79 };
     80 static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b);
     81 RB_HEAD(revoked_blob_tree, revoked_blob);
     82 RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp);
     83 
     84 /* Tracks revoked certs for a single CA */
     85 struct revoked_certs {
     86 	struct sshkey *ca_key;
     87 	struct revoked_serial_tree revoked_serials;
     88 	struct revoked_key_id_tree revoked_key_ids;
     89 	TAILQ_ENTRY(revoked_certs) entry;
     90 };
     91 TAILQ_HEAD(revoked_certs_list, revoked_certs);
     92 
     93 struct ssh_krl {
     94 	u_int64_t krl_version;
     95 	u_int64_t generated_date;
     96 	u_int64_t flags;
     97 	char *comment;
     98 	struct revoked_blob_tree revoked_keys;
     99 	struct revoked_blob_tree revoked_sha1s;
    100 	struct revoked_certs_list revoked_certs;
    101 };
    102 
    103 /* Return equal if a and b overlap */
    104 static int
    105 serial_cmp(struct revoked_serial *a, struct revoked_serial *b)
    106 {
    107 	if (a->hi >= b->lo && a->lo <= b->hi)
    108 		return 0;
    109 	return a->lo < b->lo ? -1 : 1;
    110 }
    111 
    112 static int
    113 key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b)
    114 {
    115 	return strcmp(a->key_id, b->key_id);
    116 }
    117 
    118 static int
    119 blob_cmp(struct revoked_blob *a, struct revoked_blob *b)
    120 {
    121 	int r;
    122 
    123 	if (a->len != b->len) {
    124 		if ((r = memcmp(a->blob, b->blob, MIN(a->len, b->len))) != 0)
    125 			return r;
    126 		return a->len > b->len ? 1 : -1;
    127 	} else
    128 		return memcmp(a->blob, b->blob, a->len);
    129 }
    130 
    131 struct ssh_krl *
    132 ssh_krl_init(void)
    133 {
    134 	struct ssh_krl *krl;
    135 
    136 	if ((krl = calloc(1, sizeof(*krl))) == NULL)
    137 		return NULL;
    138 	RB_INIT(&krl->revoked_keys);
    139 	RB_INIT(&krl->revoked_sha1s);
    140 	TAILQ_INIT(&krl->revoked_certs);
    141 	return krl;
    142 }
    143 
    144 static void
    145 revoked_certs_free(struct revoked_certs *rc)
    146 {
    147 	struct revoked_serial *rs, *trs;
    148 	struct revoked_key_id *rki, *trki;
    149 
    150 	RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) {
    151 		RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs);
    152 		free(rs);
    153 	}
    154 	RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) {
    155 		RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki);
    156 		free(rki->key_id);
    157 		free(rki);
    158 	}
    159 	sshkey_free(rc->ca_key);
    160 }
    161 
    162 void
    163 ssh_krl_free(struct ssh_krl *krl)
    164 {
    165 	struct revoked_blob *rb, *trb;
    166 	struct revoked_certs *rc, *trc;
    167 
    168 	if (krl == NULL)
    169 		return;
    170 
    171 	free(krl->comment);
    172 	RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) {
    173 		RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb);
    174 		free(rb->blob);
    175 		free(rb);
    176 	}
    177 	RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) {
    178 		RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb);
    179 		free(rb->blob);
    180 		free(rb);
    181 	}
    182 	TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) {
    183 		TAILQ_REMOVE(&krl->revoked_certs, rc, entry);
    184 		revoked_certs_free(rc);
    185 	}
    186 }
    187 
    188 void
    189 ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version)
    190 {
    191 	krl->krl_version = version;
    192 }
    193 
    194 int
    195 ssh_krl_set_comment(struct ssh_krl *krl, const char *comment)
    196 {
    197 	free(krl->comment);
    198 	if ((krl->comment = strdup(comment)) == NULL)
    199 		return SSH_ERR_ALLOC_FAIL;
    200 	return 0;
    201 }
    202 
    203 /*
    204  * Find the revoked_certs struct for a CA key. If allow_create is set then
    205  * create a new one in the tree if one did not exist already.
    206  */
    207 static int
    208 revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key,
    209     struct revoked_certs **rcp, int allow_create)
    210 {
    211 	struct revoked_certs *rc;
    212 	int r;
    213 
    214 	*rcp = NULL;
    215 	TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
    216 		if ((ca_key == NULL && rc->ca_key == NULL) ||
    217 		    sshkey_equal(rc->ca_key, ca_key)) {
    218 			*rcp = rc;
    219 			return 0;
    220 		}
    221 	}
    222 	if (!allow_create)
    223 		return 0;
    224 	/* If this CA doesn't exist in the list then add it now */
    225 	if ((rc = calloc(1, sizeof(*rc))) == NULL)
    226 		return SSH_ERR_ALLOC_FAIL;
    227 	if (ca_key == NULL)
    228 		rc->ca_key = NULL;
    229 	else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) {
    230 		free(rc);
    231 		return r;
    232 	}
    233 	RB_INIT(&rc->revoked_serials);
    234 	RB_INIT(&rc->revoked_key_ids);
    235 	TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry);
    236 	KRL_DBG(("%s: new CA %s", __func__,
    237 	    ca_key == NULL ? "*" : sshkey_type(ca_key)));
    238 	*rcp = rc;
    239 	return 0;
    240 }
    241 
    242 static int
    243 insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi)
    244 {
    245 	struct revoked_serial rs, *ers, *crs, *irs;
    246 
    247 	KRL_DBG(("%s: insert %llu:%llu", __func__, lo, hi));
    248 	memset(&rs, 0, sizeof(rs));
    249 	rs.lo = lo;
    250 	rs.hi = hi;
    251 	ers = RB_NFIND(revoked_serial_tree, rt, &rs);
    252 	if (ers == NULL || serial_cmp(ers, &rs) != 0) {
    253 		/* No entry matches. Just insert */
    254 		if ((irs = malloc(sizeof(rs))) == NULL)
    255 			return SSH_ERR_ALLOC_FAIL;
    256 		memcpy(irs, &rs, sizeof(*irs));
    257 		ers = RB_INSERT(revoked_serial_tree, rt, irs);
    258 		if (ers != NULL) {
    259 			KRL_DBG(("%s: bad: ers != NULL", __func__));
    260 			/* Shouldn't happen */
    261 			free(irs);
    262 			return SSH_ERR_INTERNAL_ERROR;
    263 		}
    264 		ers = irs;
    265 	} else {
    266 		KRL_DBG(("%s: overlap found %llu:%llu", __func__,
    267 		    ers->lo, ers->hi));
    268 		/*
    269 		 * The inserted entry overlaps an existing one. Grow the
    270 		 * existing entry.
    271 		 */
    272 		if (ers->lo > lo)
    273 			ers->lo = lo;
    274 		if (ers->hi < hi)
    275 			ers->hi = hi;
    276 	}
    277 
    278 	/*
    279 	 * The inserted or revised range might overlap or abut adjacent ones;
    280 	 * coalesce as necessary.
    281 	 */
    282 
    283 	/* Check predecessors */
    284 	while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) {
    285 		KRL_DBG(("%s: pred %llu:%llu", __func__, crs->lo, crs->hi));
    286 		if (ers->lo != 0 && crs->hi < ers->lo - 1)
    287 			break;
    288 		/* This entry overlaps. */
    289 		if (crs->lo < ers->lo) {
    290 			ers->lo = crs->lo;
    291 			KRL_DBG(("%s: pred extend %llu:%llu", __func__,
    292 			    ers->lo, ers->hi));
    293 		}
    294 		RB_REMOVE(revoked_serial_tree, rt, crs);
    295 		free(crs);
    296 	}
    297 	/* Check successors */
    298 	while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) {
    299 		KRL_DBG(("%s: succ %llu:%llu", __func__, crs->lo, crs->hi));
    300 		if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1)
    301 			break;
    302 		/* This entry overlaps. */
    303 		if (crs->hi > ers->hi) {
    304 			ers->hi = crs->hi;
    305 			KRL_DBG(("%s: succ extend %llu:%llu", __func__,
    306 			    ers->lo, ers->hi));
    307 		}
    308 		RB_REMOVE(revoked_serial_tree, rt, crs);
    309 		free(crs);
    310 	}
    311 	KRL_DBG(("%s: done, final %llu:%llu", __func__, ers->lo, ers->hi));
    312 	return 0;
    313 }
    314 
    315 int
    316 ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const struct sshkey *ca_key,
    317     u_int64_t serial)
    318 {
    319 	return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial);
    320 }
    321 
    322 int
    323 ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl,
    324     const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi)
    325 {
    326 	struct revoked_certs *rc;
    327 	int r;
    328 
    329 	if (lo > hi || lo == 0)
    330 		return SSH_ERR_INVALID_ARGUMENT;
    331 	if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0)
    332 		return r;
    333 	return insert_serial_range(&rc->revoked_serials, lo, hi);
    334 }
    335 
    336 int
    337 ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const struct sshkey *ca_key,
    338     const char *key_id)
    339 {
    340 	struct revoked_key_id *rki, *erki;
    341 	struct revoked_certs *rc;
    342 	int r;
    343 
    344 	if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0)
    345 		return r;
    346 
    347 	KRL_DBG(("%s: revoke %s", __func__, key_id));
    348 	if ((rki = calloc(1, sizeof(*rki))) == NULL ||
    349 	    (rki->key_id = strdup(key_id)) == NULL) {
    350 		free(rki);
    351 		return SSH_ERR_ALLOC_FAIL;
    352 	}
    353 	erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki);
    354 	if (erki != NULL) {
    355 		free(rki->key_id);
    356 		free(rki);
    357 	}
    358 	return 0;
    359 }
    360 
    361 /* Convert "key" to a public key blob without any certificate information */
    362 static int
    363 plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen)
    364 {
    365 	struct sshkey *kcopy;
    366 	int r;
    367 
    368 	if ((r = sshkey_from_private(key, &kcopy)) != 0)
    369 		return r;
    370 	if (sshkey_is_cert(kcopy)) {
    371 		if ((r = sshkey_drop_cert(kcopy)) != 0) {
    372 			sshkey_free(kcopy);
    373 			return r;
    374 		}
    375 	}
    376 	r = sshkey_to_blob(kcopy, blob, blen);
    377 	sshkey_free(kcopy);
    378 	return r;
    379 }
    380 
    381 /* Revoke a key blob. Ownership of blob is transferred to the tree */
    382 static int
    383 revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, size_t len)
    384 {
    385 	struct revoked_blob *rb, *erb;
    386 
    387 	if ((rb = calloc(1, sizeof(*rb))) == NULL)
    388 		return SSH_ERR_ALLOC_FAIL;
    389 	rb->blob = blob;
    390 	rb->len = len;
    391 	erb = RB_INSERT(revoked_blob_tree, rbt, rb);
    392 	if (erb != NULL) {
    393 		free(rb->blob);
    394 		free(rb);
    395 	}
    396 	return 0;
    397 }
    398 
    399 int
    400 ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key)
    401 {
    402 	u_char *blob;
    403 	size_t len;
    404 	int r;
    405 
    406 	debug3("%s: revoke type %s", __func__, sshkey_type(key));
    407 	if ((r = plain_key_blob(key, &blob, &len)) != 0)
    408 		return r;
    409 	return revoke_blob(&krl->revoked_keys, blob, len);
    410 }
    411 
    412 int
    413 ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key)
    414 {
    415 	u_char *blob;
    416 	size_t len;
    417 	int r;
    418 
    419 	debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key));
    420 	if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
    421 	    &blob, &len)) != 0)
    422 		return r;
    423 	return revoke_blob(&krl->revoked_sha1s, blob, len);
    424 }
    425 
    426 int
    427 ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key)
    428 {
    429 	if (!sshkey_is_cert(key))
    430 		return ssh_krl_revoke_key_sha1(krl, key);
    431 
    432 	if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) {
    433 		return ssh_krl_revoke_cert_by_key_id(krl,
    434 		    key->cert->signature_key,
    435 		    key->cert->key_id);
    436 	} else {
    437 		return ssh_krl_revoke_cert_by_serial(krl,
    438 		    key->cert->signature_key,
    439 		    key->cert->serial);
    440 	}
    441 }
    442 
    443 /*
    444  * Select the most compact section type to emit next in a KRL based on
    445  * the current section type, the run length of contiguous revoked serial
    446  * numbers and the gaps from the last and to the next revoked serial.
    447  * Applies a mostly-accurate bit cost model to select the section type
    448  * that will minimise the size of the resultant KRL.
    449  */
    450 static int
    451 choose_next_state(int current_state, u_int64_t contig, int final,
    452     u_int64_t last_gap, u_int64_t next_gap, int *force_new_section)
    453 {
    454 	int new_state;
    455 	u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart;
    456 
    457 	/*
    458 	 * Avoid unsigned overflows.
    459 	 * The limits are high enough to avoid confusing the calculations.
    460 	 */
    461 	contig = MIN(contig, 1ULL<<31);
    462 	last_gap = MIN(last_gap, 1ULL<<31);
    463 	next_gap = MIN(next_gap, 1ULL<<31);
    464 
    465 	/*
    466 	 * Calculate the cost to switch from the current state to candidates.
    467 	 * NB. range sections only ever contain a single range, so their
    468 	 * switching cost is independent of the current_state.
    469 	 */
    470 	cost_list = cost_bitmap = cost_bitmap_restart = 0;
    471 	cost_range = 8;
    472 	switch (current_state) {
    473 	case KRL_SECTION_CERT_SERIAL_LIST:
    474 		cost_bitmap_restart = cost_bitmap = 8 + 64;
    475 		break;
    476 	case KRL_SECTION_CERT_SERIAL_BITMAP:
    477 		cost_list = 8;
    478 		cost_bitmap_restart = 8 + 64;
    479 		break;
    480 	case KRL_SECTION_CERT_SERIAL_RANGE:
    481 	case 0:
    482 		cost_bitmap_restart = cost_bitmap = 8 + 64;
    483 		cost_list = 8;
    484 	}
    485 
    486 	/* Estimate base cost in bits of each section type */
    487 	cost_list += 64 * contig + (final ? 0 : 8+64);
    488 	cost_range += (2 * 64) + (final ? 0 : 8+64);
    489 	cost_bitmap += last_gap + contig + (final ? 0 : MIN(next_gap, 8+64));
    490 	cost_bitmap_restart += contig + (final ? 0 : MIN(next_gap, 8+64));
    491 
    492 	/* Convert to byte costs for actual comparison */
    493 	cost_list = (cost_list + 7) / 8;
    494 	cost_bitmap = (cost_bitmap + 7) / 8;
    495 	cost_bitmap_restart = (cost_bitmap_restart + 7) / 8;
    496 	cost_range = (cost_range + 7) / 8;
    497 
    498 	/* Now pick the best choice */
    499 	*force_new_section = 0;
    500 	new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
    501 	cost = cost_bitmap;
    502 	if (cost_range < cost) {
    503 		new_state = KRL_SECTION_CERT_SERIAL_RANGE;
    504 		cost = cost_range;
    505 	}
    506 	if (cost_list < cost) {
    507 		new_state = KRL_SECTION_CERT_SERIAL_LIST;
    508 		cost = cost_list;
    509 	}
    510 	if (cost_bitmap_restart < cost) {
    511 		new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
    512 		*force_new_section = 1;
    513 		cost = cost_bitmap_restart;
    514 	}
    515 	KRL_DBG(("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:"
    516 	    "list %llu range %llu bitmap %llu new bitmap %llu, "
    517 	    "selected 0x%02x%s", __func__, (long long unsigned)contig,
    518 	    (long long unsigned)last_gap, (long long unsigned)next_gap, final,
    519 	    (long long unsigned)cost_list, (long long unsigned)cost_range,
    520 	    (long long unsigned)cost_bitmap,
    521 	    (long long unsigned)cost_bitmap_restart, new_state,
    522 	    *force_new_section ? " restart" : ""));
    523 	return new_state;
    524 }
    525 
    526 static int
    527 put_bitmap(struct sshbuf *buf, struct bitmap *bitmap)
    528 {
    529 	size_t len;
    530 	u_char *blob;
    531 	int r;
    532 
    533 	len = bitmap_nbytes(bitmap);
    534 	if ((blob = malloc(len)) == NULL)
    535 		return SSH_ERR_ALLOC_FAIL;
    536 	if (bitmap_to_string(bitmap, blob, len) != 0) {
    537 		free(blob);
    538 		return SSH_ERR_INTERNAL_ERROR;
    539 	}
    540 	r = sshbuf_put_bignum2_bytes(buf, blob, len);
    541 	free(blob);
    542 	return r;
    543 }
    544 
    545 /* Generate a KRL_SECTION_CERTIFICATES KRL section */
    546 static int
    547 revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf)
    548 {
    549 	int final, force_new_sect, r = SSH_ERR_INTERNAL_ERROR;
    550 	u_int64_t i, contig, gap, last = 0, bitmap_start = 0;
    551 	struct revoked_serial *rs, *nrs;
    552 	struct revoked_key_id *rki;
    553 	int next_state, state = 0;
    554 	struct sshbuf *sect;
    555 	struct bitmap *bitmap = NULL;
    556 
    557 	if ((sect = sshbuf_new()) == NULL)
    558 		return SSH_ERR_ALLOC_FAIL;
    559 
    560 	/* Store the header: optional CA scope key, reserved */
    561 	if (rc->ca_key == NULL) {
    562 		if ((r = sshbuf_put_string(buf, NULL, 0)) != 0)
    563 			goto out;
    564 	} else {
    565 		if ((r = sshkey_puts(rc->ca_key, buf)) != 0)
    566 			goto out;
    567 	}
    568 	if ((r = sshbuf_put_string(buf, NULL, 0)) != 0)
    569 		goto out;
    570 
    571 	/* Store the revoked serials.  */
    572 	for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials);
    573 	     rs != NULL;
    574 	     rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) {
    575 		KRL_DBG(("%s: serial %llu:%llu state 0x%02x", __func__,
    576 		    (long long unsigned)rs->lo, (long long unsigned)rs->hi,
    577 		    state));
    578 
    579 		/* Check contiguous length and gap to next section (if any) */
    580 		nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs);
    581 		final = nrs == NULL;
    582 		gap = nrs == NULL ? 0 : nrs->lo - rs->hi;
    583 		contig = 1 + (rs->hi - rs->lo);
    584 
    585 		/* Choose next state based on these */
    586 		next_state = choose_next_state(state, contig, final,
    587 		    state == 0 ? 0 : rs->lo - last, gap, &force_new_sect);
    588 
    589 		/*
    590 		 * If the current section is a range section or has a different
    591 		 * type to the next section, then finish it off now.
    592 		 */
    593 		if (state != 0 && (force_new_sect || next_state != state ||
    594 		    state == KRL_SECTION_CERT_SERIAL_RANGE)) {
    595 			KRL_DBG(("%s: finish state 0x%02x", __func__, state));
    596 			switch (state) {
    597 			case KRL_SECTION_CERT_SERIAL_LIST:
    598 			case KRL_SECTION_CERT_SERIAL_RANGE:
    599 				break;
    600 			case KRL_SECTION_CERT_SERIAL_BITMAP:
    601 				if ((r = put_bitmap(sect, bitmap)) != 0)
    602 					goto out;
    603 				bitmap_free(bitmap);
    604 				bitmap = NULL;
    605 				break;
    606 			}
    607 			if ((r = sshbuf_put_u8(buf, state)) != 0 ||
    608 			    (r = sshbuf_put_stringb(buf, sect)) != 0)
    609 				goto out;
    610 			sshbuf_reset(sect);
    611 		}
    612 
    613 		/* If we are starting a new section then prepare it now */
    614 		if (next_state != state || force_new_sect) {
    615 			KRL_DBG(("%s: start state 0x%02x", __func__,
    616 			    next_state));
    617 			state = next_state;
    618 			sshbuf_reset(sect);
    619 			switch (state) {
    620 			case KRL_SECTION_CERT_SERIAL_LIST:
    621 			case KRL_SECTION_CERT_SERIAL_RANGE:
    622 				break;
    623 			case KRL_SECTION_CERT_SERIAL_BITMAP:
    624 				if ((bitmap = bitmap_new()) == NULL) {
    625 					r = SSH_ERR_ALLOC_FAIL;
    626 					goto out;
    627 				}
    628 				bitmap_start = rs->lo;
    629 				if ((r = sshbuf_put_u64(sect,
    630 				    bitmap_start)) != 0)
    631 					goto out;
    632 				break;
    633 			}
    634 		}
    635 
    636 		/* Perform section-specific processing */
    637 		switch (state) {
    638 		case KRL_SECTION_CERT_SERIAL_LIST:
    639 			for (i = 0; i < contig; i++) {
    640 				if ((r = sshbuf_put_u64(sect, rs->lo + i)) != 0)
    641 					goto out;
    642 			}
    643 			break;
    644 		case KRL_SECTION_CERT_SERIAL_RANGE:
    645 			if ((r = sshbuf_put_u64(sect, rs->lo)) != 0 ||
    646 			    (r = sshbuf_put_u64(sect, rs->hi)) != 0)
    647 				goto out;
    648 			break;
    649 		case KRL_SECTION_CERT_SERIAL_BITMAP:
    650 			if (rs->lo - bitmap_start > INT_MAX) {
    651 				error("%s: insane bitmap gap", __func__);
    652 				goto out;
    653 			}
    654 			for (i = 0; i < contig; i++) {
    655 				if (bitmap_set_bit(bitmap,
    656 				    rs->lo + i - bitmap_start) != 0) {
    657 					r = SSH_ERR_ALLOC_FAIL;
    658 					goto out;
    659 				}
    660 			}
    661 			break;
    662 		}
    663 		last = rs->hi;
    664 	}
    665 	/* Flush the remaining section, if any */
    666 	if (state != 0) {
    667 		KRL_DBG(("%s: serial final flush for state 0x%02x",
    668 		    __func__, state));
    669 		switch (state) {
    670 		case KRL_SECTION_CERT_SERIAL_LIST:
    671 		case KRL_SECTION_CERT_SERIAL_RANGE:
    672 			break;
    673 		case KRL_SECTION_CERT_SERIAL_BITMAP:
    674 			if ((r = put_bitmap(sect, bitmap)) != 0)
    675 				goto out;
    676 			bitmap_free(bitmap);
    677 			bitmap = NULL;
    678 			break;
    679 		}
    680 		if ((r = sshbuf_put_u8(buf, state)) != 0 ||
    681 		    (r = sshbuf_put_stringb(buf, sect)) != 0)
    682 			goto out;
    683 	}
    684 	KRL_DBG(("%s: serial done ", __func__));
    685 
    686 	/* Now output a section for any revocations by key ID */
    687 	sshbuf_reset(sect);
    688 	RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) {
    689 		KRL_DBG(("%s: key ID %s", __func__, rki->key_id));
    690 		if ((r = sshbuf_put_cstring(sect, rki->key_id)) != 0)
    691 			goto out;
    692 	}
    693 	if (sshbuf_len(sect) != 0) {
    694 		if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERT_KEY_ID)) != 0 ||
    695 		    (r = sshbuf_put_stringb(buf, sect)) != 0)
    696 			goto out;
    697 	}
    698 	r = 0;
    699  out:
    700 	bitmap_free(bitmap);
    701 	sshbuf_free(sect);
    702 	return r;
    703 }
    704 
    705 int
    706 ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
    707     const struct sshkey **sign_keys, u_int nsign_keys)
    708 {
    709 	int r = SSH_ERR_INTERNAL_ERROR;
    710 	struct revoked_certs *rc;
    711 	struct revoked_blob *rb;
    712 	struct sshbuf *sect;
    713 	u_char *sblob = NULL;
    714 	size_t slen, i;
    715 
    716 	if (krl->generated_date == 0)
    717 		krl->generated_date = time(NULL);
    718 
    719 	if ((sect = sshbuf_new()) == NULL)
    720 		return SSH_ERR_ALLOC_FAIL;
    721 
    722 	/* Store the header */
    723 	if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 ||
    724 	    (r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 ||
    725 	    (r = sshbuf_put_u64(buf, krl->krl_version)) != 0 ||
    726 	    (r = sshbuf_put_u64(buf, krl->generated_date) != 0) ||
    727 	    (r = sshbuf_put_u64(buf, krl->flags)) != 0 ||
    728 	    (r = sshbuf_put_string(buf, NULL, 0)) != 0 ||
    729 	    (r = sshbuf_put_cstring(buf, krl->comment)) != 0)
    730 		goto out;
    731 
    732 	/* Store sections for revoked certificates */
    733 	TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
    734 		sshbuf_reset(sect);
    735 		if ((r = revoked_certs_generate(rc, sect)) != 0)
    736 			goto out;
    737 		if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 ||
    738 		    (r = sshbuf_put_stringb(buf, sect)) != 0)
    739 			goto out;
    740 	}
    741 
    742 	/* Finally, output sections for revocations by public key/hash */
    743 	sshbuf_reset(sect);
    744 	RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) {
    745 		KRL_DBG(("%s: key len %zu ", __func__, rb->len));
    746 		if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
    747 			goto out;
    748 	}
    749 	if (sshbuf_len(sect) != 0) {
    750 		if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 ||
    751 		    (r = sshbuf_put_stringb(buf, sect)) != 0)
    752 			goto out;
    753 	}
    754 	sshbuf_reset(sect);
    755 	RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) {
    756 		KRL_DBG(("%s: hash len %zu ", __func__, rb->len));
    757 		if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
    758 			goto out;
    759 	}
    760 	if (sshbuf_len(sect) != 0) {
    761 		if ((r = sshbuf_put_u8(buf,
    762 		    KRL_SECTION_FINGERPRINT_SHA1)) != 0 ||
    763 		    (r = sshbuf_put_stringb(buf, sect)) != 0)
    764 			goto out;
    765 	}
    766 
    767 	for (i = 0; i < nsign_keys; i++) {
    768 		KRL_DBG(("%s: signature key %s", __func__,
    769 		    sshkey_ssh_name(sign_keys[i])));
    770 		if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 ||
    771 		    (r = sshkey_puts(sign_keys[i], buf)) != 0)
    772 			goto out;
    773 
    774 		if ((r = sshkey_sign(sign_keys[i], &sblob, &slen,
    775 		    sshbuf_ptr(buf), sshbuf_len(buf), 0)) == -1)
    776 			goto out;
    777 		KRL_DBG(("%s: signature sig len %zu", __func__, slen));
    778 		if ((r = sshbuf_put_string(buf, sblob, slen)) != 0)
    779 			goto out;
    780 	}
    781 
    782 	r = 0;
    783  out:
    784 	free(sblob);
    785 	sshbuf_free(sect);
    786 	return r;
    787 }
    788 
    789 static void
    790 format_timestamp(u_int64_t timestamp, char *ts, size_t nts)
    791 {
    792 	time_t t;
    793 	struct tm *tm;
    794 
    795 	t = timestamp;
    796 	tm = localtime(&t);
    797 	if (tm == NULL)
    798 		strlcpy(ts, "<INVALID>", nts);
    799 	else {
    800 		*ts = '\0';
    801 		strftime(ts, nts, "%Y%m%dT%H%M%S", tm);
    802 	}
    803 }
    804 
    805 static int
    806 parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl)
    807 {
    808 	int r = SSH_ERR_INTERNAL_ERROR;
    809 	u_char type;
    810 	const u_char *blob;
    811 	size_t blen, nbits;
    812 	struct sshbuf *subsect = NULL;
    813 	u_int64_t serial, serial_lo, serial_hi;
    814 	struct bitmap *bitmap = NULL;
    815 	char *key_id = NULL;
    816 	struct sshkey *ca_key = NULL;
    817 
    818 	if ((subsect = sshbuf_new()) == NULL)
    819 		return SSH_ERR_ALLOC_FAIL;
    820 
    821 	/* Header: key, reserved */
    822 	if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 ||
    823 	    (r = sshbuf_skip_string(buf)) != 0)
    824 		goto out;
    825 	if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0)
    826 		goto out;
    827 
    828 	while (sshbuf_len(buf) > 0) {
    829 		if (subsect != NULL) {
    830 			sshbuf_free(subsect);
    831 			subsect = NULL;
    832 		}
    833 		if ((r = sshbuf_get_u8(buf, &type)) != 0 ||
    834 		    (r = sshbuf_froms(buf, &subsect)) != 0)
    835 			goto out;
    836 		KRL_DBG(("%s: subsection type 0x%02x", __func__, type));
    837 		/* sshbuf_dump(subsect, stderr); */
    838 
    839 		switch (type) {
    840 		case KRL_SECTION_CERT_SERIAL_LIST:
    841 			while (sshbuf_len(subsect) > 0) {
    842 				if ((r = sshbuf_get_u64(subsect, &serial)) != 0)
    843 					goto out;
    844 				if ((r = ssh_krl_revoke_cert_by_serial(krl,
    845 				    ca_key, serial)) != 0)
    846 					goto out;
    847 			}
    848 			break;
    849 		case KRL_SECTION_CERT_SERIAL_RANGE:
    850 			if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 ||
    851 			    (r = sshbuf_get_u64(subsect, &serial_hi)) != 0)
    852 				goto out;
    853 			if ((r = ssh_krl_revoke_cert_by_serial_range(krl,
    854 			    ca_key, serial_lo, serial_hi)) != 0)
    855 				goto out;
    856 			break;
    857 		case KRL_SECTION_CERT_SERIAL_BITMAP:
    858 			if ((bitmap = bitmap_new()) == NULL) {
    859 				r = SSH_ERR_ALLOC_FAIL;
    860 				goto out;
    861 			}
    862 			if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 ||
    863 			    (r = sshbuf_get_bignum2_bytes_direct(subsect,
    864 			    &blob, &blen)) != 0)
    865 				goto out;
    866 			if (bitmap_from_string(bitmap, blob, blen) != 0) {
    867 				r = SSH_ERR_INVALID_FORMAT;
    868 				goto out;
    869 			}
    870 			nbits = bitmap_nbits(bitmap);
    871 			for (serial = 0; serial < (u_int64_t)nbits; serial++) {
    872 				if (serial > 0 && serial_lo + serial == 0) {
    873 					error("%s: bitmap wraps u64", __func__);
    874 					r = SSH_ERR_INVALID_FORMAT;
    875 					goto out;
    876 				}
    877 				if (!bitmap_test_bit(bitmap, serial))
    878 					continue;
    879 				if ((r = ssh_krl_revoke_cert_by_serial(krl,
    880 				    ca_key, serial_lo + serial)) != 0)
    881 					goto out;
    882 			}
    883 			bitmap_free(bitmap);
    884 			bitmap = NULL;
    885 			break;
    886 		case KRL_SECTION_CERT_KEY_ID:
    887 			while (sshbuf_len(subsect) > 0) {
    888 				if ((r = sshbuf_get_cstring(subsect,
    889 				    &key_id, NULL)) != 0)
    890 					goto out;
    891 				if ((r = ssh_krl_revoke_cert_by_key_id(krl,
    892 				    ca_key, key_id)) != 0)
    893 					goto out;
    894 				free(key_id);
    895 				key_id = NULL;
    896 			}
    897 			break;
    898 		default:
    899 			error("Unsupported KRL certificate section %u", type);
    900 			r = SSH_ERR_INVALID_FORMAT;
    901 			goto out;
    902 		}
    903 		if (sshbuf_len(subsect) > 0) {
    904 			error("KRL certificate section contains unparsed data");
    905 			r = SSH_ERR_INVALID_FORMAT;
    906 			goto out;
    907 		}
    908 	}
    909 
    910 	r = 0;
    911  out:
    912 	if (bitmap != NULL)
    913 		bitmap_free(bitmap);
    914 	free(key_id);
    915 	sshkey_free(ca_key);
    916 	sshbuf_free(subsect);
    917 	return r;
    918 }
    919 
    920 
    921 /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */
    922 int
    923 ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
    924     const struct sshkey **sign_ca_keys, size_t nsign_ca_keys)
    925 {
    926 	struct sshbuf *copy = NULL, *sect = NULL;
    927 	struct ssh_krl *krl = NULL;
    928 	char timestamp[64];
    929 	int r = SSH_ERR_INTERNAL_ERROR, sig_seen;
    930 	struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used;
    931 	u_char type, *rdata = NULL;
    932 	const u_char *blob;
    933 	size_t i, j, sig_off, sects_off, rlen, blen, nca_used;
    934 	u_int format_version;
    935 
    936 	nca_used = 0;
    937 	*krlp = NULL;
    938 	if (sshbuf_len(buf) < sizeof(KRL_MAGIC) - 1 ||
    939 	    memcmp(sshbuf_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) {
    940 		debug3("%s: not a KRL", __func__);
    941 		return SSH_ERR_KRL_BAD_MAGIC;
    942 	}
    943 
    944 	/* Take a copy of the KRL buffer so we can verify its signature later */
    945 	if ((copy = sshbuf_fromb(buf)) == NULL) {
    946 		r = SSH_ERR_ALLOC_FAIL;
    947 		goto out;
    948 	}
    949 	if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0)
    950 		goto out;
    951 
    952 	if ((krl = ssh_krl_init()) == NULL) {
    953 		error("%s: alloc failed", __func__);
    954 		goto out;
    955 	}
    956 
    957 	if ((r = sshbuf_get_u32(copy, &format_version)) != 0)
    958 		goto out;
    959 	if (format_version != KRL_FORMAT_VERSION) {
    960 		r = SSH_ERR_INVALID_FORMAT;
    961 		goto out;
    962 	}
    963 	if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 ||
    964 	    (r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 ||
    965 	    (r = sshbuf_get_u64(copy, &krl->flags)) != 0 ||
    966 	    (r = sshbuf_skip_string(copy)) != 0 ||
    967 	    (r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0)
    968 		goto out;
    969 
    970 	format_timestamp(krl->generated_date, timestamp, sizeof(timestamp));
    971 	debug("KRL version %llu generated at %s%s%s",
    972 	    (long long unsigned)krl->krl_version, timestamp,
    973 	    *krl->comment ? ": " : "", krl->comment);
    974 
    975 	/*
    976 	 * 1st pass: verify signatures, if any. This is done to avoid
    977 	 * detailed parsing of data whose provenance is unverified.
    978 	 */
    979 	sig_seen = 0;
    980 	if (sshbuf_len(buf) < sshbuf_len(copy)) {
    981 		/* Shouldn't happen */
    982 		r = SSH_ERR_INTERNAL_ERROR;
    983 		goto out;
    984 	}
    985 	sects_off = sshbuf_len(buf) - sshbuf_len(copy);
    986 	while (sshbuf_len(copy) > 0) {
    987 		if ((r = sshbuf_get_u8(copy, &type)) != 0 ||
    988 		    (r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0)
    989 			goto out;
    990 		KRL_DBG(("%s: first pass, section 0x%02x", __func__, type));
    991 		if (type != KRL_SECTION_SIGNATURE) {
    992 			if (sig_seen) {
    993 				error("KRL contains non-signature section "
    994 				    "after signature");
    995 				r = SSH_ERR_INVALID_FORMAT;
    996 				goto out;
    997 			}
    998 			/* Not interested for now. */
    999 			continue;
   1000 		}
   1001 		sig_seen = 1;
   1002 		/* First string component is the signing key */
   1003 		if ((r = sshkey_from_blob(blob, blen, &key)) != 0) {
   1004 			r = SSH_ERR_INVALID_FORMAT;
   1005 			goto out;
   1006 		}
   1007 		if (sshbuf_len(buf) < sshbuf_len(copy)) {
   1008 			/* Shouldn't happen */
   1009 			r = SSH_ERR_INTERNAL_ERROR;
   1010 			goto out;
   1011 		}
   1012 		sig_off = sshbuf_len(buf) - sshbuf_len(copy);
   1013 		/* Second string component is the signature itself */
   1014 		if ((r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) {
   1015 			r = SSH_ERR_INVALID_FORMAT;
   1016 			goto out;
   1017 		}
   1018 		/* Check signature over entire KRL up to this point */
   1019 		if ((r = sshkey_verify(key, blob, blen,
   1020 		    sshbuf_ptr(buf), sshbuf_len(buf) - sig_off, 0)) != 0)
   1021 			goto out;
   1022 		/* Check if this key has already signed this KRL */
   1023 		for (i = 0; i < nca_used; i++) {
   1024 			if (sshkey_equal(ca_used[i], key)) {
   1025 				error("KRL signed more than once with "
   1026 				    "the same key");
   1027 				r = SSH_ERR_INVALID_FORMAT;
   1028 				goto out;
   1029 			}
   1030 		}
   1031 		/* Record keys used to sign the KRL */
   1032 		tmp_ca_used = reallocarray(ca_used, nca_used + 1,
   1033 		    sizeof(*ca_used));
   1034 		if (tmp_ca_used == NULL) {
   1035 			r = SSH_ERR_ALLOC_FAIL;
   1036 			goto out;
   1037 		}
   1038 		ca_used = tmp_ca_used;
   1039 		ca_used[nca_used++] = key;
   1040 		key = NULL;
   1041 		break;
   1042 	}
   1043 
   1044 	if (sshbuf_len(copy) != 0) {
   1045 		/* Shouldn't happen */
   1046 		r = SSH_ERR_INTERNAL_ERROR;
   1047 		goto out;
   1048 	}
   1049 
   1050 	/*
   1051 	 * 2nd pass: parse and load the KRL, skipping the header to the point
   1052 	 * where the section start.
   1053 	 */
   1054 	sshbuf_free(copy);
   1055 	if ((copy = sshbuf_fromb(buf)) == NULL) {
   1056 		r = SSH_ERR_ALLOC_FAIL;
   1057 		goto out;
   1058 	}
   1059 	if ((r = sshbuf_consume(copy, sects_off)) != 0)
   1060 		goto out;
   1061 	while (sshbuf_len(copy) > 0) {
   1062 		if (sect != NULL) {
   1063 			sshbuf_free(sect);
   1064 			sect = NULL;
   1065 		}
   1066 		if ((r = sshbuf_get_u8(copy, &type)) != 0 ||
   1067 		    (r = sshbuf_froms(copy, &sect)) != 0)
   1068 			goto out;
   1069 		KRL_DBG(("%s: second pass, section 0x%02x", __func__, type));
   1070 
   1071 		switch (type) {
   1072 		case KRL_SECTION_CERTIFICATES:
   1073 			if ((r = parse_revoked_certs(sect, krl)) != 0)
   1074 				goto out;
   1075 			break;
   1076 		case KRL_SECTION_EXPLICIT_KEY:
   1077 		case KRL_SECTION_FINGERPRINT_SHA1:
   1078 			while (sshbuf_len(sect) > 0) {
   1079 				if ((r = sshbuf_get_string(sect,
   1080 				    &rdata, &rlen)) != 0)
   1081 					goto out;
   1082 				if (type == KRL_SECTION_FINGERPRINT_SHA1 &&
   1083 				    rlen != 20) {
   1084 					error("%s: bad SHA1 length", __func__);
   1085 					r = SSH_ERR_INVALID_FORMAT;
   1086 					goto out;
   1087 				}
   1088 				if ((r = revoke_blob(
   1089 				    type == KRL_SECTION_EXPLICIT_KEY ?
   1090 				    &krl->revoked_keys : &krl->revoked_sha1s,
   1091 				    rdata, rlen)) != 0)
   1092 					goto out;
   1093 				rdata = NULL; /* revoke_blob frees rdata */
   1094 			}
   1095 			break;
   1096 		case KRL_SECTION_SIGNATURE:
   1097 			/* Handled above, but still need to stay in synch */
   1098 			sshbuf_reset(sect);
   1099 			sect = NULL;
   1100 			if ((r = sshbuf_skip_string(copy)) != 0)
   1101 				goto out;
   1102 			break;
   1103 		default:
   1104 			error("Unsupported KRL section %u", type);
   1105 			r = SSH_ERR_INVALID_FORMAT;
   1106 			goto out;
   1107 		}
   1108 		if (sshbuf_len(sect) > 0) {
   1109 			error("KRL section contains unparsed data");
   1110 			r = SSH_ERR_INVALID_FORMAT;
   1111 			goto out;
   1112 		}
   1113 	}
   1114 
   1115 	/* Check that the key(s) used to sign the KRL weren't revoked */
   1116 	sig_seen = 0;
   1117 	for (i = 0; i < nca_used; i++) {
   1118 		if (ssh_krl_check_key(krl, ca_used[i]) == 0)
   1119 			sig_seen = 1;
   1120 		else {
   1121 			sshkey_free(ca_used[i]);
   1122 			ca_used[i] = NULL;
   1123 		}
   1124 	}
   1125 	if (nca_used && !sig_seen) {
   1126 		error("All keys used to sign KRL were revoked");
   1127 		r = SSH_ERR_KEY_REVOKED;
   1128 		goto out;
   1129 	}
   1130 
   1131 	/* If we have CA keys, then verify that one was used to sign the KRL */
   1132 	if (sig_seen && nsign_ca_keys != 0) {
   1133 		sig_seen = 0;
   1134 		for (i = 0; !sig_seen && i < nsign_ca_keys; i++) {
   1135 			for (j = 0; j < nca_used; j++) {
   1136 				if (ca_used[j] == NULL)
   1137 					continue;
   1138 				if (sshkey_equal(ca_used[j], sign_ca_keys[i])) {
   1139 					sig_seen = 1;
   1140 					break;
   1141 				}
   1142 			}
   1143 		}
   1144 		if (!sig_seen) {
   1145 			r = SSH_ERR_SIGNATURE_INVALID;
   1146 			error("KRL not signed with any trusted key");
   1147 			goto out;
   1148 		}
   1149 	}
   1150 
   1151 	*krlp = krl;
   1152 	r = 0;
   1153  out:
   1154 	if (r != 0)
   1155 		ssh_krl_free(krl);
   1156 	for (i = 0; i < nca_used; i++)
   1157 		sshkey_free(ca_used[i]);
   1158 	free(ca_used);
   1159 	free(rdata);
   1160 	sshkey_free(key);
   1161 	sshbuf_free(copy);
   1162 	sshbuf_free(sect);
   1163 	return r;
   1164 }
   1165 
   1166 /* Checks certificate serial number and key ID revocation */
   1167 static int
   1168 is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc)
   1169 {
   1170 	struct revoked_serial rs, *ers;
   1171 	struct revoked_key_id rki, *erki;
   1172 
   1173 	/* Check revocation by cert key ID */
   1174 	memset(&rki, 0, sizeof(rki));
   1175 	rki.key_id = key->cert->key_id;
   1176 	erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki);
   1177 	if (erki != NULL) {
   1178 		KRL_DBG(("%s: revoked by key ID", __func__));
   1179 		return SSH_ERR_KEY_REVOKED;
   1180 	}
   1181 
   1182 	/*
   1183 	 * Legacy cert formats lack serial numbers. Zero serials numbers
   1184 	 * are ignored (it's the default when the CA doesn't specify one).
   1185 	 */
   1186 	if (sshkey_cert_is_legacy(key) || key->cert->serial == 0)
   1187 		return 0;
   1188 
   1189 	memset(&rs, 0, sizeof(rs));
   1190 	rs.lo = rs.hi = key->cert->serial;
   1191 	ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs);
   1192 	if (ers != NULL) {
   1193 		KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__,
   1194 		    key->cert->serial, ers->lo, ers->hi));
   1195 		return SSH_ERR_KEY_REVOKED;
   1196 	}
   1197 	return 0;
   1198 }
   1199 
   1200 /* Checks whether a given key/cert is revoked. Does not check its CA */
   1201 static int
   1202 is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
   1203 {
   1204 	struct revoked_blob rb, *erb;
   1205 	struct revoked_certs *rc;
   1206 	int r;
   1207 
   1208 	/* Check explicitly revoked hashes first */
   1209 	memset(&rb, 0, sizeof(rb));
   1210 	if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
   1211 	    &rb.blob, &rb.len)) != 0)
   1212 		return r;
   1213 	erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
   1214 	free(rb.blob);
   1215 	if (erb != NULL) {
   1216 		KRL_DBG(("%s: revoked by key SHA1", __func__));
   1217 		return SSH_ERR_KEY_REVOKED;
   1218 	}
   1219 
   1220 	/* Next, explicit keys */
   1221 	memset(&rb, 0, sizeof(rb));
   1222 	if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0)
   1223 		return r;
   1224 	erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
   1225 	free(rb.blob);
   1226 	if (erb != NULL) {
   1227 		KRL_DBG(("%s: revoked by explicit key", __func__));
   1228 		return SSH_ERR_KEY_REVOKED;
   1229 	}
   1230 
   1231 	if (!sshkey_is_cert(key))
   1232 		return 0;
   1233 
   1234 	/* Check cert revocation for the specified CA */
   1235 	if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key,
   1236 	    &rc, 0)) != 0)
   1237 		return r;
   1238 	if (rc != NULL) {
   1239 		if ((r = is_cert_revoked(key, rc)) != 0)
   1240 			return r;
   1241 	}
   1242 	/* Check cert revocation for the wildcard CA */
   1243 	if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0)
   1244 		return r;
   1245 	if (rc != NULL) {
   1246 		if ((r = is_cert_revoked(key, rc)) != 0)
   1247 			return r;
   1248 	}
   1249 
   1250 	KRL_DBG(("%s: %llu no match", __func__, key->cert->serial));
   1251 	return 0;
   1252 }
   1253 
   1254 int
   1255 ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key)
   1256 {
   1257 	int r;
   1258 
   1259 	KRL_DBG(("%s: checking key", __func__));
   1260 	if ((r = is_key_revoked(krl, key)) != 0)
   1261 		return r;
   1262 	if (sshkey_is_cert(key)) {
   1263 		debug2("%s: checking CA key", __func__);
   1264 		if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0)
   1265 			return r;
   1266 	}
   1267 	KRL_DBG(("%s: key okay", __func__));
   1268 	return 0;
   1269 }
   1270 
   1271 int
   1272 ssh_krl_file_contains_key(const char *path, const struct sshkey *key)
   1273 {
   1274 	struct sshbuf *krlbuf = NULL;
   1275 	struct ssh_krl *krl = NULL;
   1276 	int oerrno = 0, r, fd;
   1277 
   1278 	if (path == NULL)
   1279 		return 0;
   1280 
   1281 	if ((krlbuf = sshbuf_new()) == NULL)
   1282 		return SSH_ERR_ALLOC_FAIL;
   1283 	if ((fd = open(path, O_RDONLY)) == -1) {
   1284 		r = SSH_ERR_SYSTEM_ERROR;
   1285 		oerrno = errno;
   1286 		goto out;
   1287 	}
   1288 	if ((r = sshkey_load_file(fd, krlbuf)) != 0) {
   1289 		oerrno = errno;
   1290 		goto out;
   1291 	}
   1292 	if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0)
   1293 		goto out;
   1294 	debug2("%s: checking KRL %s", __func__, path);
   1295 	r = ssh_krl_check_key(krl, key);
   1296  out:
   1297 	close(fd);
   1298 	sshbuf_free(krlbuf);
   1299 	ssh_krl_free(krl);
   1300 	if (r != 0)
   1301 		errno = oerrno;
   1302 	return r;
   1303 }
   1304