krl.c revision 1.5
1/* $NetBSD: krl.c,v 1.5 2015/04/03 23:58:19 christos Exp $ */ 2/* 3 * Copyright (c) 2012 Damien Miller <djm@mindrot.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $OpenBSD: krl.c,v 1.31 2015/01/30 01:10:33 djm Exp $ */ 19#include <sys/cdefs.h> 20__RCSID("$NetBSD: krl.c,v 1.5 2015/04/03 23:58:19 christos Exp $"); 21 22#include "includes.h" 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 */ 59struct revoked_serial { 60 u_int64_t lo, hi; 61 RB_ENTRY(revoked_serial) tree_entry; 62}; 63static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b); 64RB_HEAD(revoked_serial_tree, revoked_serial); 65RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp); 66 67/* Tree of key IDs */ 68struct revoked_key_id { 69 char *key_id; 70 RB_ENTRY(revoked_key_id) tree_entry; 71}; 72static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b); 73RB_HEAD(revoked_key_id_tree, revoked_key_id); 74RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp); 75 76/* Tree of blobs (used for keys and fingerprints) */ 77struct revoked_blob { 78 u_char *blob; 79 size_t len; 80 RB_ENTRY(revoked_blob) tree_entry; 81}; 82static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); 83RB_HEAD(revoked_blob_tree, revoked_blob); 84RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp); 85 86/* Tracks revoked certs for a single CA */ 87struct 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}; 93TAILQ_HEAD(revoked_certs_list, revoked_certs); 94 95struct 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 */ 106static int 107serial_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 114static int 115key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b) 116{ 117 return strcmp(a->key_id, b->key_id); 118} 119 120static int 121blob_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, MIN(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 133struct ssh_krl * 134ssh_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 146static void 147revoked_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 164void 165ssh_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 190void 191ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version) 192{ 193 krl->krl_version = version; 194} 195 196int 197ssh_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 */ 209static int 210revoked_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 244static int 245insert_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 320int 321ssh_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 327int 328ssh_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 341int 342ssh_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 */ 367static int 368plain_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 */ 387static int 388revoke_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 404int 405ssh_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 417int 418ssh_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 431int 432ssh_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 (sshkey_cert_is_legacy(key) || 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 */ 455static int 456choose_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 = MIN(contig, 1ULL<<31); 467 last_gap = MIN(last_gap, 1ULL<<31); 468 next_gap = MIN(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 : MIN(next_gap, 8+64)); 495 cost_bitmap_restart += contig + (final ? 0 : MIN(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 531static int 532put_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 */ 551static int 552revoked_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 710int 711ssh_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), 0)) == -1) 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 794static void 795format_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 810static int 811parse_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 if (subsect != NULL) { 835 sshbuf_free(subsect); 836 subsect = NULL; 837 } 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. */ 927int 928ssh_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), sshbuf_len(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 break; 1047 } 1048 1049 if (sshbuf_len(copy) != 0) { 1050 /* Shouldn't happen */ 1051 r = SSH_ERR_INTERNAL_ERROR; 1052 goto out; 1053 } 1054 1055 /* 1056 * 2nd pass: parse and load the KRL, skipping the header to the point 1057 * where the section start. 1058 */ 1059 sshbuf_free(copy); 1060 if ((copy = sshbuf_fromb(buf)) == NULL) { 1061 r = SSH_ERR_ALLOC_FAIL; 1062 goto out; 1063 } 1064 if ((r = sshbuf_consume(copy, sects_off)) != 0) 1065 goto out; 1066 while (sshbuf_len(copy) > 0) { 1067 if (sect != NULL) { 1068 sshbuf_free(sect); 1069 sect = NULL; 1070 } 1071 if ((r = sshbuf_get_u8(copy, &type)) != 0 || 1072 (r = sshbuf_froms(copy, §)) != 0) 1073 goto out; 1074 KRL_DBG(("%s: second pass, section 0x%02x", __func__, type)); 1075 1076 switch (type) { 1077 case KRL_SECTION_CERTIFICATES: 1078 if ((r = parse_revoked_certs(sect, krl)) != 0) 1079 goto out; 1080 break; 1081 case KRL_SECTION_EXPLICIT_KEY: 1082 case KRL_SECTION_FINGERPRINT_SHA1: 1083 while (sshbuf_len(sect) > 0) { 1084 if ((r = sshbuf_get_string(sect, 1085 &rdata, &rlen)) != 0) 1086 goto out; 1087 if (type == KRL_SECTION_FINGERPRINT_SHA1 && 1088 rlen != 20) { 1089 error("%s: bad SHA1 length", __func__); 1090 r = SSH_ERR_INVALID_FORMAT; 1091 goto out; 1092 } 1093 if ((r = revoke_blob( 1094 type == KRL_SECTION_EXPLICIT_KEY ? 1095 &krl->revoked_keys : &krl->revoked_sha1s, 1096 rdata, rlen)) != 0) 1097 goto out; 1098 rdata = NULL; /* revoke_blob frees rdata */ 1099 } 1100 break; 1101 case KRL_SECTION_SIGNATURE: 1102 /* Handled above, but still need to stay in synch */ 1103 sshbuf_reset(sect); 1104 sect = NULL; 1105 if ((r = sshbuf_skip_string(copy)) != 0) 1106 goto out; 1107 break; 1108 default: 1109 error("Unsupported KRL section %u", type); 1110 r = SSH_ERR_INVALID_FORMAT; 1111 goto out; 1112 } 1113 if (sshbuf_len(sect) > 0) { 1114 error("KRL section contains unparsed data"); 1115 r = SSH_ERR_INVALID_FORMAT; 1116 goto out; 1117 } 1118 } 1119 1120 /* Check that the key(s) used to sign the KRL weren't revoked */ 1121 sig_seen = 0; 1122 for (i = 0; i < nca_used; i++) { 1123 if (ssh_krl_check_key(krl, ca_used[i]) == 0) 1124 sig_seen = 1; 1125 else { 1126 sshkey_free(ca_used[i]); 1127 ca_used[i] = NULL; 1128 } 1129 } 1130 if (nca_used && !sig_seen) { 1131 error("All keys used to sign KRL were revoked"); 1132 r = SSH_ERR_KEY_REVOKED; 1133 goto out; 1134 } 1135 1136 /* If we have CA keys, then verify that one was used to sign the KRL */ 1137 if (sig_seen && nsign_ca_keys != 0) { 1138 sig_seen = 0; 1139 for (i = 0; !sig_seen && i < nsign_ca_keys; i++) { 1140 for (j = 0; j < nca_used; j++) { 1141 if (ca_used[j] == NULL) 1142 continue; 1143 if (sshkey_equal(ca_used[j], sign_ca_keys[i])) { 1144 sig_seen = 1; 1145 break; 1146 } 1147 } 1148 } 1149 if (!sig_seen) { 1150 r = SSH_ERR_SIGNATURE_INVALID; 1151 error("KRL not signed with any trusted key"); 1152 goto out; 1153 } 1154 } 1155 1156 *krlp = krl; 1157 r = 0; 1158 out: 1159 if (r != 0) 1160 ssh_krl_free(krl); 1161 for (i = 0; i < nca_used; i++) 1162 sshkey_free(ca_used[i]); 1163 free(ca_used); 1164 free(rdata); 1165 sshkey_free(key); 1166 sshbuf_free(copy); 1167 sshbuf_free(sect); 1168 return r; 1169} 1170 1171/* Checks certificate serial number and key ID revocation */ 1172static int 1173is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc) 1174{ 1175 struct revoked_serial rs, *ers; 1176 struct revoked_key_id rki, *erki; 1177 1178 /* Check revocation by cert key ID */ 1179 memset(&rki, 0, sizeof(rki)); 1180 rki.key_id = key->cert->key_id; 1181 erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); 1182 if (erki != NULL) { 1183 KRL_DBG(("%s: revoked by key ID", __func__)); 1184 return SSH_ERR_KEY_REVOKED; 1185 } 1186 1187 /* 1188 * Legacy cert formats lack serial numbers. Zero serials numbers 1189 * are ignored (it's the default when the CA doesn't specify one). 1190 */ 1191 if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) 1192 return 0; 1193 1194 memset(&rs, 0, sizeof(rs)); 1195 rs.lo = rs.hi = key->cert->serial; 1196 ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); 1197 if (ers != NULL) { 1198 KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__, 1199 key->cert->serial, ers->lo, ers->hi)); 1200 return SSH_ERR_KEY_REVOKED; 1201 } 1202 return 0; 1203} 1204 1205/* Checks whether a given key/cert is revoked. Does not check its CA */ 1206static int 1207is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) 1208{ 1209 struct revoked_blob rb, *erb; 1210 struct revoked_certs *rc; 1211 int r; 1212 1213 /* Check explicitly revoked hashes first */ 1214 memset(&rb, 0, sizeof(rb)); 1215 if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, 1216 &rb.blob, &rb.len)) != 0) 1217 return r; 1218 erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); 1219 free(rb.blob); 1220 if (erb != NULL) { 1221 KRL_DBG(("%s: revoked by key SHA1", __func__)); 1222 return SSH_ERR_KEY_REVOKED; 1223 } 1224 1225 /* Next, explicit keys */ 1226 memset(&rb, 0, sizeof(rb)); 1227 if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0) 1228 return r; 1229 erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); 1230 free(rb.blob); 1231 if (erb != NULL) { 1232 KRL_DBG(("%s: revoked by explicit key", __func__)); 1233 return SSH_ERR_KEY_REVOKED; 1234 } 1235 1236 if (!sshkey_is_cert(key)) 1237 return 0; 1238 1239 /* Check cert revocation for the specified CA */ 1240 if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, 1241 &rc, 0)) != 0) 1242 return r; 1243 if (rc != NULL) { 1244 if ((r = is_cert_revoked(key, rc)) != 0) 1245 return r; 1246 } 1247 /* Check cert revocation for the wildcard CA */ 1248 if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) 1249 return r; 1250 if (rc != NULL) { 1251 if ((r = is_cert_revoked(key, rc)) != 0) 1252 return r; 1253 } 1254 1255 KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); 1256 return 0; 1257} 1258 1259int 1260ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key) 1261{ 1262 int r; 1263 1264 KRL_DBG(("%s: checking key", __func__)); 1265 if ((r = is_key_revoked(krl, key)) != 0) 1266 return r; 1267 if (sshkey_is_cert(key)) { 1268 debug2("%s: checking CA key", __func__); 1269 if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) 1270 return r; 1271 } 1272 KRL_DBG(("%s: key okay", __func__)); 1273 return 0; 1274} 1275 1276int 1277ssh_krl_file_contains_key(const char *path, const struct sshkey *key) 1278{ 1279 struct sshbuf *krlbuf = NULL; 1280 struct ssh_krl *krl = NULL; 1281 int oerrno = 0, r, fd; 1282 1283 if (path == NULL) 1284 return 0; 1285 1286 if ((krlbuf = sshbuf_new()) == NULL) 1287 return SSH_ERR_ALLOC_FAIL; 1288 if ((fd = open(path, O_RDONLY)) == -1) { 1289 r = SSH_ERR_SYSTEM_ERROR; 1290 oerrno = errno; 1291 goto out; 1292 } 1293 if ((r = sshkey_load_file(fd, krlbuf)) != 0) { 1294 oerrno = errno; 1295 goto out; 1296 } 1297 if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0) 1298 goto out; 1299 debug2("%s: checking KRL %s", __func__, path); 1300 r = ssh_krl_check_key(krl, key); 1301 out: 1302 close(fd); 1303 sshbuf_free(krlbuf); 1304 ssh_krl_free(krl); 1305 if (r != 0) 1306 errno = oerrno; 1307 return r; 1308} 1309