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