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