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