1 /* $OpenBSD: ssh-add.c,v 1.172 2024/01/11 01:45:36 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Adds an identity to the authentication server, or removes an identity. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 * 14 * SSH2 implementation, 15 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include "includes.h" 39 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 43 #ifdef WITH_OPENSSL 44 # include <openssl/evp.h> 45 # include "openbsd-compat/openssl-compat.h" 46 #endif 47 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <pwd.h> 51 #include <stdarg.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 #include <limits.h> 57 58 #include "xmalloc.h" 59 #include "ssh.h" 60 #include "log.h" 61 #include "sshkey.h" 62 #include "sshbuf.h" 63 #include "authfd.h" 64 #include "authfile.h" 65 #include "pathnames.h" 66 #include "misc.h" 67 #include "ssherr.h" 68 #include "digest.h" 69 #include "ssh-sk.h" 70 #include "sk-api.h" 71 #include "hostfile.h" 72 73 /* argv0 */ 74 extern char *__progname; 75 76 /* Default files to add */ 77 static char *default_files[] = { 78 #ifdef WITH_OPENSSL 79 _PATH_SSH_CLIENT_ID_RSA, 80 #ifdef OPENSSL_HAS_ECC 81 _PATH_SSH_CLIENT_ID_ECDSA, 82 _PATH_SSH_CLIENT_ID_ECDSA_SK, 83 #endif 84 #endif /* WITH_OPENSSL */ 85 _PATH_SSH_CLIENT_ID_ED25519, 86 _PATH_SSH_CLIENT_ID_ED25519_SK, 87 _PATH_SSH_CLIENT_ID_XMSS, 88 #ifdef WITH_DSA 89 _PATH_SSH_CLIENT_ID_DSA, 90 #endif 91 NULL 92 }; 93 94 static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 95 96 /* Default lifetime (0 == forever) */ 97 static int lifetime = 0; 98 99 /* User has to confirm key use */ 100 static int confirm = 0; 101 102 /* Maximum number of signatures (XMSS) */ 103 static u_int maxsign = 0; 104 static u_int minleft = 0; 105 106 /* we keep a cache of one passphrase */ 107 static char *pass = NULL; 108 static void 109 clear_pass(void) 110 { 111 if (pass) { 112 freezero(pass, strlen(pass)); 113 pass = NULL; 114 } 115 } 116 117 static int 118 delete_one(int agent_fd, const struct sshkey *key, const char *comment, 119 const char *path, int qflag) 120 { 121 int r; 122 123 if ((r = ssh_remove_identity(agent_fd, key)) != 0) { 124 fprintf(stderr, "Could not remove identity \"%s\": %s\n", 125 path, ssh_err(r)); 126 return r; 127 } 128 if (!qflag) { 129 fprintf(stderr, "Identity removed: %s %s (%s)\n", path, 130 sshkey_type(key), comment ? comment : "no comment"); 131 } 132 return 0; 133 } 134 135 static int 136 delete_stdin(int agent_fd, int qflag, int key_only, int cert_only) 137 { 138 char *line = NULL, *cp; 139 size_t linesize = 0; 140 struct sshkey *key = NULL; 141 int lnum = 0, r, ret = -1; 142 143 while (getline(&line, &linesize, stdin) != -1) { 144 lnum++; 145 sshkey_free(key); 146 key = NULL; 147 line[strcspn(line, "\n")] = '\0'; 148 cp = line + strspn(line, " \t"); 149 if (*cp == '#' || *cp == '\0') 150 continue; 151 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) 152 fatal_f("sshkey_new"); 153 if ((r = sshkey_read(key, &cp)) != 0) { 154 error_r(r, "(stdin):%d: invalid key", lnum); 155 continue; 156 } 157 if ((!key_only && !cert_only) || 158 (key_only && !sshkey_is_cert(key)) || 159 (cert_only && sshkey_is_cert(key))) { 160 if (delete_one(agent_fd, key, cp, 161 "(stdin)", qflag) == 0) 162 ret = 0; 163 } 164 } 165 sshkey_free(key); 166 free(line); 167 return ret; 168 } 169 170 static int 171 delete_file(int agent_fd, const char *filename, int key_only, 172 int cert_only, int qflag) 173 { 174 struct sshkey *public, *cert = NULL; 175 char *certpath = NULL, *comment = NULL; 176 int r, ret = -1; 177 178 if (strcmp(filename, "-") == 0) 179 return delete_stdin(agent_fd, qflag, key_only, cert_only); 180 181 if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { 182 printf("Bad key file %s: %s\n", filename, ssh_err(r)); 183 return -1; 184 } 185 if ((!key_only && !cert_only) || 186 (key_only && !sshkey_is_cert(public)) || 187 (cert_only && sshkey_is_cert(public))) { 188 if (delete_one(agent_fd, public, comment, filename, qflag) == 0) 189 ret = 0; 190 } 191 192 if (key_only) 193 goto out; 194 195 /* Now try to delete the corresponding certificate too */ 196 free(comment); 197 comment = NULL; 198 xasprintf(&certpath, "%s-cert.pub", filename); 199 if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) { 200 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 201 error_r(r, "Failed to load certificate \"%s\"", certpath); 202 goto out; 203 } 204 205 if (!sshkey_equal_public(cert, public)) 206 fatal("Certificate %s does not match private key %s", 207 certpath, filename); 208 209 if (delete_one(agent_fd, cert, comment, certpath, qflag) == 0) 210 ret = 0; 211 212 out: 213 sshkey_free(cert); 214 sshkey_free(public); 215 free(certpath); 216 free(comment); 217 218 return ret; 219 } 220 221 /* Send a request to remove all identities. */ 222 static int 223 delete_all(int agent_fd, int qflag) 224 { 225 int ret = -1; 226 227 /* 228 * Since the agent might be forwarded, old or non-OpenSSH, when asked 229 * to remove all keys, attempt to remove both protocol v.1 and v.2 230 * keys. 231 */ 232 if (ssh_remove_all_identities(agent_fd, 2) == 0) 233 ret = 0; 234 /* ignore error-code for ssh1 */ 235 ssh_remove_all_identities(agent_fd, 1); 236 237 if (ret != 0) 238 fprintf(stderr, "Failed to remove all identities.\n"); 239 else if (!qflag) 240 fprintf(stderr, "All identities removed.\n"); 241 242 return ret; 243 } 244 245 static int 246 add_file(int agent_fd, const char *filename, int key_only, int cert_only, 247 int qflag, const char *skprovider, 248 struct dest_constraint **dest_constraints, 249 size_t ndest_constraints) 250 { 251 struct sshkey *private, *cert; 252 char *comment = NULL; 253 char msg[1024], *certpath = NULL; 254 int r, fd, ret = -1; 255 size_t i; 256 u_int32_t left; 257 struct sshbuf *keyblob; 258 struct ssh_identitylist *idlist; 259 260 if (strcmp(filename, "-") == 0) { 261 fd = STDIN_FILENO; 262 filename = "(stdin)"; 263 } else if ((fd = open(filename, O_RDONLY)) == -1) { 264 perror(filename); 265 return -1; 266 } 267 268 /* 269 * Since we'll try to load a keyfile multiple times, permission errors 270 * will occur multiple times, so check perms first and bail if wrong. 271 */ 272 if (fd != STDIN_FILENO) { 273 if (sshkey_perm_ok(fd, filename) != 0) { 274 close(fd); 275 return -1; 276 } 277 } 278 if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) { 279 fprintf(stderr, "Error loading key \"%s\": %s\n", 280 filename, ssh_err(r)); 281 sshbuf_free(keyblob); 282 close(fd); 283 return -1; 284 } 285 close(fd); 286 287 /* At first, try empty passphrase */ 288 if ((r = sshkey_parse_private_fileblob(keyblob, "", &private, 289 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 290 fprintf(stderr, "Error loading key \"%s\": %s\n", 291 filename, ssh_err(r)); 292 goto fail_load; 293 } 294 /* try last */ 295 if (private == NULL && pass != NULL) { 296 if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private, 297 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 298 fprintf(stderr, "Error loading key \"%s\": %s\n", 299 filename, ssh_err(r)); 300 goto fail_load; 301 } 302 } 303 if (private == NULL) { 304 /* clear passphrase since it did not work */ 305 clear_pass(); 306 snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ", 307 filename, confirm ? " (will confirm each use)" : ""); 308 for (;;) { 309 pass = read_passphrase(msg, RP_ALLOW_STDIN); 310 if (strcmp(pass, "") == 0) 311 goto fail_load; 312 if ((r = sshkey_parse_private_fileblob(keyblob, pass, 313 &private, &comment)) == 0) 314 break; 315 else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 316 fprintf(stderr, 317 "Error loading key \"%s\": %s\n", 318 filename, ssh_err(r)); 319 fail_load: 320 clear_pass(); 321 sshbuf_free(keyblob); 322 return -1; 323 } 324 clear_pass(); 325 snprintf(msg, sizeof msg, 326 "Bad passphrase, try again for %s%s: ", filename, 327 confirm ? " (will confirm each use)" : ""); 328 } 329 } 330 if (comment == NULL || *comment == '\0') 331 comment = xstrdup(filename); 332 sshbuf_free(keyblob); 333 334 /* For XMSS */ 335 if ((r = sshkey_set_filename(private, filename)) != 0) { 336 fprintf(stderr, "Could not add filename to private key: %s (%s)\n", 337 filename, comment); 338 goto out; 339 } 340 if (maxsign && minleft && 341 (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { 342 for (i = 0; i < idlist->nkeys; i++) { 343 if (!sshkey_equal_public(idlist->keys[i], private)) 344 continue; 345 left = sshkey_signatures_left(idlist->keys[i]); 346 if (left < minleft) { 347 fprintf(stderr, 348 "Only %d signatures left.\n", left); 349 break; 350 } 351 fprintf(stderr, "Skipping update: "); 352 if (left == minleft) { 353 fprintf(stderr, 354 "required signatures left (%d).\n", left); 355 } else { 356 fprintf(stderr, 357 "more signatures left (%d) than" 358 " required (%d).\n", left, minleft); 359 } 360 ssh_free_identitylist(idlist); 361 goto out; 362 } 363 ssh_free_identitylist(idlist); 364 } 365 366 if (sshkey_is_sk(private)) { 367 if (skprovider == NULL) { 368 fprintf(stderr, "Cannot load FIDO key %s " 369 "without provider\n", filename); 370 goto out; 371 } 372 } else { 373 /* Don't send provider constraint for other keys */ 374 skprovider = NULL; 375 } 376 377 if (!cert_only && 378 (r = ssh_add_identity_constrained(agent_fd, private, comment, 379 lifetime, confirm, maxsign, skprovider, 380 dest_constraints, ndest_constraints)) == 0) { 381 ret = 0; 382 if (!qflag) { 383 fprintf(stderr, "Identity added: %s (%s)\n", 384 filename, comment); 385 if (lifetime != 0) { 386 fprintf(stderr, 387 "Lifetime set to %d seconds\n", lifetime); 388 } 389 if (confirm != 0) { 390 fprintf(stderr, "The user must confirm " 391 "each use of the key\n"); 392 } 393 } 394 } else { 395 fprintf(stderr, "Could not add identity \"%s\": %s\n", 396 filename, ssh_err(r)); 397 } 398 399 /* Skip trying to load the cert if requested */ 400 if (key_only) 401 goto out; 402 403 /* Now try to add the certificate flavour too */ 404 xasprintf(&certpath, "%s-cert.pub", filename); 405 if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { 406 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 407 error_r(r, "Failed to load certificate \"%s\"", 408 certpath); 409 goto out; 410 } 411 412 if (!sshkey_equal_public(cert, private)) { 413 error("Certificate %s does not match private key %s", 414 certpath, filename); 415 sshkey_free(cert); 416 goto out; 417 } 418 419 /* Graft with private bits */ 420 if ((r = sshkey_to_certified(private)) != 0) { 421 error_fr(r, "sshkey_to_certified"); 422 sshkey_free(cert); 423 goto out; 424 } 425 if ((r = sshkey_cert_copy(cert, private)) != 0) { 426 error_fr(r, "sshkey_cert_copy"); 427 sshkey_free(cert); 428 goto out; 429 } 430 sshkey_free(cert); 431 432 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 433 lifetime, confirm, maxsign, skprovider, 434 dest_constraints, ndest_constraints)) != 0) { 435 error_r(r, "Certificate %s (%s) add failed", certpath, 436 private->cert->key_id); 437 goto out; 438 } 439 /* success */ 440 if (!qflag) { 441 fprintf(stderr, "Certificate added: %s (%s)\n", certpath, 442 private->cert->key_id); 443 if (lifetime != 0) { 444 fprintf(stderr, "Lifetime set to %d seconds\n", 445 lifetime); 446 } 447 if (confirm != 0) { 448 fprintf(stderr, "The user must confirm each use " 449 "of the key\n"); 450 } 451 } 452 453 out: 454 free(certpath); 455 free(comment); 456 sshkey_free(private); 457 458 return ret; 459 } 460 461 static int 462 update_card(int agent_fd, int add, const char *id, int qflag, 463 int key_only, int cert_only, 464 struct dest_constraint **dest_constraints, size_t ndest_constraints, 465 struct sshkey **certs, size_t ncerts) 466 { 467 char *pin = NULL; 468 int r, ret = -1; 469 470 if (key_only) 471 ncerts = 0; 472 473 if (add) { 474 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", 475 RP_ALLOW_STDIN)) == NULL) 476 return -1; 477 } 478 479 if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, 480 lifetime, confirm, dest_constraints, ndest_constraints, 481 cert_only, certs, ncerts)) == 0) { 482 ret = 0; 483 if (!qflag) { 484 fprintf(stderr, "Card %s: %s\n", 485 add ? "added" : "removed", id); 486 } 487 } else { 488 fprintf(stderr, "Could not %s card \"%s\": %s\n", 489 add ? "add" : "remove", id, ssh_err(r)); 490 ret = -1; 491 } 492 free(pin); 493 return ret; 494 } 495 496 static int 497 test_key(int agent_fd, const char *filename) 498 { 499 struct sshkey *key = NULL; 500 u_char *sig = NULL; 501 const char *alg = NULL; 502 size_t slen = 0; 503 int r, ret = -1; 504 char data[1024]; 505 506 if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { 507 error_r(r, "Couldn't read public key %s", filename); 508 return -1; 509 } 510 if (sshkey_type_plain(key->type) == KEY_RSA) 511 alg = "rsa-sha2-256"; 512 arc4random_buf(data, sizeof(data)); 513 if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), 514 alg, 0)) != 0) { 515 error_r(r, "Agent signature failed for %s", filename); 516 goto done; 517 } 518 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 519 alg, 0, NULL)) != 0) { 520 error_r(r, "Signature verification failed for %s", filename); 521 goto done; 522 } 523 /* success */ 524 ret = 0; 525 done: 526 free(sig); 527 sshkey_free(key); 528 return ret; 529 } 530 531 static int 532 list_identities(int agent_fd, int do_fp) 533 { 534 char *fp; 535 int r; 536 struct ssh_identitylist *idlist; 537 u_int32_t left; 538 size_t i; 539 540 if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 541 if (r != SSH_ERR_AGENT_NO_IDENTITIES) 542 fprintf(stderr, "error fetching identities: %s\n", 543 ssh_err(r)); 544 else 545 printf("The agent has no identities.\n"); 546 return -1; 547 } 548 for (i = 0; i < idlist->nkeys; i++) { 549 if (do_fp) { 550 fp = sshkey_fingerprint(idlist->keys[i], 551 fingerprint_hash, SSH_FP_DEFAULT); 552 printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]), 553 fp == NULL ? "(null)" : fp, idlist->comments[i], 554 sshkey_type(idlist->keys[i])); 555 free(fp); 556 } else { 557 if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) { 558 fprintf(stderr, "sshkey_write: %s\n", 559 ssh_err(r)); 560 continue; 561 } 562 fprintf(stdout, " %s", idlist->comments[i]); 563 left = sshkey_signatures_left(idlist->keys[i]); 564 if (left > 0) 565 fprintf(stdout, 566 " [signatures left %d]", left); 567 fprintf(stdout, "\n"); 568 } 569 } 570 ssh_free_identitylist(idlist); 571 return 0; 572 } 573 574 static int 575 lock_agent(int agent_fd, int lock) 576 { 577 char prompt[100], *p1, *p2; 578 int r, passok = 1, ret = -1; 579 580 strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); 581 p1 = read_passphrase(prompt, RP_ALLOW_STDIN); 582 if (lock) { 583 strlcpy(prompt, "Again: ", sizeof prompt); 584 p2 = read_passphrase(prompt, RP_ALLOW_STDIN); 585 if (strcmp(p1, p2) != 0) { 586 fprintf(stderr, "Passwords do not match.\n"); 587 passok = 0; 588 } 589 freezero(p2, strlen(p2)); 590 } 591 if (passok) { 592 if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { 593 fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); 594 ret = 0; 595 } else { 596 fprintf(stderr, "Failed to %slock agent: %s\n", 597 lock ? "" : "un", ssh_err(r)); 598 } 599 } 600 freezero(p1, strlen(p1)); 601 return (ret); 602 } 603 604 static int 605 load_resident_keys(int agent_fd, const char *skprovider, int qflag, 606 struct dest_constraint **dest_constraints, size_t ndest_constraints) 607 { 608 struct sshsk_resident_key **srks; 609 size_t nsrks, i; 610 struct sshkey *key; 611 int r, ok = 0; 612 char *fp; 613 614 pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN); 615 if ((r = sshsk_load_resident(skprovider, NULL, pass, 0, 616 &srks, &nsrks)) != 0) { 617 error_r(r, "Unable to load resident keys"); 618 return r; 619 } 620 for (i = 0; i < nsrks; i++) { 621 key = srks[i]->key; 622 if ((fp = sshkey_fingerprint(key, 623 fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 624 fatal_f("sshkey_fingerprint failed"); 625 if ((r = ssh_add_identity_constrained(agent_fd, key, "", 626 lifetime, confirm, maxsign, skprovider, 627 dest_constraints, ndest_constraints)) != 0) { 628 error("Unable to add key %s %s", 629 sshkey_type(key), fp); 630 free(fp); 631 ok = r; 632 continue; 633 } 634 if (ok == 0) 635 ok = 1; 636 if (!qflag) { 637 fprintf(stderr, "Resident identity added: %s %s\n", 638 sshkey_type(key), fp); 639 if (lifetime != 0) { 640 fprintf(stderr, 641 "Lifetime set to %d seconds\n", lifetime); 642 } 643 if (confirm != 0) { 644 fprintf(stderr, "The user must confirm " 645 "each use of the key\n"); 646 } 647 } 648 free(fp); 649 } 650 sshsk_free_resident_keys(srks, nsrks); 651 if (nsrks == 0) 652 return SSH_ERR_KEY_NOT_FOUND; 653 return ok == 1 ? 0 : ok; 654 } 655 656 static int 657 do_file(int agent_fd, int deleting, int key_only, int cert_only, 658 char *file, int qflag, const char *skprovider, 659 struct dest_constraint **dest_constraints, size_t ndest_constraints) 660 { 661 if (deleting) { 662 if (delete_file(agent_fd, file, key_only, 663 cert_only, qflag) == -1) 664 return -1; 665 } else { 666 if (add_file(agent_fd, file, key_only, cert_only, qflag, 667 skprovider, dest_constraints, ndest_constraints) == -1) 668 return -1; 669 } 670 return 0; 671 } 672 673 /* Append string 's' to a NULL-terminated array of strings */ 674 static void 675 stringlist_append(char ***listp, const char *s) 676 { 677 size_t i = 0; 678 679 if (*listp == NULL) 680 *listp = xcalloc(2, sizeof(**listp)); 681 else { 682 for (i = 0; (*listp)[i] != NULL; i++) 683 ; /* count */ 684 *listp = xrecallocarray(*listp, i + 1, i + 2, sizeof(**listp)); 685 } 686 (*listp)[i] = xstrdup(s); 687 } 688 689 static void 690 parse_dest_constraint_hop(const char *s, struct dest_constraint_hop *dch, 691 char **hostkey_files) 692 { 693 char *user = NULL, *host, *os, *path; 694 size_t i; 695 struct hostkeys *hostkeys; 696 const struct hostkey_entry *hke; 697 int r, want_ca; 698 699 memset(dch, '\0', sizeof(*dch)); 700 os = xstrdup(s); 701 if ((host = strchr(os, '@')) == NULL) 702 host = os; 703 else { 704 *host++ = '\0'; 705 user = os; 706 } 707 cleanhostname(host); 708 /* Trivial case: username@ (all hosts) */ 709 if (*host == '\0') { 710 if (user == NULL) { 711 fatal("Invalid key destination constraint \"%s\": " 712 "does not specify user or host", s); 713 } 714 dch->user = xstrdup(user); 715 /* other fields left blank */ 716 free(os); 717 return; 718 } 719 if (hostkey_files == NULL) 720 fatal_f("no hostkey files"); 721 /* Otherwise we need to look up the keys for this hostname */ 722 hostkeys = init_hostkeys(); 723 for (i = 0; hostkey_files[i]; i++) { 724 path = tilde_expand_filename(hostkey_files[i], getuid()); 725 debug2_f("looking up host keys for \"%s\" in %s", host, path); 726 load_hostkeys(hostkeys, host, path, 0); 727 free(path); 728 } 729 dch->user = user == NULL ? NULL : xstrdup(user); 730 dch->hostname = xstrdup(host); 731 for (i = 0; i < hostkeys->num_entries; i++) { 732 hke = hostkeys->entries + i; 733 want_ca = hke->marker == MRK_CA; 734 if (hke->marker != MRK_NONE && !want_ca) 735 continue; 736 debug3_f("%s%s%s: adding %s %skey from %s:%lu as key %u", 737 user == NULL ? "": user, user == NULL ? "" : "@", 738 host, sshkey_type(hke->key), want_ca ? "CA " : "", 739 hke->file, hke->line, dch->nkeys); 740 dch->keys = xrecallocarray(dch->keys, dch->nkeys, 741 dch->nkeys + 1, sizeof(*dch->keys)); 742 dch->key_is_ca = xrecallocarray(dch->key_is_ca, dch->nkeys, 743 dch->nkeys + 1, sizeof(*dch->key_is_ca)); 744 if ((r = sshkey_from_private(hke->key, 745 &(dch->keys[dch->nkeys]))) != 0) 746 fatal_fr(r, "sshkey_from_private"); 747 dch->key_is_ca[dch->nkeys] = want_ca; 748 dch->nkeys++; 749 } 750 if (dch->nkeys == 0) 751 fatal("No host keys found for destination \"%s\"", host); 752 free_hostkeys(hostkeys); 753 free(os); 754 return; 755 } 756 757 static void 758 parse_dest_constraint(const char *s, struct dest_constraint ***dcp, 759 size_t *ndcp, char **hostkey_files) 760 { 761 struct dest_constraint *dc; 762 char *os, *cp; 763 764 dc = xcalloc(1, sizeof(*dc)); 765 os = xstrdup(s); 766 if ((cp = strchr(os, '>')) == NULL) { 767 /* initial hop; no 'from' hop specified */ 768 parse_dest_constraint_hop(os, &dc->to, hostkey_files); 769 } else { 770 /* two hops specified */ 771 *(cp++) = '\0'; 772 parse_dest_constraint_hop(os, &dc->from, hostkey_files); 773 parse_dest_constraint_hop(cp, &dc->to, hostkey_files); 774 if (dc->from.user != NULL) { 775 fatal("Invalid key constraint %s: cannot specify " 776 "user on 'from' host", os); 777 } 778 } 779 /* XXX eliminate or error on duplicates */ 780 debug2_f("constraint %zu: %s%s%s (%u keys) > %s%s%s (%u keys)", *ndcp, 781 dc->from.user ? dc->from.user : "", dc->from.user ? "@" : "", 782 dc->from.hostname ? dc->from.hostname : "(ORIGIN)", dc->from.nkeys, 783 dc->to.user ? dc->to.user : "", dc->to.user ? "@" : "", 784 dc->to.hostname ? dc->to.hostname : "(ANY)", dc->to.nkeys); 785 *dcp = xrecallocarray(*dcp, *ndcp, *ndcp + 1, sizeof(**dcp)); 786 (*dcp)[(*ndcp)++] = dc; 787 free(os); 788 } 789 790 791 static void 792 usage(void) 793 { 794 fprintf(stderr, 795 "usage: ssh-add [-CcDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n" 796 " [-h destination_constraint] [-S provider] [-t life]\n" 797 #ifdef WITH_XMSS 798 " [-M maxsign] [-m minleft]\n" 799 #endif 800 " [file ...]\n" 801 " ssh-add -s pkcs11 [-Cv] [certificate ...]\n" 802 " ssh-add -e pkcs11\n" 803 " ssh-add -T pubkey ...\n" 804 ); 805 } 806 807 int 808 main(int argc, char **argv) 809 { 810 extern char *optarg; 811 extern int optind; 812 int agent_fd; 813 char *pkcs11provider = NULL, *skprovider = NULL; 814 char **dest_constraint_strings = NULL, **hostkey_files = NULL; 815 int r, i, ch, deleting = 0, ret = 0, key_only = 0, cert_only = 0; 816 int do_download = 0, xflag = 0, lflag = 0, Dflag = 0; 817 int qflag = 0, Tflag = 0; 818 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 819 LogLevel log_level = SYSLOG_LEVEL_INFO; 820 struct sshkey *k, **certs = NULL; 821 struct dest_constraint **dest_constraints = NULL; 822 size_t ndest_constraints = 0, ncerts = 0; 823 824 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 825 sanitise_stdfd(); 826 827 __progname = ssh_get_progname(argv[0]); 828 seed_rng(); 829 830 log_init(__progname, log_level, log_facility, 1); 831 832 setvbuf(stdout, NULL, _IOLBF, 0); 833 834 /* First, get a connection to the authentication agent. */ 835 switch (r = ssh_get_authentication_socket(&agent_fd)) { 836 case 0: 837 break; 838 case SSH_ERR_AGENT_NOT_PRESENT: 839 fprintf(stderr, "Could not open a connection to your " 840 "authentication agent.\n"); 841 exit(2); 842 default: 843 fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); 844 exit(2); 845 } 846 847 skprovider = getenv("SSH_SK_PROVIDER"); 848 849 while ((ch = getopt(argc, argv, "vkKlLCcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) { 850 switch (ch) { 851 case 'v': 852 if (log_level == SYSLOG_LEVEL_INFO) 853 log_level = SYSLOG_LEVEL_DEBUG1; 854 else if (log_level < SYSLOG_LEVEL_DEBUG3) 855 log_level++; 856 break; 857 case 'E': 858 fingerprint_hash = ssh_digest_alg_by_name(optarg); 859 if (fingerprint_hash == -1) 860 fatal("Invalid hash algorithm \"%s\"", optarg); 861 break; 862 case 'H': 863 stringlist_append(&hostkey_files, optarg); 864 break; 865 case 'h': 866 stringlist_append(&dest_constraint_strings, optarg); 867 break; 868 case 'k': 869 key_only = 1; 870 break; 871 case 'C': 872 cert_only = 1; 873 break; 874 case 'K': 875 do_download = 1; 876 break; 877 case 'l': 878 case 'L': 879 if (lflag != 0) 880 fatal("-%c flag already specified", lflag); 881 lflag = ch; 882 break; 883 case 'x': 884 case 'X': 885 if (xflag != 0) 886 fatal("-%c flag already specified", xflag); 887 xflag = ch; 888 break; 889 case 'c': 890 confirm = 1; 891 break; 892 case 'm': 893 minleft = (u_int)strtonum(optarg, 1, UINT_MAX, NULL); 894 if (minleft == 0) { 895 usage(); 896 ret = 1; 897 goto done; 898 } 899 break; 900 case 'M': 901 maxsign = (u_int)strtonum(optarg, 1, UINT_MAX, NULL); 902 if (maxsign == 0) { 903 usage(); 904 ret = 1; 905 goto done; 906 } 907 break; 908 case 'd': 909 deleting = 1; 910 break; 911 case 'D': 912 Dflag = 1; 913 break; 914 case 's': 915 pkcs11provider = optarg; 916 break; 917 case 'S': 918 skprovider = optarg; 919 break; 920 case 'e': 921 deleting = 1; 922 pkcs11provider = optarg; 923 break; 924 case 't': 925 if ((lifetime = convtime(optarg)) == -1 || 926 lifetime < 0 || (u_long)lifetime > UINT32_MAX) { 927 fprintf(stderr, "Invalid lifetime\n"); 928 ret = 1; 929 goto done; 930 } 931 break; 932 case 'q': 933 qflag = 1; 934 break; 935 case 'T': 936 Tflag = 1; 937 break; 938 default: 939 usage(); 940 ret = 1; 941 goto done; 942 } 943 } 944 log_init(__progname, log_level, log_facility, 1); 945 946 if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) 947 fatal("Invalid combination of actions"); 948 else if (xflag) { 949 if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) 950 ret = 1; 951 goto done; 952 } else if (lflag) { 953 if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) 954 ret = 1; 955 goto done; 956 } else if (Dflag) { 957 if (delete_all(agent_fd, qflag) == -1) 958 ret = 1; 959 goto done; 960 } 961 962 #ifdef ENABLE_SK_INTERNAL 963 if (skprovider == NULL) 964 skprovider = "internal"; 965 #endif 966 967 if (hostkey_files == NULL) { 968 /* use defaults from readconf.c */ 969 stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE); 970 stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE2); 971 stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE); 972 stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE2); 973 } 974 if (dest_constraint_strings != NULL) { 975 for (i = 0; dest_constraint_strings[i] != NULL; i++) { 976 parse_dest_constraint(dest_constraint_strings[i], 977 &dest_constraints, &ndest_constraints, hostkey_files); 978 } 979 } 980 981 argc -= optind; 982 argv += optind; 983 if (Tflag) { 984 if (argc <= 0) 985 fatal("no keys to test"); 986 for (r = i = 0; i < argc; i++) 987 r |= test_key(agent_fd, argv[i]); 988 ret = r == 0 ? 0 : 1; 989 goto done; 990 } 991 if (pkcs11provider != NULL) { 992 for (i = 0; i < argc; i++) { 993 if ((r = sshkey_load_public(argv[i], &k, NULL)) != 0) 994 fatal_fr(r, "load certificate %s", argv[i]); 995 certs = xrecallocarray(certs, ncerts, ncerts + 1, 996 sizeof(*certs)); 997 debug2("%s: %s", argv[i], sshkey_ssh_name(k)); 998 certs[ncerts++] = k; 999 } 1000 debug2_f("loaded %zu certificates", ncerts); 1001 if (update_card(agent_fd, !deleting, pkcs11provider, 1002 qflag, key_only, cert_only, 1003 dest_constraints, ndest_constraints, 1004 certs, ncerts) == -1) 1005 ret = 1; 1006 goto done; 1007 } 1008 if (do_download) { 1009 if (skprovider == NULL) 1010 fatal("Cannot download keys without provider"); 1011 if (load_resident_keys(agent_fd, skprovider, qflag, 1012 dest_constraints, ndest_constraints) != 0) 1013 ret = 1; 1014 goto done; 1015 } 1016 if (argc == 0) { 1017 char buf[PATH_MAX]; 1018 struct passwd *pw; 1019 struct stat st; 1020 int count = 0; 1021 1022 if ((pw = getpwuid(getuid())) == NULL) { 1023 fprintf(stderr, "No user found with uid %u\n", 1024 (u_int)getuid()); 1025 ret = 1; 1026 goto done; 1027 } 1028 1029 for (i = 0; default_files[i]; i++) { 1030 snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, 1031 default_files[i]); 1032 if (stat(buf, &st) == -1) 1033 continue; 1034 if (do_file(agent_fd, deleting, key_only, cert_only, 1035 buf, qflag, skprovider, 1036 dest_constraints, ndest_constraints) == -1) 1037 ret = 1; 1038 else 1039 count++; 1040 } 1041 if (count == 0) 1042 ret = 1; 1043 } else { 1044 for (i = 0; i < argc; i++) { 1045 if (do_file(agent_fd, deleting, key_only, cert_only, 1046 argv[i], qflag, skprovider, 1047 dest_constraints, ndest_constraints) == -1) 1048 ret = 1; 1049 } 1050 } 1051 done: 1052 clear_pass(); 1053 ssh_close_authentication_socket(agent_fd); 1054 return ret; 1055 } 1056