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