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