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