1 /* $OpenBSD: krl.c,v 1.59 2023/07/17 05:22:30 djm Exp $ */ 2 /* 3 * Copyright (c) 2012 Damien Miller <djm@mindrot.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/tree.h> 20 #include <sys/queue.h> 21 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <limits.h> 25 #include <string.h> 26 #include <time.h> 27 #include <unistd.h> 28 #include <stdlib.h> 29 30 #include "sshbuf.h" 31 #include "ssherr.h" 32 #include "sshkey.h" 33 #include "authfile.h" 34 #include "misc.h" 35 #include "log.h" 36 #include "digest.h" 37 #include "bitmap.h" 38 #include "utf8.h" 39 40 #include "krl.h" 41 42 /* #define DEBUG_KRL */ 43 #ifdef DEBUG_KRL 44 # define KRL_DBG(x) debug3_f x 45 #else 46 # define KRL_DBG(x) 47 #endif 48 49 /* 50 * Trees of revoked serial numbers, key IDs and keys. This allows 51 * quick searching, querying and producing lists in canonical order. 52 */ 53 54 /* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */ 55 struct revoked_serial { 56 u_int64_t lo, hi; 57 RB_ENTRY(revoked_serial) tree_entry; 58 }; 59 static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b); 60 RB_HEAD(revoked_serial_tree, revoked_serial); 61 RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp) 62 63 /* Tree of key IDs */ 64 struct revoked_key_id { 65 char *key_id; 66 RB_ENTRY(revoked_key_id) tree_entry; 67 }; 68 static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b); 69 RB_HEAD(revoked_key_id_tree, revoked_key_id); 70 RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp) 71 72 /* Tree of blobs (used for keys and fingerprints) */ 73 struct revoked_blob { 74 u_char *blob; 75 size_t len; 76 RB_ENTRY(revoked_blob) tree_entry; 77 }; 78 static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); 79 RB_HEAD(revoked_blob_tree, revoked_blob); 80 RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp) 81 82 /* Tracks revoked certs for a single CA */ 83 struct revoked_certs { 84 struct sshkey *ca_key; 85 struct revoked_serial_tree revoked_serials; 86 struct revoked_key_id_tree revoked_key_ids; 87 TAILQ_ENTRY(revoked_certs) entry; 88 }; 89 TAILQ_HEAD(revoked_certs_list, revoked_certs); 90 91 struct ssh_krl { 92 u_int64_t krl_version; 93 u_int64_t generated_date; 94 u_int64_t flags; 95 char *comment; 96 struct revoked_blob_tree revoked_keys; 97 struct revoked_blob_tree revoked_sha1s; 98 struct revoked_blob_tree revoked_sha256s; 99 struct revoked_certs_list revoked_certs; 100 }; 101 102 /* Return equal if a and b overlap */ 103 static int 104 serial_cmp(struct revoked_serial *a, struct revoked_serial *b) 105 { 106 if (a->hi >= b->lo && a->lo <= b->hi) 107 return 0; 108 return a->lo < b->lo ? -1 : 1; 109 } 110 111 static int 112 key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b) 113 { 114 return strcmp(a->key_id, b->key_id); 115 } 116 117 static int 118 blob_cmp(struct revoked_blob *a, struct revoked_blob *b) 119 { 120 int r; 121 122 if (a->len != b->len) { 123 if ((r = memcmp(a->blob, b->blob, MINIMUM(a->len, b->len))) != 0) 124 return r; 125 return a->len > b->len ? 1 : -1; 126 } else 127 return memcmp(a->blob, b->blob, a->len); 128 } 129 130 struct ssh_krl * 131 ssh_krl_init(void) 132 { 133 struct ssh_krl *krl; 134 135 if ((krl = calloc(1, sizeof(*krl))) == NULL) 136 return NULL; 137 RB_INIT(&krl->revoked_keys); 138 RB_INIT(&krl->revoked_sha1s); 139 RB_INIT(&krl->revoked_sha256s); 140 TAILQ_INIT(&krl->revoked_certs); 141 return krl; 142 } 143 144 static void 145 revoked_certs_free(struct revoked_certs *rc) 146 { 147 struct revoked_serial *rs, *trs; 148 struct revoked_key_id *rki, *trki; 149 150 RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) { 151 RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs); 152 free(rs); 153 } 154 RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) { 155 RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki); 156 free(rki->key_id); 157 free(rki); 158 } 159 sshkey_free(rc->ca_key); 160 } 161 162 void 163 ssh_krl_free(struct ssh_krl *krl) 164 { 165 struct revoked_blob *rb, *trb; 166 struct revoked_certs *rc, *trc; 167 168 if (krl == NULL) 169 return; 170 171 free(krl->comment); 172 RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) { 173 RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb); 174 free(rb->blob); 175 free(rb); 176 } 177 RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) { 178 RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb); 179 free(rb->blob); 180 free(rb); 181 } 182 RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha256s, trb) { 183 RB_REMOVE(revoked_blob_tree, &krl->revoked_sha256s, rb); 184 free(rb->blob); 185 free(rb); 186 } 187 TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) { 188 TAILQ_REMOVE(&krl->revoked_certs, rc, entry); 189 revoked_certs_free(rc); 190 } 191 free(krl); 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 { 731 int r = SSH_ERR_INTERNAL_ERROR; 732 struct revoked_certs *rc; 733 struct revoked_blob *rb; 734 struct sshbuf *sect; 735 u_char *sblob = NULL; 736 737 if (krl->generated_date == 0) 738 krl->generated_date = time(NULL); 739 740 if ((sect = sshbuf_new()) == NULL) 741 return SSH_ERR_ALLOC_FAIL; 742 743 /* Store the header */ 744 if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 || 745 (r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 || 746 (r = sshbuf_put_u64(buf, krl->krl_version)) != 0 || 747 (r = sshbuf_put_u64(buf, krl->generated_date)) != 0 || 748 (r = sshbuf_put_u64(buf, krl->flags)) != 0 || 749 (r = sshbuf_put_string(buf, NULL, 0)) != 0 || 750 (r = sshbuf_put_cstring(buf, krl->comment)) != 0) 751 goto out; 752 753 /* Store sections for revoked certificates */ 754 TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 755 sshbuf_reset(sect); 756 if ((r = revoked_certs_generate(rc, sect)) != 0) 757 goto out; 758 if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 || 759 (r = sshbuf_put_stringb(buf, sect)) != 0) 760 goto out; 761 } 762 763 /* Finally, output sections for revocations by public key/hash */ 764 sshbuf_reset(sect); 765 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { 766 KRL_DBG(("key len %zu ", rb->len)); 767 if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 768 goto out; 769 } 770 if (sshbuf_len(sect) != 0) { 771 if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 || 772 (r = sshbuf_put_stringb(buf, sect)) != 0) 773 goto out; 774 } 775 sshbuf_reset(sect); 776 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { 777 KRL_DBG(("hash len %zu ", rb->len)); 778 if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 779 goto out; 780 } 781 if (sshbuf_len(sect) != 0) { 782 if ((r = sshbuf_put_u8(buf, 783 KRL_SECTION_FINGERPRINT_SHA1)) != 0 || 784 (r = sshbuf_put_stringb(buf, sect)) != 0) 785 goto out; 786 } 787 sshbuf_reset(sect); 788 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) { 789 KRL_DBG(("hash len %zu ", rb->len)); 790 if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) 791 goto out; 792 } 793 if (sshbuf_len(sect) != 0) { 794 if ((r = sshbuf_put_u8(buf, 795 KRL_SECTION_FINGERPRINT_SHA256)) != 0 || 796 (r = sshbuf_put_stringb(buf, sect)) != 0) 797 goto out; 798 } 799 /* success */ 800 r = 0; 801 out: 802 free(sblob); 803 sshbuf_free(sect); 804 return r; 805 } 806 807 static void 808 format_timestamp(u_int64_t timestamp, char *ts, size_t nts) 809 { 810 time_t t; 811 struct tm *tm; 812 813 t = timestamp; 814 tm = localtime(&t); 815 if (tm == NULL) 816 strlcpy(ts, "<INVALID>", nts); 817 else { 818 *ts = '\0'; 819 strftime(ts, nts, "%Y%m%dT%H%M%S", tm); 820 } 821 } 822 823 static int 824 cert_extension_subsection(struct sshbuf *subsect, struct ssh_krl *krl) 825 { 826 int r = SSH_ERR_INTERNAL_ERROR; 827 u_char critical = 1; 828 struct sshbuf *value = NULL; 829 char *name = NULL; 830 831 if ((r = sshbuf_get_cstring(subsect, &name, NULL)) != 0 || 832 (r = sshbuf_get_u8(subsect, &critical)) != 0 || 833 (r = sshbuf_froms(subsect, &value)) != 0) { 834 debug_fr(r, "parse"); 835 error("KRL has invalid certificate extension subsection"); 836 r = SSH_ERR_INVALID_FORMAT; 837 goto out; 838 } 839 if (sshbuf_len(subsect) != 0) { 840 error("KRL has invalid certificate extension subsection: " 841 "trailing data"); 842 r = SSH_ERR_INVALID_FORMAT; 843 goto out; 844 } 845 debug_f("cert extension %s critical %u len %zu", 846 name, critical, sshbuf_len(value)); 847 /* no extensions are currently supported */ 848 if (critical) { 849 error("KRL contains unsupported critical certificate " 850 "subsection \"%s\"", name); 851 r = SSH_ERR_FEATURE_UNSUPPORTED; 852 goto out; 853 } 854 /* success */ 855 r = 0; 856 out: 857 free(name); 858 sshbuf_free(value); 859 return r; 860 } 861 862 static int 863 parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl) 864 { 865 int r = SSH_ERR_INTERNAL_ERROR; 866 u_char type; 867 const u_char *blob; 868 size_t blen, nbits; 869 struct sshbuf *subsect = NULL; 870 u_int64_t serial, serial_lo, serial_hi; 871 struct bitmap *bitmap = NULL; 872 char *key_id = NULL; 873 struct sshkey *ca_key = NULL; 874 875 if ((subsect = sshbuf_new()) == NULL) 876 return SSH_ERR_ALLOC_FAIL; 877 878 /* Header: key, reserved */ 879 if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || 880 (r = sshbuf_skip_string(buf)) != 0) 881 goto out; 882 if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0) 883 goto out; 884 885 while (sshbuf_len(buf) > 0) { 886 sshbuf_free(subsect); 887 subsect = NULL; 888 if ((r = sshbuf_get_u8(buf, &type)) != 0 || 889 (r = sshbuf_froms(buf, &subsect)) != 0) 890 goto out; 891 KRL_DBG(("subsection type 0x%02x", type)); 892 /* sshbuf_dump(subsect, stderr); */ 893 894 switch (type) { 895 case KRL_SECTION_CERT_SERIAL_LIST: 896 while (sshbuf_len(subsect) > 0) { 897 if ((r = sshbuf_get_u64(subsect, &serial)) != 0) 898 goto out; 899 if ((r = ssh_krl_revoke_cert_by_serial(krl, 900 ca_key, serial)) != 0) 901 goto out; 902 } 903 break; 904 case KRL_SECTION_CERT_SERIAL_RANGE: 905 if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || 906 (r = sshbuf_get_u64(subsect, &serial_hi)) != 0) 907 goto out; 908 if ((r = ssh_krl_revoke_cert_by_serial_range(krl, 909 ca_key, serial_lo, serial_hi)) != 0) 910 goto out; 911 break; 912 case KRL_SECTION_CERT_SERIAL_BITMAP: 913 if ((bitmap = bitmap_new()) == NULL) { 914 r = SSH_ERR_ALLOC_FAIL; 915 goto out; 916 } 917 if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || 918 (r = sshbuf_get_bignum2_bytes_direct(subsect, 919 &blob, &blen)) != 0) 920 goto out; 921 if (bitmap_from_string(bitmap, blob, blen) != 0) { 922 r = SSH_ERR_INVALID_FORMAT; 923 goto out; 924 } 925 nbits = bitmap_nbits(bitmap); 926 for (serial = 0; serial < (u_int64_t)nbits; serial++) { 927 if (serial > 0 && serial_lo + serial == 0) { 928 error_f("bitmap wraps u64"); 929 r = SSH_ERR_INVALID_FORMAT; 930 goto out; 931 } 932 if (!bitmap_test_bit(bitmap, serial)) 933 continue; 934 if ((r = ssh_krl_revoke_cert_by_serial(krl, 935 ca_key, serial_lo + serial)) != 0) 936 goto out; 937 } 938 bitmap_free(bitmap); 939 bitmap = NULL; 940 break; 941 case KRL_SECTION_CERT_KEY_ID: 942 while (sshbuf_len(subsect) > 0) { 943 if ((r = sshbuf_get_cstring(subsect, 944 &key_id, NULL)) != 0) 945 goto out; 946 if ((r = ssh_krl_revoke_cert_by_key_id(krl, 947 ca_key, key_id)) != 0) 948 goto out; 949 free(key_id); 950 key_id = NULL; 951 } 952 break; 953 case KRL_SECTION_CERT_EXTENSION: 954 if ((r = cert_extension_subsection(subsect, krl)) != 0) 955 goto out; 956 break; 957 default: 958 error("Unsupported KRL certificate section %u", type); 959 r = SSH_ERR_INVALID_FORMAT; 960 goto out; 961 } 962 if (sshbuf_len(subsect) > 0) { 963 error("KRL certificate section contains unparsed data"); 964 r = SSH_ERR_INVALID_FORMAT; 965 goto out; 966 } 967 } 968 969 r = 0; 970 out: 971 if (bitmap != NULL) 972 bitmap_free(bitmap); 973 free(key_id); 974 sshkey_free(ca_key); 975 sshbuf_free(subsect); 976 return r; 977 } 978 979 static int 980 blob_section(struct sshbuf *sect, struct revoked_blob_tree *target_tree, 981 size_t expected_len) 982 { 983 u_char *rdata = NULL; 984 size_t rlen = 0; 985 int r; 986 987 while (sshbuf_len(sect) > 0) { 988 if ((r = sshbuf_get_string(sect, &rdata, &rlen)) != 0) 989 return r; 990 if (expected_len != 0 && rlen != expected_len) { 991 error_f("bad length"); 992 free(rdata); 993 return SSH_ERR_INVALID_FORMAT; 994 } 995 if ((r = revoke_blob(target_tree, rdata, rlen)) != 0) { 996 free(rdata); 997 return r; 998 } 999 } 1000 return 0; 1001 } 1002 1003 static int 1004 extension_section(struct sshbuf *sect, struct ssh_krl *krl) 1005 { 1006 int r = SSH_ERR_INTERNAL_ERROR; 1007 u_char critical = 1; 1008 struct sshbuf *value = NULL; 1009 char *name = NULL; 1010 1011 if ((r = sshbuf_get_cstring(sect, &name, NULL)) != 0 || 1012 (r = sshbuf_get_u8(sect, &critical)) != 0 || 1013 (r = sshbuf_froms(sect, &value)) != 0) { 1014 debug_fr(r, "parse"); 1015 error("KRL has invalid extension section"); 1016 r = SSH_ERR_INVALID_FORMAT; 1017 goto out; 1018 } 1019 if (sshbuf_len(sect) != 0) { 1020 error("KRL has invalid extension section: trailing data"); 1021 r = SSH_ERR_INVALID_FORMAT; 1022 goto out; 1023 } 1024 debug_f("extension %s critical %u len %zu", 1025 name, critical, sshbuf_len(value)); 1026 /* no extensions are currently supported */ 1027 if (critical) { 1028 error("KRL contains unsupported critical section \"%s\"", name); 1029 r = SSH_ERR_FEATURE_UNSUPPORTED; 1030 goto out; 1031 } 1032 /* success */ 1033 r = 0; 1034 out: 1035 free(name); 1036 sshbuf_free(value); 1037 return r; 1038 } 1039 1040 /* Attempt to parse a KRL */ 1041 int 1042 ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp) 1043 { 1044 struct sshbuf *copy = NULL, *sect = NULL; 1045 struct ssh_krl *krl = NULL; 1046 char timestamp[64]; 1047 int r = SSH_ERR_INTERNAL_ERROR; 1048 u_char type; 1049 u_int format_version; 1050 1051 *krlp = NULL; 1052 1053 /* KRL must begin with magic string */ 1054 if ((r = sshbuf_cmp(buf, 0, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0) { 1055 debug2_f("bad KRL magic header"); 1056 return SSH_ERR_KRL_BAD_MAGIC; 1057 } 1058 1059 if ((krl = ssh_krl_init()) == NULL) { 1060 error_f("alloc failed"); 1061 goto out; 1062 } 1063 /* Don't modify buffer */ 1064 if ((copy = sshbuf_fromb(buf)) == NULL) { 1065 r = SSH_ERR_ALLOC_FAIL; 1066 goto out; 1067 } 1068 if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0 || 1069 (r = sshbuf_get_u32(copy, &format_version)) != 0) 1070 goto out; 1071 if (format_version != KRL_FORMAT_VERSION) { 1072 error_f("unsupported KRL format version %u", format_version); 1073 r = SSH_ERR_INVALID_FORMAT; 1074 goto out; 1075 } 1076 if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 || 1077 (r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 || 1078 (r = sshbuf_get_u64(copy, &krl->flags)) != 0 || 1079 (r = sshbuf_skip_string(copy)) != 0 || 1080 (r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0) { 1081 error_fr(r, "parse KRL header"); 1082 goto out; 1083 } 1084 format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); 1085 debug("KRL version %llu generated at %s%s%s", 1086 (long long unsigned)krl->krl_version, timestamp, 1087 *krl->comment ? ": " : "", krl->comment); 1088 1089 /* Parse and load the KRL sections. */ 1090 while (sshbuf_len(copy) > 0) { 1091 sshbuf_free(sect); 1092 sect = NULL; 1093 if ((r = sshbuf_get_u8(copy, &type)) != 0 || 1094 (r = sshbuf_froms(copy, §)) != 0) 1095 goto out; 1096 KRL_DBG(("section 0x%02x", type)); 1097 1098 switch (type) { 1099 case KRL_SECTION_CERTIFICATES: 1100 if ((r = parse_revoked_certs(sect, krl)) != 0) 1101 goto out; 1102 break; 1103 case KRL_SECTION_EXPLICIT_KEY: 1104 if ((r = blob_section(sect, 1105 &krl->revoked_keys, 0)) != 0) 1106 goto out; 1107 break; 1108 case KRL_SECTION_FINGERPRINT_SHA1: 1109 if ((r = blob_section(sect, 1110 &krl->revoked_sha1s, 20)) != 0) 1111 goto out; 1112 break; 1113 case KRL_SECTION_FINGERPRINT_SHA256: 1114 if ((r = blob_section(sect, 1115 &krl->revoked_sha256s, 32)) != 0) 1116 goto out; 1117 break; 1118 case KRL_SECTION_EXTENSION: 1119 if ((r = extension_section(sect, krl)) != 0) 1120 goto out; 1121 break; 1122 case KRL_SECTION_SIGNATURE: 1123 /* Handled above, but still need to stay in synch */ 1124 sshbuf_free(sect); 1125 sect = NULL; 1126 if ((r = sshbuf_skip_string(copy)) != 0) 1127 goto out; 1128 break; 1129 default: 1130 error("Unsupported KRL section %u", type); 1131 r = SSH_ERR_INVALID_FORMAT; 1132 goto out; 1133 } 1134 if (sect != NULL && sshbuf_len(sect) > 0) { 1135 error("KRL section contains unparsed data"); 1136 r = SSH_ERR_INVALID_FORMAT; 1137 goto out; 1138 } 1139 } 1140 1141 /* Success */ 1142 *krlp = krl; 1143 r = 0; 1144 out: 1145 if (r != 0) 1146 ssh_krl_free(krl); 1147 sshbuf_free(copy); 1148 sshbuf_free(sect); 1149 return r; 1150 } 1151 1152 /* Checks certificate serial number and key ID revocation */ 1153 static int 1154 is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc) 1155 { 1156 struct revoked_serial rs, *ers; 1157 struct revoked_key_id rki, *erki; 1158 1159 /* Check revocation by cert key ID */ 1160 memset(&rki, 0, sizeof(rki)); 1161 rki.key_id = key->cert->key_id; 1162 erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); 1163 if (erki != NULL) { 1164 KRL_DBG(("revoked by key ID")); 1165 return SSH_ERR_KEY_REVOKED; 1166 } 1167 1168 /* 1169 * Zero serials numbers are ignored (it's the default when the 1170 * CA doesn't specify one). 1171 */ 1172 if (key->cert->serial == 0) 1173 return 0; 1174 1175 memset(&rs, 0, sizeof(rs)); 1176 rs.lo = rs.hi = key->cert->serial; 1177 ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); 1178 if (ers != NULL) { 1179 KRL_DBG(("revoked serial %llu matched %llu:%llu", 1180 key->cert->serial, ers->lo, ers->hi)); 1181 return SSH_ERR_KEY_REVOKED; 1182 } 1183 return 0; 1184 } 1185 1186 /* Checks whether a given key/cert is revoked. Does not check its CA */ 1187 static int 1188 is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) 1189 { 1190 struct revoked_blob rb, *erb; 1191 struct revoked_certs *rc; 1192 int r; 1193 1194 /* Check explicitly revoked hashes first */ 1195 memset(&rb, 0, sizeof(rb)); 1196 if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, 1197 &rb.blob, &rb.len)) != 0) 1198 return r; 1199 erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); 1200 free(rb.blob); 1201 if (erb != NULL) { 1202 KRL_DBG(("revoked by key SHA1")); 1203 return SSH_ERR_KEY_REVOKED; 1204 } 1205 memset(&rb, 0, sizeof(rb)); 1206 if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA256, 1207 &rb.blob, &rb.len)) != 0) 1208 return r; 1209 erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); 1210 free(rb.blob); 1211 if (erb != NULL) { 1212 KRL_DBG(("revoked by key SHA256")); 1213 return SSH_ERR_KEY_REVOKED; 1214 } 1215 1216 /* Next, explicit keys */ 1217 memset(&rb, 0, sizeof(rb)); 1218 if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0) 1219 return r; 1220 erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); 1221 free(rb.blob); 1222 if (erb != NULL) { 1223 KRL_DBG(("revoked by explicit key")); 1224 return SSH_ERR_KEY_REVOKED; 1225 } 1226 1227 if (!sshkey_is_cert(key)) 1228 return 0; 1229 1230 /* Check cert revocation for the specified CA */ 1231 if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, 1232 &rc, 0)) != 0) 1233 return r; 1234 if (rc != NULL) { 1235 if ((r = is_cert_revoked(key, rc)) != 0) 1236 return r; 1237 } 1238 /* Check cert revocation for the wildcard CA */ 1239 if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) 1240 return r; 1241 if (rc != NULL) { 1242 if ((r = is_cert_revoked(key, rc)) != 0) 1243 return r; 1244 } 1245 1246 KRL_DBG(("%llu no match", key->cert->serial)); 1247 return 0; 1248 } 1249 1250 int 1251 ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key) 1252 { 1253 int r; 1254 1255 KRL_DBG(("checking key")); 1256 if ((r = is_key_revoked(krl, key)) != 0) 1257 return r; 1258 if (sshkey_is_cert(key)) { 1259 debug2_f("checking CA key"); 1260 if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) 1261 return r; 1262 } 1263 KRL_DBG(("key okay")); 1264 return 0; 1265 } 1266 1267 int 1268 ssh_krl_file_contains_key(const char *path, const struct sshkey *key) 1269 { 1270 struct sshbuf *krlbuf = NULL; 1271 struct ssh_krl *krl = NULL; 1272 int oerrno = 0, r; 1273 1274 if (path == NULL) 1275 return 0; 1276 if ((r = sshbuf_load_file(path, &krlbuf)) != 0) { 1277 oerrno = errno; 1278 goto out; 1279 } 1280 if ((r = ssh_krl_from_blob(krlbuf, &krl)) != 0) 1281 goto out; 1282 debug2_f("checking KRL %s", path); 1283 r = ssh_krl_check_key(krl, key); 1284 out: 1285 sshbuf_free(krlbuf); 1286 ssh_krl_free(krl); 1287 if (r != 0) 1288 errno = oerrno; 1289 return r; 1290 } 1291 1292 int 1293 krl_dump(struct ssh_krl *krl, FILE *f) 1294 { 1295 struct sshkey *key = NULL; 1296 struct revoked_blob *rb; 1297 struct revoked_certs *rc; 1298 struct revoked_serial *rs; 1299 struct revoked_key_id *rki; 1300 int r, ret = 0; 1301 char *fp, timestamp[64]; 1302 1303 /* Try to print in a KRL spec-compatible format */ 1304 format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); 1305 fprintf(f, "# KRL version %llu\n", 1306 (unsigned long long)krl->krl_version); 1307 fprintf(f, "# Generated at %s\n", timestamp); 1308 if (krl->comment != NULL && *krl->comment != '\0') { 1309 r = INT_MAX; 1310 asmprintf(&fp, INT_MAX, &r, "%s", krl->comment); 1311 fprintf(f, "# Comment: %s\n", fp); 1312 free(fp); 1313 } 1314 fputc('\n', f); 1315 1316 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { 1317 if ((r = sshkey_from_blob(rb->blob, rb->len, &key)) != 0) { 1318 ret = SSH_ERR_INVALID_FORMAT; 1319 error_r(r, "parse KRL key"); 1320 continue; 1321 } 1322 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, 1323 SSH_FP_DEFAULT)) == NULL) { 1324 ret = SSH_ERR_INVALID_FORMAT; 1325 error("sshkey_fingerprint failed"); 1326 continue; 1327 } 1328 fprintf(f, "hash: %s # %s\n", fp, sshkey_ssh_name(key)); 1329 free(fp); 1330 free(key); 1331 } 1332 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) { 1333 fp = tohex(rb->blob, rb->len); 1334 fprintf(f, "hash: SHA256:%s\n", fp); 1335 free(fp); 1336 } 1337 RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { 1338 /* 1339 * There is not KRL spec keyword for raw SHA1 hashes, so 1340 * print them as comments. 1341 */ 1342 fp = tohex(rb->blob, rb->len); 1343 fprintf(f, "# hash SHA1:%s\n", fp); 1344 free(fp); 1345 } 1346 1347 TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { 1348 fputc('\n', f); 1349 if (rc->ca_key == NULL) 1350 fprintf(f, "# Wildcard CA\n"); 1351 else { 1352 if ((fp = sshkey_fingerprint(rc->ca_key, 1353 SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL) { 1354 ret = SSH_ERR_INVALID_FORMAT; 1355 error("sshkey_fingerprint failed"); 1356 continue; 1357 } 1358 fprintf(f, "# CA key %s %s\n", 1359 sshkey_ssh_name(rc->ca_key), fp); 1360 free(fp); 1361 } 1362 RB_FOREACH(rs, revoked_serial_tree, &rc->revoked_serials) { 1363 if (rs->lo == rs->hi) { 1364 fprintf(f, "serial: %llu\n", 1365 (unsigned long long)rs->lo); 1366 } else { 1367 fprintf(f, "serial: %llu-%llu\n", 1368 (unsigned long long)rs->lo, 1369 (unsigned long long)rs->hi); 1370 } 1371 } 1372 RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) { 1373 /* 1374 * We don't want key IDs with embedded newlines to 1375 * mess up the display. 1376 */ 1377 r = INT_MAX; 1378 asmprintf(&fp, INT_MAX, &r, "%s", rki->key_id); 1379 fprintf(f, "id: %s\n", fp); 1380 free(fp); 1381 } 1382 } 1383 return ret; 1384 } 1385