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