summaryrefslogtreecommitdiff
path: root/ssh-add.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-add.c')
-rw-r--r--ssh-add.c142
1 files changed, 106 insertions, 36 deletions
diff --git a/ssh-add.c b/ssh-add.c
index ebfb8a32b..8057eb1fe 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-add.c,v 1.141 2019/09/06 05:23:55 djm Exp $ */ 1/* $OpenBSD: ssh-add.c,v 1.152 2020/02/06 22:30:54 naddy Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -66,6 +66,7 @@
66#include "misc.h" 66#include "misc.h"
67#include "ssherr.h" 67#include "ssherr.h"
68#include "digest.h" 68#include "digest.h"
69#include "ssh-sk.h"
69 70
70/* argv0 */ 71/* argv0 */
71extern char *__progname; 72extern char *__progname;
@@ -77,9 +78,11 @@ static char *default_files[] = {
77 _PATH_SSH_CLIENT_ID_DSA, 78 _PATH_SSH_CLIENT_ID_DSA,
78#ifdef OPENSSL_HAS_ECC 79#ifdef OPENSSL_HAS_ECC
79 _PATH_SSH_CLIENT_ID_ECDSA, 80 _PATH_SSH_CLIENT_ID_ECDSA,
81 _PATH_SSH_CLIENT_ID_ECDSA_SK,
80#endif 82#endif
81#endif /* WITH_OPENSSL */ 83#endif /* WITH_OPENSSL */
82 _PATH_SSH_CLIENT_ID_ED25519, 84 _PATH_SSH_CLIENT_ID_ED25519,
85 _PATH_SSH_CLIENT_ID_ED25519_SK,
83 _PATH_SSH_CLIENT_ID_XMSS, 86 _PATH_SSH_CLIENT_ID_XMSS,
84 NULL 87 NULL
85}; 88};
@@ -191,7 +194,8 @@ delete_all(int agent_fd, int qflag)
191} 194}
192 195
193static int 196static int
194add_file(int agent_fd, const char *filename, int key_only, int qflag) 197add_file(int agent_fd, const char *filename, int key_only, int qflag,
198 const char *skprovider)
195{ 199{
196 struct sshkey *private, *cert; 200 struct sshkey *private, *cert;
197 char *comment = NULL; 201 char *comment = NULL;
@@ -220,9 +224,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
220 return -1; 224 return -1;
221 } 225 }
222 } 226 }
223 if ((keyblob = sshbuf_new()) == NULL) 227 if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) {
224 fatal("%s: sshbuf_new failed", __func__);
225 if ((r = sshkey_load_file(fd, keyblob)) != 0) {
226 fprintf(stderr, "Error loading key \"%s\": %s\n", 228 fprintf(stderr, "Error loading key \"%s\": %s\n",
227 filename, ssh_err(r)); 229 filename, ssh_err(r));
228 sshbuf_free(keyblob); 230 sshbuf_free(keyblob);
@@ -310,8 +312,16 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
310 ssh_free_identitylist(idlist); 312 ssh_free_identitylist(idlist);
311 } 313 }
312 314
315 if (!sshkey_is_sk(private))
316 skprovider = NULL; /* Don't send constraint for other keys */
317 else if (skprovider == NULL) {
318 fprintf(stderr, "Cannot load authenticator-hosted key %s "
319 "without provider\n", filename);
320 goto out;
321 }
322
313 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 323 if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
314 lifetime, confirm, maxsign)) == 0) { 324 lifetime, confirm, maxsign, skprovider)) == 0) {
315 ret = 0; 325 ret = 0;
316 if (!qflag) { 326 if (!qflag) {
317 fprintf(stderr, "Identity added: %s (%s)\n", 327 fprintf(stderr, "Identity added: %s (%s)\n",
@@ -364,7 +374,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
364 sshkey_free(cert); 374 sshkey_free(cert);
365 375
366 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 376 if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
367 lifetime, confirm, maxsign)) != 0) { 377 lifetime, confirm, maxsign, skprovider)) != 0) {
368 error("Certificate %s (%s) add failed: %s", certpath, 378 error("Certificate %s (%s) add failed: %s", certpath,
369 private->cert->key_id, ssh_err(r)); 379 private->cert->key_id, ssh_err(r));
370 goto out; 380 goto out;
@@ -440,7 +450,7 @@ test_key(int agent_fd, const char *filename)
440 goto done; 450 goto done;
441 } 451 }
442 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 452 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data),
443 NULL, 0)) != 0) { 453 NULL, 0, NULL)) != 0) {
444 error("Signature verification failed for %s: %s", 454 error("Signature verification failed for %s: %s",
445 filename, ssh_err(r)); 455 filename, ssh_err(r));
446 goto done; 456 goto done;
@@ -529,13 +539,63 @@ lock_agent(int agent_fd, int lock)
529} 539}
530 540
531static int 541static int
532do_file(int agent_fd, int deleting, int key_only, char *file, int qflag) 542load_resident_keys(int agent_fd, const char *skprovider, int qflag)
543{
544 struct sshkey **keys;
545 size_t nkeys, i;
546 int r, ok = 0;
547 char *fp;
548
549 pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
550 if ((r = sshsk_load_resident(skprovider, NULL, pass,
551 &keys, &nkeys)) != 0) {
552 error("Unable to load resident keys: %s", ssh_err(r));
553 return r;
554 }
555 for (i = 0; i < nkeys; i++) {
556 if ((fp = sshkey_fingerprint(keys[i],
557 fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
558 fatal("%s: sshkey_fingerprint failed", __func__);
559 if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "",
560 lifetime, confirm, maxsign, skprovider)) != 0) {
561 error("Unable to add key %s %s",
562 sshkey_type(keys[i]), fp);
563 free(fp);
564 ok = r;
565 continue;
566 }
567 if (ok == 0)
568 ok = 1;
569 if (!qflag) {
570 fprintf(stderr, "Resident identity added: %s %s\n",
571 sshkey_type(keys[i]), fp);
572 if (lifetime != 0) {
573 fprintf(stderr,
574 "Lifetime set to %d seconds\n", lifetime);
575 }
576 if (confirm != 0) {
577 fprintf(stderr, "The user must confirm "
578 "each use of the key\n");
579 }
580 }
581 free(fp);
582 sshkey_free(keys[i]);
583 }
584 free(keys);
585 if (nkeys == 0)
586 return SSH_ERR_KEY_NOT_FOUND;
587 return ok == 1 ? 0 : ok;
588}
589
590static int
591do_file(int agent_fd, int deleting, int key_only, char *file, int qflag,
592 const char *skprovider)
533{ 593{
534 if (deleting) { 594 if (deleting) {
535 if (delete_file(agent_fd, file, key_only, qflag) == -1) 595 if (delete_file(agent_fd, file, key_only, qflag) == -1)
536 return -1; 596 return -1;
537 } else { 597 } else {
538 if (add_file(agent_fd, file, key_only, qflag) == -1) 598 if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1)
539 return -1; 599 return -1;
540 } 600 }
541 return 0; 601 return 0;
@@ -544,25 +604,16 @@ do_file(int agent_fd, int deleting, int key_only, char *file, int qflag)
544static void 604static void
545usage(void) 605usage(void)
546{ 606{
547 fprintf(stderr, "usage: %s [options] [file ...]\n", __progname); 607 fprintf(stderr,
548 fprintf(stderr, "Options:\n"); 608"usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-S provider] [-t life]\n"
549 fprintf(stderr, " -l List fingerprints of all identities.\n"); 609#ifdef WITH_XMSS
550 fprintf(stderr, " -E hash Specify hash algorithm used for fingerprints.\n"); 610" [-M maxsign] [-m minleft]\n"
551 fprintf(stderr, " -L List public key parameters of all identities.\n"); 611#endif
552 fprintf(stderr, " -k Load only keys and not certificates.\n"); 612" [file ...]\n"
553 fprintf(stderr, " -c Require confirmation to sign using identities\n"); 613" ssh-add -s pkcs11\n"
554 fprintf(stderr, " -m minleft Maxsign is only changed if less than minleft are left (for XMSS)\n"); 614" ssh-add -e pkcs11\n"
555 fprintf(stderr, " -M maxsign Maximum number of signatures allowed (for XMSS)\n"); 615" ssh-add -T pubkey ...\n"
556 fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); 616 );
557 fprintf(stderr, " -d Delete identity.\n");
558 fprintf(stderr, " -D Delete all identities.\n");
559 fprintf(stderr, " -x Lock agent.\n");
560 fprintf(stderr, " -X Unlock agent.\n");
561 fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n");
562 fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n");
563 fprintf(stderr, " -T pubkey Test if ssh-agent can access matching private key.\n");
564 fprintf(stderr, " -q Be quiet after a successful operation.\n");
565 fprintf(stderr, " -v Be more verbose.\n");
566} 617}
567 618
568int 619int
@@ -571,8 +622,8 @@ main(int argc, char **argv)
571 extern char *optarg; 622 extern char *optarg;
572 extern int optind; 623 extern int optind;
573 int agent_fd; 624 int agent_fd;
574 char *pkcs11provider = NULL; 625 char *pkcs11provider = NULL, *skprovider = NULL;
575 int r, i, ch, deleting = 0, ret = 0, key_only = 0; 626 int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
576 int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; 627 int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
577 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 628 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
578 LogLevel log_level = SYSLOG_LEVEL_INFO; 629 LogLevel log_level = SYSLOG_LEVEL_INFO;
@@ -600,7 +651,9 @@ main(int argc, char **argv)
600 exit(2); 651 exit(2);
601 } 652 }
602 653
603 while ((ch = getopt(argc, argv, "vklLcdDTxXE:e:M:m:qs:t:")) != -1) { 654 skprovider = getenv("SSH_SK_PROVIDER");
655
656 while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:M:m:qs:S:t:")) != -1) {
604 switch (ch) { 657 switch (ch) {
605 case 'v': 658 case 'v':
606 if (log_level == SYSLOG_LEVEL_INFO) 659 if (log_level == SYSLOG_LEVEL_INFO)
@@ -616,6 +669,9 @@ main(int argc, char **argv)
616 case 'k': 669 case 'k':
617 key_only = 1; 670 key_only = 1;
618 break; 671 break;
672 case 'K':
673 do_download = 1;
674 break;
619 case 'l': 675 case 'l':
620 case 'L': 676 case 'L':
621 if (lflag != 0) 677 if (lflag != 0)
@@ -656,6 +712,9 @@ main(int argc, char **argv)
656 case 's': 712 case 's':
657 pkcs11provider = optarg; 713 pkcs11provider = optarg;
658 break; 714 break;
715 case 'S':
716 skprovider = optarg;
717 break;
659 case 'e': 718 case 'e':
660 deleting = 1; 719 deleting = 1;
661 pkcs11provider = optarg; 720 pkcs11provider = optarg;
@@ -697,6 +756,11 @@ main(int argc, char **argv)
697 goto done; 756 goto done;
698 } 757 }
699 758
759#ifdef ENABLE_SK_INTERNAL
760 if (skprovider == NULL)
761 skprovider = "internal";
762#endif
763
700 argc -= optind; 764 argc -= optind;
701 argv += optind; 765 argv += optind;
702 if (Tflag) { 766 if (Tflag) {
@@ -713,6 +777,13 @@ main(int argc, char **argv)
713 ret = 1; 777 ret = 1;
714 goto done; 778 goto done;
715 } 779 }
780 if (do_download) {
781 if (skprovider == NULL)
782 fatal("Cannot download keys without provider");
783 if (load_resident_keys(agent_fd, skprovider, qflag) != 0)
784 ret = 1;
785 goto done;
786 }
716 if (argc == 0) { 787 if (argc == 0) {
717 char buf[PATH_MAX]; 788 char buf[PATH_MAX];
718 struct passwd *pw; 789 struct passwd *pw;
@@ -732,7 +803,7 @@ main(int argc, char **argv)
732 if (stat(buf, &st) == -1) 803 if (stat(buf, &st) == -1)
733 continue; 804 continue;
734 if (do_file(agent_fd, deleting, key_only, buf, 805 if (do_file(agent_fd, deleting, key_only, buf,
735 qflag) == -1) 806 qflag, skprovider) == -1)
736 ret = 1; 807 ret = 1;
737 else 808 else
738 count++; 809 count++;
@@ -742,13 +813,12 @@ main(int argc, char **argv)
742 } else { 813 } else {
743 for (i = 0; i < argc; i++) { 814 for (i = 0; i < argc; i++) {
744 if (do_file(agent_fd, deleting, key_only, 815 if (do_file(agent_fd, deleting, key_only,
745 argv[i], qflag) == -1) 816 argv[i], qflag, skprovider) == -1)
746 ret = 1; 817 ret = 1;
747 } 818 }
748 } 819 }
749 clear_pass();
750
751done: 820done:
821 clear_pass();
752 ssh_close_authentication_socket(agent_fd); 822 ssh_close_authentication_socket(agent_fd);
753 return ret; 823 return ret;
754} 824}