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