blob: d6bd10935cd23a1725dbd65a9aae9d2e0121a43d [file] [log] [blame]
Damien Millerf3747bf2013-01-18 11:44:04 +11001/*
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
djm@openbsd.orge7fd9522015-01-13 19:04:35 +000017/* $OpenBSD: krl.c,v 1.25 2015/01/13 19:04:35 djm Exp $ */
Damien Millerf3747bf2013-01-18 11:44:04 +110018
19#include "includes.h"
20
21#include <sys/types.h>
22#include <sys/param.h>
Damien Millerd60b2102013-01-20 22:49:58 +110023#include <openbsd-compat/sys-tree.h>
24#include <openbsd-compat/sys-queue.h>
Damien Millerf3747bf2013-01-18 11:44:04 +110025
26#include <errno.h>
27#include <fcntl.h>
28#include <limits.h>
29#include <string.h>
30#include <time.h>
31#include <unistd.h>
32
djm@openbsd.org74de2542014-12-04 01:49:59 +000033#include "sshbuf.h"
djm@openbsd.orge7fd9522015-01-13 19:04:35 +000034#include "ssherr.h"
djm@openbsd.org74de2542014-12-04 01:49:59 +000035#include "sshkey.h"
Damien Millerf3747bf2013-01-18 11:44:04 +110036#include "authfile.h"
Damien Millerf3747bf2013-01-18 11:44:04 +110037#include "misc.h"
38#include "log.h"
djm@openbsd.org56d1c832014-12-21 22:27:55 +000039#include "digest.h"
Damien Millerf3747bf2013-01-18 11:44:04 +110040
41#include "krl.h"
42
43/* #define DEBUG_KRL */
44#ifdef DEBUG_KRL
45# define KRL_DBG(x) debug3 x
46#else
47# define KRL_DBG(x)
48#endif
49
50/*
51 * Trees of revoked serial numbers, key IDs and keys. This allows
52 * quick searching, querying and producing lists in canonical order.
53 */
54
55/* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */
56struct revoked_serial {
57 u_int64_t lo, hi;
58 RB_ENTRY(revoked_serial) tree_entry;
59};
60static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b);
61RB_HEAD(revoked_serial_tree, revoked_serial);
62RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp);
63
64/* Tree of key IDs */
65struct revoked_key_id {
66 char *key_id;
67 RB_ENTRY(revoked_key_id) tree_entry;
68};
69static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b);
70RB_HEAD(revoked_key_id_tree, revoked_key_id);
71RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp);
72
73/* Tree of blobs (used for keys and fingerprints) */
74struct revoked_blob {
75 u_char *blob;
djm@openbsd.org74de2542014-12-04 01:49:59 +000076 size_t len;
Damien Millerf3747bf2013-01-18 11:44:04 +110077 RB_ENTRY(revoked_blob) tree_entry;
78};
79static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b);
80RB_HEAD(revoked_blob_tree, revoked_blob);
81RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp);
82
83/* Tracks revoked certs for a single CA */
84struct revoked_certs {
djm@openbsd.org74de2542014-12-04 01:49:59 +000085 struct sshkey *ca_key;
Damien Millerf3747bf2013-01-18 11:44:04 +110086 struct revoked_serial_tree revoked_serials;
87 struct revoked_key_id_tree revoked_key_ids;
88 TAILQ_ENTRY(revoked_certs) entry;
89};
90TAILQ_HEAD(revoked_certs_list, revoked_certs);
91
92struct ssh_krl {
93 u_int64_t krl_version;
94 u_int64_t generated_date;
95 u_int64_t flags;
96 char *comment;
97 struct revoked_blob_tree revoked_keys;
98 struct revoked_blob_tree revoked_sha1s;
99 struct revoked_certs_list revoked_certs;
100};
101
102/* Return equal if a and b overlap */
103static int
104serial_cmp(struct revoked_serial *a, struct revoked_serial *b)
105{
106 if (a->hi >= b->lo && a->lo <= b->hi)
107 return 0;
108 return a->lo < b->lo ? -1 : 1;
109}
110
111static int
112key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b)
113{
114 return strcmp(a->key_id, b->key_id);
115}
116
117static int
118blob_cmp(struct revoked_blob *a, struct revoked_blob *b)
119{
120 int r;
121
122 if (a->len != b->len) {
123 if ((r = memcmp(a->blob, b->blob, MIN(a->len, b->len))) != 0)
124 return r;
125 return a->len > b->len ? 1 : -1;
126 } else
127 return memcmp(a->blob, b->blob, a->len);
128}
129
130struct ssh_krl *
131ssh_krl_init(void)
132{
133 struct ssh_krl *krl;
134
135 if ((krl = calloc(1, sizeof(*krl))) == NULL)
136 return NULL;
137 RB_INIT(&krl->revoked_keys);
138 RB_INIT(&krl->revoked_sha1s);
139 TAILQ_INIT(&krl->revoked_certs);
140 return krl;
141}
142
143static void
144revoked_certs_free(struct revoked_certs *rc)
145{
146 struct revoked_serial *rs, *trs;
147 struct revoked_key_id *rki, *trki;
148
149 RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) {
150 RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs);
151 free(rs);
152 }
153 RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) {
154 RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki);
155 free(rki->key_id);
156 free(rki);
157 }
158 if (rc->ca_key != NULL)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000159 sshkey_free(rc->ca_key);
Damien Millerf3747bf2013-01-18 11:44:04 +1100160}
161
162void
163ssh_krl_free(struct ssh_krl *krl)
164{
165 struct revoked_blob *rb, *trb;
166 struct revoked_certs *rc, *trc;
167
168 if (krl == NULL)
169 return;
170
171 free(krl->comment);
172 RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) {
173 RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb);
174 free(rb->blob);
175 free(rb);
176 }
177 RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) {
178 RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb);
179 free(rb->blob);
180 free(rb);
181 }
182 TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) {
183 TAILQ_REMOVE(&krl->revoked_certs, rc, entry);
184 revoked_certs_free(rc);
185 }
186}
187
188void
189ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version)
190{
191 krl->krl_version = version;
192}
193
djm@openbsd.org74de2542014-12-04 01:49:59 +0000194int
Damien Millerf3747bf2013-01-18 11:44:04 +1100195ssh_krl_set_comment(struct ssh_krl *krl, const char *comment)
196{
197 free(krl->comment);
198 if ((krl->comment = strdup(comment)) == NULL)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000199 return SSH_ERR_ALLOC_FAIL;
200 return 0;
Damien Millerf3747bf2013-01-18 11:44:04 +1100201}
202
203/*
204 * Find the revoked_certs struct for a CA key. If allow_create is set then
205 * create a new one in the tree if one did not exist already.
206 */
207static int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000208revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key,
Damien Millerf3747bf2013-01-18 11:44:04 +1100209 struct revoked_certs **rcp, int allow_create)
210{
211 struct revoked_certs *rc;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000212 int r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100213
214 *rcp = NULL;
215 TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
djm@openbsd.org74de2542014-12-04 01:49:59 +0000216 if (sshkey_equal(rc->ca_key, ca_key)) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100217 *rcp = rc;
218 return 0;
219 }
220 }
221 if (!allow_create)
222 return 0;
223 /* If this CA doesn't exist in the list then add it now */
224 if ((rc = calloc(1, sizeof(*rc))) == NULL)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000225 return SSH_ERR_ALLOC_FAIL;
226 if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100227 free(rc);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000228 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100229 }
230 RB_INIT(&rc->revoked_serials);
231 RB_INIT(&rc->revoked_key_ids);
232 TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry);
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000233 KRL_DBG(("%s: new CA %s", __func__, sshkey_type(ca_key)));
Damien Millerf3747bf2013-01-18 11:44:04 +1100234 *rcp = rc;
235 return 0;
236}
237
238static int
239insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi)
240{
241 struct revoked_serial rs, *ers, *crs, *irs;
242
243 KRL_DBG(("%s: insert %llu:%llu", __func__, lo, hi));
Damien Miller1d2c4562014-02-04 11:18:20 +1100244 memset(&rs, 0, sizeof(rs));
Damien Millerf3747bf2013-01-18 11:44:04 +1100245 rs.lo = lo;
246 rs.hi = hi;
247 ers = RB_NFIND(revoked_serial_tree, rt, &rs);
248 if (ers == NULL || serial_cmp(ers, &rs) != 0) {
249 /* No entry matches. Just insert */
250 if ((irs = malloc(sizeof(rs))) == NULL)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000251 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100252 memcpy(irs, &rs, sizeof(*irs));
253 ers = RB_INSERT(revoked_serial_tree, rt, irs);
254 if (ers != NULL) {
255 KRL_DBG(("%s: bad: ers != NULL", __func__));
256 /* Shouldn't happen */
Damien Millera7522d92013-01-20 22:35:31 +1100257 free(irs);
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000258 return SSH_ERR_INTERNAL_ERROR;
Damien Millerf3747bf2013-01-18 11:44:04 +1100259 }
260 ers = irs;
261 } else {
262 KRL_DBG(("%s: overlap found %llu:%llu", __func__,
263 ers->lo, ers->hi));
264 /*
265 * The inserted entry overlaps an existing one. Grow the
266 * existing entry.
267 */
268 if (ers->lo > lo)
269 ers->lo = lo;
270 if (ers->hi < hi)
271 ers->hi = hi;
272 }
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000273
Damien Millerf3747bf2013-01-18 11:44:04 +1100274 /*
275 * The inserted or revised range might overlap or abut adjacent ones;
276 * coalesce as necessary.
277 */
278
279 /* Check predecessors */
280 while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) {
281 KRL_DBG(("%s: pred %llu:%llu", __func__, crs->lo, crs->hi));
282 if (ers->lo != 0 && crs->hi < ers->lo - 1)
283 break;
284 /* This entry overlaps. */
285 if (crs->lo < ers->lo) {
286 ers->lo = crs->lo;
287 KRL_DBG(("%s: pred extend %llu:%llu", __func__,
288 ers->lo, ers->hi));
289 }
290 RB_REMOVE(revoked_serial_tree, rt, crs);
291 free(crs);
292 }
293 /* Check successors */
294 while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) {
295 KRL_DBG(("%s: succ %llu:%llu", __func__, crs->lo, crs->hi));
296 if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1)
297 break;
298 /* This entry overlaps. */
299 if (crs->hi > ers->hi) {
300 ers->hi = crs->hi;
301 KRL_DBG(("%s: succ extend %llu:%llu", __func__,
302 ers->lo, ers->hi));
303 }
304 RB_REMOVE(revoked_serial_tree, rt, crs);
305 free(crs);
306 }
307 KRL_DBG(("%s: done, final %llu:%llu", __func__, ers->lo, ers->hi));
308 return 0;
309}
310
311int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000312ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const struct sshkey *ca_key,
Damien Millerf3747bf2013-01-18 11:44:04 +1100313 u_int64_t serial)
314{
315 return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial);
316}
317
318int
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000319ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl,
320 const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi)
Damien Millerf3747bf2013-01-18 11:44:04 +1100321{
322 struct revoked_certs *rc;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000323 int r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100324
325 if (lo > hi || lo == 0)
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000326 return SSH_ERR_INVALID_ARGUMENT;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000327 if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0)
328 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100329 return insert_serial_range(&rc->revoked_serials, lo, hi);
330}
331
332int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000333ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const struct sshkey *ca_key,
Damien Millerf3747bf2013-01-18 11:44:04 +1100334 const char *key_id)
335{
336 struct revoked_key_id *rki, *erki;
337 struct revoked_certs *rc;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000338 int r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100339
djm@openbsd.org74de2542014-12-04 01:49:59 +0000340 if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0)
341 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100342
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000343 KRL_DBG(("%s: revoke %s", __func__, key_id));
Damien Millerf3747bf2013-01-18 11:44:04 +1100344 if ((rki = calloc(1, sizeof(*rki))) == NULL ||
345 (rki->key_id = strdup(key_id)) == NULL) {
346 free(rki);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000347 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100348 }
349 erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki);
350 if (erki != NULL) {
351 free(rki->key_id);
352 free(rki);
353 }
354 return 0;
355}
356
357/* Convert "key" to a public key blob without any certificate information */
358static int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000359plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen)
Damien Millerf3747bf2013-01-18 11:44:04 +1100360{
djm@openbsd.org74de2542014-12-04 01:49:59 +0000361 struct sshkey *kcopy;
Damien Millerf3747bf2013-01-18 11:44:04 +1100362 int r;
363
djm@openbsd.org74de2542014-12-04 01:49:59 +0000364 if ((r = sshkey_from_private(key, &kcopy)) != 0)
365 return r;
366 if (sshkey_is_cert(kcopy)) {
367 if ((r = sshkey_drop_cert(kcopy)) != 0) {
368 sshkey_free(kcopy);
369 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100370 }
371 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000372 r = sshkey_to_blob(kcopy, blob, blen);
markus@openbsd.org905fe302015-01-12 14:05:19 +0000373 sshkey_free(kcopy);
Damien Miller86687062014-07-02 15:28:02 +1000374 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100375}
376
377/* Revoke a key blob. Ownership of blob is transferred to the tree */
378static int
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000379revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, size_t len)
Damien Millerf3747bf2013-01-18 11:44:04 +1100380{
381 struct revoked_blob *rb, *erb;
382
383 if ((rb = calloc(1, sizeof(*rb))) == NULL)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000384 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100385 rb->blob = blob;
386 rb->len = len;
387 erb = RB_INSERT(revoked_blob_tree, rbt, rb);
388 if (erb != NULL) {
389 free(rb->blob);
390 free(rb);
391 }
392 return 0;
393}
394
395int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000396ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key)
Damien Millerf3747bf2013-01-18 11:44:04 +1100397{
398 u_char *blob;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000399 size_t len;
400 int r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100401
djm@openbsd.org74de2542014-12-04 01:49:59 +0000402 debug3("%s: revoke type %s", __func__, sshkey_type(key));
403 if ((r = plain_key_blob(key, &blob, &len)) != 0)
404 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100405 return revoke_blob(&krl->revoked_keys, blob, len);
406}
407
408int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000409ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key)
Damien Millerf3747bf2013-01-18 11:44:04 +1100410{
411 u_char *blob;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000412 size_t len;
413 int r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100414
djm@openbsd.org74de2542014-12-04 01:49:59 +0000415 debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key));
djm@openbsd.org56d1c832014-12-21 22:27:55 +0000416 if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
417 &blob, &len)) != 0)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000418 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100419 return revoke_blob(&krl->revoked_sha1s, blob, len);
420}
421
422int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000423ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key)
Damien Millerf3747bf2013-01-18 11:44:04 +1100424{
djm@openbsd.org74de2542014-12-04 01:49:59 +0000425 if (!sshkey_is_cert(key))
Damien Millerf3747bf2013-01-18 11:44:04 +1100426 return ssh_krl_revoke_key_sha1(krl, key);
427
djm@openbsd.org74de2542014-12-04 01:49:59 +0000428 if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100429 return ssh_krl_revoke_cert_by_key_id(krl,
430 key->cert->signature_key,
431 key->cert->key_id);
432 } else {
433 return ssh_krl_revoke_cert_by_serial(krl,
434 key->cert->signature_key,
435 key->cert->serial);
436 }
437}
438
439/*
djm@openbsd.org74de2542014-12-04 01:49:59 +0000440 * Select the most compact section type to emit next in a KRL based on
441 * the current section type, the run length of contiguous revoked serial
Damien Millerf3747bf2013-01-18 11:44:04 +1100442 * numbers and the gaps from the last and to the next revoked serial.
443 * Applies a mostly-accurate bit cost model to select the section type
444 * that will minimise the size of the resultant KRL.
445 */
446static int
447choose_next_state(int current_state, u_int64_t contig, int final,
448 u_int64_t last_gap, u_int64_t next_gap, int *force_new_section)
449{
450 int new_state;
451 u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart;
452
453 /*
454 * Avoid unsigned overflows.
455 * The limits are high enough to avoid confusing the calculations.
456 */
457 contig = MIN(contig, 1ULL<<31);
458 last_gap = MIN(last_gap, 1ULL<<31);
459 next_gap = MIN(next_gap, 1ULL<<31);
460
461 /*
462 * Calculate the cost to switch from the current state to candidates.
463 * NB. range sections only ever contain a single range, so their
464 * switching cost is independent of the current_state.
465 */
466 cost_list = cost_bitmap = cost_bitmap_restart = 0;
467 cost_range = 8;
468 switch (current_state) {
469 case KRL_SECTION_CERT_SERIAL_LIST:
470 cost_bitmap_restart = cost_bitmap = 8 + 64;
471 break;
472 case KRL_SECTION_CERT_SERIAL_BITMAP:
473 cost_list = 8;
474 cost_bitmap_restart = 8 + 64;
475 break;
476 case KRL_SECTION_CERT_SERIAL_RANGE:
477 case 0:
478 cost_bitmap_restart = cost_bitmap = 8 + 64;
479 cost_list = 8;
480 }
481
482 /* Estimate base cost in bits of each section type */
483 cost_list += 64 * contig + (final ? 0 : 8+64);
484 cost_range += (2 * 64) + (final ? 0 : 8+64);
485 cost_bitmap += last_gap + contig + (final ? 0 : MIN(next_gap, 8+64));
486 cost_bitmap_restart += contig + (final ? 0 : MIN(next_gap, 8+64));
487
488 /* Convert to byte costs for actual comparison */
489 cost_list = (cost_list + 7) / 8;
490 cost_bitmap = (cost_bitmap + 7) / 8;
491 cost_bitmap_restart = (cost_bitmap_restart + 7) / 8;
492 cost_range = (cost_range + 7) / 8;
493
494 /* Now pick the best choice */
495 *force_new_section = 0;
496 new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
497 cost = cost_bitmap;
498 if (cost_range < cost) {
499 new_state = KRL_SECTION_CERT_SERIAL_RANGE;
500 cost = cost_range;
501 }
502 if (cost_list < cost) {
503 new_state = KRL_SECTION_CERT_SERIAL_LIST;
504 cost = cost_list;
505 }
506 if (cost_bitmap_restart < cost) {
507 new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
508 *force_new_section = 1;
509 cost = cost_bitmap_restart;
510 }
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000511 KRL_DBG(("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:"
Damien Millerf3747bf2013-01-18 11:44:04 +1100512 "list %llu range %llu bitmap %llu new bitmap %llu, "
Damien Millerd677ad12013-04-23 15:18:51 +1000513 "selected 0x%02x%s", __func__, (long long unsigned)contig,
514 (long long unsigned)last_gap, (long long unsigned)next_gap, final,
515 (long long unsigned)cost_list, (long long unsigned)cost_range,
516 (long long unsigned)cost_bitmap,
517 (long long unsigned)cost_bitmap_restart, new_state,
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000518 *force_new_section ? " restart" : ""));
Damien Millerf3747bf2013-01-18 11:44:04 +1100519 return new_state;
520}
521
522/* Generate a KRL_SECTION_CERTIFICATES KRL section */
523static int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000524revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf)
Damien Millerf3747bf2013-01-18 11:44:04 +1100525{
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000526 int final, force_new_sect, r = SSH_ERR_INTERNAL_ERROR;
Damien Millerf3747bf2013-01-18 11:44:04 +1100527 u_int64_t i, contig, gap, last = 0, bitmap_start = 0;
528 struct revoked_serial *rs, *nrs;
529 struct revoked_key_id *rki;
530 int next_state, state = 0;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000531 struct sshbuf *sect;
Damien Millerf3747bf2013-01-18 11:44:04 +1100532 BIGNUM *bitmap = NULL;
533
djm@openbsd.org74de2542014-12-04 01:49:59 +0000534 if ((sect = sshbuf_new()) == NULL)
535 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100536
djm@openbsd.org74de2542014-12-04 01:49:59 +0000537 /* Store the header: CA scope key, reserved */
538 if ((r = sshkey_to_blob_buf(rc->ca_key, sect)) != 0 ||
539 (r = sshbuf_put_stringb(buf, sect)) != 0 ||
540 (r = sshbuf_put_string(buf, NULL, 0)) != 0)
541 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100542
djm@openbsd.org74de2542014-12-04 01:49:59 +0000543 sshbuf_reset(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100544
545 /* Store the revoked serials. */
546 for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials);
547 rs != NULL;
548 rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000549 KRL_DBG(("%s: serial %llu:%llu state 0x%02x", __func__,
Damien Millerd677ad12013-04-23 15:18:51 +1000550 (long long unsigned)rs->lo, (long long unsigned)rs->hi,
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000551 state));
Damien Millerf3747bf2013-01-18 11:44:04 +1100552
553 /* Check contiguous length and gap to next section (if any) */
554 nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs);
555 final = nrs == NULL;
556 gap = nrs == NULL ? 0 : nrs->lo - rs->hi;
557 contig = 1 + (rs->hi - rs->lo);
558
559 /* Choose next state based on these */
560 next_state = choose_next_state(state, contig, final,
561 state == 0 ? 0 : rs->lo - last, gap, &force_new_sect);
562
563 /*
564 * If the current section is a range section or has a different
565 * type to the next section, then finish it off now.
566 */
567 if (state != 0 && (force_new_sect || next_state != state ||
568 state == KRL_SECTION_CERT_SERIAL_RANGE)) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000569 KRL_DBG(("%s: finish state 0x%02x", __func__, state));
Damien Millerf3747bf2013-01-18 11:44:04 +1100570 switch (state) {
571 case KRL_SECTION_CERT_SERIAL_LIST:
572 case KRL_SECTION_CERT_SERIAL_RANGE:
573 break;
574 case KRL_SECTION_CERT_SERIAL_BITMAP:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000575 if ((r = sshbuf_put_bignum2(sect, bitmap)) != 0)
576 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100577 BN_free(bitmap);
578 bitmap = NULL;
579 break;
580 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000581 if ((r = sshbuf_put_u8(buf, state)) != 0 ||
582 (r = sshbuf_put_stringb(buf, sect)) != 0)
583 goto out;
584 sshbuf_reset(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100585 }
586
587 /* If we are starting a new section then prepare it now */
588 if (next_state != state || force_new_sect) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000589 KRL_DBG(("%s: start state 0x%02x", __func__,
590 next_state));
Damien Millerf3747bf2013-01-18 11:44:04 +1100591 state = next_state;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000592 sshbuf_reset(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100593 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:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000598 if ((bitmap = BN_new()) == NULL) {
599 r = SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100600 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000601 }
Damien Millerf3747bf2013-01-18 11:44:04 +1100602 bitmap_start = rs->lo;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000603 if ((r = sshbuf_put_u64(sect,
604 bitmap_start)) != 0)
605 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100606 break;
607 }
608 }
609
610 /* Perform section-specific processing */
611 switch (state) {
612 case KRL_SECTION_CERT_SERIAL_LIST:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000613 for (i = 0; i < contig; i++) {
614 if ((r = sshbuf_put_u64(sect, rs->lo + i)) != 0)
615 goto out;
616 }
Damien Millerf3747bf2013-01-18 11:44:04 +1100617 break;
618 case KRL_SECTION_CERT_SERIAL_RANGE:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000619 if ((r = sshbuf_put_u64(sect, rs->lo)) != 0 ||
620 (r = sshbuf_put_u64(sect, rs->hi)) != 0)
621 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100622 break;
623 case KRL_SECTION_CERT_SERIAL_BITMAP:
624 if (rs->lo - bitmap_start > INT_MAX) {
625 error("%s: insane bitmap gap", __func__);
626 goto out;
627 }
628 for (i = 0; i < contig; i++) {
629 if (BN_set_bit(bitmap,
djm@openbsd.org74de2542014-12-04 01:49:59 +0000630 rs->lo + i - bitmap_start) != 1) {
631 r = SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100632 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000633 }
Damien Millerf3747bf2013-01-18 11:44:04 +1100634 }
635 break;
636 }
637 last = rs->hi;
638 }
639 /* Flush the remaining section, if any */
640 if (state != 0) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000641 KRL_DBG(("%s: serial final flush for state 0x%02x",
642 __func__, state));
Damien Millerf3747bf2013-01-18 11:44:04 +1100643 switch (state) {
644 case KRL_SECTION_CERT_SERIAL_LIST:
645 case KRL_SECTION_CERT_SERIAL_RANGE:
646 break;
647 case KRL_SECTION_CERT_SERIAL_BITMAP:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000648 if ((r = sshbuf_put_bignum2(sect, bitmap)) != 0)
649 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100650 BN_free(bitmap);
651 bitmap = NULL;
652 break;
653 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000654 if ((r = sshbuf_put_u8(buf, state)) != 0 ||
655 (r = sshbuf_put_stringb(buf, sect)) != 0)
656 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100657 }
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000658 KRL_DBG(("%s: serial done ", __func__));
Damien Millerf3747bf2013-01-18 11:44:04 +1100659
660 /* Now output a section for any revocations by key ID */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000661 sshbuf_reset(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100662 RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000663 KRL_DBG(("%s: key ID %s", __func__, rki->key_id));
djm@openbsd.org74de2542014-12-04 01:49:59 +0000664 if ((r = sshbuf_put_cstring(sect, rki->key_id)) != 0)
665 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100666 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000667 if (sshbuf_len(sect) != 0) {
668 if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERT_KEY_ID)) != 0 ||
669 (r = sshbuf_put_stringb(buf, sect)) != 0)
670 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100671 }
672 r = 0;
673 out:
674 if (bitmap != NULL)
675 BN_free(bitmap);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000676 sshbuf_free(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100677 return r;
678}
679
680int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000681ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
682 const struct sshkey **sign_keys, u_int nsign_keys)
Damien Millerf3747bf2013-01-18 11:44:04 +1100683{
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000684 int r = SSH_ERR_INTERNAL_ERROR;
Damien Millerf3747bf2013-01-18 11:44:04 +1100685 struct revoked_certs *rc;
686 struct revoked_blob *rb;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000687 struct sshbuf *sect;
688 u_char *sblob = NULL;
689 size_t slen, i;
Damien Millerf3747bf2013-01-18 11:44:04 +1100690
691 if (krl->generated_date == 0)
692 krl->generated_date = time(NULL);
693
djm@openbsd.org74de2542014-12-04 01:49:59 +0000694 if ((sect = sshbuf_new()) == NULL)
695 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100696
697 /* Store the header */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000698 if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 ||
699 (r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 ||
700 (r = sshbuf_put_u64(buf, krl->krl_version)) != 0 ||
701 (r = sshbuf_put_u64(buf, krl->generated_date) != 0) ||
702 (r = sshbuf_put_u64(buf, krl->flags)) != 0 ||
703 (r = sshbuf_put_string(buf, NULL, 0)) != 0 ||
704 (r = sshbuf_put_cstring(buf, krl->comment)) != 0)
705 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100706
707 /* Store sections for revoked certificates */
708 TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
djm@openbsd.org74de2542014-12-04 01:49:59 +0000709 sshbuf_reset(sect);
710 if ((r = revoked_certs_generate(rc, sect)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100711 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000712 if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 ||
713 (r = sshbuf_put_stringb(buf, sect)) != 0)
714 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100715 }
716
717 /* Finally, output sections for revocations by public key/hash */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000718 sshbuf_reset(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100719 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000720 KRL_DBG(("%s: key len %u ", __func__, rb->len));
markus@openbsd.org00975652015-01-12 19:22:46 +0000721 if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000722 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100723 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000724 if (sshbuf_len(sect) != 0) {
725 if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 ||
726 (r = sshbuf_put_stringb(buf, sect)) != 0)
727 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100728 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000729 sshbuf_reset(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100730 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000731 KRL_DBG(("%s: hash len %u ", __func__, rb->len));
markus@openbsd.org00975652015-01-12 19:22:46 +0000732 if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
djm@openbsd.org74de2542014-12-04 01:49:59 +0000733 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100734 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000735 if (sshbuf_len(sect) != 0) {
736 if ((r = sshbuf_put_u8(buf,
737 KRL_SECTION_FINGERPRINT_SHA1)) != 0 ||
738 (r = sshbuf_put_stringb(buf, sect)) != 0)
739 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100740 }
741
742 for (i = 0; i < nsign_keys; i++) {
djm@openbsd.org74de2542014-12-04 01:49:59 +0000743 sshbuf_reset(sect);
744 if ((r = sshkey_to_blob_buf(sign_keys[i], sect)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100745 goto out;
746
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000747 KRL_DBG(("%s: signature key len %zu", __func__,
748 sshbuf_len(sect)));
djm@openbsd.org74de2542014-12-04 01:49:59 +0000749 if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 ||
750 (r = sshbuf_put_stringb(buf, sect)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100751 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000752
753 if ((r = sshkey_sign(sign_keys[i], &sblob, &slen,
754 sshbuf_ptr(buf), sshbuf_len(buf), 0)) == -1)
755 goto out;
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000756 KRL_DBG(("%s: signature sig len %u", __func__, slen));
djm@openbsd.org74de2542014-12-04 01:49:59 +0000757 if ((r = sshbuf_put_string(buf, sblob, slen)) != 0)
758 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100759 }
760
761 r = 0;
762 out:
Damien Millerf3747bf2013-01-18 11:44:04 +1100763 free(sblob);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000764 sshbuf_free(sect);
Damien Millerf3747bf2013-01-18 11:44:04 +1100765 return r;
766}
767
768static void
769format_timestamp(u_int64_t timestamp, char *ts, size_t nts)
770{
771 time_t t;
772 struct tm *tm;
773
774 t = timestamp;
775 tm = localtime(&t);
djm@openbsd.orgb6de5ac2014-11-21 01:00:38 +0000776 if (tm == NULL)
777 strlcpy(ts, "<INVALID>", sizeof(nts));
778 else {
779 *ts = '\0';
780 strftime(ts, nts, "%Y%m%dT%H%M%S", tm);
781 }
Damien Millerf3747bf2013-01-18 11:44:04 +1100782}
783
784static int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000785parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl)
Damien Millerf3747bf2013-01-18 11:44:04 +1100786{
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000787 int r = SSH_ERR_INTERNAL_ERROR, nbits;
Damien Miller633de332014-05-15 13:48:26 +1000788 u_char type;
789 const u_char *blob;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000790 size_t blen;
791 struct sshbuf *subsect = NULL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100792 u_int64_t serial, serial_lo, serial_hi;
793 BIGNUM *bitmap = NULL;
794 char *key_id = NULL;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000795 struct sshkey *ca_key = NULL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100796
djm@openbsd.org74de2542014-12-04 01:49:59 +0000797 if ((subsect = sshbuf_new()) == NULL)
798 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100799
djm@openbsd.org74de2542014-12-04 01:49:59 +0000800 /* Header: key, reserved */
801 if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 ||
802 (r = sshbuf_skip_string(buf)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100803 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000804 if ((r = sshkey_from_blob(blob, blen, &ca_key)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100805 goto out;
806
djm@openbsd.org74de2542014-12-04 01:49:59 +0000807 while (sshbuf_len(buf) > 0) {
808 if (subsect != NULL) {
809 sshbuf_free(subsect);
810 subsect = NULL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100811 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000812 if ((r = sshbuf_get_u8(buf, &type)) != 0 ||
813 (r = sshbuf_froms(buf, &subsect)) != 0)
814 goto out;
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000815 KRL_DBG(("%s: subsection type 0x%02x", __func__, type));
816 /* sshbuf_dump(subsect, stderr); */
Damien Millerf3747bf2013-01-18 11:44:04 +1100817
818 switch (type) {
819 case KRL_SECTION_CERT_SERIAL_LIST:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000820 while (sshbuf_len(subsect) > 0) {
821 if ((r = sshbuf_get_u64(subsect, &serial)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100822 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000823 if ((r = ssh_krl_revoke_cert_by_serial(krl,
824 ca_key, serial)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100825 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100826 }
827 break;
828 case KRL_SECTION_CERT_SERIAL_RANGE:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000829 if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 ||
830 (r = sshbuf_get_u64(subsect, &serial_hi)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100831 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000832 if ((r = ssh_krl_revoke_cert_by_serial_range(krl,
833 ca_key, serial_lo, serial_hi)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100834 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100835 break;
836 case KRL_SECTION_CERT_SERIAL_BITMAP:
837 if ((bitmap = BN_new()) == NULL) {
djm@openbsd.org74de2542014-12-04 01:49:59 +0000838 r = SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100839 goto out;
840 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000841 if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 ||
842 (r = sshbuf_get_bignum2(subsect, bitmap)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100843 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100844 if ((nbits = BN_num_bits(bitmap)) < 0) {
845 error("%s: bitmap bits < 0", __func__);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000846 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100847 goto out;
848 }
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000849 for (serial = 0; serial < (u_int64_t)nbits; serial++) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100850 if (serial > 0 && serial_lo + serial == 0) {
851 error("%s: bitmap wraps u64", __func__);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000852 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100853 goto out;
854 }
855 if (!BN_is_bit_set(bitmap, serial))
856 continue;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000857 if ((r = ssh_krl_revoke_cert_by_serial(krl,
858 ca_key, serial_lo + serial)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100859 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100860 }
861 BN_free(bitmap);
862 bitmap = NULL;
863 break;
864 case KRL_SECTION_CERT_KEY_ID:
djm@openbsd.org74de2542014-12-04 01:49:59 +0000865 while (sshbuf_len(subsect) > 0) {
866 if ((r = sshbuf_get_cstring(subsect,
867 &key_id, NULL)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100868 goto out;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000869 if ((r = ssh_krl_revoke_cert_by_key_id(krl,
870 ca_key, key_id)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100871 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100872 free(key_id);
873 key_id = NULL;
874 }
875 break;
876 default:
877 error("Unsupported KRL certificate section %u", type);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000878 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100879 goto out;
880 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000881 if (sshbuf_len(subsect) > 0) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100882 error("KRL certificate section contains unparsed data");
djm@openbsd.org74de2542014-12-04 01:49:59 +0000883 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100884 goto out;
885 }
886 }
887
djm@openbsd.org74de2542014-12-04 01:49:59 +0000888 r = 0;
Damien Millerf3747bf2013-01-18 11:44:04 +1100889 out:
Damien Millerf3747bf2013-01-18 11:44:04 +1100890 if (bitmap != NULL)
891 BN_free(bitmap);
892 free(key_id);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000893 sshkey_free(ca_key);
894 sshbuf_free(subsect);
895 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +1100896}
897
898
899/* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */
900int
djm@openbsd.org74de2542014-12-04 01:49:59 +0000901ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000902 const struct sshkey **sign_ca_keys, size_t nsign_ca_keys)
Damien Millerf3747bf2013-01-18 11:44:04 +1100903{
djm@openbsd.org74de2542014-12-04 01:49:59 +0000904 struct sshbuf *copy = NULL, *sect = NULL;
905 struct ssh_krl *krl = NULL;
Damien Millerf3747bf2013-01-18 11:44:04 +1100906 char timestamp[64];
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000907 int r = SSH_ERR_INTERNAL_ERROR, sig_seen;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000908 struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used;
Damien Miller633de332014-05-15 13:48:26 +1000909 u_char type, *rdata = NULL;
910 const u_char *blob;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000911 size_t i, j, sig_off, sects_off, rlen, blen, nca_used;
912 u_int format_version;
Damien Millerf3747bf2013-01-18 11:44:04 +1100913
Damien Miller30710702013-07-18 16:09:44 +1000914 nca_used = 0;
Damien Millerf3747bf2013-01-18 11:44:04 +1100915 *krlp = NULL;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000916 if (sshbuf_len(buf) < sizeof(KRL_MAGIC) - 1 ||
917 memcmp(sshbuf_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) {
Damien Millerf3747bf2013-01-18 11:44:04 +1100918 debug3("%s: not a KRL", __func__);
djm@openbsd.org74de2542014-12-04 01:49:59 +0000919 return SSH_ERR_KRL_BAD_MAGIC;
Damien Millerf3747bf2013-01-18 11:44:04 +1100920 }
921
922 /* Take a copy of the KRL buffer so we can verify its signature later */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000923 if ((copy = sshbuf_fromb(buf)) == NULL) {
924 r = SSH_ERR_ALLOC_FAIL;
925 goto out;
926 }
927 if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0)
928 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100929
930 if ((krl = ssh_krl_init()) == NULL) {
931 error("%s: alloc failed", __func__);
932 goto out;
933 }
934
djm@openbsd.org74de2542014-12-04 01:49:59 +0000935 if ((r = sshbuf_get_u32(copy, &format_version)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100936 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100937 if (format_version != KRL_FORMAT_VERSION) {
djm@openbsd.org74de2542014-12-04 01:49:59 +0000938 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100939 goto out;
940 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000941 if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 ||
942 (r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 ||
943 (r = sshbuf_get_u64(copy, &krl->flags)) != 0 ||
944 (r = sshbuf_skip_string(copy)) != 0 ||
945 (r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100946 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +1100947
948 format_timestamp(krl->generated_date, timestamp, sizeof(timestamp));
Damien Millerd677ad12013-04-23 15:18:51 +1000949 debug("KRL version %llu generated at %s%s%s",
950 (long long unsigned)krl->krl_version, timestamp,
951 *krl->comment ? ": " : "", krl->comment);
Damien Millerf3747bf2013-01-18 11:44:04 +1100952
953 /*
954 * 1st pass: verify signatures, if any. This is done to avoid
955 * detailed parsing of data whose provenance is unverified.
956 */
957 sig_seen = 0;
djm@openbsd.org74de2542014-12-04 01:49:59 +0000958 if (sshbuf_len(buf) < sshbuf_len(copy)) {
959 /* Shouldn't happen */
960 r = SSH_ERR_INTERNAL_ERROR;
961 goto out;
962 }
963 sects_off = sshbuf_len(buf) - sshbuf_len(copy);
964 while (sshbuf_len(copy) > 0) {
965 if ((r = sshbuf_get_u8(copy, &type)) != 0 ||
966 (r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100967 goto out;
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000968 KRL_DBG(("%s: first pass, section 0x%02x", __func__, type));
Damien Millerf3747bf2013-01-18 11:44:04 +1100969 if (type != KRL_SECTION_SIGNATURE) {
970 if (sig_seen) {
971 error("KRL contains non-signature section "
972 "after signature");
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000973 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100974 goto out;
975 }
976 /* Not interested for now. */
977 continue;
978 }
979 sig_seen = 1;
980 /* First string component is the signing key */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000981 if ((r = sshkey_from_blob(blob, blen, &key)) != 0) {
982 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100983 goto out;
984 }
djm@openbsd.org74de2542014-12-04 01:49:59 +0000985 if (sshbuf_len(buf) < sshbuf_len(copy)) {
986 /* Shouldn't happen */
987 r = SSH_ERR_INTERNAL_ERROR;
988 goto out;
989 }
990 sig_off = sshbuf_len(buf) - sshbuf_len(copy);
Damien Millerf3747bf2013-01-18 11:44:04 +1100991 /* Second string component is the signature itself */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000992 if ((r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) {
993 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +1100994 goto out;
995 }
996 /* Check signature over entire KRL up to this point */
djm@openbsd.org74de2542014-12-04 01:49:59 +0000997 if ((r = sshkey_verify(key, blob, blen,
djm@openbsd.orge7fd9522015-01-13 19:04:35 +0000998 sshbuf_ptr(buf), sshbuf_len(buf) - sig_off, 0)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +1100999 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +11001000 /* Check if this key has already signed this KRL */
1001 for (i = 0; i < nca_used; i++) {
djm@openbsd.org74de2542014-12-04 01:49:59 +00001002 if (sshkey_equal(ca_used[i], key)) {
Damien Millerf3747bf2013-01-18 11:44:04 +11001003 error("KRL signed more than once with "
1004 "the same key");
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001005 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +11001006 goto out;
1007 }
1008 }
1009 /* Record keys used to sign the KRL */
djm@openbsd.org74de2542014-12-04 01:49:59 +00001010 tmp_ca_used = reallocarray(ca_used, nca_used + 1,
1011 sizeof(*ca_used));
1012 if (tmp_ca_used == NULL) {
1013 r = SSH_ERR_ALLOC_FAIL;
1014 goto out;
1015 }
1016 ca_used = tmp_ca_used;
Damien Millerf3747bf2013-01-18 11:44:04 +11001017 ca_used[nca_used++] = key;
1018 key = NULL;
1019 break;
1020 }
1021
djm@openbsd.org74de2542014-12-04 01:49:59 +00001022 if (sshbuf_len(copy) != 0) {
1023 /* Shouldn't happen */
1024 r = SSH_ERR_INTERNAL_ERROR;
1025 goto out;
1026 }
1027
Damien Millerf3747bf2013-01-18 11:44:04 +11001028 /*
1029 * 2nd pass: parse and load the KRL, skipping the header to the point
1030 * where the section start.
1031 */
djm@openbsd.org74de2542014-12-04 01:49:59 +00001032 sshbuf_free(copy);
1033 if ((copy = sshbuf_fromb(buf)) == NULL) {
1034 r = SSH_ERR_ALLOC_FAIL;
1035 goto out;
1036 }
1037 if ((r = sshbuf_consume(copy, sects_off)) != 0)
1038 goto out;
1039 while (sshbuf_len(copy) > 0) {
1040 if (sect != NULL) {
1041 sshbuf_free(sect);
1042 sect = NULL;
1043 }
1044 if ((r = sshbuf_get_u8(copy, &type)) != 0 ||
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001045 (r = sshbuf_froms(copy, &sect)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +11001046 goto out;
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001047 KRL_DBG(("%s: second pass, section 0x%02x", __func__, type));
Damien Millerf3747bf2013-01-18 11:44:04 +11001048
1049 switch (type) {
1050 case KRL_SECTION_CERTIFICATES:
djm@openbsd.org74de2542014-12-04 01:49:59 +00001051 if ((r = parse_revoked_certs(sect, krl)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +11001052 goto out;
1053 break;
1054 case KRL_SECTION_EXPLICIT_KEY:
1055 case KRL_SECTION_FINGERPRINT_SHA1:
djm@openbsd.org74de2542014-12-04 01:49:59 +00001056 while (sshbuf_len(sect) > 0) {
1057 if ((r = sshbuf_get_string(sect,
1058 &rdata, &rlen)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +11001059 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +11001060 if (type == KRL_SECTION_FINGERPRINT_SHA1 &&
Damien Miller30710702013-07-18 16:09:44 +10001061 rlen != 20) {
Damien Millerf3747bf2013-01-18 11:44:04 +11001062 error("%s: bad SHA1 length", __func__);
djm@openbsd.org74de2542014-12-04 01:49:59 +00001063 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +11001064 goto out;
1065 }
djm@openbsd.org74de2542014-12-04 01:49:59 +00001066 if ((r = revoke_blob(
Damien Millerf3747bf2013-01-18 11:44:04 +11001067 type == KRL_SECTION_EXPLICIT_KEY ?
1068 &krl->revoked_keys : &krl->revoked_sha1s,
djm@openbsd.org74de2542014-12-04 01:49:59 +00001069 rdata, rlen)) != 0)
Damien Miller30710702013-07-18 16:09:44 +10001070 goto out;
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001071 rdata = NULL; /* revoke_blob frees rdata */
Damien Millerf3747bf2013-01-18 11:44:04 +11001072 }
1073 break;
1074 case KRL_SECTION_SIGNATURE:
1075 /* Handled above, but still need to stay in synch */
djm@openbsd.org74de2542014-12-04 01:49:59 +00001076 sshbuf_reset(sect);
1077 sect = NULL;
1078 if ((r = sshbuf_skip_string(copy)) != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +11001079 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +11001080 break;
1081 default:
1082 error("Unsupported KRL section %u", type);
djm@openbsd.org74de2542014-12-04 01:49:59 +00001083 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +11001084 goto out;
1085 }
djm@openbsd.org74de2542014-12-04 01:49:59 +00001086 if (sshbuf_len(sect) > 0) {
Damien Millerf3747bf2013-01-18 11:44:04 +11001087 error("KRL section contains unparsed data");
djm@openbsd.org74de2542014-12-04 01:49:59 +00001088 r = SSH_ERR_INVALID_FORMAT;
Damien Millerf3747bf2013-01-18 11:44:04 +11001089 goto out;
1090 }
1091 }
1092
1093 /* Check that the key(s) used to sign the KRL weren't revoked */
1094 sig_seen = 0;
1095 for (i = 0; i < nca_used; i++) {
1096 if (ssh_krl_check_key(krl, ca_used[i]) == 0)
1097 sig_seen = 1;
1098 else {
djm@openbsd.org74de2542014-12-04 01:49:59 +00001099 sshkey_free(ca_used[i]);
Damien Millerf3747bf2013-01-18 11:44:04 +11001100 ca_used[i] = NULL;
1101 }
1102 }
1103 if (nca_used && !sig_seen) {
1104 error("All keys used to sign KRL were revoked");
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001105 r = SSH_ERR_KEY_REVOKED;
Damien Millerf3747bf2013-01-18 11:44:04 +11001106 goto out;
1107 }
1108
1109 /* If we have CA keys, then verify that one was used to sign the KRL */
1110 if (sig_seen && nsign_ca_keys != 0) {
1111 sig_seen = 0;
1112 for (i = 0; !sig_seen && i < nsign_ca_keys; i++) {
1113 for (j = 0; j < nca_used; j++) {
1114 if (ca_used[j] == NULL)
1115 continue;
djm@openbsd.org74de2542014-12-04 01:49:59 +00001116 if (sshkey_equal(ca_used[j], sign_ca_keys[i])) {
Damien Millerf3747bf2013-01-18 11:44:04 +11001117 sig_seen = 1;
1118 break;
1119 }
1120 }
1121 }
1122 if (!sig_seen) {
djm@openbsd.org74de2542014-12-04 01:49:59 +00001123 r = SSH_ERR_SIGNATURE_INVALID;
Damien Millerf3747bf2013-01-18 11:44:04 +11001124 error("KRL not signed with any trusted key");
1125 goto out;
1126 }
1127 }
1128
1129 *krlp = krl;
djm@openbsd.org74de2542014-12-04 01:49:59 +00001130 r = 0;
Damien Millerf3747bf2013-01-18 11:44:04 +11001131 out:
djm@openbsd.org74de2542014-12-04 01:49:59 +00001132 if (r != 0)
Damien Millerf3747bf2013-01-18 11:44:04 +11001133 ssh_krl_free(krl);
djm@openbsd.org74de2542014-12-04 01:49:59 +00001134 for (i = 0; i < nca_used; i++)
1135 sshkey_free(ca_used[i]);
Damien Millerf3747bf2013-01-18 11:44:04 +11001136 free(ca_used);
Damien Miller30710702013-07-18 16:09:44 +10001137 free(rdata);
djm@openbsd.org74de2542014-12-04 01:49:59 +00001138 sshkey_free(key);
1139 sshbuf_free(copy);
1140 sshbuf_free(sect);
1141 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +11001142}
1143
1144/* Checks whether a given key/cert is revoked. Does not check its CA */
1145static int
djm@openbsd.org74de2542014-12-04 01:49:59 +00001146is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
Damien Millerf3747bf2013-01-18 11:44:04 +11001147{
1148 struct revoked_blob rb, *erb;
1149 struct revoked_serial rs, *ers;
1150 struct revoked_key_id rki, *erki;
1151 struct revoked_certs *rc;
djm@openbsd.org74de2542014-12-04 01:49:59 +00001152 int r;
Damien Millerf3747bf2013-01-18 11:44:04 +11001153
1154 /* Check explicitly revoked hashes first */
Damien Miller1d2c4562014-02-04 11:18:20 +11001155 memset(&rb, 0, sizeof(rb));
djm@openbsd.org56d1c832014-12-21 22:27:55 +00001156 if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
djm@openbsd.org74de2542014-12-04 01:49:59 +00001157 &rb.blob, &rb.len)) != 0)
1158 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +11001159 erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
1160 free(rb.blob);
1161 if (erb != NULL) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001162 KRL_DBG(("%s: revoked by key SHA1", __func__));
djm@openbsd.org74de2542014-12-04 01:49:59 +00001163 return SSH_ERR_KEY_REVOKED;
Damien Millerf3747bf2013-01-18 11:44:04 +11001164 }
1165
1166 /* Next, explicit keys */
Damien Miller1d2c4562014-02-04 11:18:20 +11001167 memset(&rb, 0, sizeof(rb));
djm@openbsd.org74de2542014-12-04 01:49:59 +00001168 if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0)
1169 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +11001170 erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
1171 free(rb.blob);
1172 if (erb != NULL) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001173 KRL_DBG(("%s: revoked by explicit key", __func__));
djm@openbsd.org74de2542014-12-04 01:49:59 +00001174 return SSH_ERR_KEY_REVOKED;
Damien Millerf3747bf2013-01-18 11:44:04 +11001175 }
1176
djm@openbsd.org74de2542014-12-04 01:49:59 +00001177 if (!sshkey_is_cert(key))
Damien Millerf3747bf2013-01-18 11:44:04 +11001178 return 0;
1179
1180 /* Check cert revocation */
djm@openbsd.org74de2542014-12-04 01:49:59 +00001181 if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key,
1182 &rc, 0)) != 0)
1183 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +11001184 if (rc == NULL)
1185 return 0; /* No entry for this CA */
1186
1187 /* Check revocation by cert key ID */
Damien Miller1d2c4562014-02-04 11:18:20 +11001188 memset(&rki, 0, sizeof(rki));
Damien Millerf3747bf2013-01-18 11:44:04 +11001189 rki.key_id = key->cert->key_id;
1190 erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki);
1191 if (erki != NULL) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001192 KRL_DBG(("%s: revoked by key ID", __func__));
djm@openbsd.org74de2542014-12-04 01:49:59 +00001193 return SSH_ERR_KEY_REVOKED;
Damien Millerf3747bf2013-01-18 11:44:04 +11001194 }
1195
Damien Miller60565bc2013-02-12 10:56:42 +11001196 /*
1197 * Legacy cert formats lack serial numbers. Zero serials numbers
1198 * are ignored (it's the default when the CA doesn't specify one).
1199 */
djm@openbsd.org74de2542014-12-04 01:49:59 +00001200 if (sshkey_cert_is_legacy(key) || key->cert->serial == 0)
Damien Millerf3747bf2013-01-18 11:44:04 +11001201 return 0;
1202
Damien Miller1d2c4562014-02-04 11:18:20 +11001203 memset(&rs, 0, sizeof(rs));
Damien Millerf3747bf2013-01-18 11:44:04 +11001204 rs.lo = rs.hi = key->cert->serial;
1205 ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs);
1206 if (ers != NULL) {
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001207 KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__,
Damien Millerf3747bf2013-01-18 11:44:04 +11001208 key->cert->serial, ers->lo, ers->hi));
djm@openbsd.org74de2542014-12-04 01:49:59 +00001209 return SSH_ERR_KEY_REVOKED;
Damien Millerf3747bf2013-01-18 11:44:04 +11001210 }
1211 KRL_DBG(("%s: %llu no match", __func__, key->cert->serial));
Damien Millerf3747bf2013-01-18 11:44:04 +11001212 return 0;
1213}
1214
1215int
djm@openbsd.org74de2542014-12-04 01:49:59 +00001216ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key)
Damien Millerf3747bf2013-01-18 11:44:04 +11001217{
1218 int r;
1219
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001220 KRL_DBG(("%s: checking key", __func__));
Damien Millerf3747bf2013-01-18 11:44:04 +11001221 if ((r = is_key_revoked(krl, key)) != 0)
1222 return r;
djm@openbsd.org74de2542014-12-04 01:49:59 +00001223 if (sshkey_is_cert(key)) {
Damien Millerf3747bf2013-01-18 11:44:04 +11001224 debug2("%s: checking CA key", __func__);
1225 if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0)
1226 return r;
1227 }
djm@openbsd.orge7fd9522015-01-13 19:04:35 +00001228 KRL_DBG(("%s: key okay", __func__));
Damien Millerf3747bf2013-01-18 11:44:04 +11001229 return 0;
1230}
1231
Damien Millerf3747bf2013-01-18 11:44:04 +11001232int
djm@openbsd.org74de2542014-12-04 01:49:59 +00001233ssh_krl_file_contains_key(const char *path, const struct sshkey *key)
Damien Millerf3747bf2013-01-18 11:44:04 +11001234{
djm@openbsd.org74de2542014-12-04 01:49:59 +00001235 struct sshbuf *krlbuf = NULL;
1236 struct ssh_krl *krl = NULL;
1237 int oerrno = 0, r, fd;
Damien Millerf3747bf2013-01-18 11:44:04 +11001238
1239 if (path == NULL)
1240 return 0;
1241
djm@openbsd.org74de2542014-12-04 01:49:59 +00001242 if ((krlbuf = sshbuf_new()) == NULL)
1243 return SSH_ERR_ALLOC_FAIL;
Damien Millerf3747bf2013-01-18 11:44:04 +11001244 if ((fd = open(path, O_RDONLY)) == -1) {
djm@openbsd.org74de2542014-12-04 01:49:59 +00001245 r = SSH_ERR_SYSTEM_ERROR;
1246 oerrno = errno;
1247 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +11001248 }
djm@openbsd.org1195f4c2015-01-08 10:14:08 +00001249 if ((r = sshkey_load_file(fd, krlbuf)) != 0) {
djm@openbsd.org74de2542014-12-04 01:49:59 +00001250 oerrno = errno;
1251 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +11001252 }
djm@openbsd.org74de2542014-12-04 01:49:59 +00001253 if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0)
1254 goto out;
Damien Millerf3747bf2013-01-18 11:44:04 +11001255 debug2("%s: checking KRL %s", __func__, path);
djm@openbsd.org74de2542014-12-04 01:49:59 +00001256 r = ssh_krl_check_key(krl, key);
1257 out:
1258 close(fd);
1259 sshbuf_free(krlbuf);
Damien Millerf3747bf2013-01-18 11:44:04 +11001260 ssh_krl_free(krl);
djm@openbsd.org74de2542014-12-04 01:49:59 +00001261 if (r != 0)
1262 errno = oerrno;
1263 return r;
Damien Millerf3747bf2013-01-18 11:44:04 +11001264}