16888a9beSDag-Erling Smørgrav /* 26888a9beSDag-Erling Smørgrav * Copyright (c) 2012 Damien Miller <djm@mindrot.org> 36888a9beSDag-Erling Smørgrav * 46888a9beSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 56888a9beSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 66888a9beSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 76888a9beSDag-Erling Smørgrav * 86888a9beSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 96888a9beSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 106888a9beSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 116888a9beSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 126888a9beSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 136888a9beSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 146888a9beSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 156888a9beSDag-Erling Smørgrav */ 166888a9beSDag-Erling Smørgrav 17*2f513db7SEd Maste /* $OpenBSD: krl.c,v 1.42 2018/09/12 01:21:34 djm Exp $ */ 186888a9beSDag-Erling Smørgrav 196888a9beSDag-Erling Smørgrav #include "includes.h" 206888a9beSDag-Erling Smørgrav 216888a9beSDag-Erling Smørgrav #include <sys/types.h> 226888a9beSDag-Erling Smørgrav #include <openbsd-compat/sys-tree.h> 236888a9beSDag-Erling Smørgrav #include <openbsd-compat/sys-queue.h> 246888a9beSDag-Erling Smørgrav 256888a9beSDag-Erling Smørgrav #include <errno.h> 266888a9beSDag-Erling Smørgrav #include <fcntl.h> 276888a9beSDag-Erling Smørgrav #include <limits.h> 286888a9beSDag-Erling Smørgrav #include <string.h> 296888a9beSDag-Erling Smørgrav #include <time.h> 306888a9beSDag-Erling Smørgrav #include <unistd.h> 316888a9beSDag-Erling Smørgrav 32bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 33bc5531deSDag-Erling Smørgrav #include "ssherr.h" 34bc5531deSDag-Erling Smørgrav #include "sshkey.h" 356888a9beSDag-Erling Smørgrav #include "authfile.h" 366888a9beSDag-Erling Smørgrav #include "misc.h" 376888a9beSDag-Erling Smørgrav #include "log.h" 38bc5531deSDag-Erling Smørgrav #include "digest.h" 39bc5531deSDag-Erling Smørgrav #include "bitmap.h" 406888a9beSDag-Erling Smørgrav 416888a9beSDag-Erling Smørgrav #include "krl.h" 426888a9beSDag-Erling Smørgrav 436888a9beSDag-Erling Smørgrav /* #define DEBUG_KRL */ 446888a9beSDag-Erling Smørgrav #ifdef DEBUG_KRL 456888a9beSDag-Erling Smørgrav # define KRL_DBG(x) debug3 x 466888a9beSDag-Erling Smørgrav #else 476888a9beSDag-Erling Smørgrav # define KRL_DBG(x) 486888a9beSDag-Erling Smørgrav #endif 496888a9beSDag-Erling Smørgrav 506888a9beSDag-Erling Smørgrav /* 516888a9beSDag-Erling Smørgrav * Trees of revoked serial numbers, key IDs and keys. This allows 526888a9beSDag-Erling Smørgrav * quick searching, querying and producing lists in canonical order. 536888a9beSDag-Erling Smørgrav */ 546888a9beSDag-Erling Smørgrav 556888a9beSDag-Erling Smørgrav /* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */ 566888a9beSDag-Erling Smørgrav struct revoked_serial { 576888a9beSDag-Erling Smørgrav u_int64_t lo, hi; 586888a9beSDag-Erling Smørgrav RB_ENTRY(revoked_serial) tree_entry; 596888a9beSDag-Erling Smørgrav }; 606888a9beSDag-Erling Smørgrav static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b); 616888a9beSDag-Erling Smørgrav RB_HEAD(revoked_serial_tree, revoked_serial); 626888a9beSDag-Erling Smørgrav RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp); 636888a9beSDag-Erling Smørgrav 646888a9beSDag-Erling Smørgrav /* Tree of key IDs */ 656888a9beSDag-Erling Smørgrav struct revoked_key_id { 666888a9beSDag-Erling Smørgrav char *key_id; 676888a9beSDag-Erling Smørgrav RB_ENTRY(revoked_key_id) tree_entry; 686888a9beSDag-Erling Smørgrav }; 696888a9beSDag-Erling Smørgrav static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b); 706888a9beSDag-Erling Smørgrav RB_HEAD(revoked_key_id_tree, revoked_key_id); 716888a9beSDag-Erling Smørgrav RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp); 726888a9beSDag-Erling Smørgrav 736888a9beSDag-Erling Smørgrav /* Tree of blobs (used for keys and fingerprints) */ 746888a9beSDag-Erling Smørgrav struct revoked_blob { 756888a9beSDag-Erling Smørgrav u_char *blob; 76bc5531deSDag-Erling Smørgrav size_t len; 776888a9beSDag-Erling Smørgrav RB_ENTRY(revoked_blob) tree_entry; 786888a9beSDag-Erling Smørgrav }; 796888a9beSDag-Erling Smørgrav static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); 806888a9beSDag-Erling Smørgrav RB_HEAD(revoked_blob_tree, revoked_blob); 816888a9beSDag-Erling Smørgrav RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp); 826888a9beSDag-Erling Smørgrav 836888a9beSDag-Erling Smørgrav /* Tracks revoked certs for a single CA */ 846888a9beSDag-Erling Smørgrav struct revoked_certs { 85bc5531deSDag-Erling Smørgrav struct sshkey *ca_key; 866888a9beSDag-Erling Smørgrav struct revoked_serial_tree revoked_serials; 876888a9beSDag-Erling Smørgrav struct revoked_key_id_tree revoked_key_ids; 886888a9beSDag-Erling Smørgrav TAILQ_ENTRY(revoked_certs) entry; 896888a9beSDag-Erling Smørgrav }; 906888a9beSDag-Erling Smørgrav TAILQ_HEAD(revoked_certs_list, revoked_certs); 916888a9beSDag-Erling Smørgrav 926888a9beSDag-Erling Smørgrav struct ssh_krl { 936888a9beSDag-Erling Smørgrav u_int64_t krl_version; 946888a9beSDag-Erling Smørgrav u_int64_t generated_date; 956888a9beSDag-Erling Smørgrav u_int64_t flags; 966888a9beSDag-Erling Smørgrav char *comment; 976888a9beSDag-Erling Smørgrav struct revoked_blob_tree revoked_keys; 986888a9beSDag-Erling Smørgrav struct revoked_blob_tree revoked_sha1s; 99*2f513db7SEd Maste struct revoked_blob_tree revoked_sha256s; 1006888a9beSDag-Erling Smørgrav struct revoked_certs_list revoked_certs; 1016888a9beSDag-Erling Smørgrav }; 1026888a9beSDag-Erling Smørgrav 1036888a9beSDag-Erling Smørgrav /* Return equal if a and b overlap */ 1046888a9beSDag-Erling Smørgrav static int 1056888a9beSDag-Erling Smørgrav serial_cmp(struct revoked_serial *a, struct revoked_serial *b) 1066888a9beSDag-Erling Smørgrav { 1076888a9beSDag-Erling Smørgrav if (a->hi >= b->lo && a->lo <= b->hi) 1086888a9beSDag-Erling Smørgrav return 0; 1096888a9beSDag-Erling Smørgrav return a->lo < b->lo ? -1 : 1; 1106888a9beSDag-Erling Smørgrav } 1116888a9beSDag-Erling Smørgrav 1126888a9beSDag-Erling Smørgrav static int 1136888a9beSDag-Erling Smørgrav key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b) 1146888a9beSDag-Erling Smørgrav { 1156888a9beSDag-Erling Smørgrav return strcmp(a->key_id, b->key_id); 1166888a9beSDag-Erling Smørgrav } 1176888a9beSDag-Erling Smørgrav 1186888a9beSDag-Erling Smørgrav static int 1196888a9beSDag-Erling Smørgrav blob_cmp(struct revoked_blob *a, struct revoked_blob *b) 1206888a9beSDag-Erling Smørgrav { 1216888a9beSDag-Erling Smørgrav int r; 1226888a9beSDag-Erling Smørgrav 1236888a9beSDag-Erling Smørgrav if (a->len != b->len) { 124ca86bcf2SDag-Erling Smørgrav if ((r = memcmp(a->blob, b->blob, MINIMUM(a->len, b->len))) != 0) 1256888a9beSDag-Erling Smørgrav return r; 1266888a9beSDag-Erling Smørgrav return a->len > b->len ? 1 : -1; 1276888a9beSDag-Erling Smørgrav } else 1286888a9beSDag-Erling Smørgrav return memcmp(a->blob, b->blob, a->len); 1296888a9beSDag-Erling Smørgrav } 1306888a9beSDag-Erling Smørgrav 1316888a9beSDag-Erling Smørgrav struct ssh_krl * 1326888a9beSDag-Erling Smørgrav ssh_krl_init(void) 1336888a9beSDag-Erling Smørgrav { 1346888a9beSDag-Erling Smørgrav struct ssh_krl *krl; 1356888a9beSDag-Erling Smørgrav 1366888a9beSDag-Erling Smørgrav if ((krl = calloc(1, sizeof(*krl))) == NULL) 1376888a9beSDag-Erling Smørgrav return NULL; 1386888a9beSDag-Erling Smørgrav RB_INIT(&krl->revoked_keys); 1396888a9beSDag-Erling Smørgrav RB_INIT(&krl->revoked_sha1s); 140*2f513db7SEd Maste RB_INIT(&krl->revoked_sha256s); 1416888a9beSDag-Erling Smørgrav TAILQ_INIT(&krl->revoked_certs); 1426888a9beSDag-Erling Smørgrav return krl; 1436888a9beSDag-Erling Smørgrav } 1446888a9beSDag-Erling Smørgrav 1456888a9beSDag-Erling Smørgrav static void 1466888a9beSDag-Erling Smørgrav revoked_certs_free(struct revoked_certs *rc) 1476888a9beSDag-Erling Smørgrav { 1486888a9beSDag-Erling Smørgrav struct revoked_serial *rs, *trs; 1496888a9beSDag-Erling Smørgrav struct revoked_key_id *rki, *trki; 1506888a9beSDag-Erling Smørgrav 1516888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) { 1526888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs); 1536888a9beSDag-Erling Smørgrav free(rs); 1546888a9beSDag-Erling Smørgrav } 1556888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) { 1566888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki); 1576888a9beSDag-Erling Smørgrav free(rki->key_id); 1586888a9beSDag-Erling Smørgrav free(rki); 1596888a9beSDag-Erling Smørgrav } 160bc5531deSDag-Erling Smørgrav sshkey_free(rc->ca_key); 1616888a9beSDag-Erling Smørgrav } 1626888a9beSDag-Erling Smørgrav 1636888a9beSDag-Erling Smørgrav void 1646888a9beSDag-Erling Smørgrav ssh_krl_free(struct ssh_krl *krl) 1656888a9beSDag-Erling Smørgrav { 1666888a9beSDag-Erling Smørgrav struct revoked_blob *rb, *trb; 1676888a9beSDag-Erling Smørgrav struct revoked_certs *rc, *trc; 1686888a9beSDag-Erling Smørgrav 1696888a9beSDag-Erling Smørgrav if (krl == NULL) 1706888a9beSDag-Erling Smørgrav return; 1716888a9beSDag-Erling Smørgrav 1726888a9beSDag-Erling Smørgrav free(krl->comment); 1736888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) { 1746888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb); 1756888a9beSDag-Erling Smørgrav free(rb->blob); 1766888a9beSDag-Erling Smørgrav free(rb); 1776888a9beSDag-Erling Smørgrav } 1786888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) { 1796888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb); 1806888a9beSDag-Erling Smørgrav free(rb->blob); 1816888a9beSDag-Erling Smørgrav free(rb); 1826888a9beSDag-Erling Smørgrav } 183*2f513db7SEd Maste RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha256s, trb) { 184*2f513db7SEd Maste RB_REMOVE(revoked_blob_tree, &krl->revoked_sha256s, rb); 185*2f513db7SEd Maste free(rb->blob); 186*2f513db7SEd Maste free(rb); 187*2f513db7SEd Maste } 1886888a9beSDag-Erling Smørgrav TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) { 1896888a9beSDag-Erling Smørgrav TAILQ_REMOVE(&krl->revoked_certs, rc, entry); 1906888a9beSDag-Erling Smørgrav revoked_certs_free(rc); 1916888a9beSDag-Erling Smørgrav } 1926888a9beSDag-Erling Smørgrav } 1936888a9beSDag-Erling Smørgrav 1946888a9beSDag-Erling Smørgrav void 1956888a9beSDag-Erling Smørgrav ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version) 1966888a9beSDag-Erling Smørgrav { 1976888a9beSDag-Erling Smørgrav krl->krl_version = version; 1986888a9beSDag-Erling Smørgrav } 1996888a9beSDag-Erling Smørgrav 200bc5531deSDag-Erling Smørgrav int 2016888a9beSDag-Erling Smørgrav ssh_krl_set_comment(struct ssh_krl *krl, const char *comment) 2026888a9beSDag-Erling Smørgrav { 2036888a9beSDag-Erling Smørgrav free(krl->comment); 2046888a9beSDag-Erling Smørgrav if ((krl->comment = strdup(comment)) == NULL) 205bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 206bc5531deSDag-Erling Smørgrav return 0; 2076888a9beSDag-Erling Smørgrav } 2086888a9beSDag-Erling Smørgrav 2096888a9beSDag-Erling Smørgrav /* 2106888a9beSDag-Erling Smørgrav * Find the revoked_certs struct for a CA key. If allow_create is set then 2116888a9beSDag-Erling Smørgrav * create a new one in the tree if one did not exist already. 2126888a9beSDag-Erling Smørgrav */ 2136888a9beSDag-Erling Smørgrav static int 214bc5531deSDag-Erling Smørgrav revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key, 2156888a9beSDag-Erling Smørgrav struct revoked_certs **rcp, int allow_create) 2166888a9beSDag-Erling Smørgrav { 2176888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 218bc5531deSDag-Erling Smørgrav int r; 2196888a9beSDag-Erling Smørgrav 2206888a9beSDag-Erling Smørgrav *rcp = NULL; 2216888a9beSDag-Erling Smørgrav TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 222bc5531deSDag-Erling Smørgrav if ((ca_key == NULL && rc->ca_key == NULL) || 223bc5531deSDag-Erling Smørgrav sshkey_equal(rc->ca_key, ca_key)) { 2246888a9beSDag-Erling Smørgrav *rcp = rc; 2256888a9beSDag-Erling Smørgrav return 0; 2266888a9beSDag-Erling Smørgrav } 2276888a9beSDag-Erling Smørgrav } 2286888a9beSDag-Erling Smørgrav if (!allow_create) 2296888a9beSDag-Erling Smørgrav return 0; 2306888a9beSDag-Erling Smørgrav /* If this CA doesn't exist in the list then add it now */ 2316888a9beSDag-Erling Smørgrav if ((rc = calloc(1, sizeof(*rc))) == NULL) 232bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 233bc5531deSDag-Erling Smørgrav if (ca_key == NULL) 234bc5531deSDag-Erling Smørgrav rc->ca_key = NULL; 235bc5531deSDag-Erling Smørgrav else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { 2366888a9beSDag-Erling Smørgrav free(rc); 237bc5531deSDag-Erling Smørgrav return r; 2386888a9beSDag-Erling Smørgrav } 2396888a9beSDag-Erling Smørgrav RB_INIT(&rc->revoked_serials); 2406888a9beSDag-Erling Smørgrav RB_INIT(&rc->revoked_key_ids); 2416888a9beSDag-Erling Smørgrav TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); 242bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: new CA %s", __func__, 243bc5531deSDag-Erling Smørgrav ca_key == NULL ? "*" : sshkey_type(ca_key))); 2446888a9beSDag-Erling Smørgrav *rcp = rc; 2456888a9beSDag-Erling Smørgrav return 0; 2466888a9beSDag-Erling Smørgrav } 2476888a9beSDag-Erling Smørgrav 2486888a9beSDag-Erling Smørgrav static int 2496888a9beSDag-Erling Smørgrav insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi) 2506888a9beSDag-Erling Smørgrav { 2516888a9beSDag-Erling Smørgrav struct revoked_serial rs, *ers, *crs, *irs; 2526888a9beSDag-Erling Smørgrav 2536888a9beSDag-Erling Smørgrav KRL_DBG(("%s: insert %llu:%llu", __func__, lo, hi)); 254b83788ffSDag-Erling Smørgrav memset(&rs, 0, sizeof(rs)); 2556888a9beSDag-Erling Smørgrav rs.lo = lo; 2566888a9beSDag-Erling Smørgrav rs.hi = hi; 2576888a9beSDag-Erling Smørgrav ers = RB_NFIND(revoked_serial_tree, rt, &rs); 2586888a9beSDag-Erling Smørgrav if (ers == NULL || serial_cmp(ers, &rs) != 0) { 2596888a9beSDag-Erling Smørgrav /* No entry matches. Just insert */ 2606888a9beSDag-Erling Smørgrav if ((irs = malloc(sizeof(rs))) == NULL) 261bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 2626888a9beSDag-Erling Smørgrav memcpy(irs, &rs, sizeof(*irs)); 2636888a9beSDag-Erling Smørgrav ers = RB_INSERT(revoked_serial_tree, rt, irs); 2646888a9beSDag-Erling Smørgrav if (ers != NULL) { 2656888a9beSDag-Erling Smørgrav KRL_DBG(("%s: bad: ers != NULL", __func__)); 2666888a9beSDag-Erling Smørgrav /* Shouldn't happen */ 2676888a9beSDag-Erling Smørgrav free(irs); 268bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 2696888a9beSDag-Erling Smørgrav } 2706888a9beSDag-Erling Smørgrav ers = irs; 2716888a9beSDag-Erling Smørgrav } else { 2726888a9beSDag-Erling Smørgrav KRL_DBG(("%s: overlap found %llu:%llu", __func__, 2736888a9beSDag-Erling Smørgrav ers->lo, ers->hi)); 2746888a9beSDag-Erling Smørgrav /* 2756888a9beSDag-Erling Smørgrav * The inserted entry overlaps an existing one. Grow the 2766888a9beSDag-Erling Smørgrav * existing entry. 2776888a9beSDag-Erling Smørgrav */ 2786888a9beSDag-Erling Smørgrav if (ers->lo > lo) 2796888a9beSDag-Erling Smørgrav ers->lo = lo; 2806888a9beSDag-Erling Smørgrav if (ers->hi < hi) 2816888a9beSDag-Erling Smørgrav ers->hi = hi; 2826888a9beSDag-Erling Smørgrav } 283bc5531deSDag-Erling Smørgrav 2846888a9beSDag-Erling Smørgrav /* 2856888a9beSDag-Erling Smørgrav * The inserted or revised range might overlap or abut adjacent ones; 2866888a9beSDag-Erling Smørgrav * coalesce as necessary. 2876888a9beSDag-Erling Smørgrav */ 2886888a9beSDag-Erling Smørgrav 2896888a9beSDag-Erling Smørgrav /* Check predecessors */ 2906888a9beSDag-Erling Smørgrav while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) { 2916888a9beSDag-Erling Smørgrav KRL_DBG(("%s: pred %llu:%llu", __func__, crs->lo, crs->hi)); 2926888a9beSDag-Erling Smørgrav if (ers->lo != 0 && crs->hi < ers->lo - 1) 2936888a9beSDag-Erling Smørgrav break; 2946888a9beSDag-Erling Smørgrav /* This entry overlaps. */ 2956888a9beSDag-Erling Smørgrav if (crs->lo < ers->lo) { 2966888a9beSDag-Erling Smørgrav ers->lo = crs->lo; 2976888a9beSDag-Erling Smørgrav KRL_DBG(("%s: pred extend %llu:%llu", __func__, 2986888a9beSDag-Erling Smørgrav ers->lo, ers->hi)); 2996888a9beSDag-Erling Smørgrav } 3006888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_serial_tree, rt, crs); 3016888a9beSDag-Erling Smørgrav free(crs); 3026888a9beSDag-Erling Smørgrav } 3036888a9beSDag-Erling Smørgrav /* Check successors */ 3046888a9beSDag-Erling Smørgrav while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) { 3056888a9beSDag-Erling Smørgrav KRL_DBG(("%s: succ %llu:%llu", __func__, crs->lo, crs->hi)); 3066888a9beSDag-Erling Smørgrav if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1) 3076888a9beSDag-Erling Smørgrav break; 3086888a9beSDag-Erling Smørgrav /* This entry overlaps. */ 3096888a9beSDag-Erling Smørgrav if (crs->hi > ers->hi) { 3106888a9beSDag-Erling Smørgrav ers->hi = crs->hi; 3116888a9beSDag-Erling Smørgrav KRL_DBG(("%s: succ extend %llu:%llu", __func__, 3126888a9beSDag-Erling Smørgrav ers->lo, ers->hi)); 3136888a9beSDag-Erling Smørgrav } 3146888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_serial_tree, rt, crs); 3156888a9beSDag-Erling Smørgrav free(crs); 3166888a9beSDag-Erling Smørgrav } 3176888a9beSDag-Erling Smørgrav KRL_DBG(("%s: done, final %llu:%llu", __func__, ers->lo, ers->hi)); 3186888a9beSDag-Erling Smørgrav return 0; 3196888a9beSDag-Erling Smørgrav } 3206888a9beSDag-Erling Smørgrav 3216888a9beSDag-Erling Smørgrav int 322bc5531deSDag-Erling Smørgrav ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const struct sshkey *ca_key, 3236888a9beSDag-Erling Smørgrav u_int64_t serial) 3246888a9beSDag-Erling Smørgrav { 3256888a9beSDag-Erling Smørgrav return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial); 3266888a9beSDag-Erling Smørgrav } 3276888a9beSDag-Erling Smørgrav 3286888a9beSDag-Erling Smørgrav int 329bc5531deSDag-Erling Smørgrav ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, 330bc5531deSDag-Erling Smørgrav const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi) 3316888a9beSDag-Erling Smørgrav { 3326888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 333bc5531deSDag-Erling Smørgrav int r; 3346888a9beSDag-Erling Smørgrav 3356888a9beSDag-Erling Smørgrav if (lo > hi || lo == 0) 336bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 337bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0) 338bc5531deSDag-Erling Smørgrav return r; 3396888a9beSDag-Erling Smørgrav return insert_serial_range(&rc->revoked_serials, lo, hi); 3406888a9beSDag-Erling Smørgrav } 3416888a9beSDag-Erling Smørgrav 3426888a9beSDag-Erling Smørgrav int 343bc5531deSDag-Erling Smørgrav ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const struct sshkey *ca_key, 3446888a9beSDag-Erling Smørgrav const char *key_id) 3456888a9beSDag-Erling Smørgrav { 3466888a9beSDag-Erling Smørgrav struct revoked_key_id *rki, *erki; 3476888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 348bc5531deSDag-Erling Smørgrav int r; 3496888a9beSDag-Erling Smørgrav 350bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0) 351bc5531deSDag-Erling Smørgrav return r; 3526888a9beSDag-Erling Smørgrav 353bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoke %s", __func__, key_id)); 3546888a9beSDag-Erling Smørgrav if ((rki = calloc(1, sizeof(*rki))) == NULL || 3556888a9beSDag-Erling Smørgrav (rki->key_id = strdup(key_id)) == NULL) { 3566888a9beSDag-Erling Smørgrav free(rki); 357bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 3586888a9beSDag-Erling Smørgrav } 3596888a9beSDag-Erling Smørgrav erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki); 3606888a9beSDag-Erling Smørgrav if (erki != NULL) { 3616888a9beSDag-Erling Smørgrav free(rki->key_id); 3626888a9beSDag-Erling Smørgrav free(rki); 3636888a9beSDag-Erling Smørgrav } 3646888a9beSDag-Erling Smørgrav return 0; 3656888a9beSDag-Erling Smørgrav } 3666888a9beSDag-Erling Smørgrav 3676888a9beSDag-Erling Smørgrav /* Convert "key" to a public key blob without any certificate information */ 3686888a9beSDag-Erling Smørgrav static int 369bc5531deSDag-Erling Smørgrav plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen) 3706888a9beSDag-Erling Smørgrav { 371bc5531deSDag-Erling Smørgrav struct sshkey *kcopy; 3726888a9beSDag-Erling Smørgrav int r; 3736888a9beSDag-Erling Smørgrav 374bc5531deSDag-Erling Smørgrav if ((r = sshkey_from_private(key, &kcopy)) != 0) 375bc5531deSDag-Erling Smørgrav return r; 376bc5531deSDag-Erling Smørgrav if (sshkey_is_cert(kcopy)) { 377bc5531deSDag-Erling Smørgrav if ((r = sshkey_drop_cert(kcopy)) != 0) { 378bc5531deSDag-Erling Smørgrav sshkey_free(kcopy); 379bc5531deSDag-Erling Smørgrav return r; 3806888a9beSDag-Erling Smørgrav } 3816888a9beSDag-Erling Smørgrav } 382bc5531deSDag-Erling Smørgrav r = sshkey_to_blob(kcopy, blob, blen); 383bc5531deSDag-Erling Smørgrav sshkey_free(kcopy); 384a0ee8cc6SDag-Erling Smørgrav return r; 3856888a9beSDag-Erling Smørgrav } 3866888a9beSDag-Erling Smørgrav 3876888a9beSDag-Erling Smørgrav /* Revoke a key blob. Ownership of blob is transferred to the tree */ 3886888a9beSDag-Erling Smørgrav static int 389bc5531deSDag-Erling Smørgrav revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, size_t len) 3906888a9beSDag-Erling Smørgrav { 3916888a9beSDag-Erling Smørgrav struct revoked_blob *rb, *erb; 3926888a9beSDag-Erling Smørgrav 3936888a9beSDag-Erling Smørgrav if ((rb = calloc(1, sizeof(*rb))) == NULL) 394bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 3956888a9beSDag-Erling Smørgrav rb->blob = blob; 3966888a9beSDag-Erling Smørgrav rb->len = len; 3976888a9beSDag-Erling Smørgrav erb = RB_INSERT(revoked_blob_tree, rbt, rb); 3986888a9beSDag-Erling Smørgrav if (erb != NULL) { 3996888a9beSDag-Erling Smørgrav free(rb->blob); 4006888a9beSDag-Erling Smørgrav free(rb); 4016888a9beSDag-Erling Smørgrav } 4026888a9beSDag-Erling Smørgrav return 0; 4036888a9beSDag-Erling Smørgrav } 4046888a9beSDag-Erling Smørgrav 4056888a9beSDag-Erling Smørgrav int 406bc5531deSDag-Erling Smørgrav ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key) 4076888a9beSDag-Erling Smørgrav { 4086888a9beSDag-Erling Smørgrav u_char *blob; 409bc5531deSDag-Erling Smørgrav size_t len; 410bc5531deSDag-Erling Smørgrav int r; 4116888a9beSDag-Erling Smørgrav 412bc5531deSDag-Erling Smørgrav debug3("%s: revoke type %s", __func__, sshkey_type(key)); 413bc5531deSDag-Erling Smørgrav if ((r = plain_key_blob(key, &blob, &len)) != 0) 414bc5531deSDag-Erling Smørgrav return r; 4156888a9beSDag-Erling Smørgrav return revoke_blob(&krl->revoked_keys, blob, len); 4166888a9beSDag-Erling Smørgrav } 4176888a9beSDag-Erling Smørgrav 418*2f513db7SEd Maste static int 419*2f513db7SEd Maste revoke_by_hash(struct revoked_blob_tree *target, const u_char *p, size_t len) 4206888a9beSDag-Erling Smørgrav { 4216888a9beSDag-Erling Smørgrav u_char *blob; 422bc5531deSDag-Erling Smørgrav int r; 4236888a9beSDag-Erling Smørgrav 424*2f513db7SEd Maste /* need to copy hash, as revoke_blob steals ownership */ 425*2f513db7SEd Maste if ((blob = malloc(len)) == NULL) 426*2f513db7SEd Maste return SSH_ERR_SYSTEM_ERROR; 427*2f513db7SEd Maste memcpy(blob, p, len); 428*2f513db7SEd Maste if ((r = revoke_blob(target, blob, len)) != 0) { 429*2f513db7SEd Maste free(blob); 430bc5531deSDag-Erling Smørgrav return r; 431*2f513db7SEd Maste } 432*2f513db7SEd Maste return 0; 433*2f513db7SEd Maste } 434*2f513db7SEd Maste 435*2f513db7SEd Maste int 436*2f513db7SEd Maste ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len) 437*2f513db7SEd Maste { 438*2f513db7SEd Maste debug3("%s: revoke by sha1", __func__); 439*2f513db7SEd Maste if (len != 20) 440*2f513db7SEd Maste return SSH_ERR_INVALID_FORMAT; 441*2f513db7SEd Maste return revoke_by_hash(&krl->revoked_sha1s, p, len); 442*2f513db7SEd Maste } 443*2f513db7SEd Maste 444*2f513db7SEd Maste int 445*2f513db7SEd Maste ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len) 446*2f513db7SEd Maste { 447*2f513db7SEd Maste debug3("%s: revoke by sha256", __func__); 448*2f513db7SEd Maste if (len != 32) 449*2f513db7SEd Maste return SSH_ERR_INVALID_FORMAT; 450*2f513db7SEd Maste return revoke_by_hash(&krl->revoked_sha256s, p, len); 4516888a9beSDag-Erling Smørgrav } 4526888a9beSDag-Erling Smørgrav 4536888a9beSDag-Erling Smørgrav int 454bc5531deSDag-Erling Smørgrav ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key) 4556888a9beSDag-Erling Smørgrav { 456*2f513db7SEd Maste /* XXX replace with SHA256? */ 457bc5531deSDag-Erling Smørgrav if (!sshkey_is_cert(key)) 458*2f513db7SEd Maste return ssh_krl_revoke_key_explicit(krl, key); 4596888a9beSDag-Erling Smørgrav 460eccfee6eSDag-Erling Smørgrav if (key->cert->serial == 0) { 4616888a9beSDag-Erling Smørgrav return ssh_krl_revoke_cert_by_key_id(krl, 4626888a9beSDag-Erling Smørgrav key->cert->signature_key, 4636888a9beSDag-Erling Smørgrav key->cert->key_id); 4646888a9beSDag-Erling Smørgrav } else { 4656888a9beSDag-Erling Smørgrav return ssh_krl_revoke_cert_by_serial(krl, 4666888a9beSDag-Erling Smørgrav key->cert->signature_key, 4676888a9beSDag-Erling Smørgrav key->cert->serial); 4686888a9beSDag-Erling Smørgrav } 4696888a9beSDag-Erling Smørgrav } 4706888a9beSDag-Erling Smørgrav 4716888a9beSDag-Erling Smørgrav /* 472bc5531deSDag-Erling Smørgrav * Select the most compact section type to emit next in a KRL based on 473bc5531deSDag-Erling Smørgrav * the current section type, the run length of contiguous revoked serial 4746888a9beSDag-Erling Smørgrav * numbers and the gaps from the last and to the next revoked serial. 4756888a9beSDag-Erling Smørgrav * Applies a mostly-accurate bit cost model to select the section type 4766888a9beSDag-Erling Smørgrav * that will minimise the size of the resultant KRL. 4776888a9beSDag-Erling Smørgrav */ 4786888a9beSDag-Erling Smørgrav static int 4796888a9beSDag-Erling Smørgrav choose_next_state(int current_state, u_int64_t contig, int final, 4806888a9beSDag-Erling Smørgrav u_int64_t last_gap, u_int64_t next_gap, int *force_new_section) 4816888a9beSDag-Erling Smørgrav { 4826888a9beSDag-Erling Smørgrav int new_state; 4836888a9beSDag-Erling Smørgrav u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart; 4846888a9beSDag-Erling Smørgrav 4856888a9beSDag-Erling Smørgrav /* 4866888a9beSDag-Erling Smørgrav * Avoid unsigned overflows. 4876888a9beSDag-Erling Smørgrav * The limits are high enough to avoid confusing the calculations. 4886888a9beSDag-Erling Smørgrav */ 489ca86bcf2SDag-Erling Smørgrav contig = MINIMUM(contig, 1ULL<<31); 490ca86bcf2SDag-Erling Smørgrav last_gap = MINIMUM(last_gap, 1ULL<<31); 491ca86bcf2SDag-Erling Smørgrav next_gap = MINIMUM(next_gap, 1ULL<<31); 4926888a9beSDag-Erling Smørgrav 4936888a9beSDag-Erling Smørgrav /* 4946888a9beSDag-Erling Smørgrav * Calculate the cost to switch from the current state to candidates. 4956888a9beSDag-Erling Smørgrav * NB. range sections only ever contain a single range, so their 4966888a9beSDag-Erling Smørgrav * switching cost is independent of the current_state. 4976888a9beSDag-Erling Smørgrav */ 4986888a9beSDag-Erling Smørgrav cost_list = cost_bitmap = cost_bitmap_restart = 0; 4996888a9beSDag-Erling Smørgrav cost_range = 8; 5006888a9beSDag-Erling Smørgrav switch (current_state) { 5016888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 5026888a9beSDag-Erling Smørgrav cost_bitmap_restart = cost_bitmap = 8 + 64; 5036888a9beSDag-Erling Smørgrav break; 5046888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 5056888a9beSDag-Erling Smørgrav cost_list = 8; 5066888a9beSDag-Erling Smørgrav cost_bitmap_restart = 8 + 64; 5076888a9beSDag-Erling Smørgrav break; 5086888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 5096888a9beSDag-Erling Smørgrav case 0: 5106888a9beSDag-Erling Smørgrav cost_bitmap_restart = cost_bitmap = 8 + 64; 5116888a9beSDag-Erling Smørgrav cost_list = 8; 5126888a9beSDag-Erling Smørgrav } 5136888a9beSDag-Erling Smørgrav 5146888a9beSDag-Erling Smørgrav /* Estimate base cost in bits of each section type */ 5156888a9beSDag-Erling Smørgrav cost_list += 64 * contig + (final ? 0 : 8+64); 5166888a9beSDag-Erling Smørgrav cost_range += (2 * 64) + (final ? 0 : 8+64); 517ca86bcf2SDag-Erling Smørgrav cost_bitmap += last_gap + contig + (final ? 0 : MINIMUM(next_gap, 8+64)); 518ca86bcf2SDag-Erling Smørgrav cost_bitmap_restart += contig + (final ? 0 : MINIMUM(next_gap, 8+64)); 5196888a9beSDag-Erling Smørgrav 5206888a9beSDag-Erling Smørgrav /* Convert to byte costs for actual comparison */ 5216888a9beSDag-Erling Smørgrav cost_list = (cost_list + 7) / 8; 5226888a9beSDag-Erling Smørgrav cost_bitmap = (cost_bitmap + 7) / 8; 5236888a9beSDag-Erling Smørgrav cost_bitmap_restart = (cost_bitmap_restart + 7) / 8; 5246888a9beSDag-Erling Smørgrav cost_range = (cost_range + 7) / 8; 5256888a9beSDag-Erling Smørgrav 5266888a9beSDag-Erling Smørgrav /* Now pick the best choice */ 5276888a9beSDag-Erling Smørgrav *force_new_section = 0; 5286888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_BITMAP; 5296888a9beSDag-Erling Smørgrav cost = cost_bitmap; 5306888a9beSDag-Erling Smørgrav if (cost_range < cost) { 5316888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_RANGE; 5326888a9beSDag-Erling Smørgrav cost = cost_range; 5336888a9beSDag-Erling Smørgrav } 5346888a9beSDag-Erling Smørgrav if (cost_list < cost) { 5356888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_LIST; 5366888a9beSDag-Erling Smørgrav cost = cost_list; 5376888a9beSDag-Erling Smørgrav } 5386888a9beSDag-Erling Smørgrav if (cost_bitmap_restart < cost) { 5396888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_BITMAP; 5406888a9beSDag-Erling Smørgrav *force_new_section = 1; 5416888a9beSDag-Erling Smørgrav cost = cost_bitmap_restart; 5426888a9beSDag-Erling Smørgrav } 543bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:" 5446888a9beSDag-Erling Smørgrav "list %llu range %llu bitmap %llu new bitmap %llu, " 545e4a9863fSDag-Erling Smørgrav "selected 0x%02x%s", __func__, (long long unsigned)contig, 546e4a9863fSDag-Erling Smørgrav (long long unsigned)last_gap, (long long unsigned)next_gap, final, 547e4a9863fSDag-Erling Smørgrav (long long unsigned)cost_list, (long long unsigned)cost_range, 548e4a9863fSDag-Erling Smørgrav (long long unsigned)cost_bitmap, 549e4a9863fSDag-Erling Smørgrav (long long unsigned)cost_bitmap_restart, new_state, 550bc5531deSDag-Erling Smørgrav *force_new_section ? " restart" : "")); 5516888a9beSDag-Erling Smørgrav return new_state; 5526888a9beSDag-Erling Smørgrav } 5536888a9beSDag-Erling Smørgrav 554bc5531deSDag-Erling Smørgrav static int 555bc5531deSDag-Erling Smørgrav put_bitmap(struct sshbuf *buf, struct bitmap *bitmap) 556bc5531deSDag-Erling Smørgrav { 557bc5531deSDag-Erling Smørgrav size_t len; 558bc5531deSDag-Erling Smørgrav u_char *blob; 559bc5531deSDag-Erling Smørgrav int r; 560bc5531deSDag-Erling Smørgrav 561bc5531deSDag-Erling Smørgrav len = bitmap_nbytes(bitmap); 562bc5531deSDag-Erling Smørgrav if ((blob = malloc(len)) == NULL) 563bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 564bc5531deSDag-Erling Smørgrav if (bitmap_to_string(bitmap, blob, len) != 0) { 565bc5531deSDag-Erling Smørgrav free(blob); 566bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 567bc5531deSDag-Erling Smørgrav } 568bc5531deSDag-Erling Smørgrav r = sshbuf_put_bignum2_bytes(buf, blob, len); 569bc5531deSDag-Erling Smørgrav free(blob); 570bc5531deSDag-Erling Smørgrav return r; 571bc5531deSDag-Erling Smørgrav } 572bc5531deSDag-Erling Smørgrav 5736888a9beSDag-Erling Smørgrav /* Generate a KRL_SECTION_CERTIFICATES KRL section */ 5746888a9beSDag-Erling Smørgrav static int 575bc5531deSDag-Erling Smørgrav revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf) 5766888a9beSDag-Erling Smørgrav { 577bc5531deSDag-Erling Smørgrav int final, force_new_sect, r = SSH_ERR_INTERNAL_ERROR; 5786888a9beSDag-Erling Smørgrav u_int64_t i, contig, gap, last = 0, bitmap_start = 0; 5796888a9beSDag-Erling Smørgrav struct revoked_serial *rs, *nrs; 5806888a9beSDag-Erling Smørgrav struct revoked_key_id *rki; 5816888a9beSDag-Erling Smørgrav int next_state, state = 0; 582bc5531deSDag-Erling Smørgrav struct sshbuf *sect; 583bc5531deSDag-Erling Smørgrav struct bitmap *bitmap = NULL; 5846888a9beSDag-Erling Smørgrav 585bc5531deSDag-Erling Smørgrav if ((sect = sshbuf_new()) == NULL) 586bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 5876888a9beSDag-Erling Smørgrav 588bc5531deSDag-Erling Smørgrav /* Store the header: optional CA scope key, reserved */ 589bc5531deSDag-Erling Smørgrav if (rc->ca_key == NULL) { 590bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) 591bc5531deSDag-Erling Smørgrav goto out; 592bc5531deSDag-Erling Smørgrav } else { 593bc5531deSDag-Erling Smørgrav if ((r = sshkey_puts(rc->ca_key, buf)) != 0) 594bc5531deSDag-Erling Smørgrav goto out; 595bc5531deSDag-Erling Smørgrav } 596bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) 597bc5531deSDag-Erling Smørgrav goto out; 5986888a9beSDag-Erling Smørgrav 5996888a9beSDag-Erling Smørgrav /* Store the revoked serials. */ 6006888a9beSDag-Erling Smørgrav for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials); 6016888a9beSDag-Erling Smørgrav rs != NULL; 6026888a9beSDag-Erling Smørgrav rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) { 603bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: serial %llu:%llu state 0x%02x", __func__, 604e4a9863fSDag-Erling Smørgrav (long long unsigned)rs->lo, (long long unsigned)rs->hi, 605bc5531deSDag-Erling Smørgrav state)); 6066888a9beSDag-Erling Smørgrav 6076888a9beSDag-Erling Smørgrav /* Check contiguous length and gap to next section (if any) */ 6086888a9beSDag-Erling Smørgrav nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs); 6096888a9beSDag-Erling Smørgrav final = nrs == NULL; 6106888a9beSDag-Erling Smørgrav gap = nrs == NULL ? 0 : nrs->lo - rs->hi; 6116888a9beSDag-Erling Smørgrav contig = 1 + (rs->hi - rs->lo); 6126888a9beSDag-Erling Smørgrav 6136888a9beSDag-Erling Smørgrav /* Choose next state based on these */ 6146888a9beSDag-Erling Smørgrav next_state = choose_next_state(state, contig, final, 6156888a9beSDag-Erling Smørgrav state == 0 ? 0 : rs->lo - last, gap, &force_new_sect); 6166888a9beSDag-Erling Smørgrav 6176888a9beSDag-Erling Smørgrav /* 6186888a9beSDag-Erling Smørgrav * If the current section is a range section or has a different 6196888a9beSDag-Erling Smørgrav * type to the next section, then finish it off now. 6206888a9beSDag-Erling Smørgrav */ 6216888a9beSDag-Erling Smørgrav if (state != 0 && (force_new_sect || next_state != state || 6226888a9beSDag-Erling Smørgrav state == KRL_SECTION_CERT_SERIAL_RANGE)) { 623bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: finish state 0x%02x", __func__, state)); 6246888a9beSDag-Erling Smørgrav switch (state) { 6256888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 6266888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 6276888a9beSDag-Erling Smørgrav break; 6286888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 629bc5531deSDag-Erling Smørgrav if ((r = put_bitmap(sect, bitmap)) != 0) 630bc5531deSDag-Erling Smørgrav goto out; 631bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 6326888a9beSDag-Erling Smørgrav bitmap = NULL; 6336888a9beSDag-Erling Smørgrav break; 6346888a9beSDag-Erling Smørgrav } 635bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, state)) != 0 || 636bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 637bc5531deSDag-Erling Smørgrav goto out; 638bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 6396888a9beSDag-Erling Smørgrav } 6406888a9beSDag-Erling Smørgrav 6416888a9beSDag-Erling Smørgrav /* If we are starting a new section then prepare it now */ 6426888a9beSDag-Erling Smørgrav if (next_state != state || force_new_sect) { 643bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: start state 0x%02x", __func__, 644bc5531deSDag-Erling Smørgrav next_state)); 6456888a9beSDag-Erling Smørgrav state = next_state; 646bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 6476888a9beSDag-Erling Smørgrav switch (state) { 6486888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 6496888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 6506888a9beSDag-Erling Smørgrav break; 6516888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 652bc5531deSDag-Erling Smørgrav if ((bitmap = bitmap_new()) == NULL) { 653bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 6546888a9beSDag-Erling Smørgrav goto out; 655bc5531deSDag-Erling Smørgrav } 6566888a9beSDag-Erling Smørgrav bitmap_start = rs->lo; 657bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u64(sect, 658bc5531deSDag-Erling Smørgrav bitmap_start)) != 0) 659bc5531deSDag-Erling Smørgrav goto out; 6606888a9beSDag-Erling Smørgrav break; 6616888a9beSDag-Erling Smørgrav } 6626888a9beSDag-Erling Smørgrav } 6636888a9beSDag-Erling Smørgrav 6646888a9beSDag-Erling Smørgrav /* Perform section-specific processing */ 6656888a9beSDag-Erling Smørgrav switch (state) { 6666888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 667bc5531deSDag-Erling Smørgrav for (i = 0; i < contig; i++) { 668bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u64(sect, rs->lo + i)) != 0) 669bc5531deSDag-Erling Smørgrav goto out; 670bc5531deSDag-Erling Smørgrav } 6716888a9beSDag-Erling Smørgrav break; 6726888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 673bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u64(sect, rs->lo)) != 0 || 674bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u64(sect, rs->hi)) != 0) 675bc5531deSDag-Erling Smørgrav goto out; 6766888a9beSDag-Erling Smørgrav break; 6776888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 6786888a9beSDag-Erling Smørgrav if (rs->lo - bitmap_start > INT_MAX) { 6796888a9beSDag-Erling Smørgrav error("%s: insane bitmap gap", __func__); 6806888a9beSDag-Erling Smørgrav goto out; 6816888a9beSDag-Erling Smørgrav } 6826888a9beSDag-Erling Smørgrav for (i = 0; i < contig; i++) { 683bc5531deSDag-Erling Smørgrav if (bitmap_set_bit(bitmap, 684bc5531deSDag-Erling Smørgrav rs->lo + i - bitmap_start) != 0) { 685bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 6866888a9beSDag-Erling Smørgrav goto out; 6876888a9beSDag-Erling Smørgrav } 688bc5531deSDag-Erling Smørgrav } 6896888a9beSDag-Erling Smørgrav break; 6906888a9beSDag-Erling Smørgrav } 6916888a9beSDag-Erling Smørgrav last = rs->hi; 6926888a9beSDag-Erling Smørgrav } 6936888a9beSDag-Erling Smørgrav /* Flush the remaining section, if any */ 6946888a9beSDag-Erling Smørgrav if (state != 0) { 695bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: serial final flush for state 0x%02x", 696bc5531deSDag-Erling Smørgrav __func__, state)); 6976888a9beSDag-Erling Smørgrav switch (state) { 6986888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 6996888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 7006888a9beSDag-Erling Smørgrav break; 7016888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 702bc5531deSDag-Erling Smørgrav if ((r = put_bitmap(sect, bitmap)) != 0) 703bc5531deSDag-Erling Smørgrav goto out; 704bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 7056888a9beSDag-Erling Smørgrav bitmap = NULL; 7066888a9beSDag-Erling Smørgrav break; 7076888a9beSDag-Erling Smørgrav } 708bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, state)) != 0 || 709bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 710bc5531deSDag-Erling Smørgrav goto out; 7116888a9beSDag-Erling Smørgrav } 712bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: serial done ", __func__)); 7136888a9beSDag-Erling Smørgrav 7146888a9beSDag-Erling Smørgrav /* Now output a section for any revocations by key ID */ 715bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 7166888a9beSDag-Erling Smørgrav RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) { 717bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: key ID %s", __func__, rki->key_id)); 718bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_cstring(sect, rki->key_id)) != 0) 719bc5531deSDag-Erling Smørgrav goto out; 7206888a9beSDag-Erling Smørgrav } 721bc5531deSDag-Erling Smørgrav if (sshbuf_len(sect) != 0) { 722bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERT_KEY_ID)) != 0 || 723bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 724bc5531deSDag-Erling Smørgrav goto out; 7256888a9beSDag-Erling Smørgrav } 7266888a9beSDag-Erling Smørgrav r = 0; 7276888a9beSDag-Erling Smørgrav out: 728bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 729bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 7306888a9beSDag-Erling Smørgrav return r; 7316888a9beSDag-Erling Smørgrav } 7326888a9beSDag-Erling Smørgrav 7336888a9beSDag-Erling Smørgrav int 734bc5531deSDag-Erling Smørgrav ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, 735bc5531deSDag-Erling Smørgrav const struct sshkey **sign_keys, u_int nsign_keys) 7366888a9beSDag-Erling Smørgrav { 737bc5531deSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR; 7386888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 7396888a9beSDag-Erling Smørgrav struct revoked_blob *rb; 740bc5531deSDag-Erling Smørgrav struct sshbuf *sect; 741bc5531deSDag-Erling Smørgrav u_char *sblob = NULL; 742bc5531deSDag-Erling Smørgrav size_t slen, i; 7436888a9beSDag-Erling Smørgrav 7446888a9beSDag-Erling Smørgrav if (krl->generated_date == 0) 7456888a9beSDag-Erling Smørgrav krl->generated_date = time(NULL); 7466888a9beSDag-Erling Smørgrav 747bc5531deSDag-Erling Smørgrav if ((sect = sshbuf_new()) == NULL) 748bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 7496888a9beSDag-Erling Smørgrav 7506888a9beSDag-Erling Smørgrav /* Store the header */ 751bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 || 752bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 || 753bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u64(buf, krl->krl_version)) != 0 || 754acc1a9efSDag-Erling Smørgrav (r = sshbuf_put_u64(buf, krl->generated_date)) != 0 || 755bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u64(buf, krl->flags)) != 0 || 756bc5531deSDag-Erling Smørgrav (r = sshbuf_put_string(buf, NULL, 0)) != 0 || 757bc5531deSDag-Erling Smørgrav (r = sshbuf_put_cstring(buf, krl->comment)) != 0) 758bc5531deSDag-Erling Smørgrav goto out; 7596888a9beSDag-Erling Smørgrav 7606888a9beSDag-Erling Smørgrav /* Store sections for revoked certificates */ 7616888a9beSDag-Erling Smørgrav TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 762bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 763bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_generate(rc, sect)) != 0) 7646888a9beSDag-Erling Smørgrav goto out; 765bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 || 766bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 767bc5531deSDag-Erling Smørgrav goto out; 7686888a9beSDag-Erling Smørgrav } 7696888a9beSDag-Erling Smørgrav 7706888a9beSDag-Erling Smørgrav /* Finally, output sections for revocations by public key/hash */ 771bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 7726888a9beSDag-Erling Smørgrav RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { 773bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: key len %zu ", __func__, rb->len)); 774bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 775bc5531deSDag-Erling Smørgrav goto out; 7766888a9beSDag-Erling Smørgrav } 777bc5531deSDag-Erling Smørgrav if (sshbuf_len(sect) != 0) { 778bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 || 779bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 780bc5531deSDag-Erling Smørgrav goto out; 7816888a9beSDag-Erling Smørgrav } 782bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 7836888a9beSDag-Erling Smørgrav RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { 784bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: hash len %zu ", __func__, rb->len)); 785bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 786bc5531deSDag-Erling Smørgrav goto out; 7876888a9beSDag-Erling Smørgrav } 788bc5531deSDag-Erling Smørgrav if (sshbuf_len(sect) != 0) { 789bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, 790bc5531deSDag-Erling Smørgrav KRL_SECTION_FINGERPRINT_SHA1)) != 0 || 791bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 792bc5531deSDag-Erling Smørgrav goto out; 7936888a9beSDag-Erling Smørgrav } 794*2f513db7SEd Maste sshbuf_reset(sect); 795*2f513db7SEd Maste RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) { 796*2f513db7SEd Maste KRL_DBG(("%s: hash len %zu ", __func__, rb->len)); 797*2f513db7SEd Maste if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 798*2f513db7SEd Maste goto out; 799*2f513db7SEd Maste } 800*2f513db7SEd Maste if (sshbuf_len(sect) != 0) { 801*2f513db7SEd Maste if ((r = sshbuf_put_u8(buf, 802*2f513db7SEd Maste KRL_SECTION_FINGERPRINT_SHA256)) != 0 || 803*2f513db7SEd Maste (r = sshbuf_put_stringb(buf, sect)) != 0) 804*2f513db7SEd Maste goto out; 805*2f513db7SEd Maste } 8066888a9beSDag-Erling Smørgrav 8076888a9beSDag-Erling Smørgrav for (i = 0; i < nsign_keys; i++) { 808bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: signature key %s", __func__, 809bc5531deSDag-Erling Smørgrav sshkey_ssh_name(sign_keys[i]))); 810bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 || 811bc5531deSDag-Erling Smørgrav (r = sshkey_puts(sign_keys[i], buf)) != 0) 8126888a9beSDag-Erling Smørgrav goto out; 8136888a9beSDag-Erling Smørgrav 814bc5531deSDag-Erling Smørgrav if ((r = sshkey_sign(sign_keys[i], &sblob, &slen, 815acc1a9efSDag-Erling Smørgrav sshbuf_ptr(buf), sshbuf_len(buf), NULL, 0)) != 0) 8166888a9beSDag-Erling Smørgrav goto out; 817bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: signature sig len %zu", __func__, slen)); 818bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(buf, sblob, slen)) != 0) 819bc5531deSDag-Erling Smørgrav goto out; 8206888a9beSDag-Erling Smørgrav } 8216888a9beSDag-Erling Smørgrav 8226888a9beSDag-Erling Smørgrav r = 0; 8236888a9beSDag-Erling Smørgrav out: 8246888a9beSDag-Erling Smørgrav free(sblob); 825bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 8266888a9beSDag-Erling Smørgrav return r; 8276888a9beSDag-Erling Smørgrav } 8286888a9beSDag-Erling Smørgrav 8296888a9beSDag-Erling Smørgrav static void 8306888a9beSDag-Erling Smørgrav format_timestamp(u_int64_t timestamp, char *ts, size_t nts) 8316888a9beSDag-Erling Smørgrav { 8326888a9beSDag-Erling Smørgrav time_t t; 8336888a9beSDag-Erling Smørgrav struct tm *tm; 8346888a9beSDag-Erling Smørgrav 8356888a9beSDag-Erling Smørgrav t = timestamp; 8366888a9beSDag-Erling Smørgrav tm = localtime(&t); 837bc5531deSDag-Erling Smørgrav if (tm == NULL) 838bc5531deSDag-Erling Smørgrav strlcpy(ts, "<INVALID>", nts); 839bc5531deSDag-Erling Smørgrav else { 8406888a9beSDag-Erling Smørgrav *ts = '\0'; 8416888a9beSDag-Erling Smørgrav strftime(ts, nts, "%Y%m%dT%H%M%S", tm); 8426888a9beSDag-Erling Smørgrav } 843bc5531deSDag-Erling Smørgrav } 8446888a9beSDag-Erling Smørgrav 8456888a9beSDag-Erling Smørgrav static int 846bc5531deSDag-Erling Smørgrav parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl) 8476888a9beSDag-Erling Smørgrav { 848bc5531deSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR; 849a0ee8cc6SDag-Erling Smørgrav u_char type; 850a0ee8cc6SDag-Erling Smørgrav const u_char *blob; 851bc5531deSDag-Erling Smørgrav size_t blen, nbits; 852bc5531deSDag-Erling Smørgrav struct sshbuf *subsect = NULL; 8536888a9beSDag-Erling Smørgrav u_int64_t serial, serial_lo, serial_hi; 854bc5531deSDag-Erling Smørgrav struct bitmap *bitmap = NULL; 8556888a9beSDag-Erling Smørgrav char *key_id = NULL; 856bc5531deSDag-Erling Smørgrav struct sshkey *ca_key = NULL; 8576888a9beSDag-Erling Smørgrav 858bc5531deSDag-Erling Smørgrav if ((subsect = sshbuf_new()) == NULL) 859bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 8606888a9beSDag-Erling Smørgrav 861bc5531deSDag-Erling Smørgrav /* Header: key, reserved */ 862bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || 863bc5531deSDag-Erling Smørgrav (r = sshbuf_skip_string(buf)) != 0) 8646888a9beSDag-Erling Smørgrav goto out; 865bc5531deSDag-Erling Smørgrav if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0) 866bc5531deSDag-Erling Smørgrav goto out; 867bc5531deSDag-Erling Smørgrav 868bc5531deSDag-Erling Smørgrav while (sshbuf_len(buf) > 0) { 869bc5531deSDag-Erling Smørgrav sshbuf_free(subsect); 870bc5531deSDag-Erling Smørgrav subsect = NULL; 871bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(buf, &type)) != 0 || 872bc5531deSDag-Erling Smørgrav (r = sshbuf_froms(buf, &subsect)) != 0) 8736888a9beSDag-Erling Smørgrav goto out; 874bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: subsection type 0x%02x", __func__, type)); 875bc5531deSDag-Erling Smørgrav /* sshbuf_dump(subsect, stderr); */ 8766888a9beSDag-Erling Smørgrav 8776888a9beSDag-Erling Smørgrav switch (type) { 8786888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 879bc5531deSDag-Erling Smørgrav while (sshbuf_len(subsect) > 0) { 880bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(subsect, &serial)) != 0) 8816888a9beSDag-Erling Smørgrav goto out; 882bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_serial(krl, 883bc5531deSDag-Erling Smørgrav ca_key, serial)) != 0) 8846888a9beSDag-Erling Smørgrav goto out; 8856888a9beSDag-Erling Smørgrav } 8866888a9beSDag-Erling Smørgrav break; 8876888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 888bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || 889bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u64(subsect, &serial_hi)) != 0) 8906888a9beSDag-Erling Smørgrav goto out; 891bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_serial_range(krl, 892bc5531deSDag-Erling Smørgrav ca_key, serial_lo, serial_hi)) != 0) 8936888a9beSDag-Erling Smørgrav goto out; 8946888a9beSDag-Erling Smørgrav break; 8956888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 896bc5531deSDag-Erling Smørgrav if ((bitmap = bitmap_new()) == NULL) { 897bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 8986888a9beSDag-Erling Smørgrav goto out; 8996888a9beSDag-Erling Smørgrav } 900bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || 901bc5531deSDag-Erling Smørgrav (r = sshbuf_get_bignum2_bytes_direct(subsect, 902bc5531deSDag-Erling Smørgrav &blob, &blen)) != 0) 903bc5531deSDag-Erling Smørgrav goto out; 904bc5531deSDag-Erling Smørgrav if (bitmap_from_string(bitmap, blob, blen) != 0) { 905bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9066888a9beSDag-Erling Smørgrav goto out; 9076888a9beSDag-Erling Smørgrav } 908bc5531deSDag-Erling Smørgrav nbits = bitmap_nbits(bitmap); 909bc5531deSDag-Erling Smørgrav for (serial = 0; serial < (u_int64_t)nbits; serial++) { 9106888a9beSDag-Erling Smørgrav if (serial > 0 && serial_lo + serial == 0) { 9116888a9beSDag-Erling Smørgrav error("%s: bitmap wraps u64", __func__); 912bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9136888a9beSDag-Erling Smørgrav goto out; 9146888a9beSDag-Erling Smørgrav } 915bc5531deSDag-Erling Smørgrav if (!bitmap_test_bit(bitmap, serial)) 9166888a9beSDag-Erling Smørgrav continue; 917bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_serial(krl, 918bc5531deSDag-Erling Smørgrav ca_key, serial_lo + serial)) != 0) 9196888a9beSDag-Erling Smørgrav goto out; 9206888a9beSDag-Erling Smørgrav } 921bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 9226888a9beSDag-Erling Smørgrav bitmap = NULL; 9236888a9beSDag-Erling Smørgrav break; 9246888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_KEY_ID: 925bc5531deSDag-Erling Smørgrav while (sshbuf_len(subsect) > 0) { 926bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(subsect, 927bc5531deSDag-Erling Smørgrav &key_id, NULL)) != 0) 9286888a9beSDag-Erling Smørgrav goto out; 929bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_key_id(krl, 930bc5531deSDag-Erling Smørgrav ca_key, key_id)) != 0) 9316888a9beSDag-Erling Smørgrav goto out; 9326888a9beSDag-Erling Smørgrav free(key_id); 9336888a9beSDag-Erling Smørgrav key_id = NULL; 9346888a9beSDag-Erling Smørgrav } 9356888a9beSDag-Erling Smørgrav break; 9366888a9beSDag-Erling Smørgrav default: 9376888a9beSDag-Erling Smørgrav error("Unsupported KRL certificate section %u", type); 938bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9396888a9beSDag-Erling Smørgrav goto out; 9406888a9beSDag-Erling Smørgrav } 941bc5531deSDag-Erling Smørgrav if (sshbuf_len(subsect) > 0) { 9426888a9beSDag-Erling Smørgrav error("KRL certificate section contains unparsed data"); 943bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9446888a9beSDag-Erling Smørgrav goto out; 9456888a9beSDag-Erling Smørgrav } 9466888a9beSDag-Erling Smørgrav } 9476888a9beSDag-Erling Smørgrav 948bc5531deSDag-Erling Smørgrav r = 0; 9496888a9beSDag-Erling Smørgrav out: 9506888a9beSDag-Erling Smørgrav if (bitmap != NULL) 951bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 9526888a9beSDag-Erling Smørgrav free(key_id); 953bc5531deSDag-Erling Smørgrav sshkey_free(ca_key); 954bc5531deSDag-Erling Smørgrav sshbuf_free(subsect); 955bc5531deSDag-Erling Smørgrav return r; 9566888a9beSDag-Erling Smørgrav } 9576888a9beSDag-Erling Smørgrav 958*2f513db7SEd Maste static int 959*2f513db7SEd Maste blob_section(struct sshbuf *sect, struct revoked_blob_tree *target_tree, 960*2f513db7SEd Maste size_t expected_len) 961*2f513db7SEd Maste { 962*2f513db7SEd Maste u_char *rdata = NULL; 963*2f513db7SEd Maste size_t rlen = 0; 964*2f513db7SEd Maste int r; 965*2f513db7SEd Maste 966*2f513db7SEd Maste while (sshbuf_len(sect) > 0) { 967*2f513db7SEd Maste if ((r = sshbuf_get_string(sect, &rdata, &rlen)) != 0) 968*2f513db7SEd Maste return r; 969*2f513db7SEd Maste if (expected_len != 0 && rlen != expected_len) { 970*2f513db7SEd Maste error("%s: bad length", __func__); 971*2f513db7SEd Maste free(rdata); 972*2f513db7SEd Maste return SSH_ERR_INVALID_FORMAT; 973*2f513db7SEd Maste } 974*2f513db7SEd Maste if ((r = revoke_blob(target_tree, rdata, rlen)) != 0) { 975*2f513db7SEd Maste free(rdata); 976*2f513db7SEd Maste return r; 977*2f513db7SEd Maste } 978*2f513db7SEd Maste } 979*2f513db7SEd Maste return 0; 980*2f513db7SEd Maste } 9816888a9beSDag-Erling Smørgrav 9826888a9beSDag-Erling Smørgrav /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ 9836888a9beSDag-Erling Smørgrav int 984bc5531deSDag-Erling Smørgrav ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, 985bc5531deSDag-Erling Smørgrav const struct sshkey **sign_ca_keys, size_t nsign_ca_keys) 9866888a9beSDag-Erling Smørgrav { 987bc5531deSDag-Erling Smørgrav struct sshbuf *copy = NULL, *sect = NULL; 988bc5531deSDag-Erling Smørgrav struct ssh_krl *krl = NULL; 9896888a9beSDag-Erling Smørgrav char timestamp[64]; 990bc5531deSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR, sig_seen; 991bc5531deSDag-Erling Smørgrav struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used; 992*2f513db7SEd Maste u_char type; 993a0ee8cc6SDag-Erling Smørgrav const u_char *blob; 994*2f513db7SEd Maste size_t i, j, sig_off, sects_off, blen, nca_used; 995bc5531deSDag-Erling Smørgrav u_int format_version; 9966888a9beSDag-Erling Smørgrav 997e4a9863fSDag-Erling Smørgrav nca_used = 0; 9986888a9beSDag-Erling Smørgrav *krlp = NULL; 999bc5531deSDag-Erling Smørgrav if (sshbuf_len(buf) < sizeof(KRL_MAGIC) - 1 || 1000bc5531deSDag-Erling Smørgrav memcmp(sshbuf_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) { 10016888a9beSDag-Erling Smørgrav debug3("%s: not a KRL", __func__); 1002bc5531deSDag-Erling Smørgrav return SSH_ERR_KRL_BAD_MAGIC; 10036888a9beSDag-Erling Smørgrav } 10046888a9beSDag-Erling Smørgrav 10056888a9beSDag-Erling Smørgrav /* Take a copy of the KRL buffer so we can verify its signature later */ 1006bc5531deSDag-Erling Smørgrav if ((copy = sshbuf_fromb(buf)) == NULL) { 1007bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 1008bc5531deSDag-Erling Smørgrav goto out; 1009bc5531deSDag-Erling Smørgrav } 1010bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0) 1011bc5531deSDag-Erling Smørgrav goto out; 10126888a9beSDag-Erling Smørgrav 10136888a9beSDag-Erling Smørgrav if ((krl = ssh_krl_init()) == NULL) { 10146888a9beSDag-Erling Smørgrav error("%s: alloc failed", __func__); 10156888a9beSDag-Erling Smørgrav goto out; 10166888a9beSDag-Erling Smørgrav } 10176888a9beSDag-Erling Smørgrav 1018bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u32(copy, &format_version)) != 0) 10196888a9beSDag-Erling Smørgrav goto out; 10206888a9beSDag-Erling Smørgrav if (format_version != KRL_FORMAT_VERSION) { 1021bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10226888a9beSDag-Erling Smørgrav goto out; 10236888a9beSDag-Erling Smørgrav } 1024bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 || 1025bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 || 1026bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u64(copy, &krl->flags)) != 0 || 1027bc5531deSDag-Erling Smørgrav (r = sshbuf_skip_string(copy)) != 0 || 1028bc5531deSDag-Erling Smørgrav (r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0) 10296888a9beSDag-Erling Smørgrav goto out; 10306888a9beSDag-Erling Smørgrav 10316888a9beSDag-Erling Smørgrav format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); 103259928918SDag-Erling Smørgrav debug("KRL version %llu generated at %s%s%s", 1033e4a9863fSDag-Erling Smørgrav (long long unsigned)krl->krl_version, timestamp, 103459928918SDag-Erling Smørgrav *krl->comment ? ": " : "", krl->comment); 10356888a9beSDag-Erling Smørgrav 10366888a9beSDag-Erling Smørgrav /* 10376888a9beSDag-Erling Smørgrav * 1st pass: verify signatures, if any. This is done to avoid 10386888a9beSDag-Erling Smørgrav * detailed parsing of data whose provenance is unverified. 10396888a9beSDag-Erling Smørgrav */ 10406888a9beSDag-Erling Smørgrav sig_seen = 0; 1041bc5531deSDag-Erling Smørgrav if (sshbuf_len(buf) < sshbuf_len(copy)) { 1042bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 1043bc5531deSDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 10446888a9beSDag-Erling Smørgrav goto out; 10456888a9beSDag-Erling Smørgrav } 1046bc5531deSDag-Erling Smørgrav sects_off = sshbuf_len(buf) - sshbuf_len(copy); 1047bc5531deSDag-Erling Smørgrav while (sshbuf_len(copy) > 0) { 1048bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(copy, &type)) != 0 || 1049bc5531deSDag-Erling Smørgrav (r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) 1050bc5531deSDag-Erling Smørgrav goto out; 1051bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: first pass, section 0x%02x", __func__, type)); 10526888a9beSDag-Erling Smørgrav if (type != KRL_SECTION_SIGNATURE) { 10536888a9beSDag-Erling Smørgrav if (sig_seen) { 10546888a9beSDag-Erling Smørgrav error("KRL contains non-signature section " 10556888a9beSDag-Erling Smørgrav "after signature"); 1056bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10576888a9beSDag-Erling Smørgrav goto out; 10586888a9beSDag-Erling Smørgrav } 10596888a9beSDag-Erling Smørgrav /* Not interested for now. */ 10606888a9beSDag-Erling Smørgrav continue; 10616888a9beSDag-Erling Smørgrav } 10626888a9beSDag-Erling Smørgrav sig_seen = 1; 10636888a9beSDag-Erling Smørgrav /* First string component is the signing key */ 1064bc5531deSDag-Erling Smørgrav if ((r = sshkey_from_blob(blob, blen, &key)) != 0) { 1065bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10666888a9beSDag-Erling Smørgrav goto out; 10676888a9beSDag-Erling Smørgrav } 1068bc5531deSDag-Erling Smørgrav if (sshbuf_len(buf) < sshbuf_len(copy)) { 1069bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 1070bc5531deSDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 1071bc5531deSDag-Erling Smørgrav goto out; 1072bc5531deSDag-Erling Smørgrav } 1073bc5531deSDag-Erling Smørgrav sig_off = sshbuf_len(buf) - sshbuf_len(copy); 10746888a9beSDag-Erling Smørgrav /* Second string component is the signature itself */ 1075bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) { 1076bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10776888a9beSDag-Erling Smørgrav goto out; 10786888a9beSDag-Erling Smørgrav } 10796888a9beSDag-Erling Smørgrav /* Check signature over entire KRL up to this point */ 1080bc5531deSDag-Erling Smørgrav if ((r = sshkey_verify(key, blob, blen, 108147dd1d1bSDag-Erling Smørgrav sshbuf_ptr(buf), sig_off, NULL, 0)) != 0) 10826888a9beSDag-Erling Smørgrav goto out; 10836888a9beSDag-Erling Smørgrav /* Check if this key has already signed this KRL */ 10846888a9beSDag-Erling Smørgrav for (i = 0; i < nca_used; i++) { 1085bc5531deSDag-Erling Smørgrav if (sshkey_equal(ca_used[i], key)) { 10866888a9beSDag-Erling Smørgrav error("KRL signed more than once with " 10876888a9beSDag-Erling Smørgrav "the same key"); 1088bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10896888a9beSDag-Erling Smørgrav goto out; 10906888a9beSDag-Erling Smørgrav } 10916888a9beSDag-Erling Smørgrav } 10926888a9beSDag-Erling Smørgrav /* Record keys used to sign the KRL */ 10934f52dfbbSDag-Erling Smørgrav tmp_ca_used = recallocarray(ca_used, nca_used, nca_used + 1, 1094bc5531deSDag-Erling Smørgrav sizeof(*ca_used)); 1095bc5531deSDag-Erling Smørgrav if (tmp_ca_used == NULL) { 1096bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 1097bc5531deSDag-Erling Smørgrav goto out; 1098bc5531deSDag-Erling Smørgrav } 1099bc5531deSDag-Erling Smørgrav ca_used = tmp_ca_used; 11006888a9beSDag-Erling Smørgrav ca_used[nca_used++] = key; 11016888a9beSDag-Erling Smørgrav key = NULL; 11026888a9beSDag-Erling Smørgrav } 11036888a9beSDag-Erling Smørgrav 1104bc5531deSDag-Erling Smørgrav if (sshbuf_len(copy) != 0) { 1105bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 1106bc5531deSDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 1107bc5531deSDag-Erling Smørgrav goto out; 1108bc5531deSDag-Erling Smørgrav } 1109bc5531deSDag-Erling Smørgrav 11106888a9beSDag-Erling Smørgrav /* 11116888a9beSDag-Erling Smørgrav * 2nd pass: parse and load the KRL, skipping the header to the point 11126888a9beSDag-Erling Smørgrav * where the section start. 11136888a9beSDag-Erling Smørgrav */ 1114bc5531deSDag-Erling Smørgrav sshbuf_free(copy); 1115bc5531deSDag-Erling Smørgrav if ((copy = sshbuf_fromb(buf)) == NULL) { 1116bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 11176888a9beSDag-Erling Smørgrav goto out; 11186888a9beSDag-Erling Smørgrav } 1119bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(copy, sects_off)) != 0) 1120bc5531deSDag-Erling Smørgrav goto out; 1121bc5531deSDag-Erling Smørgrav while (sshbuf_len(copy) > 0) { 1122bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 1123bc5531deSDag-Erling Smørgrav sect = NULL; 1124bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(copy, &type)) != 0 || 1125bc5531deSDag-Erling Smørgrav (r = sshbuf_froms(copy, §)) != 0) 1126bc5531deSDag-Erling Smørgrav goto out; 1127bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: second pass, section 0x%02x", __func__, type)); 11286888a9beSDag-Erling Smørgrav 11296888a9beSDag-Erling Smørgrav switch (type) { 11306888a9beSDag-Erling Smørgrav case KRL_SECTION_CERTIFICATES: 1131bc5531deSDag-Erling Smørgrav if ((r = parse_revoked_certs(sect, krl)) != 0) 11326888a9beSDag-Erling Smørgrav goto out; 11336888a9beSDag-Erling Smørgrav break; 11346888a9beSDag-Erling Smørgrav case KRL_SECTION_EXPLICIT_KEY: 1135*2f513db7SEd Maste if ((r = blob_section(sect, 1136*2f513db7SEd Maste &krl->revoked_keys, 0)) != 0) 1137*2f513db7SEd Maste goto out; 1138*2f513db7SEd Maste break; 11396888a9beSDag-Erling Smørgrav case KRL_SECTION_FINGERPRINT_SHA1: 1140*2f513db7SEd Maste if ((r = blob_section(sect, 1141*2f513db7SEd Maste &krl->revoked_sha1s, 20)) != 0) 11426888a9beSDag-Erling Smørgrav goto out; 1143*2f513db7SEd Maste break; 1144*2f513db7SEd Maste case KRL_SECTION_FINGERPRINT_SHA256: 1145*2f513db7SEd Maste if ((r = blob_section(sect, 1146*2f513db7SEd Maste &krl->revoked_sha256s, 32)) != 0) 11476888a9beSDag-Erling Smørgrav goto out; 11486888a9beSDag-Erling Smørgrav break; 11496888a9beSDag-Erling Smørgrav case KRL_SECTION_SIGNATURE: 11506888a9beSDag-Erling Smørgrav /* Handled above, but still need to stay in synch */ 1151d93a896eSDag-Erling Smørgrav sshbuf_free(sect); 1152bc5531deSDag-Erling Smørgrav sect = NULL; 1153bc5531deSDag-Erling Smørgrav if ((r = sshbuf_skip_string(copy)) != 0) 11546888a9beSDag-Erling Smørgrav goto out; 11556888a9beSDag-Erling Smørgrav break; 11566888a9beSDag-Erling Smørgrav default: 11576888a9beSDag-Erling Smørgrav error("Unsupported KRL section %u", type); 1158bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 11596888a9beSDag-Erling Smørgrav goto out; 11606888a9beSDag-Erling Smørgrav } 1161acc1a9efSDag-Erling Smørgrav if (sect != NULL && sshbuf_len(sect) > 0) { 11626888a9beSDag-Erling Smørgrav error("KRL section contains unparsed data"); 1163bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 11646888a9beSDag-Erling Smørgrav goto out; 11656888a9beSDag-Erling Smørgrav } 11666888a9beSDag-Erling Smørgrav } 11676888a9beSDag-Erling Smørgrav 11686888a9beSDag-Erling Smørgrav /* Check that the key(s) used to sign the KRL weren't revoked */ 11696888a9beSDag-Erling Smørgrav sig_seen = 0; 11706888a9beSDag-Erling Smørgrav for (i = 0; i < nca_used; i++) { 11716888a9beSDag-Erling Smørgrav if (ssh_krl_check_key(krl, ca_used[i]) == 0) 11726888a9beSDag-Erling Smørgrav sig_seen = 1; 11736888a9beSDag-Erling Smørgrav else { 1174bc5531deSDag-Erling Smørgrav sshkey_free(ca_used[i]); 11756888a9beSDag-Erling Smørgrav ca_used[i] = NULL; 11766888a9beSDag-Erling Smørgrav } 11776888a9beSDag-Erling Smørgrav } 11786888a9beSDag-Erling Smørgrav if (nca_used && !sig_seen) { 11796888a9beSDag-Erling Smørgrav error("All keys used to sign KRL were revoked"); 1180bc5531deSDag-Erling Smørgrav r = SSH_ERR_KEY_REVOKED; 11816888a9beSDag-Erling Smørgrav goto out; 11826888a9beSDag-Erling Smørgrav } 11836888a9beSDag-Erling Smørgrav 11846888a9beSDag-Erling Smørgrav /* If we have CA keys, then verify that one was used to sign the KRL */ 11856888a9beSDag-Erling Smørgrav if (sig_seen && nsign_ca_keys != 0) { 11866888a9beSDag-Erling Smørgrav sig_seen = 0; 11876888a9beSDag-Erling Smørgrav for (i = 0; !sig_seen && i < nsign_ca_keys; i++) { 11886888a9beSDag-Erling Smørgrav for (j = 0; j < nca_used; j++) { 11896888a9beSDag-Erling Smørgrav if (ca_used[j] == NULL) 11906888a9beSDag-Erling Smørgrav continue; 1191bc5531deSDag-Erling Smørgrav if (sshkey_equal(ca_used[j], sign_ca_keys[i])) { 11926888a9beSDag-Erling Smørgrav sig_seen = 1; 11936888a9beSDag-Erling Smørgrav break; 11946888a9beSDag-Erling Smørgrav } 11956888a9beSDag-Erling Smørgrav } 11966888a9beSDag-Erling Smørgrav } 11976888a9beSDag-Erling Smørgrav if (!sig_seen) { 1198bc5531deSDag-Erling Smørgrav r = SSH_ERR_SIGNATURE_INVALID; 11996888a9beSDag-Erling Smørgrav error("KRL not signed with any trusted key"); 12006888a9beSDag-Erling Smørgrav goto out; 12016888a9beSDag-Erling Smørgrav } 12026888a9beSDag-Erling Smørgrav } 12036888a9beSDag-Erling Smørgrav 12046888a9beSDag-Erling Smørgrav *krlp = krl; 1205bc5531deSDag-Erling Smørgrav r = 0; 12066888a9beSDag-Erling Smørgrav out: 1207bc5531deSDag-Erling Smørgrav if (r != 0) 12086888a9beSDag-Erling Smørgrav ssh_krl_free(krl); 1209bc5531deSDag-Erling Smørgrav for (i = 0; i < nca_used; i++) 1210bc5531deSDag-Erling Smørgrav sshkey_free(ca_used[i]); 12116888a9beSDag-Erling Smørgrav free(ca_used); 1212bc5531deSDag-Erling Smørgrav sshkey_free(key); 1213bc5531deSDag-Erling Smørgrav sshbuf_free(copy); 1214bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 1215bc5531deSDag-Erling Smørgrav return r; 12166888a9beSDag-Erling Smørgrav } 12176888a9beSDag-Erling Smørgrav 1218bc5531deSDag-Erling Smørgrav /* Checks certificate serial number and key ID revocation */ 12196888a9beSDag-Erling Smørgrav static int 1220bc5531deSDag-Erling Smørgrav is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc) 12216888a9beSDag-Erling Smørgrav { 12226888a9beSDag-Erling Smørgrav struct revoked_serial rs, *ers; 12236888a9beSDag-Erling Smørgrav struct revoked_key_id rki, *erki; 12246888a9beSDag-Erling Smørgrav 12256888a9beSDag-Erling Smørgrav /* Check revocation by cert key ID */ 1226b83788ffSDag-Erling Smørgrav memset(&rki, 0, sizeof(rki)); 12276888a9beSDag-Erling Smørgrav rki.key_id = key->cert->key_id; 12286888a9beSDag-Erling Smørgrav erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); 12296888a9beSDag-Erling Smørgrav if (erki != NULL) { 1230bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked by key ID", __func__)); 1231bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 12326888a9beSDag-Erling Smørgrav } 12336888a9beSDag-Erling Smørgrav 12346888a9beSDag-Erling Smørgrav /* 1235eccfee6eSDag-Erling Smørgrav * Zero serials numbers are ignored (it's the default when the 1236eccfee6eSDag-Erling Smørgrav * CA doesn't specify one). 12376888a9beSDag-Erling Smørgrav */ 1238eccfee6eSDag-Erling Smørgrav if (key->cert->serial == 0) 12396888a9beSDag-Erling Smørgrav return 0; 12406888a9beSDag-Erling Smørgrav 1241b83788ffSDag-Erling Smørgrav memset(&rs, 0, sizeof(rs)); 12426888a9beSDag-Erling Smørgrav rs.lo = rs.hi = key->cert->serial; 12436888a9beSDag-Erling Smørgrav ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); 12446888a9beSDag-Erling Smørgrav if (ers != NULL) { 1245bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__, 12466888a9beSDag-Erling Smørgrav key->cert->serial, ers->lo, ers->hi)); 1247bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 12486888a9beSDag-Erling Smørgrav } 1249bc5531deSDag-Erling Smørgrav return 0; 1250bc5531deSDag-Erling Smørgrav } 12516888a9beSDag-Erling Smørgrav 1252bc5531deSDag-Erling Smørgrav /* Checks whether a given key/cert is revoked. Does not check its CA */ 1253bc5531deSDag-Erling Smørgrav static int 1254bc5531deSDag-Erling Smørgrav is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) 1255bc5531deSDag-Erling Smørgrav { 1256bc5531deSDag-Erling Smørgrav struct revoked_blob rb, *erb; 1257bc5531deSDag-Erling Smørgrav struct revoked_certs *rc; 1258bc5531deSDag-Erling Smørgrav int r; 1259bc5531deSDag-Erling Smørgrav 1260bc5531deSDag-Erling Smørgrav /* Check explicitly revoked hashes first */ 1261bc5531deSDag-Erling Smørgrav memset(&rb, 0, sizeof(rb)); 1262bc5531deSDag-Erling Smørgrav if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, 1263bc5531deSDag-Erling Smørgrav &rb.blob, &rb.len)) != 0) 1264bc5531deSDag-Erling Smørgrav return r; 1265bc5531deSDag-Erling Smørgrav erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); 1266bc5531deSDag-Erling Smørgrav free(rb.blob); 1267bc5531deSDag-Erling Smørgrav if (erb != NULL) { 1268bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked by key SHA1", __func__)); 1269bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 1270bc5531deSDag-Erling Smørgrav } 1271*2f513db7SEd Maste memset(&rb, 0, sizeof(rb)); 1272*2f513db7SEd Maste if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA256, 1273*2f513db7SEd Maste &rb.blob, &rb.len)) != 0) 1274*2f513db7SEd Maste return r; 1275*2f513db7SEd Maste erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); 1276*2f513db7SEd Maste free(rb.blob); 1277*2f513db7SEd Maste if (erb != NULL) { 1278*2f513db7SEd Maste KRL_DBG(("%s: revoked by key SHA256", __func__)); 1279*2f513db7SEd Maste return SSH_ERR_KEY_REVOKED; 1280*2f513db7SEd Maste } 1281bc5531deSDag-Erling Smørgrav 1282bc5531deSDag-Erling Smørgrav /* Next, explicit keys */ 1283bc5531deSDag-Erling Smørgrav memset(&rb, 0, sizeof(rb)); 1284bc5531deSDag-Erling Smørgrav if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0) 1285bc5531deSDag-Erling Smørgrav return r; 1286bc5531deSDag-Erling Smørgrav erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); 1287bc5531deSDag-Erling Smørgrav free(rb.blob); 1288bc5531deSDag-Erling Smørgrav if (erb != NULL) { 1289bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked by explicit key", __func__)); 1290bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 1291bc5531deSDag-Erling Smørgrav } 1292bc5531deSDag-Erling Smørgrav 1293bc5531deSDag-Erling Smørgrav if (!sshkey_is_cert(key)) 1294bc5531deSDag-Erling Smørgrav return 0; 1295bc5531deSDag-Erling Smørgrav 1296bc5531deSDag-Erling Smørgrav /* Check cert revocation for the specified CA */ 1297bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, 1298bc5531deSDag-Erling Smørgrav &rc, 0)) != 0) 1299bc5531deSDag-Erling Smørgrav return r; 1300bc5531deSDag-Erling Smørgrav if (rc != NULL) { 1301bc5531deSDag-Erling Smørgrav if ((r = is_cert_revoked(key, rc)) != 0) 1302bc5531deSDag-Erling Smørgrav return r; 1303bc5531deSDag-Erling Smørgrav } 1304bc5531deSDag-Erling Smørgrav /* Check cert revocation for the wildcard CA */ 1305bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) 1306bc5531deSDag-Erling Smørgrav return r; 1307bc5531deSDag-Erling Smørgrav if (rc != NULL) { 1308bc5531deSDag-Erling Smørgrav if ((r = is_cert_revoked(key, rc)) != 0) 1309bc5531deSDag-Erling Smørgrav return r; 1310bc5531deSDag-Erling Smørgrav } 1311bc5531deSDag-Erling Smørgrav 1312bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); 13136888a9beSDag-Erling Smørgrav return 0; 13146888a9beSDag-Erling Smørgrav } 13156888a9beSDag-Erling Smørgrav 13166888a9beSDag-Erling Smørgrav int 1317bc5531deSDag-Erling Smørgrav ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key) 13186888a9beSDag-Erling Smørgrav { 13196888a9beSDag-Erling Smørgrav int r; 13206888a9beSDag-Erling Smørgrav 1321bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: checking key", __func__)); 13226888a9beSDag-Erling Smørgrav if ((r = is_key_revoked(krl, key)) != 0) 13236888a9beSDag-Erling Smørgrav return r; 1324bc5531deSDag-Erling Smørgrav if (sshkey_is_cert(key)) { 13256888a9beSDag-Erling Smørgrav debug2("%s: checking CA key", __func__); 13266888a9beSDag-Erling Smørgrav if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) 13276888a9beSDag-Erling Smørgrav return r; 13286888a9beSDag-Erling Smørgrav } 1329bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: key okay", __func__)); 13306888a9beSDag-Erling Smørgrav return 0; 13316888a9beSDag-Erling Smørgrav } 13326888a9beSDag-Erling Smørgrav 13336888a9beSDag-Erling Smørgrav int 1334bc5531deSDag-Erling Smørgrav ssh_krl_file_contains_key(const char *path, const struct sshkey *key) 13356888a9beSDag-Erling Smørgrav { 1336bc5531deSDag-Erling Smørgrav struct sshbuf *krlbuf = NULL; 1337bc5531deSDag-Erling Smørgrav struct ssh_krl *krl = NULL; 1338bc5531deSDag-Erling Smørgrav int oerrno = 0, r, fd; 13396888a9beSDag-Erling Smørgrav 13406888a9beSDag-Erling Smørgrav if (path == NULL) 13416888a9beSDag-Erling Smørgrav return 0; 13426888a9beSDag-Erling Smørgrav 1343bc5531deSDag-Erling Smørgrav if ((krlbuf = sshbuf_new()) == NULL) 1344bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 13456888a9beSDag-Erling Smørgrav if ((fd = open(path, O_RDONLY)) == -1) { 1346bc5531deSDag-Erling Smørgrav r = SSH_ERR_SYSTEM_ERROR; 1347bc5531deSDag-Erling Smørgrav oerrno = errno; 1348bc5531deSDag-Erling Smørgrav goto out; 13496888a9beSDag-Erling Smørgrav } 1350bc5531deSDag-Erling Smørgrav if ((r = sshkey_load_file(fd, krlbuf)) != 0) { 1351bc5531deSDag-Erling Smørgrav oerrno = errno; 1352bc5531deSDag-Erling Smørgrav goto out; 13536888a9beSDag-Erling Smørgrav } 1354bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0) 1355bc5531deSDag-Erling Smørgrav goto out; 13566888a9beSDag-Erling Smørgrav debug2("%s: checking KRL %s", __func__, path); 1357bc5531deSDag-Erling Smørgrav r = ssh_krl_check_key(krl, key); 1358bc5531deSDag-Erling Smørgrav out: 1359d93a896eSDag-Erling Smørgrav if (fd != -1) 1360bc5531deSDag-Erling Smørgrav close(fd); 1361bc5531deSDag-Erling Smørgrav sshbuf_free(krlbuf); 13626888a9beSDag-Erling Smørgrav ssh_krl_free(krl); 1363bc5531deSDag-Erling Smørgrav if (r != 0) 1364bc5531deSDag-Erling Smørgrav errno = oerrno; 1365bc5531deSDag-Erling Smørgrav return r; 13666888a9beSDag-Erling Smørgrav } 1367