1 /* $NetBSD: sshsig.c,v 1.10 2022/10/05 22:39:36 christos Exp $ */ 2 /* $OpenBSD: sshsig.c,v 1.30 2022/08/19 03:06:30 djm Exp $ */ 3 4 /* 5 * Copyright (c) 2019 Google LLC 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include "includes.h" 20 __RCSID("$NetBSD: sshsig.c,v 1.10 2022/10/05 22:39:36 christos Exp $"); 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <stdarg.h> 25 #include <errno.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "authfd.h" 30 #include "authfile.h" 31 #include "log.h" 32 #include "misc.h" 33 #include "sshbuf.h" 34 #include "sshsig.h" 35 #include "ssherr.h" 36 #include "sshkey.h" 37 #include "match.h" 38 #include "digest.h" 39 40 #define SIG_VERSION 0x01 41 #define MAGIC_PREAMBLE "SSHSIG" 42 #define MAGIC_PREAMBLE_LEN (sizeof(MAGIC_PREAMBLE) - 1) 43 #define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----\n" 44 #define END_SIGNATURE "-----END SSH SIGNATURE-----" 45 #define RSA_SIGN_ALG "rsa-sha2-512" /* XXX maybe make configurable */ 46 #define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256" 47 #define HASHALG_DEFAULT "sha512" /* XXX maybe make configurable */ 48 #define HASHALG_ALLOWED "sha256,sha512" 49 50 int 51 sshsig_armor(const struct sshbuf *blob, struct sshbuf **out) 52 { 53 struct sshbuf *buf = NULL; 54 int r = SSH_ERR_INTERNAL_ERROR; 55 56 *out = NULL; 57 58 if ((buf = sshbuf_new()) == NULL) { 59 error_f("sshbuf_new failed"); 60 r = SSH_ERR_ALLOC_FAIL; 61 goto out; 62 } 63 64 if ((r = sshbuf_put(buf, BEGIN_SIGNATURE, 65 sizeof(BEGIN_SIGNATURE)-1)) != 0) { 66 error_fr(r, "sshbuf_putf"); 67 goto out; 68 } 69 70 if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) { 71 error_fr(r, "base64 encode signature"); 72 goto out; 73 } 74 75 if ((r = sshbuf_put(buf, END_SIGNATURE, 76 sizeof(END_SIGNATURE)-1)) != 0 || 77 (r = sshbuf_put_u8(buf, '\n')) != 0) { 78 error_fr(r, "sshbuf_put"); 79 goto out; 80 } 81 /* success */ 82 *out = buf; 83 buf = NULL; /* transferred */ 84 r = 0; 85 out: 86 sshbuf_free(buf); 87 return r; 88 } 89 90 int 91 sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out) 92 { 93 int r; 94 size_t eoffset = 0; 95 struct sshbuf *buf = NULL; 96 struct sshbuf *sbuf = NULL; 97 char *b64 = NULL; 98 99 if ((sbuf = sshbuf_fromb(sig)) == NULL) { 100 error_f("sshbuf_fromb failed"); 101 return SSH_ERR_ALLOC_FAIL; 102 } 103 104 if ((r = sshbuf_cmp(sbuf, 0, 105 BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) { 106 error("Couldn't parse signature: missing header"); 107 goto done; 108 } 109 110 if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) { 111 error_fr(r, "consume"); 112 goto done; 113 } 114 115 if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE, 116 sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) { 117 error("Couldn't parse signature: missing footer"); 118 goto done; 119 } 120 121 if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) { 122 error_fr(r, "consume"); 123 goto done; 124 } 125 126 if ((b64 = sshbuf_dup_string(sbuf)) == NULL) { 127 error_f("sshbuf_dup_string failed"); 128 r = SSH_ERR_ALLOC_FAIL; 129 goto done; 130 } 131 132 if ((buf = sshbuf_new()) == NULL) { 133 error_f("sshbuf_new() failed"); 134 r = SSH_ERR_ALLOC_FAIL; 135 goto done; 136 } 137 138 if ((r = sshbuf_b64tod(buf, b64)) != 0) { 139 error_fr(r, "decode base64"); 140 goto done; 141 } 142 143 /* success */ 144 *out = buf; 145 r = 0; 146 buf = NULL; /* transferred */ 147 done: 148 sshbuf_free(buf); 149 sshbuf_free(sbuf); 150 free(b64); 151 return r; 152 } 153 154 static int 155 sshsig_wrap_sign(struct sshkey *key, const char *hashalg, 156 const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message, 157 const char *sig_namespace, struct sshbuf **out, 158 sshsig_signer *signer, void *signer_ctx) 159 { 160 int r; 161 size_t slen = 0; 162 u_char *sig = NULL; 163 struct sshbuf *blob = NULL; 164 struct sshbuf *tosign = NULL; 165 const char *sign_alg = NULL; 166 167 if ((tosign = sshbuf_new()) == NULL || 168 (blob = sshbuf_new()) == NULL) { 169 error_f("sshbuf_new failed"); 170 r = SSH_ERR_ALLOC_FAIL; 171 goto done; 172 } 173 174 if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 || 175 (r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 || 176 (r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */ 177 (r = sshbuf_put_cstring(tosign, hashalg)) != 0 || 178 (r = sshbuf_put_stringb(tosign, h_message)) != 0) { 179 error_fr(r, "assemble message to sign"); 180 goto done; 181 } 182 183 /* If using RSA keys then default to a good signature algorithm */ 184 if (sshkey_type_plain(key->type) == KEY_RSA) 185 sign_alg = RSA_SIGN_ALG; 186 187 if (signer != NULL) { 188 if ((r = signer(key, &sig, &slen, 189 sshbuf_ptr(tosign), sshbuf_len(tosign), 190 sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) { 191 error_r(r, "Couldn't sign message (signer)"); 192 goto done; 193 } 194 } else { 195 if ((r = sshkey_sign(key, &sig, &slen, 196 sshbuf_ptr(tosign), sshbuf_len(tosign), 197 sign_alg, sk_provider, sk_pin, 0)) != 0) { 198 error_r(r, "Couldn't sign message"); 199 goto done; 200 } 201 } 202 203 if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 || 204 (r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 || 205 (r = sshkey_puts(key, blob)) != 0 || 206 (r = sshbuf_put_cstring(blob, sig_namespace)) != 0 || 207 (r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */ 208 (r = sshbuf_put_cstring(blob, hashalg)) != 0 || 209 (r = sshbuf_put_string(blob, sig, slen)) != 0) { 210 error_fr(r, "assemble signature object"); 211 goto done; 212 } 213 214 if (out != NULL) { 215 *out = blob; 216 blob = NULL; 217 } 218 r = 0; 219 done: 220 free(sig); 221 sshbuf_free(blob); 222 sshbuf_free(tosign); 223 return r; 224 } 225 226 /* Check preamble and version. */ 227 static int 228 sshsig_parse_preamble(struct sshbuf *buf) 229 { 230 int r = SSH_ERR_INTERNAL_ERROR; 231 uint32_t sversion; 232 233 if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 || 234 (r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 || 235 (r = sshbuf_get_u32(buf, &sversion)) != 0) { 236 error("Couldn't verify signature: invalid format"); 237 return r; 238 } 239 240 if (sversion > SIG_VERSION) { 241 error("Signature version %lu is larger than supported " 242 "version %u", (unsigned long)sversion, SIG_VERSION); 243 return SSH_ERR_INVALID_FORMAT; 244 } 245 return 0; 246 } 247 248 static int 249 sshsig_check_hashalg(const char *hashalg) 250 { 251 if (hashalg == NULL || 252 match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1) 253 return 0; 254 error_f("unsupported hash algorithm \"%.100s\"", hashalg); 255 return SSH_ERR_SIGN_ALG_UNSUPPORTED; 256 } 257 258 static int 259 sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp) 260 { 261 struct sshbuf *buf = NULL; 262 char *hashalg = NULL; 263 int r = SSH_ERR_INTERNAL_ERROR; 264 265 if (hashalgp != NULL) 266 *hashalgp = NULL; 267 if ((buf = sshbuf_fromb(signature)) == NULL) 268 return SSH_ERR_ALLOC_FAIL; 269 if ((r = sshsig_parse_preamble(buf)) != 0) 270 goto done; 271 if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 || 272 (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 || 273 (r = sshbuf_get_string(buf, NULL, NULL)) != 0 || 274 (r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 || 275 (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) { 276 error_fr(r, "parse signature object"); 277 goto done; 278 } 279 280 /* success */ 281 r = 0; 282 *hashalgp = hashalg; 283 hashalg = NULL; 284 done: 285 free(hashalg); 286 sshbuf_free(buf); 287 return r; 288 } 289 290 static int 291 sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, 292 const struct sshbuf *h_message, const char *expect_namespace, 293 struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details) 294 { 295 int r = SSH_ERR_INTERNAL_ERROR; 296 struct sshbuf *buf = NULL, *toverify = NULL; 297 struct sshkey *key = NULL; 298 const u_char *sig; 299 char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL; 300 size_t siglen; 301 302 debug_f("verify message length %zu", sshbuf_len(h_message)); 303 if (sig_details != NULL) 304 *sig_details = NULL; 305 if (sign_keyp != NULL) 306 *sign_keyp = NULL; 307 308 if ((toverify = sshbuf_new()) == NULL) { 309 error_f("sshbuf_new failed"); 310 r = SSH_ERR_ALLOC_FAIL; 311 goto done; 312 } 313 if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE, 314 MAGIC_PREAMBLE_LEN)) != 0 || 315 (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 || 316 (r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */ 317 (r = sshbuf_put_cstring(toverify, hashalg)) != 0 || 318 (r = sshbuf_put_stringb(toverify, h_message)) != 0) { 319 error_fr(r, "assemble message to verify"); 320 goto done; 321 } 322 323 if ((r = sshsig_parse_preamble(signature)) != 0) 324 goto done; 325 326 if ((r = sshkey_froms(signature, &key)) != 0 || 327 (r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 || 328 (r = sshbuf_get_string(signature, NULL, NULL)) != 0 || 329 (r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 || 330 (r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) { 331 error_fr(r, "parse signature object"); 332 goto done; 333 } 334 335 if (sshbuf_len(signature) != 0) { 336 error("Signature contains trailing data"); 337 r = SSH_ERR_INVALID_FORMAT; 338 goto done; 339 } 340 341 if (strcmp(expect_namespace, got_namespace) != 0) { 342 error("Couldn't verify signature: namespace does not match"); 343 debug_f("expected namespace \"%s\" received \"%s\"", 344 expect_namespace, got_namespace); 345 r = SSH_ERR_SIGNATURE_INVALID; 346 goto done; 347 } 348 if (strcmp(hashalg, sig_hashalg) != 0) { 349 error("Couldn't verify signature: hash algorithm mismatch"); 350 debug_f("expected algorithm \"%s\" received \"%s\"", 351 hashalg, sig_hashalg); 352 r = SSH_ERR_SIGNATURE_INVALID; 353 goto done; 354 } 355 /* Ensure that RSA keys use an acceptable signature algorithm */ 356 if (sshkey_type_plain(key->type) == KEY_RSA) { 357 if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) { 358 error_r(r, "Couldn't verify signature: unable to get " 359 "signature type"); 360 goto done; 361 } 362 if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) { 363 error("Couldn't verify signature: unsupported RSA " 364 "signature algorithm %s", sigtype); 365 r = SSH_ERR_SIGN_ALG_UNSUPPORTED; 366 goto done; 367 } 368 } 369 if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify), 370 sshbuf_len(toverify), NULL, 0, sig_details)) != 0) { 371 error_r(r, "Signature verification failed"); 372 goto done; 373 } 374 375 /* success */ 376 r = 0; 377 if (sign_keyp != NULL) { 378 *sign_keyp = key; 379 key = NULL; /* transferred */ 380 } 381 done: 382 free(got_namespace); 383 free(sigtype); 384 free(sig_hashalg); 385 sshbuf_free(buf); 386 sshbuf_free(toverify); 387 sshkey_free(key); 388 return r; 389 } 390 391 static int 392 hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp) 393 { 394 char *hex, hash[SSH_DIGEST_MAX_LENGTH]; 395 int alg, r = SSH_ERR_INTERNAL_ERROR; 396 struct sshbuf *b = NULL; 397 398 *bp = NULL; 399 memset(hash, 0, sizeof(hash)); 400 401 if ((r = sshsig_check_hashalg(hashalg)) != 0) 402 return r; 403 if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { 404 error_f("can't look up hash algorithm %s", hashalg); 405 return SSH_ERR_INTERNAL_ERROR; 406 } 407 if ((r = ssh_digest_buffer(alg, m, (unsigned char *)hash, sizeof(hash))) != 0) { 408 error_fr(r, "ssh_digest_buffer"); 409 return r; 410 } 411 if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) { 412 debug3_f("final hash: %s", hex); 413 freezero(hex, strlen(hex)); 414 } 415 if ((b = sshbuf_new()) == NULL) { 416 r = SSH_ERR_ALLOC_FAIL; 417 goto out; 418 } 419 if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) { 420 error_fr(r, "sshbuf_put"); 421 goto out; 422 } 423 *bp = b; 424 b = NULL; /* transferred */ 425 /* success */ 426 r = 0; 427 out: 428 sshbuf_free(b); 429 explicit_bzero(hash, sizeof(hash)); 430 return r; 431 } 432 433 int 434 sshsig_signb(struct sshkey *key, const char *hashalg, 435 const char *sk_provider, const char *sk_pin, 436 const struct sshbuf *message, const char *sig_namespace, 437 struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) 438 { 439 struct sshbuf *b = NULL; 440 int r = SSH_ERR_INTERNAL_ERROR; 441 442 if (hashalg == NULL) 443 hashalg = HASHALG_DEFAULT; 444 if (out != NULL) 445 *out = NULL; 446 if ((r = hash_buffer(message, hashalg, &b)) != 0) { 447 error_fr(r, "hash buffer"); 448 goto out; 449 } 450 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b, 451 sig_namespace, out, signer, signer_ctx)) != 0) 452 goto out; 453 /* success */ 454 r = 0; 455 out: 456 sshbuf_free(b); 457 return r; 458 } 459 460 int 461 sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message, 462 const char *expect_namespace, struct sshkey **sign_keyp, 463 struct sshkey_sig_details **sig_details) 464 { 465 struct sshbuf *b = NULL; 466 int r = SSH_ERR_INTERNAL_ERROR; 467 char *hashalg = NULL; 468 469 if (sig_details != NULL) 470 *sig_details = NULL; 471 if (sign_keyp != NULL) 472 *sign_keyp = NULL; 473 if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) 474 return r; 475 debug_f("signature made with hash \"%s\"", hashalg); 476 if ((r = hash_buffer(message, hashalg, &b)) != 0) { 477 error_fr(r, "hash buffer"); 478 goto out; 479 } 480 if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, 481 sign_keyp, sig_details)) != 0) 482 goto out; 483 /* success */ 484 r = 0; 485 out: 486 sshbuf_free(b); 487 free(hashalg); 488 return r; 489 } 490 491 static int 492 hash_file(int fd, const char *hashalg, struct sshbuf **bp) 493 { 494 char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH]; 495 ssize_t n, total = 0; 496 struct ssh_digest_ctx *ctx = NULL; 497 int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR; 498 struct sshbuf *b = NULL; 499 500 *bp = NULL; 501 memset(hash, 0, sizeof(hash)); 502 503 if ((r = sshsig_check_hashalg(hashalg)) != 0) 504 return r; 505 if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { 506 error_f("can't look up hash algorithm %s", hashalg); 507 return SSH_ERR_INTERNAL_ERROR; 508 } 509 if ((ctx = ssh_digest_start(alg)) == NULL) { 510 error_f("ssh_digest_start failed"); 511 return SSH_ERR_INTERNAL_ERROR; 512 } 513 for (;;) { 514 if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) { 515 if (errno == EINTR || errno == EAGAIN) 516 continue; 517 oerrno = errno; 518 error_f("read: %s", strerror(errno)); 519 errno = oerrno; 520 r = SSH_ERR_SYSTEM_ERROR; 521 goto out; 522 } else if (n == 0) { 523 debug2_f("hashed %zu bytes", total); 524 break; /* EOF */ 525 } 526 total += (size_t)n; 527 if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) { 528 error_fr(r, "ssh_digest_update"); 529 goto out; 530 } 531 } 532 if ((r = ssh_digest_final(ctx, (unsigned char *)hash, sizeof(hash))) != 0) { 533 error_fr(r, "ssh_digest_final"); 534 goto out; 535 } 536 if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) { 537 debug3_f("final hash: %s", hex); 538 freezero(hex, strlen(hex)); 539 } 540 if ((b = sshbuf_new()) == NULL) { 541 r = SSH_ERR_ALLOC_FAIL; 542 goto out; 543 } 544 if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) { 545 error_fr(r, "sshbuf_put"); 546 goto out; 547 } 548 *bp = b; 549 b = NULL; /* transferred */ 550 /* success */ 551 r = 0; 552 out: 553 oerrno = errno; 554 sshbuf_free(b); 555 ssh_digest_free(ctx); 556 explicit_bzero(hash, sizeof(hash)); 557 errno = oerrno; 558 return r; 559 } 560 561 int 562 sshsig_sign_fd(struct sshkey *key, const char *hashalg, 563 const char *sk_provider, const char *sk_pin, 564 int fd, const char *sig_namespace, struct sshbuf **out, 565 sshsig_signer *signer, void *signer_ctx) 566 { 567 struct sshbuf *b = NULL; 568 int r = SSH_ERR_INTERNAL_ERROR; 569 570 if (hashalg == NULL) 571 hashalg = HASHALG_DEFAULT; 572 if (out != NULL) 573 *out = NULL; 574 if ((r = hash_file(fd, hashalg, &b)) != 0) { 575 error_fr(r, "hash_file"); 576 return r; 577 } 578 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b, 579 sig_namespace, out, signer, signer_ctx)) != 0) 580 goto out; 581 /* success */ 582 r = 0; 583 out: 584 sshbuf_free(b); 585 return r; 586 } 587 588 int 589 sshsig_verify_fd(struct sshbuf *signature, int fd, 590 const char *expect_namespace, struct sshkey **sign_keyp, 591 struct sshkey_sig_details **sig_details) 592 { 593 struct sshbuf *b = NULL; 594 int r = SSH_ERR_INTERNAL_ERROR; 595 char *hashalg = NULL; 596 597 if (sig_details != NULL) 598 *sig_details = NULL; 599 if (sign_keyp != NULL) 600 *sign_keyp = NULL; 601 if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) 602 return r; 603 debug_f("signature made with hash \"%s\"", hashalg); 604 if ((r = hash_file(fd, hashalg, &b)) != 0) { 605 error_fr(r, "hash_file"); 606 goto out; 607 } 608 if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, 609 sign_keyp, sig_details)) != 0) 610 goto out; 611 /* success */ 612 r = 0; 613 out: 614 sshbuf_free(b); 615 free(hashalg); 616 return r; 617 } 618 619 struct sshsigopt { 620 int ca; 621 char *namespaces; 622 uint64_t valid_after, valid_before; 623 }; 624 625 struct sshsigopt * 626 sshsigopt_parse(const char *opts, const char *path, u_long linenum, 627 const char **errstrp) 628 { 629 struct sshsigopt *ret; 630 int r; 631 char *opt; 632 const char *errstr = NULL; 633 634 if ((ret = calloc(1, sizeof(*ret))) == NULL) 635 return NULL; 636 if (opts == NULL || *opts == '\0') 637 return ret; /* Empty options yields empty options :) */ 638 639 while (*opts && *opts != ' ' && *opts != '\t') { 640 /* flag options */ 641 if ((r = opt_flag("cert-authority", 0, &opts)) != -1) { 642 ret->ca = 1; 643 } else if (opt_match(&opts, "namespaces")) { 644 if (ret->namespaces != NULL) { 645 errstr = "multiple \"namespaces\" clauses"; 646 goto fail; 647 } 648 ret->namespaces = opt_dequote(&opts, &errstr); 649 if (ret->namespaces == NULL) 650 goto fail; 651 } else if (opt_match(&opts, "valid-after")) { 652 if (ret->valid_after != 0) { 653 errstr = "multiple \"valid-after\" clauses"; 654 goto fail; 655 } 656 if ((opt = opt_dequote(&opts, &errstr)) == NULL) 657 goto fail; 658 if (parse_absolute_time(opt, &ret->valid_after) != 0 || 659 ret->valid_after == 0) { 660 free(opt); 661 errstr = "invalid \"valid-after\" time"; 662 goto fail; 663 } 664 free(opt); 665 } else if (opt_match(&opts, "valid-before")) { 666 if (ret->valid_before != 0) { 667 errstr = "multiple \"valid-before\" clauses"; 668 goto fail; 669 } 670 if ((opt = opt_dequote(&opts, &errstr)) == NULL) 671 goto fail; 672 if (parse_absolute_time(opt, &ret->valid_before) != 0 || 673 ret->valid_before == 0) { 674 free(opt); 675 errstr = "invalid \"valid-before\" time"; 676 goto fail; 677 } 678 free(opt); 679 } 680 /* 681 * Skip the comma, and move to the next option 682 * (or break out if there are no more). 683 */ 684 if (*opts == '\0' || *opts == ' ' || *opts == '\t') 685 break; /* End of options. */ 686 /* Anything other than a comma is an unknown option */ 687 if (*opts != ',') { 688 errstr = "unknown key option"; 689 goto fail; 690 } 691 opts++; 692 if (*opts == '\0') { 693 errstr = "unexpected end-of-options"; 694 goto fail; 695 } 696 } 697 /* final consistency check */ 698 if (ret->valid_after != 0 && ret->valid_before != 0 && 699 ret->valid_before <= ret->valid_after) { 700 errstr = "\"valid-before\" time is before \"valid-after\""; 701 goto fail; 702 } 703 /* success */ 704 return ret; 705 fail: 706 if (errstrp != NULL) 707 *errstrp = errstr; 708 sshsigopt_free(ret); 709 return NULL; 710 } 711 712 void 713 sshsigopt_free(struct sshsigopt *opts) 714 { 715 if (opts == NULL) 716 return; 717 free(opts->namespaces); 718 free(opts); 719 } 720 721 static int 722 parse_principals_key_and_options(const char *path, u_long linenum, char *line, 723 const char *required_principal, char **principalsp, struct sshkey **keyp, 724 struct sshsigopt **sigoptsp) 725 { 726 char *opts = NULL, *tmp, *cp, *principals = NULL; 727 const char *reason = NULL; 728 struct sshsigopt *sigopts = NULL; 729 struct sshkey *key = NULL; 730 int r = SSH_ERR_INTERNAL_ERROR; 731 732 if (principalsp != NULL) 733 *principalsp = NULL; 734 if (sigoptsp != NULL) 735 *sigoptsp = NULL; 736 if (keyp != NULL) 737 *keyp = NULL; 738 739 cp = line; 740 cp = cp + strspn(cp, " \t"); /* skip leading whitespace */ 741 if (*cp == '#' || *cp == '\0') 742 return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */ 743 744 /* format: identity[,identity...] [option[,option...]] key */ 745 if ((tmp = strdelimw(&cp)) == NULL || cp == NULL) { 746 error("%s:%lu: invalid line", path, linenum); 747 r = SSH_ERR_INVALID_FORMAT; 748 goto out; 749 } 750 if ((principals = strdup(tmp)) == NULL) { 751 error_f("strdup failed"); 752 r = SSH_ERR_ALLOC_FAIL; 753 goto out; 754 } 755 /* 756 * Bail out early if we're looking for a particular principal and this 757 * line does not list it. 758 */ 759 if (required_principal != NULL) { 760 if (match_pattern_list(required_principal, 761 principals, 0) != 1) { 762 /* principal didn't match */ 763 r = SSH_ERR_KEY_NOT_FOUND; 764 goto out; 765 } 766 debug_f("%s:%lu: matched principal \"%s\"", 767 path, linenum, required_principal); 768 } 769 770 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) { 771 error_f("sshkey_new failed"); 772 r = SSH_ERR_ALLOC_FAIL; 773 goto out; 774 } 775 if (sshkey_read(key, &cp) != 0) { 776 /* no key? Check for options */ 777 opts = cp; 778 if (sshkey_advance_past_options(&cp) != 0) { 779 error("%s:%lu: invalid options", path, linenum); 780 r = SSH_ERR_INVALID_FORMAT; 781 goto out; 782 } 783 if (cp == NULL || *cp == '\0') { 784 error("%s:%lu: missing key", path, linenum); 785 r = SSH_ERR_INVALID_FORMAT; 786 goto out; 787 } 788 *cp++ = '\0'; 789 skip_space(&cp); 790 if (sshkey_read(key, &cp) != 0) { 791 error("%s:%lu: invalid key", path, linenum); 792 r = SSH_ERR_INVALID_FORMAT; 793 goto out; 794 } 795 } 796 debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts); 797 if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) { 798 error("%s:%lu: bad options: %s", path, linenum, reason); 799 r = SSH_ERR_INVALID_FORMAT; 800 goto out; 801 } 802 /* success */ 803 if (principalsp != NULL) { 804 *principalsp = principals; 805 principals = NULL; /* transferred */ 806 } 807 if (sigoptsp != NULL) { 808 *sigoptsp = sigopts; 809 sigopts = NULL; /* transferred */ 810 } 811 if (keyp != NULL) { 812 *keyp = key; 813 key = NULL; /* transferred */ 814 } 815 r = 0; 816 out: 817 free(principals); 818 sshsigopt_free(sigopts); 819 sshkey_free(key); 820 return r; 821 } 822 823 static int 824 cert_filter_principals(const char *path, u_long linenum, 825 char **principalsp, const struct sshkey *cert, uint64_t verify_time) 826 { 827 char *cp, *oprincipals, *principals; 828 const char *reason; 829 struct sshbuf *nprincipals; 830 int r = SSH_ERR_INTERNAL_ERROR, success = 0; 831 u_int i; 832 833 oprincipals = principals = *principalsp; 834 *principalsp = NULL; 835 836 if ((nprincipals = sshbuf_new()) == NULL) { 837 r = SSH_ERR_ALLOC_FAIL; 838 goto out; 839 } 840 841 while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') { 842 /* Check certificate validity */ 843 if ((r = sshkey_cert_check_authority(cert, 0, 1, 0, 844 verify_time, NULL, &reason)) != 0) { 845 debug("%s:%lu: principal \"%s\" not authorized: %s", 846 path, linenum, cp, reason); 847 continue; 848 } 849 /* Return all matching principal names from the cert */ 850 for (i = 0; i < cert->cert->nprincipals; i++) { 851 if (match_pattern(cert->cert->principals[i], cp)) { 852 if ((r = sshbuf_putf(nprincipals, "%s%s", 853 sshbuf_len(nprincipals) != 0 ? "," : "", 854 cert->cert->principals[i])) != 0) { 855 error_f("buffer error"); 856 goto out; 857 } 858 } 859 } 860 } 861 if (sshbuf_len(nprincipals) == 0) { 862 error("%s:%lu: no valid principals found", path, linenum); 863 r = SSH_ERR_KEY_CERT_INVALID; 864 goto out; 865 } 866 if ((principals = sshbuf_dup_string(nprincipals)) == NULL) { 867 error_f("buffer error"); 868 goto out; 869 } 870 /* success */ 871 success = 1; 872 *principalsp = principals; 873 out: 874 sshbuf_free(nprincipals); 875 free(oprincipals); 876 return success ? 0 : r; 877 } 878 879 static int 880 check_allowed_keys_line(const char *path, u_long linenum, char *line, 881 const struct sshkey *sign_key, const char *principal, 882 const char *sig_namespace, uint64_t verify_time, char **principalsp) 883 { 884 struct sshkey *found_key = NULL; 885 char *principals = NULL; 886 int r, success = 0; 887 const char *reason = NULL; 888 struct sshsigopt *sigopts = NULL; 889 char tvalid[64], tverify[64]; 890 891 if (principalsp != NULL) 892 *principalsp = NULL; 893 894 /* Parse the line */ 895 if ((r = parse_principals_key_and_options(path, linenum, line, 896 principal, &principals, &found_key, &sigopts)) != 0) { 897 /* error already logged */ 898 goto done; 899 } 900 901 if (!sigopts->ca && sshkey_equal(found_key, sign_key)) { 902 /* Exact match of key */ 903 debug("%s:%lu: matched key", path, linenum); 904 } else if (sigopts->ca && sshkey_is_cert(sign_key) && 905 sshkey_equal_public(sign_key->cert->signature_key, found_key)) { 906 if (principal) { 907 /* Match certificate CA key with specified principal */ 908 if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0, 909 verify_time, principal, &reason)) != 0) { 910 error("%s:%lu: certificate not authorized: %s", 911 path, linenum, reason); 912 goto done; 913 } 914 debug("%s:%lu: matched certificate CA key", 915 path, linenum); 916 } else { 917 /* No principal specified - find all matching ones */ 918 if ((r = cert_filter_principals(path, linenum, 919 &principals, sign_key, verify_time)) != 0) { 920 /* error already displayed */ 921 debug_r(r, "%s:%lu: cert_filter_principals", 922 path, linenum); 923 goto done; 924 } 925 debug("%s:%lu: matched certificate CA key", 926 path, linenum); 927 } 928 } else { 929 /* Didn't match key */ 930 goto done; 931 } 932 933 /* Check whether options preclude the use of this key */ 934 if (sigopts->namespaces != NULL && sig_namespace != NULL && 935 match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) { 936 error("%s:%lu: key is not permitted for use in signature " 937 "namespace \"%s\"", path, linenum, sig_namespace); 938 goto done; 939 } 940 941 /* check key time validity */ 942 format_absolute_time((uint64_t)verify_time, tverify, sizeof(tverify)); 943 if (sigopts->valid_after != 0 && 944 (uint64_t)verify_time < sigopts->valid_after) { 945 format_absolute_time(sigopts->valid_after, 946 tvalid, sizeof(tvalid)); 947 error("%s:%lu: key is not yet valid: " 948 "verify time %s < valid-after %s", path, linenum, 949 tverify, tvalid); 950 goto done; 951 } 952 if (sigopts->valid_before != 0 && 953 (uint64_t)verify_time > sigopts->valid_before) { 954 format_absolute_time(sigopts->valid_before, 955 tvalid, sizeof(tvalid)); 956 error("%s:%lu: key has expired: " 957 "verify time %s > valid-before %s", path, linenum, 958 tverify, tvalid); 959 goto done; 960 } 961 success = 1; 962 963 done: 964 if (success && principalsp != NULL) { 965 *principalsp = principals; 966 principals = NULL; /* transferred */ 967 } 968 free(principals); 969 sshkey_free(found_key); 970 sshsigopt_free(sigopts); 971 return success ? 0 : SSH_ERR_KEY_NOT_FOUND; 972 } 973 974 int 975 sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, 976 const char *principal, const char *sig_namespace, uint64_t verify_time) 977 { 978 FILE *f = NULL; 979 char *line = NULL; 980 size_t linesize = 0; 981 u_long linenum = 0; 982 int r = SSH_ERR_INTERNAL_ERROR, oerrno; 983 984 /* Check key and principal against file */ 985 if ((f = fopen(path, "r")) == NULL) { 986 oerrno = errno; 987 error("Unable to open allowed keys file \"%s\": %s", 988 path, strerror(errno)); 989 errno = oerrno; 990 return SSH_ERR_SYSTEM_ERROR; 991 } 992 993 while (getline(&line, &linesize, f) != -1) { 994 linenum++; 995 r = check_allowed_keys_line(path, linenum, line, sign_key, 996 principal, sig_namespace, verify_time, NULL); 997 free(line); 998 line = NULL; 999 linesize = 0; 1000 if (r == SSH_ERR_KEY_NOT_FOUND) 1001 continue; 1002 else if (r == 0) { 1003 /* success */ 1004 fclose(f); 1005 return 0; 1006 } else 1007 break; 1008 } 1009 /* Either we hit an error parsing or we simply didn't find the key */ 1010 fclose(f); 1011 free(line); 1012 return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; 1013 } 1014 1015 int 1016 sshsig_find_principals(const char *path, const struct sshkey *sign_key, 1017 uint64_t verify_time, char **principals) 1018 { 1019 FILE *f = NULL; 1020 char *line = NULL; 1021 size_t linesize = 0; 1022 u_long linenum = 0; 1023 int r = SSH_ERR_INTERNAL_ERROR, oerrno; 1024 1025 if ((f = fopen(path, "r")) == NULL) { 1026 oerrno = errno; 1027 error("Unable to open allowed keys file \"%s\": %s", 1028 path, strerror(errno)); 1029 errno = oerrno; 1030 return SSH_ERR_SYSTEM_ERROR; 1031 } 1032 1033 r = SSH_ERR_KEY_NOT_FOUND; 1034 while (getline(&line, &linesize, f) != -1) { 1035 linenum++; 1036 r = check_allowed_keys_line(path, linenum, line, 1037 sign_key, NULL, NULL, verify_time, principals); 1038 free(line); 1039 line = NULL; 1040 linesize = 0; 1041 if (r == SSH_ERR_KEY_NOT_FOUND) 1042 continue; 1043 else if (r == 0) { 1044 /* success */ 1045 fclose(f); 1046 return 0; 1047 } else 1048 break; 1049 } 1050 free(line); 1051 /* Either we hit an error parsing or we simply didn't find the key */ 1052 if (ferror(f) != 0) { 1053 oerrno = errno; 1054 fclose(f); 1055 error("Unable to read allowed keys file \"%s\": %s", 1056 path, strerror(errno)); 1057 errno = oerrno; 1058 return SSH_ERR_SYSTEM_ERROR; 1059 } 1060 fclose(f); 1061 return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; 1062 } 1063 1064 int 1065 sshsig_match_principals(const char *path, const char *principal, 1066 char ***principalsp, size_t *nprincipalsp) 1067 { 1068 FILE *f = NULL; 1069 char *found, *line = NULL, **principals = NULL, **tmp; 1070 size_t i, nprincipals = 0, linesize = 0; 1071 u_long linenum = 0; 1072 int oerrno = 0, r, ret = 0; 1073 1074 if (principalsp != NULL) 1075 *principalsp = NULL; 1076 if (nprincipalsp != NULL) 1077 *nprincipalsp = 0; 1078 1079 /* Check key and principal against file */ 1080 if ((f = fopen(path, "r")) == NULL) { 1081 oerrno = errno; 1082 error("Unable to open allowed keys file \"%s\": %s", 1083 path, strerror(errno)); 1084 errno = oerrno; 1085 return SSH_ERR_SYSTEM_ERROR; 1086 } 1087 1088 while (getline(&line, &linesize, f) != -1) { 1089 linenum++; 1090 /* Parse the line */ 1091 if ((r = parse_principals_key_and_options(path, linenum, line, 1092 principal, &found, NULL, NULL)) != 0) { 1093 if (r == SSH_ERR_KEY_NOT_FOUND) 1094 continue; 1095 ret = r; 1096 oerrno = errno; 1097 break; /* unexpected error */ 1098 } 1099 if ((tmp = recallocarray(principals, nprincipals, 1100 nprincipals + 1, sizeof(*principals))) == NULL) { 1101 ret = SSH_ERR_ALLOC_FAIL; 1102 free(found); 1103 break; 1104 } 1105 principals = tmp; 1106 principals[nprincipals++] = found; /* transferred */ 1107 free(line); 1108 line = NULL; 1109 linesize = 0; 1110 } 1111 fclose(f); 1112 1113 if (ret == 0) { 1114 if (nprincipals == 0) 1115 ret = SSH_ERR_KEY_NOT_FOUND; 1116 if (principalsp != NULL) { 1117 *principalsp = principals; 1118 principals = NULL; /* transferred */ 1119 } 1120 if (nprincipalsp != 0) { 1121 *nprincipalsp = nprincipals; 1122 nprincipals = 0; 1123 } 1124 } 1125 1126 for (i = 0; i < nprincipals; i++) 1127 free(principals[i]); 1128 free(principals); 1129 1130 errno = oerrno; 1131 return ret; 1132 } 1133 1134 int 1135 sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey) 1136 { 1137 struct sshkey *pk = NULL; 1138 int r = SSH_ERR_SIGNATURE_INVALID; 1139 1140 if (pubkey == NULL) 1141 return SSH_ERR_INTERNAL_ERROR; 1142 if ((r = sshsig_parse_preamble(signature)) != 0) 1143 return r; 1144 if ((r = sshkey_froms(signature, &pk)) != 0) 1145 return r; 1146 1147 *pubkey = pk; 1148 pk = NULL; 1149 return 0; 1150 } 1151