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