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