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