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