GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../krl.c Lines: 0 549 0.0 %
Date: 2017-11-13 Branches: 0 981 0.0 %

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