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*acc1a9efSDag-Erling Smørgrav /* $OpenBSD: krl.c,v 1.37 2015/12/31 00:33:52 djm Exp $ */ 186888a9beSDag-Erling Smørgrav 196888a9beSDag-Erling Smørgrav #include "includes.h" 206888a9beSDag-Erling Smørgrav 21bc5531deSDag-Erling Smørgrav #include <sys/param.h> /* MIN */ 226888a9beSDag-Erling Smørgrav #include <sys/types.h> 236888a9beSDag-Erling Smørgrav #include <openbsd-compat/sys-tree.h> 246888a9beSDag-Erling Smørgrav #include <openbsd-compat/sys-queue.h> 256888a9beSDag-Erling Smørgrav 266888a9beSDag-Erling Smørgrav #include <errno.h> 276888a9beSDag-Erling Smørgrav #include <fcntl.h> 286888a9beSDag-Erling Smørgrav #include <limits.h> 296888a9beSDag-Erling Smørgrav #include <string.h> 306888a9beSDag-Erling Smørgrav #include <time.h> 316888a9beSDag-Erling Smørgrav #include <unistd.h> 326888a9beSDag-Erling Smørgrav 33bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 34bc5531deSDag-Erling Smørgrav #include "ssherr.h" 35bc5531deSDag-Erling Smørgrav #include "sshkey.h" 366888a9beSDag-Erling Smørgrav #include "authfile.h" 376888a9beSDag-Erling Smørgrav #include "misc.h" 386888a9beSDag-Erling Smørgrav #include "log.h" 39bc5531deSDag-Erling Smørgrav #include "digest.h" 40bc5531deSDag-Erling Smørgrav #include "bitmap.h" 416888a9beSDag-Erling Smørgrav 426888a9beSDag-Erling Smørgrav #include "krl.h" 436888a9beSDag-Erling Smørgrav 446888a9beSDag-Erling Smørgrav /* #define DEBUG_KRL */ 456888a9beSDag-Erling Smørgrav #ifdef DEBUG_KRL 466888a9beSDag-Erling Smørgrav # define KRL_DBG(x) debug3 x 476888a9beSDag-Erling Smørgrav #else 486888a9beSDag-Erling Smørgrav # define KRL_DBG(x) 496888a9beSDag-Erling Smørgrav #endif 506888a9beSDag-Erling Smørgrav 516888a9beSDag-Erling Smørgrav /* 526888a9beSDag-Erling Smørgrav * Trees of revoked serial numbers, key IDs and keys. This allows 536888a9beSDag-Erling Smørgrav * quick searching, querying and producing lists in canonical order. 546888a9beSDag-Erling Smørgrav */ 556888a9beSDag-Erling Smørgrav 566888a9beSDag-Erling Smørgrav /* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */ 576888a9beSDag-Erling Smørgrav struct revoked_serial { 586888a9beSDag-Erling Smørgrav u_int64_t lo, hi; 596888a9beSDag-Erling Smørgrav RB_ENTRY(revoked_serial) tree_entry; 606888a9beSDag-Erling Smørgrav }; 616888a9beSDag-Erling Smørgrav static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b); 626888a9beSDag-Erling Smørgrav RB_HEAD(revoked_serial_tree, revoked_serial); 636888a9beSDag-Erling Smørgrav RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp); 646888a9beSDag-Erling Smørgrav 656888a9beSDag-Erling Smørgrav /* Tree of key IDs */ 666888a9beSDag-Erling Smørgrav struct revoked_key_id { 676888a9beSDag-Erling Smørgrav char *key_id; 686888a9beSDag-Erling Smørgrav RB_ENTRY(revoked_key_id) tree_entry; 696888a9beSDag-Erling Smørgrav }; 706888a9beSDag-Erling Smørgrav static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b); 716888a9beSDag-Erling Smørgrav RB_HEAD(revoked_key_id_tree, revoked_key_id); 726888a9beSDag-Erling Smørgrav RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp); 736888a9beSDag-Erling Smørgrav 746888a9beSDag-Erling Smørgrav /* Tree of blobs (used for keys and fingerprints) */ 756888a9beSDag-Erling Smørgrav struct revoked_blob { 766888a9beSDag-Erling Smørgrav u_char *blob; 77bc5531deSDag-Erling Smørgrav size_t len; 786888a9beSDag-Erling Smørgrav RB_ENTRY(revoked_blob) tree_entry; 796888a9beSDag-Erling Smørgrav }; 806888a9beSDag-Erling Smørgrav static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); 816888a9beSDag-Erling Smørgrav RB_HEAD(revoked_blob_tree, revoked_blob); 826888a9beSDag-Erling Smørgrav RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp); 836888a9beSDag-Erling Smørgrav 846888a9beSDag-Erling Smørgrav /* Tracks revoked certs for a single CA */ 856888a9beSDag-Erling Smørgrav struct revoked_certs { 86bc5531deSDag-Erling Smørgrav struct sshkey *ca_key; 876888a9beSDag-Erling Smørgrav struct revoked_serial_tree revoked_serials; 886888a9beSDag-Erling Smørgrav struct revoked_key_id_tree revoked_key_ids; 896888a9beSDag-Erling Smørgrav TAILQ_ENTRY(revoked_certs) entry; 906888a9beSDag-Erling Smørgrav }; 916888a9beSDag-Erling Smørgrav TAILQ_HEAD(revoked_certs_list, revoked_certs); 926888a9beSDag-Erling Smørgrav 936888a9beSDag-Erling Smørgrav struct ssh_krl { 946888a9beSDag-Erling Smørgrav u_int64_t krl_version; 956888a9beSDag-Erling Smørgrav u_int64_t generated_date; 966888a9beSDag-Erling Smørgrav u_int64_t flags; 976888a9beSDag-Erling Smørgrav char *comment; 986888a9beSDag-Erling Smørgrav struct revoked_blob_tree revoked_keys; 996888a9beSDag-Erling Smørgrav struct revoked_blob_tree revoked_sha1s; 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) { 1246888a9beSDag-Erling Smørgrav if ((r = memcmp(a->blob, b->blob, MIN(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); 1406888a9beSDag-Erling Smørgrav TAILQ_INIT(&krl->revoked_certs); 1416888a9beSDag-Erling Smørgrav return krl; 1426888a9beSDag-Erling Smørgrav } 1436888a9beSDag-Erling Smørgrav 1446888a9beSDag-Erling Smørgrav static void 1456888a9beSDag-Erling Smørgrav revoked_certs_free(struct revoked_certs *rc) 1466888a9beSDag-Erling Smørgrav { 1476888a9beSDag-Erling Smørgrav struct revoked_serial *rs, *trs; 1486888a9beSDag-Erling Smørgrav struct revoked_key_id *rki, *trki; 1496888a9beSDag-Erling Smørgrav 1506888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) { 1516888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs); 1526888a9beSDag-Erling Smørgrav free(rs); 1536888a9beSDag-Erling Smørgrav } 1546888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) { 1556888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki); 1566888a9beSDag-Erling Smørgrav free(rki->key_id); 1576888a9beSDag-Erling Smørgrav free(rki); 1586888a9beSDag-Erling Smørgrav } 159bc5531deSDag-Erling Smørgrav sshkey_free(rc->ca_key); 1606888a9beSDag-Erling Smørgrav } 1616888a9beSDag-Erling Smørgrav 1626888a9beSDag-Erling Smørgrav void 1636888a9beSDag-Erling Smørgrav ssh_krl_free(struct ssh_krl *krl) 1646888a9beSDag-Erling Smørgrav { 1656888a9beSDag-Erling Smørgrav struct revoked_blob *rb, *trb; 1666888a9beSDag-Erling Smørgrav struct revoked_certs *rc, *trc; 1676888a9beSDag-Erling Smørgrav 1686888a9beSDag-Erling Smørgrav if (krl == NULL) 1696888a9beSDag-Erling Smørgrav return; 1706888a9beSDag-Erling Smørgrav 1716888a9beSDag-Erling Smørgrav free(krl->comment); 1726888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) { 1736888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb); 1746888a9beSDag-Erling Smørgrav free(rb->blob); 1756888a9beSDag-Erling Smørgrav free(rb); 1766888a9beSDag-Erling Smørgrav } 1776888a9beSDag-Erling Smørgrav RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) { 1786888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb); 1796888a9beSDag-Erling Smørgrav free(rb->blob); 1806888a9beSDag-Erling Smørgrav free(rb); 1816888a9beSDag-Erling Smørgrav } 1826888a9beSDag-Erling Smørgrav TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) { 1836888a9beSDag-Erling Smørgrav TAILQ_REMOVE(&krl->revoked_certs, rc, entry); 1846888a9beSDag-Erling Smørgrav revoked_certs_free(rc); 1856888a9beSDag-Erling Smørgrav } 1866888a9beSDag-Erling Smørgrav } 1876888a9beSDag-Erling Smørgrav 1886888a9beSDag-Erling Smørgrav void 1896888a9beSDag-Erling Smørgrav ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version) 1906888a9beSDag-Erling Smørgrav { 1916888a9beSDag-Erling Smørgrav krl->krl_version = version; 1926888a9beSDag-Erling Smørgrav } 1936888a9beSDag-Erling Smørgrav 194bc5531deSDag-Erling Smørgrav int 1956888a9beSDag-Erling Smørgrav ssh_krl_set_comment(struct ssh_krl *krl, const char *comment) 1966888a9beSDag-Erling Smørgrav { 1976888a9beSDag-Erling Smørgrav free(krl->comment); 1986888a9beSDag-Erling Smørgrav if ((krl->comment = strdup(comment)) == NULL) 199bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 200bc5531deSDag-Erling Smørgrav return 0; 2016888a9beSDag-Erling Smørgrav } 2026888a9beSDag-Erling Smørgrav 2036888a9beSDag-Erling Smørgrav /* 2046888a9beSDag-Erling Smørgrav * Find the revoked_certs struct for a CA key. If allow_create is set then 2056888a9beSDag-Erling Smørgrav * create a new one in the tree if one did not exist already. 2066888a9beSDag-Erling Smørgrav */ 2076888a9beSDag-Erling Smørgrav static int 208bc5531deSDag-Erling Smørgrav revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key, 2096888a9beSDag-Erling Smørgrav struct revoked_certs **rcp, int allow_create) 2106888a9beSDag-Erling Smørgrav { 2116888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 212bc5531deSDag-Erling Smørgrav int r; 2136888a9beSDag-Erling Smørgrav 2146888a9beSDag-Erling Smørgrav *rcp = NULL; 2156888a9beSDag-Erling Smørgrav TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 216bc5531deSDag-Erling Smørgrav if ((ca_key == NULL && rc->ca_key == NULL) || 217bc5531deSDag-Erling Smørgrav sshkey_equal(rc->ca_key, ca_key)) { 2186888a9beSDag-Erling Smørgrav *rcp = rc; 2196888a9beSDag-Erling Smørgrav return 0; 2206888a9beSDag-Erling Smørgrav } 2216888a9beSDag-Erling Smørgrav } 2226888a9beSDag-Erling Smørgrav if (!allow_create) 2236888a9beSDag-Erling Smørgrav return 0; 2246888a9beSDag-Erling Smørgrav /* If this CA doesn't exist in the list then add it now */ 2256888a9beSDag-Erling Smørgrav if ((rc = calloc(1, sizeof(*rc))) == NULL) 226bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 227bc5531deSDag-Erling Smørgrav if (ca_key == NULL) 228bc5531deSDag-Erling Smørgrav rc->ca_key = NULL; 229bc5531deSDag-Erling Smørgrav else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { 2306888a9beSDag-Erling Smørgrav free(rc); 231bc5531deSDag-Erling Smørgrav return r; 2326888a9beSDag-Erling Smørgrav } 2336888a9beSDag-Erling Smørgrav RB_INIT(&rc->revoked_serials); 2346888a9beSDag-Erling Smørgrav RB_INIT(&rc->revoked_key_ids); 2356888a9beSDag-Erling Smørgrav TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); 236bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: new CA %s", __func__, 237bc5531deSDag-Erling Smørgrav ca_key == NULL ? "*" : sshkey_type(ca_key))); 2386888a9beSDag-Erling Smørgrav *rcp = rc; 2396888a9beSDag-Erling Smørgrav return 0; 2406888a9beSDag-Erling Smørgrav } 2416888a9beSDag-Erling Smørgrav 2426888a9beSDag-Erling Smørgrav static int 2436888a9beSDag-Erling Smørgrav insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi) 2446888a9beSDag-Erling Smørgrav { 2456888a9beSDag-Erling Smørgrav struct revoked_serial rs, *ers, *crs, *irs; 2466888a9beSDag-Erling Smørgrav 2476888a9beSDag-Erling Smørgrav KRL_DBG(("%s: insert %llu:%llu", __func__, lo, hi)); 248b83788ffSDag-Erling Smørgrav memset(&rs, 0, sizeof(rs)); 2496888a9beSDag-Erling Smørgrav rs.lo = lo; 2506888a9beSDag-Erling Smørgrav rs.hi = hi; 2516888a9beSDag-Erling Smørgrav ers = RB_NFIND(revoked_serial_tree, rt, &rs); 2526888a9beSDag-Erling Smørgrav if (ers == NULL || serial_cmp(ers, &rs) != 0) { 2536888a9beSDag-Erling Smørgrav /* No entry matches. Just insert */ 2546888a9beSDag-Erling Smørgrav if ((irs = malloc(sizeof(rs))) == NULL) 255bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 2566888a9beSDag-Erling Smørgrav memcpy(irs, &rs, sizeof(*irs)); 2576888a9beSDag-Erling Smørgrav ers = RB_INSERT(revoked_serial_tree, rt, irs); 2586888a9beSDag-Erling Smørgrav if (ers != NULL) { 2596888a9beSDag-Erling Smørgrav KRL_DBG(("%s: bad: ers != NULL", __func__)); 2606888a9beSDag-Erling Smørgrav /* Shouldn't happen */ 2616888a9beSDag-Erling Smørgrav free(irs); 262bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 2636888a9beSDag-Erling Smørgrav } 2646888a9beSDag-Erling Smørgrav ers = irs; 2656888a9beSDag-Erling Smørgrav } else { 2666888a9beSDag-Erling Smørgrav KRL_DBG(("%s: overlap found %llu:%llu", __func__, 2676888a9beSDag-Erling Smørgrav ers->lo, ers->hi)); 2686888a9beSDag-Erling Smørgrav /* 2696888a9beSDag-Erling Smørgrav * The inserted entry overlaps an existing one. Grow the 2706888a9beSDag-Erling Smørgrav * existing entry. 2716888a9beSDag-Erling Smørgrav */ 2726888a9beSDag-Erling Smørgrav if (ers->lo > lo) 2736888a9beSDag-Erling Smørgrav ers->lo = lo; 2746888a9beSDag-Erling Smørgrav if (ers->hi < hi) 2756888a9beSDag-Erling Smørgrav ers->hi = hi; 2766888a9beSDag-Erling Smørgrav } 277bc5531deSDag-Erling Smørgrav 2786888a9beSDag-Erling Smørgrav /* 2796888a9beSDag-Erling Smørgrav * The inserted or revised range might overlap or abut adjacent ones; 2806888a9beSDag-Erling Smørgrav * coalesce as necessary. 2816888a9beSDag-Erling Smørgrav */ 2826888a9beSDag-Erling Smørgrav 2836888a9beSDag-Erling Smørgrav /* Check predecessors */ 2846888a9beSDag-Erling Smørgrav while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) { 2856888a9beSDag-Erling Smørgrav KRL_DBG(("%s: pred %llu:%llu", __func__, crs->lo, crs->hi)); 2866888a9beSDag-Erling Smørgrav if (ers->lo != 0 && crs->hi < ers->lo - 1) 2876888a9beSDag-Erling Smørgrav break; 2886888a9beSDag-Erling Smørgrav /* This entry overlaps. */ 2896888a9beSDag-Erling Smørgrav if (crs->lo < ers->lo) { 2906888a9beSDag-Erling Smørgrav ers->lo = crs->lo; 2916888a9beSDag-Erling Smørgrav KRL_DBG(("%s: pred extend %llu:%llu", __func__, 2926888a9beSDag-Erling Smørgrav ers->lo, ers->hi)); 2936888a9beSDag-Erling Smørgrav } 2946888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_serial_tree, rt, crs); 2956888a9beSDag-Erling Smørgrav free(crs); 2966888a9beSDag-Erling Smørgrav } 2976888a9beSDag-Erling Smørgrav /* Check successors */ 2986888a9beSDag-Erling Smørgrav while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) { 2996888a9beSDag-Erling Smørgrav KRL_DBG(("%s: succ %llu:%llu", __func__, crs->lo, crs->hi)); 3006888a9beSDag-Erling Smørgrav if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1) 3016888a9beSDag-Erling Smørgrav break; 3026888a9beSDag-Erling Smørgrav /* This entry overlaps. */ 3036888a9beSDag-Erling Smørgrav if (crs->hi > ers->hi) { 3046888a9beSDag-Erling Smørgrav ers->hi = crs->hi; 3056888a9beSDag-Erling Smørgrav KRL_DBG(("%s: succ extend %llu:%llu", __func__, 3066888a9beSDag-Erling Smørgrav ers->lo, ers->hi)); 3076888a9beSDag-Erling Smørgrav } 3086888a9beSDag-Erling Smørgrav RB_REMOVE(revoked_serial_tree, rt, crs); 3096888a9beSDag-Erling Smørgrav free(crs); 3106888a9beSDag-Erling Smørgrav } 3116888a9beSDag-Erling Smørgrav KRL_DBG(("%s: done, final %llu:%llu", __func__, ers->lo, ers->hi)); 3126888a9beSDag-Erling Smørgrav return 0; 3136888a9beSDag-Erling Smørgrav } 3146888a9beSDag-Erling Smørgrav 3156888a9beSDag-Erling Smørgrav int 316bc5531deSDag-Erling Smørgrav ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const struct sshkey *ca_key, 3176888a9beSDag-Erling Smørgrav u_int64_t serial) 3186888a9beSDag-Erling Smørgrav { 3196888a9beSDag-Erling Smørgrav return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial); 3206888a9beSDag-Erling Smørgrav } 3216888a9beSDag-Erling Smørgrav 3226888a9beSDag-Erling Smørgrav int 323bc5531deSDag-Erling Smørgrav ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, 324bc5531deSDag-Erling Smørgrav const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi) 3256888a9beSDag-Erling Smørgrav { 3266888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 327bc5531deSDag-Erling Smørgrav int r; 3286888a9beSDag-Erling Smørgrav 3296888a9beSDag-Erling Smørgrav if (lo > hi || lo == 0) 330bc5531deSDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 331bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0) 332bc5531deSDag-Erling Smørgrav return r; 3336888a9beSDag-Erling Smørgrav return insert_serial_range(&rc->revoked_serials, lo, hi); 3346888a9beSDag-Erling Smørgrav } 3356888a9beSDag-Erling Smørgrav 3366888a9beSDag-Erling Smørgrav int 337bc5531deSDag-Erling Smørgrav ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const struct sshkey *ca_key, 3386888a9beSDag-Erling Smørgrav const char *key_id) 3396888a9beSDag-Erling Smørgrav { 3406888a9beSDag-Erling Smørgrav struct revoked_key_id *rki, *erki; 3416888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 342bc5531deSDag-Erling Smørgrav int r; 3436888a9beSDag-Erling Smørgrav 344bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0) 345bc5531deSDag-Erling Smørgrav return r; 3466888a9beSDag-Erling Smørgrav 347bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoke %s", __func__, key_id)); 3486888a9beSDag-Erling Smørgrav if ((rki = calloc(1, sizeof(*rki))) == NULL || 3496888a9beSDag-Erling Smørgrav (rki->key_id = strdup(key_id)) == NULL) { 3506888a9beSDag-Erling Smørgrav free(rki); 351bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 3526888a9beSDag-Erling Smørgrav } 3536888a9beSDag-Erling Smørgrav erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki); 3546888a9beSDag-Erling Smørgrav if (erki != NULL) { 3556888a9beSDag-Erling Smørgrav free(rki->key_id); 3566888a9beSDag-Erling Smørgrav free(rki); 3576888a9beSDag-Erling Smørgrav } 3586888a9beSDag-Erling Smørgrav return 0; 3596888a9beSDag-Erling Smørgrav } 3606888a9beSDag-Erling Smørgrav 3616888a9beSDag-Erling Smørgrav /* Convert "key" to a public key blob without any certificate information */ 3626888a9beSDag-Erling Smørgrav static int 363bc5531deSDag-Erling Smørgrav plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen) 3646888a9beSDag-Erling Smørgrav { 365bc5531deSDag-Erling Smørgrav struct sshkey *kcopy; 3666888a9beSDag-Erling Smørgrav int r; 3676888a9beSDag-Erling Smørgrav 368bc5531deSDag-Erling Smørgrav if ((r = sshkey_from_private(key, &kcopy)) != 0) 369bc5531deSDag-Erling Smørgrav return r; 370bc5531deSDag-Erling Smørgrav if (sshkey_is_cert(kcopy)) { 371bc5531deSDag-Erling Smørgrav if ((r = sshkey_drop_cert(kcopy)) != 0) { 372bc5531deSDag-Erling Smørgrav sshkey_free(kcopy); 373bc5531deSDag-Erling Smørgrav return r; 3746888a9beSDag-Erling Smørgrav } 3756888a9beSDag-Erling Smørgrav } 376bc5531deSDag-Erling Smørgrav r = sshkey_to_blob(kcopy, blob, blen); 377bc5531deSDag-Erling Smørgrav sshkey_free(kcopy); 378a0ee8cc6SDag-Erling Smørgrav return r; 3796888a9beSDag-Erling Smørgrav } 3806888a9beSDag-Erling Smørgrav 3816888a9beSDag-Erling Smørgrav /* Revoke a key blob. Ownership of blob is transferred to the tree */ 3826888a9beSDag-Erling Smørgrav static int 383bc5531deSDag-Erling Smørgrav revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, size_t len) 3846888a9beSDag-Erling Smørgrav { 3856888a9beSDag-Erling Smørgrav struct revoked_blob *rb, *erb; 3866888a9beSDag-Erling Smørgrav 3876888a9beSDag-Erling Smørgrav if ((rb = calloc(1, sizeof(*rb))) == NULL) 388bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 3896888a9beSDag-Erling Smørgrav rb->blob = blob; 3906888a9beSDag-Erling Smørgrav rb->len = len; 3916888a9beSDag-Erling Smørgrav erb = RB_INSERT(revoked_blob_tree, rbt, rb); 3926888a9beSDag-Erling Smørgrav if (erb != NULL) { 3936888a9beSDag-Erling Smørgrav free(rb->blob); 3946888a9beSDag-Erling Smørgrav free(rb); 3956888a9beSDag-Erling Smørgrav } 3966888a9beSDag-Erling Smørgrav return 0; 3976888a9beSDag-Erling Smørgrav } 3986888a9beSDag-Erling Smørgrav 3996888a9beSDag-Erling Smørgrav int 400bc5531deSDag-Erling Smørgrav ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key) 4016888a9beSDag-Erling Smørgrav { 4026888a9beSDag-Erling Smørgrav u_char *blob; 403bc5531deSDag-Erling Smørgrav size_t len; 404bc5531deSDag-Erling Smørgrav int r; 4056888a9beSDag-Erling Smørgrav 406bc5531deSDag-Erling Smørgrav debug3("%s: revoke type %s", __func__, sshkey_type(key)); 407bc5531deSDag-Erling Smørgrav if ((r = plain_key_blob(key, &blob, &len)) != 0) 408bc5531deSDag-Erling Smørgrav return r; 4096888a9beSDag-Erling Smørgrav return revoke_blob(&krl->revoked_keys, blob, len); 4106888a9beSDag-Erling Smørgrav } 4116888a9beSDag-Erling Smørgrav 4126888a9beSDag-Erling Smørgrav int 413bc5531deSDag-Erling Smørgrav ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key) 4146888a9beSDag-Erling Smørgrav { 4156888a9beSDag-Erling Smørgrav u_char *blob; 416bc5531deSDag-Erling Smørgrav size_t len; 417bc5531deSDag-Erling Smørgrav int r; 4186888a9beSDag-Erling Smørgrav 419bc5531deSDag-Erling Smørgrav debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key)); 420bc5531deSDag-Erling Smørgrav if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, 421bc5531deSDag-Erling Smørgrav &blob, &len)) != 0) 422bc5531deSDag-Erling Smørgrav return r; 4236888a9beSDag-Erling Smørgrav return revoke_blob(&krl->revoked_sha1s, blob, len); 4246888a9beSDag-Erling Smørgrav } 4256888a9beSDag-Erling Smørgrav 4266888a9beSDag-Erling Smørgrav int 427bc5531deSDag-Erling Smørgrav ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key) 4286888a9beSDag-Erling Smørgrav { 429bc5531deSDag-Erling Smørgrav if (!sshkey_is_cert(key)) 4306888a9beSDag-Erling Smørgrav return ssh_krl_revoke_key_sha1(krl, key); 4316888a9beSDag-Erling Smørgrav 432eccfee6eSDag-Erling Smørgrav if (key->cert->serial == 0) { 4336888a9beSDag-Erling Smørgrav return ssh_krl_revoke_cert_by_key_id(krl, 4346888a9beSDag-Erling Smørgrav key->cert->signature_key, 4356888a9beSDag-Erling Smørgrav key->cert->key_id); 4366888a9beSDag-Erling Smørgrav } else { 4376888a9beSDag-Erling Smørgrav return ssh_krl_revoke_cert_by_serial(krl, 4386888a9beSDag-Erling Smørgrav key->cert->signature_key, 4396888a9beSDag-Erling Smørgrav key->cert->serial); 4406888a9beSDag-Erling Smørgrav } 4416888a9beSDag-Erling Smørgrav } 4426888a9beSDag-Erling Smørgrav 4436888a9beSDag-Erling Smørgrav /* 444bc5531deSDag-Erling Smørgrav * Select the most compact section type to emit next in a KRL based on 445bc5531deSDag-Erling Smørgrav * the current section type, the run length of contiguous revoked serial 4466888a9beSDag-Erling Smørgrav * numbers and the gaps from the last and to the next revoked serial. 4476888a9beSDag-Erling Smørgrav * Applies a mostly-accurate bit cost model to select the section type 4486888a9beSDag-Erling Smørgrav * that will minimise the size of the resultant KRL. 4496888a9beSDag-Erling Smørgrav */ 4506888a9beSDag-Erling Smørgrav static int 4516888a9beSDag-Erling Smørgrav choose_next_state(int current_state, u_int64_t contig, int final, 4526888a9beSDag-Erling Smørgrav u_int64_t last_gap, u_int64_t next_gap, int *force_new_section) 4536888a9beSDag-Erling Smørgrav { 4546888a9beSDag-Erling Smørgrav int new_state; 4556888a9beSDag-Erling Smørgrav u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart; 4566888a9beSDag-Erling Smørgrav 4576888a9beSDag-Erling Smørgrav /* 4586888a9beSDag-Erling Smørgrav * Avoid unsigned overflows. 4596888a9beSDag-Erling Smørgrav * The limits are high enough to avoid confusing the calculations. 4606888a9beSDag-Erling Smørgrav */ 4616888a9beSDag-Erling Smørgrav contig = MIN(contig, 1ULL<<31); 4626888a9beSDag-Erling Smørgrav last_gap = MIN(last_gap, 1ULL<<31); 4636888a9beSDag-Erling Smørgrav next_gap = MIN(next_gap, 1ULL<<31); 4646888a9beSDag-Erling Smørgrav 4656888a9beSDag-Erling Smørgrav /* 4666888a9beSDag-Erling Smørgrav * Calculate the cost to switch from the current state to candidates. 4676888a9beSDag-Erling Smørgrav * NB. range sections only ever contain a single range, so their 4686888a9beSDag-Erling Smørgrav * switching cost is independent of the current_state. 4696888a9beSDag-Erling Smørgrav */ 4706888a9beSDag-Erling Smørgrav cost_list = cost_bitmap = cost_bitmap_restart = 0; 4716888a9beSDag-Erling Smørgrav cost_range = 8; 4726888a9beSDag-Erling Smørgrav switch (current_state) { 4736888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 4746888a9beSDag-Erling Smørgrav cost_bitmap_restart = cost_bitmap = 8 + 64; 4756888a9beSDag-Erling Smørgrav break; 4766888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 4776888a9beSDag-Erling Smørgrav cost_list = 8; 4786888a9beSDag-Erling Smørgrav cost_bitmap_restart = 8 + 64; 4796888a9beSDag-Erling Smørgrav break; 4806888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 4816888a9beSDag-Erling Smørgrav case 0: 4826888a9beSDag-Erling Smørgrav cost_bitmap_restart = cost_bitmap = 8 + 64; 4836888a9beSDag-Erling Smørgrav cost_list = 8; 4846888a9beSDag-Erling Smørgrav } 4856888a9beSDag-Erling Smørgrav 4866888a9beSDag-Erling Smørgrav /* Estimate base cost in bits of each section type */ 4876888a9beSDag-Erling Smørgrav cost_list += 64 * contig + (final ? 0 : 8+64); 4886888a9beSDag-Erling Smørgrav cost_range += (2 * 64) + (final ? 0 : 8+64); 4896888a9beSDag-Erling Smørgrav cost_bitmap += last_gap + contig + (final ? 0 : MIN(next_gap, 8+64)); 4906888a9beSDag-Erling Smørgrav cost_bitmap_restart += contig + (final ? 0 : MIN(next_gap, 8+64)); 4916888a9beSDag-Erling Smørgrav 4926888a9beSDag-Erling Smørgrav /* Convert to byte costs for actual comparison */ 4936888a9beSDag-Erling Smørgrav cost_list = (cost_list + 7) / 8; 4946888a9beSDag-Erling Smørgrav cost_bitmap = (cost_bitmap + 7) / 8; 4956888a9beSDag-Erling Smørgrav cost_bitmap_restart = (cost_bitmap_restart + 7) / 8; 4966888a9beSDag-Erling Smørgrav cost_range = (cost_range + 7) / 8; 4976888a9beSDag-Erling Smørgrav 4986888a9beSDag-Erling Smørgrav /* Now pick the best choice */ 4996888a9beSDag-Erling Smørgrav *force_new_section = 0; 5006888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_BITMAP; 5016888a9beSDag-Erling Smørgrav cost = cost_bitmap; 5026888a9beSDag-Erling Smørgrav if (cost_range < cost) { 5036888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_RANGE; 5046888a9beSDag-Erling Smørgrav cost = cost_range; 5056888a9beSDag-Erling Smørgrav } 5066888a9beSDag-Erling Smørgrav if (cost_list < cost) { 5076888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_LIST; 5086888a9beSDag-Erling Smørgrav cost = cost_list; 5096888a9beSDag-Erling Smørgrav } 5106888a9beSDag-Erling Smørgrav if (cost_bitmap_restart < cost) { 5116888a9beSDag-Erling Smørgrav new_state = KRL_SECTION_CERT_SERIAL_BITMAP; 5126888a9beSDag-Erling Smørgrav *force_new_section = 1; 5136888a9beSDag-Erling Smørgrav cost = cost_bitmap_restart; 5146888a9beSDag-Erling Smørgrav } 515bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:" 5166888a9beSDag-Erling Smørgrav "list %llu range %llu bitmap %llu new bitmap %llu, " 517e4a9863fSDag-Erling Smørgrav "selected 0x%02x%s", __func__, (long long unsigned)contig, 518e4a9863fSDag-Erling Smørgrav (long long unsigned)last_gap, (long long unsigned)next_gap, final, 519e4a9863fSDag-Erling Smørgrav (long long unsigned)cost_list, (long long unsigned)cost_range, 520e4a9863fSDag-Erling Smørgrav (long long unsigned)cost_bitmap, 521e4a9863fSDag-Erling Smørgrav (long long unsigned)cost_bitmap_restart, new_state, 522bc5531deSDag-Erling Smørgrav *force_new_section ? " restart" : "")); 5236888a9beSDag-Erling Smørgrav return new_state; 5246888a9beSDag-Erling Smørgrav } 5256888a9beSDag-Erling Smørgrav 526bc5531deSDag-Erling Smørgrav static int 527bc5531deSDag-Erling Smørgrav put_bitmap(struct sshbuf *buf, struct bitmap *bitmap) 528bc5531deSDag-Erling Smørgrav { 529bc5531deSDag-Erling Smørgrav size_t len; 530bc5531deSDag-Erling Smørgrav u_char *blob; 531bc5531deSDag-Erling Smørgrav int r; 532bc5531deSDag-Erling Smørgrav 533bc5531deSDag-Erling Smørgrav len = bitmap_nbytes(bitmap); 534bc5531deSDag-Erling Smørgrav if ((blob = malloc(len)) == NULL) 535bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 536bc5531deSDag-Erling Smørgrav if (bitmap_to_string(bitmap, blob, len) != 0) { 537bc5531deSDag-Erling Smørgrav free(blob); 538bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 539bc5531deSDag-Erling Smørgrav } 540bc5531deSDag-Erling Smørgrav r = sshbuf_put_bignum2_bytes(buf, blob, len); 541bc5531deSDag-Erling Smørgrav free(blob); 542bc5531deSDag-Erling Smørgrav return r; 543bc5531deSDag-Erling Smørgrav } 544bc5531deSDag-Erling Smørgrav 5456888a9beSDag-Erling Smørgrav /* Generate a KRL_SECTION_CERTIFICATES KRL section */ 5466888a9beSDag-Erling Smørgrav static int 547bc5531deSDag-Erling Smørgrav revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf) 5486888a9beSDag-Erling Smørgrav { 549bc5531deSDag-Erling Smørgrav int final, force_new_sect, r = SSH_ERR_INTERNAL_ERROR; 5506888a9beSDag-Erling Smørgrav u_int64_t i, contig, gap, last = 0, bitmap_start = 0; 5516888a9beSDag-Erling Smørgrav struct revoked_serial *rs, *nrs; 5526888a9beSDag-Erling Smørgrav struct revoked_key_id *rki; 5536888a9beSDag-Erling Smørgrav int next_state, state = 0; 554bc5531deSDag-Erling Smørgrav struct sshbuf *sect; 555bc5531deSDag-Erling Smørgrav struct bitmap *bitmap = NULL; 5566888a9beSDag-Erling Smørgrav 557bc5531deSDag-Erling Smørgrav if ((sect = sshbuf_new()) == NULL) 558bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 5596888a9beSDag-Erling Smørgrav 560bc5531deSDag-Erling Smørgrav /* Store the header: optional CA scope key, reserved */ 561bc5531deSDag-Erling Smørgrav if (rc->ca_key == NULL) { 562bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) 563bc5531deSDag-Erling Smørgrav goto out; 564bc5531deSDag-Erling Smørgrav } else { 565bc5531deSDag-Erling Smørgrav if ((r = sshkey_puts(rc->ca_key, buf)) != 0) 566bc5531deSDag-Erling Smørgrav goto out; 567bc5531deSDag-Erling Smørgrav } 568bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) 569bc5531deSDag-Erling Smørgrav goto out; 5706888a9beSDag-Erling Smørgrav 5716888a9beSDag-Erling Smørgrav /* Store the revoked serials. */ 5726888a9beSDag-Erling Smørgrav for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials); 5736888a9beSDag-Erling Smørgrav rs != NULL; 5746888a9beSDag-Erling Smørgrav rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) { 575bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: serial %llu:%llu state 0x%02x", __func__, 576e4a9863fSDag-Erling Smørgrav (long long unsigned)rs->lo, (long long unsigned)rs->hi, 577bc5531deSDag-Erling Smørgrav state)); 5786888a9beSDag-Erling Smørgrav 5796888a9beSDag-Erling Smørgrav /* Check contiguous length and gap to next section (if any) */ 5806888a9beSDag-Erling Smørgrav nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs); 5816888a9beSDag-Erling Smørgrav final = nrs == NULL; 5826888a9beSDag-Erling Smørgrav gap = nrs == NULL ? 0 : nrs->lo - rs->hi; 5836888a9beSDag-Erling Smørgrav contig = 1 + (rs->hi - rs->lo); 5846888a9beSDag-Erling Smørgrav 5856888a9beSDag-Erling Smørgrav /* Choose next state based on these */ 5866888a9beSDag-Erling Smørgrav next_state = choose_next_state(state, contig, final, 5876888a9beSDag-Erling Smørgrav state == 0 ? 0 : rs->lo - last, gap, &force_new_sect); 5886888a9beSDag-Erling Smørgrav 5896888a9beSDag-Erling Smørgrav /* 5906888a9beSDag-Erling Smørgrav * If the current section is a range section or has a different 5916888a9beSDag-Erling Smørgrav * type to the next section, then finish it off now. 5926888a9beSDag-Erling Smørgrav */ 5936888a9beSDag-Erling Smørgrav if (state != 0 && (force_new_sect || next_state != state || 5946888a9beSDag-Erling Smørgrav state == KRL_SECTION_CERT_SERIAL_RANGE)) { 595bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: finish state 0x%02x", __func__, state)); 5966888a9beSDag-Erling Smørgrav switch (state) { 5976888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 5986888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 5996888a9beSDag-Erling Smørgrav break; 6006888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 601bc5531deSDag-Erling Smørgrav if ((r = put_bitmap(sect, bitmap)) != 0) 602bc5531deSDag-Erling Smørgrav goto out; 603bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 6046888a9beSDag-Erling Smørgrav bitmap = NULL; 6056888a9beSDag-Erling Smørgrav break; 6066888a9beSDag-Erling Smørgrav } 607bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, state)) != 0 || 608bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 609bc5531deSDag-Erling Smørgrav goto out; 610bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 6116888a9beSDag-Erling Smørgrav } 6126888a9beSDag-Erling Smørgrav 6136888a9beSDag-Erling Smørgrav /* If we are starting a new section then prepare it now */ 6146888a9beSDag-Erling Smørgrav if (next_state != state || force_new_sect) { 615bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: start state 0x%02x", __func__, 616bc5531deSDag-Erling Smørgrav next_state)); 6176888a9beSDag-Erling Smørgrav state = next_state; 618bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 6196888a9beSDag-Erling Smørgrav switch (state) { 6206888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 6216888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 6226888a9beSDag-Erling Smørgrav break; 6236888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 624bc5531deSDag-Erling Smørgrav if ((bitmap = bitmap_new()) == NULL) { 625bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 6266888a9beSDag-Erling Smørgrav goto out; 627bc5531deSDag-Erling Smørgrav } 6286888a9beSDag-Erling Smørgrav bitmap_start = rs->lo; 629bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u64(sect, 630bc5531deSDag-Erling Smørgrav bitmap_start)) != 0) 631bc5531deSDag-Erling Smørgrav goto out; 6326888a9beSDag-Erling Smørgrav break; 6336888a9beSDag-Erling Smørgrav } 6346888a9beSDag-Erling Smørgrav } 6356888a9beSDag-Erling Smørgrav 6366888a9beSDag-Erling Smørgrav /* Perform section-specific processing */ 6376888a9beSDag-Erling Smørgrav switch (state) { 6386888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 639bc5531deSDag-Erling Smørgrav for (i = 0; i < contig; i++) { 640bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u64(sect, rs->lo + i)) != 0) 641bc5531deSDag-Erling Smørgrav goto out; 642bc5531deSDag-Erling Smørgrav } 6436888a9beSDag-Erling Smørgrav break; 6446888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 645bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u64(sect, rs->lo)) != 0 || 646bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u64(sect, rs->hi)) != 0) 647bc5531deSDag-Erling Smørgrav goto out; 6486888a9beSDag-Erling Smørgrav break; 6496888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 6506888a9beSDag-Erling Smørgrav if (rs->lo - bitmap_start > INT_MAX) { 6516888a9beSDag-Erling Smørgrav error("%s: insane bitmap gap", __func__); 6526888a9beSDag-Erling Smørgrav goto out; 6536888a9beSDag-Erling Smørgrav } 6546888a9beSDag-Erling Smørgrav for (i = 0; i < contig; i++) { 655bc5531deSDag-Erling Smørgrav if (bitmap_set_bit(bitmap, 656bc5531deSDag-Erling Smørgrav rs->lo + i - bitmap_start) != 0) { 657bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 6586888a9beSDag-Erling Smørgrav goto out; 6596888a9beSDag-Erling Smørgrav } 660bc5531deSDag-Erling Smørgrav } 6616888a9beSDag-Erling Smørgrav break; 6626888a9beSDag-Erling Smørgrav } 6636888a9beSDag-Erling Smørgrav last = rs->hi; 6646888a9beSDag-Erling Smørgrav } 6656888a9beSDag-Erling Smørgrav /* Flush the remaining section, if any */ 6666888a9beSDag-Erling Smørgrav if (state != 0) { 667bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: serial final flush for state 0x%02x", 668bc5531deSDag-Erling Smørgrav __func__, state)); 6696888a9beSDag-Erling Smørgrav switch (state) { 6706888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 6716888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 6726888a9beSDag-Erling Smørgrav break; 6736888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 674bc5531deSDag-Erling Smørgrav if ((r = put_bitmap(sect, bitmap)) != 0) 675bc5531deSDag-Erling Smørgrav goto out; 676bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 6776888a9beSDag-Erling Smørgrav bitmap = NULL; 6786888a9beSDag-Erling Smørgrav break; 6796888a9beSDag-Erling Smørgrav } 680bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, state)) != 0 || 681bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 682bc5531deSDag-Erling Smørgrav goto out; 6836888a9beSDag-Erling Smørgrav } 684bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: serial done ", __func__)); 6856888a9beSDag-Erling Smørgrav 6866888a9beSDag-Erling Smørgrav /* Now output a section for any revocations by key ID */ 687bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 6886888a9beSDag-Erling Smørgrav RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) { 689bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: key ID %s", __func__, rki->key_id)); 690bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_cstring(sect, rki->key_id)) != 0) 691bc5531deSDag-Erling Smørgrav goto out; 6926888a9beSDag-Erling Smørgrav } 693bc5531deSDag-Erling Smørgrav if (sshbuf_len(sect) != 0) { 694bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERT_KEY_ID)) != 0 || 695bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 696bc5531deSDag-Erling Smørgrav goto out; 6976888a9beSDag-Erling Smørgrav } 6986888a9beSDag-Erling Smørgrav r = 0; 6996888a9beSDag-Erling Smørgrav out: 700bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 701bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 7026888a9beSDag-Erling Smørgrav return r; 7036888a9beSDag-Erling Smørgrav } 7046888a9beSDag-Erling Smørgrav 7056888a9beSDag-Erling Smørgrav int 706bc5531deSDag-Erling Smørgrav ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, 707bc5531deSDag-Erling Smørgrav const struct sshkey **sign_keys, u_int nsign_keys) 7086888a9beSDag-Erling Smørgrav { 709bc5531deSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR; 7106888a9beSDag-Erling Smørgrav struct revoked_certs *rc; 7116888a9beSDag-Erling Smørgrav struct revoked_blob *rb; 712bc5531deSDag-Erling Smørgrav struct sshbuf *sect; 713bc5531deSDag-Erling Smørgrav u_char *sblob = NULL; 714bc5531deSDag-Erling Smørgrav size_t slen, i; 7156888a9beSDag-Erling Smørgrav 7166888a9beSDag-Erling Smørgrav if (krl->generated_date == 0) 7176888a9beSDag-Erling Smørgrav krl->generated_date = time(NULL); 7186888a9beSDag-Erling Smørgrav 719bc5531deSDag-Erling Smørgrav if ((sect = sshbuf_new()) == NULL) 720bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 7216888a9beSDag-Erling Smørgrav 7226888a9beSDag-Erling Smørgrav /* Store the header */ 723bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 || 724bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 || 725bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u64(buf, krl->krl_version)) != 0 || 726*acc1a9efSDag-Erling Smørgrav (r = sshbuf_put_u64(buf, krl->generated_date)) != 0 || 727bc5531deSDag-Erling Smørgrav (r = sshbuf_put_u64(buf, krl->flags)) != 0 || 728bc5531deSDag-Erling Smørgrav (r = sshbuf_put_string(buf, NULL, 0)) != 0 || 729bc5531deSDag-Erling Smørgrav (r = sshbuf_put_cstring(buf, krl->comment)) != 0) 730bc5531deSDag-Erling Smørgrav goto out; 7316888a9beSDag-Erling Smørgrav 7326888a9beSDag-Erling Smørgrav /* Store sections for revoked certificates */ 7336888a9beSDag-Erling Smørgrav TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 734bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 735bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_generate(rc, sect)) != 0) 7366888a9beSDag-Erling Smørgrav goto out; 737bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 || 738bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 739bc5531deSDag-Erling Smørgrav goto out; 7406888a9beSDag-Erling Smørgrav } 7416888a9beSDag-Erling Smørgrav 7426888a9beSDag-Erling Smørgrav /* Finally, output sections for revocations by public key/hash */ 743bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 7446888a9beSDag-Erling Smørgrav RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { 745bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: key len %zu ", __func__, rb->len)); 746bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 747bc5531deSDag-Erling Smørgrav goto out; 7486888a9beSDag-Erling Smørgrav } 749bc5531deSDag-Erling Smørgrav if (sshbuf_len(sect) != 0) { 750bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 || 751bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 752bc5531deSDag-Erling Smørgrav goto out; 7536888a9beSDag-Erling Smørgrav } 754bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 7556888a9beSDag-Erling Smørgrav RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { 756bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: hash len %zu ", __func__, rb->len)); 757bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 758bc5531deSDag-Erling Smørgrav goto out; 7596888a9beSDag-Erling Smørgrav } 760bc5531deSDag-Erling Smørgrav if (sshbuf_len(sect) != 0) { 761bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, 762bc5531deSDag-Erling Smørgrav KRL_SECTION_FINGERPRINT_SHA1)) != 0 || 763bc5531deSDag-Erling Smørgrav (r = sshbuf_put_stringb(buf, sect)) != 0) 764bc5531deSDag-Erling Smørgrav goto out; 7656888a9beSDag-Erling Smørgrav } 7666888a9beSDag-Erling Smørgrav 7676888a9beSDag-Erling Smørgrav for (i = 0; i < nsign_keys; i++) { 768bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: signature key %s", __func__, 769bc5531deSDag-Erling Smørgrav sshkey_ssh_name(sign_keys[i]))); 770bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 || 771bc5531deSDag-Erling Smørgrav (r = sshkey_puts(sign_keys[i], buf)) != 0) 7726888a9beSDag-Erling Smørgrav goto out; 7736888a9beSDag-Erling Smørgrav 774bc5531deSDag-Erling Smørgrav if ((r = sshkey_sign(sign_keys[i], &sblob, &slen, 775*acc1a9efSDag-Erling Smørgrav sshbuf_ptr(buf), sshbuf_len(buf), NULL, 0)) != 0) 7766888a9beSDag-Erling Smørgrav goto out; 777bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: signature sig len %zu", __func__, slen)); 778bc5531deSDag-Erling Smørgrav if ((r = sshbuf_put_string(buf, sblob, slen)) != 0) 779bc5531deSDag-Erling Smørgrav goto out; 7806888a9beSDag-Erling Smørgrav } 7816888a9beSDag-Erling Smørgrav 7826888a9beSDag-Erling Smørgrav r = 0; 7836888a9beSDag-Erling Smørgrav out: 7846888a9beSDag-Erling Smørgrav free(sblob); 785bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 7866888a9beSDag-Erling Smørgrav return r; 7876888a9beSDag-Erling Smørgrav } 7886888a9beSDag-Erling Smørgrav 7896888a9beSDag-Erling Smørgrav static void 7906888a9beSDag-Erling Smørgrav format_timestamp(u_int64_t timestamp, char *ts, size_t nts) 7916888a9beSDag-Erling Smørgrav { 7926888a9beSDag-Erling Smørgrav time_t t; 7936888a9beSDag-Erling Smørgrav struct tm *tm; 7946888a9beSDag-Erling Smørgrav 7956888a9beSDag-Erling Smørgrav t = timestamp; 7966888a9beSDag-Erling Smørgrav tm = localtime(&t); 797bc5531deSDag-Erling Smørgrav if (tm == NULL) 798bc5531deSDag-Erling Smørgrav strlcpy(ts, "<INVALID>", nts); 799bc5531deSDag-Erling Smørgrav else { 8006888a9beSDag-Erling Smørgrav *ts = '\0'; 8016888a9beSDag-Erling Smørgrav strftime(ts, nts, "%Y%m%dT%H%M%S", tm); 8026888a9beSDag-Erling Smørgrav } 803bc5531deSDag-Erling Smørgrav } 8046888a9beSDag-Erling Smørgrav 8056888a9beSDag-Erling Smørgrav static int 806bc5531deSDag-Erling Smørgrav parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl) 8076888a9beSDag-Erling Smørgrav { 808bc5531deSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR; 809a0ee8cc6SDag-Erling Smørgrav u_char type; 810a0ee8cc6SDag-Erling Smørgrav const u_char *blob; 811bc5531deSDag-Erling Smørgrav size_t blen, nbits; 812bc5531deSDag-Erling Smørgrav struct sshbuf *subsect = NULL; 8136888a9beSDag-Erling Smørgrav u_int64_t serial, serial_lo, serial_hi; 814bc5531deSDag-Erling Smørgrav struct bitmap *bitmap = NULL; 8156888a9beSDag-Erling Smørgrav char *key_id = NULL; 816bc5531deSDag-Erling Smørgrav struct sshkey *ca_key = NULL; 8176888a9beSDag-Erling Smørgrav 818bc5531deSDag-Erling Smørgrav if ((subsect = sshbuf_new()) == NULL) 819bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 8206888a9beSDag-Erling Smørgrav 821bc5531deSDag-Erling Smørgrav /* Header: key, reserved */ 822bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || 823bc5531deSDag-Erling Smørgrav (r = sshbuf_skip_string(buf)) != 0) 8246888a9beSDag-Erling Smørgrav goto out; 825bc5531deSDag-Erling Smørgrav if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0) 826bc5531deSDag-Erling Smørgrav goto out; 827bc5531deSDag-Erling Smørgrav 828bc5531deSDag-Erling Smørgrav while (sshbuf_len(buf) > 0) { 829bc5531deSDag-Erling Smørgrav sshbuf_free(subsect); 830bc5531deSDag-Erling Smørgrav subsect = NULL; 831bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(buf, &type)) != 0 || 832bc5531deSDag-Erling Smørgrav (r = sshbuf_froms(buf, &subsect)) != 0) 8336888a9beSDag-Erling Smørgrav goto out; 834bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: subsection type 0x%02x", __func__, type)); 835bc5531deSDag-Erling Smørgrav /* sshbuf_dump(subsect, stderr); */ 8366888a9beSDag-Erling Smørgrav 8376888a9beSDag-Erling Smørgrav switch (type) { 8386888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_LIST: 839bc5531deSDag-Erling Smørgrav while (sshbuf_len(subsect) > 0) { 840bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(subsect, &serial)) != 0) 8416888a9beSDag-Erling Smørgrav goto out; 842bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_serial(krl, 843bc5531deSDag-Erling Smørgrav ca_key, serial)) != 0) 8446888a9beSDag-Erling Smørgrav goto out; 8456888a9beSDag-Erling Smørgrav } 8466888a9beSDag-Erling Smørgrav break; 8476888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_RANGE: 848bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || 849bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u64(subsect, &serial_hi)) != 0) 8506888a9beSDag-Erling Smørgrav goto out; 851bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_serial_range(krl, 852bc5531deSDag-Erling Smørgrav ca_key, serial_lo, serial_hi)) != 0) 8536888a9beSDag-Erling Smørgrav goto out; 8546888a9beSDag-Erling Smørgrav break; 8556888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_SERIAL_BITMAP: 856bc5531deSDag-Erling Smørgrav if ((bitmap = bitmap_new()) == NULL) { 857bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 8586888a9beSDag-Erling Smørgrav goto out; 8596888a9beSDag-Erling Smørgrav } 860bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || 861bc5531deSDag-Erling Smørgrav (r = sshbuf_get_bignum2_bytes_direct(subsect, 862bc5531deSDag-Erling Smørgrav &blob, &blen)) != 0) 863bc5531deSDag-Erling Smørgrav goto out; 864bc5531deSDag-Erling Smørgrav if (bitmap_from_string(bitmap, blob, blen) != 0) { 865bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 8666888a9beSDag-Erling Smørgrav goto out; 8676888a9beSDag-Erling Smørgrav } 868bc5531deSDag-Erling Smørgrav nbits = bitmap_nbits(bitmap); 869bc5531deSDag-Erling Smørgrav for (serial = 0; serial < (u_int64_t)nbits; serial++) { 8706888a9beSDag-Erling Smørgrav if (serial > 0 && serial_lo + serial == 0) { 8716888a9beSDag-Erling Smørgrav error("%s: bitmap wraps u64", __func__); 872bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 8736888a9beSDag-Erling Smørgrav goto out; 8746888a9beSDag-Erling Smørgrav } 875bc5531deSDag-Erling Smørgrav if (!bitmap_test_bit(bitmap, serial)) 8766888a9beSDag-Erling Smørgrav continue; 877bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_serial(krl, 878bc5531deSDag-Erling Smørgrav ca_key, serial_lo + serial)) != 0) 8796888a9beSDag-Erling Smørgrav goto out; 8806888a9beSDag-Erling Smørgrav } 881bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 8826888a9beSDag-Erling Smørgrav bitmap = NULL; 8836888a9beSDag-Erling Smørgrav break; 8846888a9beSDag-Erling Smørgrav case KRL_SECTION_CERT_KEY_ID: 885bc5531deSDag-Erling Smørgrav while (sshbuf_len(subsect) > 0) { 886bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(subsect, 887bc5531deSDag-Erling Smørgrav &key_id, NULL)) != 0) 8886888a9beSDag-Erling Smørgrav goto out; 889bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_revoke_cert_by_key_id(krl, 890bc5531deSDag-Erling Smørgrav ca_key, key_id)) != 0) 8916888a9beSDag-Erling Smørgrav goto out; 8926888a9beSDag-Erling Smørgrav free(key_id); 8936888a9beSDag-Erling Smørgrav key_id = NULL; 8946888a9beSDag-Erling Smørgrav } 8956888a9beSDag-Erling Smørgrav break; 8966888a9beSDag-Erling Smørgrav default: 8976888a9beSDag-Erling Smørgrav error("Unsupported KRL certificate section %u", type); 898bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 8996888a9beSDag-Erling Smørgrav goto out; 9006888a9beSDag-Erling Smørgrav } 901bc5531deSDag-Erling Smørgrav if (sshbuf_len(subsect) > 0) { 9026888a9beSDag-Erling Smørgrav error("KRL certificate section contains unparsed data"); 903bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9046888a9beSDag-Erling Smørgrav goto out; 9056888a9beSDag-Erling Smørgrav } 9066888a9beSDag-Erling Smørgrav } 9076888a9beSDag-Erling Smørgrav 908bc5531deSDag-Erling Smørgrav r = 0; 9096888a9beSDag-Erling Smørgrav out: 9106888a9beSDag-Erling Smørgrav if (bitmap != NULL) 911bc5531deSDag-Erling Smørgrav bitmap_free(bitmap); 9126888a9beSDag-Erling Smørgrav free(key_id); 913bc5531deSDag-Erling Smørgrav sshkey_free(ca_key); 914bc5531deSDag-Erling Smørgrav sshbuf_free(subsect); 915bc5531deSDag-Erling Smørgrav return r; 9166888a9beSDag-Erling Smørgrav } 9176888a9beSDag-Erling Smørgrav 9186888a9beSDag-Erling Smørgrav 9196888a9beSDag-Erling Smørgrav /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ 9206888a9beSDag-Erling Smørgrav int 921bc5531deSDag-Erling Smørgrav ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, 922bc5531deSDag-Erling Smørgrav const struct sshkey **sign_ca_keys, size_t nsign_ca_keys) 9236888a9beSDag-Erling Smørgrav { 924bc5531deSDag-Erling Smørgrav struct sshbuf *copy = NULL, *sect = NULL; 925bc5531deSDag-Erling Smørgrav struct ssh_krl *krl = NULL; 9266888a9beSDag-Erling Smørgrav char timestamp[64]; 927bc5531deSDag-Erling Smørgrav int r = SSH_ERR_INTERNAL_ERROR, sig_seen; 928bc5531deSDag-Erling Smørgrav struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used; 929a0ee8cc6SDag-Erling Smørgrav u_char type, *rdata = NULL; 930a0ee8cc6SDag-Erling Smørgrav const u_char *blob; 931bc5531deSDag-Erling Smørgrav size_t i, j, sig_off, sects_off, rlen, blen, nca_used; 932bc5531deSDag-Erling Smørgrav u_int format_version; 9336888a9beSDag-Erling Smørgrav 934e4a9863fSDag-Erling Smørgrav nca_used = 0; 9356888a9beSDag-Erling Smørgrav *krlp = NULL; 936bc5531deSDag-Erling Smørgrav if (sshbuf_len(buf) < sizeof(KRL_MAGIC) - 1 || 937bc5531deSDag-Erling Smørgrav memcmp(sshbuf_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) { 9386888a9beSDag-Erling Smørgrav debug3("%s: not a KRL", __func__); 939bc5531deSDag-Erling Smørgrav return SSH_ERR_KRL_BAD_MAGIC; 9406888a9beSDag-Erling Smørgrav } 9416888a9beSDag-Erling Smørgrav 9426888a9beSDag-Erling Smørgrav /* Take a copy of the KRL buffer so we can verify its signature later */ 943bc5531deSDag-Erling Smørgrav if ((copy = sshbuf_fromb(buf)) == NULL) { 944bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 945bc5531deSDag-Erling Smørgrav goto out; 946bc5531deSDag-Erling Smørgrav } 947bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0) 948bc5531deSDag-Erling Smørgrav goto out; 9496888a9beSDag-Erling Smørgrav 9506888a9beSDag-Erling Smørgrav if ((krl = ssh_krl_init()) == NULL) { 9516888a9beSDag-Erling Smørgrav error("%s: alloc failed", __func__); 9526888a9beSDag-Erling Smørgrav goto out; 9536888a9beSDag-Erling Smørgrav } 9546888a9beSDag-Erling Smørgrav 955bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u32(copy, &format_version)) != 0) 9566888a9beSDag-Erling Smørgrav goto out; 9576888a9beSDag-Erling Smørgrav if (format_version != KRL_FORMAT_VERSION) { 958bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9596888a9beSDag-Erling Smørgrav goto out; 9606888a9beSDag-Erling Smørgrav } 961bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 || 962bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 || 963bc5531deSDag-Erling Smørgrav (r = sshbuf_get_u64(copy, &krl->flags)) != 0 || 964bc5531deSDag-Erling Smørgrav (r = sshbuf_skip_string(copy)) != 0 || 965bc5531deSDag-Erling Smørgrav (r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0) 9666888a9beSDag-Erling Smørgrav goto out; 9676888a9beSDag-Erling Smørgrav 9686888a9beSDag-Erling Smørgrav format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); 96959928918SDag-Erling Smørgrav debug("KRL version %llu generated at %s%s%s", 970e4a9863fSDag-Erling Smørgrav (long long unsigned)krl->krl_version, timestamp, 97159928918SDag-Erling Smørgrav *krl->comment ? ": " : "", krl->comment); 9726888a9beSDag-Erling Smørgrav 9736888a9beSDag-Erling Smørgrav /* 9746888a9beSDag-Erling Smørgrav * 1st pass: verify signatures, if any. This is done to avoid 9756888a9beSDag-Erling Smørgrav * detailed parsing of data whose provenance is unverified. 9766888a9beSDag-Erling Smørgrav */ 9776888a9beSDag-Erling Smørgrav sig_seen = 0; 978bc5531deSDag-Erling Smørgrav if (sshbuf_len(buf) < sshbuf_len(copy)) { 979bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 980bc5531deSDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 9816888a9beSDag-Erling Smørgrav goto out; 9826888a9beSDag-Erling Smørgrav } 983bc5531deSDag-Erling Smørgrav sects_off = sshbuf_len(buf) - sshbuf_len(copy); 984bc5531deSDag-Erling Smørgrav while (sshbuf_len(copy) > 0) { 985bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(copy, &type)) != 0 || 986bc5531deSDag-Erling Smørgrav (r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) 987bc5531deSDag-Erling Smørgrav goto out; 988bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: first pass, section 0x%02x", __func__, type)); 9896888a9beSDag-Erling Smørgrav if (type != KRL_SECTION_SIGNATURE) { 9906888a9beSDag-Erling Smørgrav if (sig_seen) { 9916888a9beSDag-Erling Smørgrav error("KRL contains non-signature section " 9926888a9beSDag-Erling Smørgrav "after signature"); 993bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 9946888a9beSDag-Erling Smørgrav goto out; 9956888a9beSDag-Erling Smørgrav } 9966888a9beSDag-Erling Smørgrav /* Not interested for now. */ 9976888a9beSDag-Erling Smørgrav continue; 9986888a9beSDag-Erling Smørgrav } 9996888a9beSDag-Erling Smørgrav sig_seen = 1; 10006888a9beSDag-Erling Smørgrav /* First string component is the signing key */ 1001bc5531deSDag-Erling Smørgrav if ((r = sshkey_from_blob(blob, blen, &key)) != 0) { 1002bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10036888a9beSDag-Erling Smørgrav goto out; 10046888a9beSDag-Erling Smørgrav } 1005bc5531deSDag-Erling Smørgrav if (sshbuf_len(buf) < sshbuf_len(copy)) { 1006bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 1007bc5531deSDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 1008bc5531deSDag-Erling Smørgrav goto out; 1009bc5531deSDag-Erling Smørgrav } 1010bc5531deSDag-Erling Smørgrav sig_off = sshbuf_len(buf) - sshbuf_len(copy); 10116888a9beSDag-Erling Smørgrav /* Second string component is the signature itself */ 1012bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) { 1013bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10146888a9beSDag-Erling Smørgrav goto out; 10156888a9beSDag-Erling Smørgrav } 10166888a9beSDag-Erling Smørgrav /* Check signature over entire KRL up to this point */ 1017bc5531deSDag-Erling Smørgrav if ((r = sshkey_verify(key, blob, blen, 1018*acc1a9efSDag-Erling Smørgrav sshbuf_ptr(buf), sig_off, 0)) != 0) 10196888a9beSDag-Erling Smørgrav goto out; 10206888a9beSDag-Erling Smørgrav /* Check if this key has already signed this KRL */ 10216888a9beSDag-Erling Smørgrav for (i = 0; i < nca_used; i++) { 1022bc5531deSDag-Erling Smørgrav if (sshkey_equal(ca_used[i], key)) { 10236888a9beSDag-Erling Smørgrav error("KRL signed more than once with " 10246888a9beSDag-Erling Smørgrav "the same key"); 1025bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10266888a9beSDag-Erling Smørgrav goto out; 10276888a9beSDag-Erling Smørgrav } 10286888a9beSDag-Erling Smørgrav } 10296888a9beSDag-Erling Smørgrav /* Record keys used to sign the KRL */ 1030bc5531deSDag-Erling Smørgrav tmp_ca_used = reallocarray(ca_used, nca_used + 1, 1031bc5531deSDag-Erling Smørgrav sizeof(*ca_used)); 1032bc5531deSDag-Erling Smørgrav if (tmp_ca_used == NULL) { 1033bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 1034bc5531deSDag-Erling Smørgrav goto out; 1035bc5531deSDag-Erling Smørgrav } 1036bc5531deSDag-Erling Smørgrav ca_used = tmp_ca_used; 10376888a9beSDag-Erling Smørgrav ca_used[nca_used++] = key; 10386888a9beSDag-Erling Smørgrav key = NULL; 10396888a9beSDag-Erling Smørgrav } 10406888a9beSDag-Erling Smørgrav 1041bc5531deSDag-Erling Smørgrav if (sshbuf_len(copy) != 0) { 1042bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 1043bc5531deSDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 1044bc5531deSDag-Erling Smørgrav goto out; 1045bc5531deSDag-Erling Smørgrav } 1046bc5531deSDag-Erling Smørgrav 10476888a9beSDag-Erling Smørgrav /* 10486888a9beSDag-Erling Smørgrav * 2nd pass: parse and load the KRL, skipping the header to the point 10496888a9beSDag-Erling Smørgrav * where the section start. 10506888a9beSDag-Erling Smørgrav */ 1051bc5531deSDag-Erling Smørgrav sshbuf_free(copy); 1052bc5531deSDag-Erling Smørgrav if ((copy = sshbuf_fromb(buf)) == NULL) { 1053bc5531deSDag-Erling Smørgrav r = SSH_ERR_ALLOC_FAIL; 10546888a9beSDag-Erling Smørgrav goto out; 10556888a9beSDag-Erling Smørgrav } 1056bc5531deSDag-Erling Smørgrav if ((r = sshbuf_consume(copy, sects_off)) != 0) 1057bc5531deSDag-Erling Smørgrav goto out; 1058bc5531deSDag-Erling Smørgrav while (sshbuf_len(copy) > 0) { 1059bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 1060bc5531deSDag-Erling Smørgrav sect = NULL; 1061bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_u8(copy, &type)) != 0 || 1062bc5531deSDag-Erling Smørgrav (r = sshbuf_froms(copy, §)) != 0) 1063bc5531deSDag-Erling Smørgrav goto out; 1064bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: second pass, section 0x%02x", __func__, type)); 10656888a9beSDag-Erling Smørgrav 10666888a9beSDag-Erling Smørgrav switch (type) { 10676888a9beSDag-Erling Smørgrav case KRL_SECTION_CERTIFICATES: 1068bc5531deSDag-Erling Smørgrav if ((r = parse_revoked_certs(sect, krl)) != 0) 10696888a9beSDag-Erling Smørgrav goto out; 10706888a9beSDag-Erling Smørgrav break; 10716888a9beSDag-Erling Smørgrav case KRL_SECTION_EXPLICIT_KEY: 10726888a9beSDag-Erling Smørgrav case KRL_SECTION_FINGERPRINT_SHA1: 1073bc5531deSDag-Erling Smørgrav while (sshbuf_len(sect) > 0) { 1074bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_string(sect, 1075bc5531deSDag-Erling Smørgrav &rdata, &rlen)) != 0) 10766888a9beSDag-Erling Smørgrav goto out; 10776888a9beSDag-Erling Smørgrav if (type == KRL_SECTION_FINGERPRINT_SHA1 && 1078e4a9863fSDag-Erling Smørgrav rlen != 20) { 10796888a9beSDag-Erling Smørgrav error("%s: bad SHA1 length", __func__); 1080bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 10816888a9beSDag-Erling Smørgrav goto out; 10826888a9beSDag-Erling Smørgrav } 1083bc5531deSDag-Erling Smørgrav if ((r = revoke_blob( 10846888a9beSDag-Erling Smørgrav type == KRL_SECTION_EXPLICIT_KEY ? 10856888a9beSDag-Erling Smørgrav &krl->revoked_keys : &krl->revoked_sha1s, 1086bc5531deSDag-Erling Smørgrav rdata, rlen)) != 0) 1087e4a9863fSDag-Erling Smørgrav goto out; 1088bc5531deSDag-Erling Smørgrav rdata = NULL; /* revoke_blob frees rdata */ 10896888a9beSDag-Erling Smørgrav } 10906888a9beSDag-Erling Smørgrav break; 10916888a9beSDag-Erling Smørgrav case KRL_SECTION_SIGNATURE: 10926888a9beSDag-Erling Smørgrav /* Handled above, but still need to stay in synch */ 1093bc5531deSDag-Erling Smørgrav sshbuf_reset(sect); 1094bc5531deSDag-Erling Smørgrav sect = NULL; 1095bc5531deSDag-Erling Smørgrav if ((r = sshbuf_skip_string(copy)) != 0) 10966888a9beSDag-Erling Smørgrav goto out; 10976888a9beSDag-Erling Smørgrav break; 10986888a9beSDag-Erling Smørgrav default: 10996888a9beSDag-Erling Smørgrav error("Unsupported KRL section %u", type); 1100bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 11016888a9beSDag-Erling Smørgrav goto out; 11026888a9beSDag-Erling Smørgrav } 1103*acc1a9efSDag-Erling Smørgrav if (sect != NULL && sshbuf_len(sect) > 0) { 11046888a9beSDag-Erling Smørgrav error("KRL section contains unparsed data"); 1105bc5531deSDag-Erling Smørgrav r = SSH_ERR_INVALID_FORMAT; 11066888a9beSDag-Erling Smørgrav goto out; 11076888a9beSDag-Erling Smørgrav } 11086888a9beSDag-Erling Smørgrav } 11096888a9beSDag-Erling Smørgrav 11106888a9beSDag-Erling Smørgrav /* Check that the key(s) used to sign the KRL weren't revoked */ 11116888a9beSDag-Erling Smørgrav sig_seen = 0; 11126888a9beSDag-Erling Smørgrav for (i = 0; i < nca_used; i++) { 11136888a9beSDag-Erling Smørgrav if (ssh_krl_check_key(krl, ca_used[i]) == 0) 11146888a9beSDag-Erling Smørgrav sig_seen = 1; 11156888a9beSDag-Erling Smørgrav else { 1116bc5531deSDag-Erling Smørgrav sshkey_free(ca_used[i]); 11176888a9beSDag-Erling Smørgrav ca_used[i] = NULL; 11186888a9beSDag-Erling Smørgrav } 11196888a9beSDag-Erling Smørgrav } 11206888a9beSDag-Erling Smørgrav if (nca_used && !sig_seen) { 11216888a9beSDag-Erling Smørgrav error("All keys used to sign KRL were revoked"); 1122bc5531deSDag-Erling Smørgrav r = SSH_ERR_KEY_REVOKED; 11236888a9beSDag-Erling Smørgrav goto out; 11246888a9beSDag-Erling Smørgrav } 11256888a9beSDag-Erling Smørgrav 11266888a9beSDag-Erling Smørgrav /* If we have CA keys, then verify that one was used to sign the KRL */ 11276888a9beSDag-Erling Smørgrav if (sig_seen && nsign_ca_keys != 0) { 11286888a9beSDag-Erling Smørgrav sig_seen = 0; 11296888a9beSDag-Erling Smørgrav for (i = 0; !sig_seen && i < nsign_ca_keys; i++) { 11306888a9beSDag-Erling Smørgrav for (j = 0; j < nca_used; j++) { 11316888a9beSDag-Erling Smørgrav if (ca_used[j] == NULL) 11326888a9beSDag-Erling Smørgrav continue; 1133bc5531deSDag-Erling Smørgrav if (sshkey_equal(ca_used[j], sign_ca_keys[i])) { 11346888a9beSDag-Erling Smørgrav sig_seen = 1; 11356888a9beSDag-Erling Smørgrav break; 11366888a9beSDag-Erling Smørgrav } 11376888a9beSDag-Erling Smørgrav } 11386888a9beSDag-Erling Smørgrav } 11396888a9beSDag-Erling Smørgrav if (!sig_seen) { 1140bc5531deSDag-Erling Smørgrav r = SSH_ERR_SIGNATURE_INVALID; 11416888a9beSDag-Erling Smørgrav error("KRL not signed with any trusted key"); 11426888a9beSDag-Erling Smørgrav goto out; 11436888a9beSDag-Erling Smørgrav } 11446888a9beSDag-Erling Smørgrav } 11456888a9beSDag-Erling Smørgrav 11466888a9beSDag-Erling Smørgrav *krlp = krl; 1147bc5531deSDag-Erling Smørgrav r = 0; 11486888a9beSDag-Erling Smørgrav out: 1149bc5531deSDag-Erling Smørgrav if (r != 0) 11506888a9beSDag-Erling Smørgrav ssh_krl_free(krl); 1151bc5531deSDag-Erling Smørgrav for (i = 0; i < nca_used; i++) 1152bc5531deSDag-Erling Smørgrav sshkey_free(ca_used[i]); 11536888a9beSDag-Erling Smørgrav free(ca_used); 1154e4a9863fSDag-Erling Smørgrav free(rdata); 1155bc5531deSDag-Erling Smørgrav sshkey_free(key); 1156bc5531deSDag-Erling Smørgrav sshbuf_free(copy); 1157bc5531deSDag-Erling Smørgrav sshbuf_free(sect); 1158bc5531deSDag-Erling Smørgrav return r; 11596888a9beSDag-Erling Smørgrav } 11606888a9beSDag-Erling Smørgrav 1161bc5531deSDag-Erling Smørgrav /* Checks certificate serial number and key ID revocation */ 11626888a9beSDag-Erling Smørgrav static int 1163bc5531deSDag-Erling Smørgrav is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc) 11646888a9beSDag-Erling Smørgrav { 11656888a9beSDag-Erling Smørgrav struct revoked_serial rs, *ers; 11666888a9beSDag-Erling Smørgrav struct revoked_key_id rki, *erki; 11676888a9beSDag-Erling Smørgrav 11686888a9beSDag-Erling Smørgrav /* Check revocation by cert key ID */ 1169b83788ffSDag-Erling Smørgrav memset(&rki, 0, sizeof(rki)); 11706888a9beSDag-Erling Smørgrav rki.key_id = key->cert->key_id; 11716888a9beSDag-Erling Smørgrav erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); 11726888a9beSDag-Erling Smørgrav if (erki != NULL) { 1173bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked by key ID", __func__)); 1174bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 11756888a9beSDag-Erling Smørgrav } 11766888a9beSDag-Erling Smørgrav 11776888a9beSDag-Erling Smørgrav /* 1178eccfee6eSDag-Erling Smørgrav * Zero serials numbers are ignored (it's the default when the 1179eccfee6eSDag-Erling Smørgrav * CA doesn't specify one). 11806888a9beSDag-Erling Smørgrav */ 1181eccfee6eSDag-Erling Smørgrav if (key->cert->serial == 0) 11826888a9beSDag-Erling Smørgrav return 0; 11836888a9beSDag-Erling Smørgrav 1184b83788ffSDag-Erling Smørgrav memset(&rs, 0, sizeof(rs)); 11856888a9beSDag-Erling Smørgrav rs.lo = rs.hi = key->cert->serial; 11866888a9beSDag-Erling Smørgrav ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); 11876888a9beSDag-Erling Smørgrav if (ers != NULL) { 1188bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__, 11896888a9beSDag-Erling Smørgrav key->cert->serial, ers->lo, ers->hi)); 1190bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 11916888a9beSDag-Erling Smørgrav } 1192bc5531deSDag-Erling Smørgrav return 0; 1193bc5531deSDag-Erling Smørgrav } 11946888a9beSDag-Erling Smørgrav 1195bc5531deSDag-Erling Smørgrav /* Checks whether a given key/cert is revoked. Does not check its CA */ 1196bc5531deSDag-Erling Smørgrav static int 1197bc5531deSDag-Erling Smørgrav is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) 1198bc5531deSDag-Erling Smørgrav { 1199bc5531deSDag-Erling Smørgrav struct revoked_blob rb, *erb; 1200bc5531deSDag-Erling Smørgrav struct revoked_certs *rc; 1201bc5531deSDag-Erling Smørgrav int r; 1202bc5531deSDag-Erling Smørgrav 1203bc5531deSDag-Erling Smørgrav /* Check explicitly revoked hashes first */ 1204bc5531deSDag-Erling Smørgrav memset(&rb, 0, sizeof(rb)); 1205bc5531deSDag-Erling Smørgrav if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, 1206bc5531deSDag-Erling Smørgrav &rb.blob, &rb.len)) != 0) 1207bc5531deSDag-Erling Smørgrav return r; 1208bc5531deSDag-Erling Smørgrav erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); 1209bc5531deSDag-Erling Smørgrav free(rb.blob); 1210bc5531deSDag-Erling Smørgrav if (erb != NULL) { 1211bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked by key SHA1", __func__)); 1212bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 1213bc5531deSDag-Erling Smørgrav } 1214bc5531deSDag-Erling Smørgrav 1215bc5531deSDag-Erling Smørgrav /* Next, explicit keys */ 1216bc5531deSDag-Erling Smørgrav memset(&rb, 0, sizeof(rb)); 1217bc5531deSDag-Erling Smørgrav if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0) 1218bc5531deSDag-Erling Smørgrav return r; 1219bc5531deSDag-Erling Smørgrav erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); 1220bc5531deSDag-Erling Smørgrav free(rb.blob); 1221bc5531deSDag-Erling Smørgrav if (erb != NULL) { 1222bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: revoked by explicit key", __func__)); 1223bc5531deSDag-Erling Smørgrav return SSH_ERR_KEY_REVOKED; 1224bc5531deSDag-Erling Smørgrav } 1225bc5531deSDag-Erling Smørgrav 1226bc5531deSDag-Erling Smørgrav if (!sshkey_is_cert(key)) 1227bc5531deSDag-Erling Smørgrav return 0; 1228bc5531deSDag-Erling Smørgrav 1229bc5531deSDag-Erling Smørgrav /* Check cert revocation for the specified CA */ 1230bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, 1231bc5531deSDag-Erling Smørgrav &rc, 0)) != 0) 1232bc5531deSDag-Erling Smørgrav return r; 1233bc5531deSDag-Erling Smørgrav if (rc != NULL) { 1234bc5531deSDag-Erling Smørgrav if ((r = is_cert_revoked(key, rc)) != 0) 1235bc5531deSDag-Erling Smørgrav return r; 1236bc5531deSDag-Erling Smørgrav } 1237bc5531deSDag-Erling Smørgrav /* Check cert revocation for the wildcard CA */ 1238bc5531deSDag-Erling Smørgrav if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) 1239bc5531deSDag-Erling Smørgrav return r; 1240bc5531deSDag-Erling Smørgrav if (rc != NULL) { 1241bc5531deSDag-Erling Smørgrav if ((r = is_cert_revoked(key, rc)) != 0) 1242bc5531deSDag-Erling Smørgrav return r; 1243bc5531deSDag-Erling Smørgrav } 1244bc5531deSDag-Erling Smørgrav 1245bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); 12466888a9beSDag-Erling Smørgrav return 0; 12476888a9beSDag-Erling Smørgrav } 12486888a9beSDag-Erling Smørgrav 12496888a9beSDag-Erling Smørgrav int 1250bc5531deSDag-Erling Smørgrav ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key) 12516888a9beSDag-Erling Smørgrav { 12526888a9beSDag-Erling Smørgrav int r; 12536888a9beSDag-Erling Smørgrav 1254bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: checking key", __func__)); 12556888a9beSDag-Erling Smørgrav if ((r = is_key_revoked(krl, key)) != 0) 12566888a9beSDag-Erling Smørgrav return r; 1257bc5531deSDag-Erling Smørgrav if (sshkey_is_cert(key)) { 12586888a9beSDag-Erling Smørgrav debug2("%s: checking CA key", __func__); 12596888a9beSDag-Erling Smørgrav if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) 12606888a9beSDag-Erling Smørgrav return r; 12616888a9beSDag-Erling Smørgrav } 1262bc5531deSDag-Erling Smørgrav KRL_DBG(("%s: key okay", __func__)); 12636888a9beSDag-Erling Smørgrav return 0; 12646888a9beSDag-Erling Smørgrav } 12656888a9beSDag-Erling Smørgrav 12666888a9beSDag-Erling Smørgrav int 1267bc5531deSDag-Erling Smørgrav ssh_krl_file_contains_key(const char *path, const struct sshkey *key) 12686888a9beSDag-Erling Smørgrav { 1269bc5531deSDag-Erling Smørgrav struct sshbuf *krlbuf = NULL; 1270bc5531deSDag-Erling Smørgrav struct ssh_krl *krl = NULL; 1271bc5531deSDag-Erling Smørgrav int oerrno = 0, r, fd; 12726888a9beSDag-Erling Smørgrav 12736888a9beSDag-Erling Smørgrav if (path == NULL) 12746888a9beSDag-Erling Smørgrav return 0; 12756888a9beSDag-Erling Smørgrav 1276bc5531deSDag-Erling Smørgrav if ((krlbuf = sshbuf_new()) == NULL) 1277bc5531deSDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 12786888a9beSDag-Erling Smørgrav if ((fd = open(path, O_RDONLY)) == -1) { 1279bc5531deSDag-Erling Smørgrav r = SSH_ERR_SYSTEM_ERROR; 1280bc5531deSDag-Erling Smørgrav oerrno = errno; 1281bc5531deSDag-Erling Smørgrav goto out; 12826888a9beSDag-Erling Smørgrav } 1283bc5531deSDag-Erling Smørgrav if ((r = sshkey_load_file(fd, krlbuf)) != 0) { 1284bc5531deSDag-Erling Smørgrav oerrno = errno; 1285bc5531deSDag-Erling Smørgrav goto out; 12866888a9beSDag-Erling Smørgrav } 1287bc5531deSDag-Erling Smørgrav if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0) 1288bc5531deSDag-Erling Smørgrav goto out; 12896888a9beSDag-Erling Smørgrav debug2("%s: checking KRL %s", __func__, path); 1290bc5531deSDag-Erling Smørgrav r = ssh_krl_check_key(krl, key); 1291bc5531deSDag-Erling Smørgrav out: 1292bc5531deSDag-Erling Smørgrav close(fd); 1293bc5531deSDag-Erling Smørgrav sshbuf_free(krlbuf); 12946888a9beSDag-Erling Smørgrav ssh_krl_free(krl); 1295bc5531deSDag-Erling Smørgrav if (r != 0) 1296bc5531deSDag-Erling Smørgrav errno = oerrno; 1297bc5531deSDag-Erling Smørgrav return r; 12986888a9beSDag-Erling Smørgrav } 1299