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