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