From 79fe22d9bc2868c5118f032ec1200ac9c2e3aaef Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 30 Dec 2019 09:22:49 +0000 Subject: upstream: implement loading resident keys in ssh-add "ssh-add -O" will load resident keys from a FIDO2 token and add them to a ssh-agent. feedback and ok markus@ OpenBSD-Commit-ID: 608104ae957a7d65cb84e0a3a26c8f60e0df3290 --- ssh-add.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 5 deletions(-) (limited to 'ssh-add.c') diff --git a/ssh-add.c b/ssh-add.c index 1d85e9d60..c25b57cc1 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.147 2019/11/25 00:51:37 djm Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.148 2019/12/30 09:22:49 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -66,6 +66,7 @@ #include "misc.h" #include "ssherr.h" #include "digest.h" +#include "ssh-sk.h" /* argv0 */ extern char *__progname; @@ -539,6 +540,54 @@ lock_agent(int agent_fd, int lock) return (ret); } +static int +load_resident_keys(int agent_fd, const char *skprovider, int qflag) +{ + struct sshkey **keys; + size_t nkeys, i; + int r, ok = 0; + char *fp; + + pass = read_passphrase("Enter PIN for security key: ", RP_ALLOW_STDIN); + if ((r = sshsk_load_resident(skprovider, pass, &keys, &nkeys)) != 0) { + error("Unable to load resident keys: %s", ssh_err(r)); + return r; + } + for (i = 0; i < nkeys; i++) { + if ((fp = sshkey_fingerprint(keys[i], + fingerprint_hash, SSH_FP_DEFAULT)) == NULL) + fatal("%s: sshkey_fingerprint failed", __func__); + if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "", + lifetime, confirm, maxsign, skprovider)) != 0) { + error("Unable to add key %s %s", + sshkey_type(keys[i]), fp); + free(fp); + ok = r; + continue; + } + if (ok == 0) + ok = 1; + if (!qflag) { + fprintf(stderr, "Resident identity added: %s %s\n", + sshkey_type(keys[i]), fp); + if (lifetime != 0) { + fprintf(stderr, + "Lifetime set to %d seconds\n", lifetime); + } + if (confirm != 0) { + fprintf(stderr, "The user must confirm " + "each use of the key\n"); + } + } + free(fp); + sshkey_free(keys[i]); + } + free(keys); + if (nkeys == 0) + return SSH_ERR_KEY_NOT_FOUND; + return ok == 1 ? 0 : ok; +} + static int do_file(int agent_fd, int deleting, int key_only, char *file, int qflag, const char *skprovider) @@ -585,7 +634,7 @@ main(int argc, char **argv) extern int optind; int agent_fd; char *pkcs11provider = NULL, *skprovider = NULL; - int r, i, ch, deleting = 0, ret = 0, key_only = 0; + int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0; int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; LogLevel log_level = SYSLOG_LEVEL_INFO; @@ -615,7 +664,7 @@ main(int argc, char **argv) skprovider = getenv("SSH_SK_PROVIDER"); - while ((ch = getopt(argc, argv, "vklLcdDTxXE:e:M:m:qs:S:t:")) != -1) { + while ((ch = getopt(argc, argv, "vklLcdDTxXE:e:M:m:Oqs:S:t:")) != -1) { switch (ch) { case 'v': if (log_level == SYSLOG_LEVEL_INFO) @@ -637,6 +686,9 @@ main(int argc, char **argv) fatal("-%c flag already specified", lflag); lflag = ch; break; + case 'O': + do_download = 1; + break; case 'x': case 'X': if (xflag != 0) @@ -736,6 +788,13 @@ main(int argc, char **argv) ret = 1; goto done; } + if (do_download) { + if (skprovider == NULL) + fatal("Cannot download keys without provider"); + if (load_resident_keys(agent_fd, skprovider, qflag) != 0) + ret = 1; + goto done; + } if (argc == 0) { char buf[PATH_MAX]; struct passwd *pw; @@ -769,9 +828,8 @@ main(int argc, char **argv) ret = 1; } } - clear_pass(); - done: + clear_pass(); ssh_close_authentication_socket(agent_fd); return ret; } -- cgit v1.2.3