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