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