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