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