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