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