upstream: ssh-add support for U2F/FIDO keys

OpenBSD-Commit-ID: 7f88a5181c982687afedf3130c6ab2bba60f7644
This commit is contained in:
djm@openbsd.org 2019-10-31 21:19:56 +00:00 committed by Damien Miller
parent b9dd14d309
commit 486164d060
2 changed files with 38 additions and 12 deletions

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-add.1,v 1.69 2019/01/21 12:53:35 djm Exp $ .\" $OpenBSD: ssh-add.1,v 1.70 2019/10/31 21:19:56 djm Exp $
.\" .\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd $Mdocdate: January 21 2019 $ .Dd $Mdocdate: October 31 2019 $
.Dt SSH-ADD 1 .Dt SSH-ADD 1
.Os .Os
.Sh NAME .Sh NAME
@ -46,6 +46,7 @@
.Op Fl cDdkLlqvXx .Op Fl cDdkLlqvXx
.Op Fl E Ar fingerprint_hash .Op Fl E Ar fingerprint_hash
.Op Fl t Ar life .Op Fl t Ar life
.Op Fl S Ar provider
.Op Ar .Op Ar
.Nm ssh-add .Nm ssh-add
.Fl s Ar pkcs11 .Fl s Ar pkcs11
@ -134,6 +135,11 @@ Be quiet after a successful operation.
.It Fl s Ar pkcs11 .It Fl s Ar pkcs11
Add keys provided by the PKCS#11 shared library Add keys provided by the PKCS#11 shared library
.Ar pkcs11 . .Ar pkcs11 .
.It Fl S Ar provider
Specifies a path to a security key provider library that will be used when
adding any security key-hosted keys, overriding the default of using the
.Ev "SSH_SK_PROVIDER"
environment variable to specify a provider.
.It Fl T Ar pubkey ... .It Fl T Ar pubkey ...
Tests whether the private keys that correspond to the specified Tests whether the private keys that correspond to the specified
.Ar pubkey .Ar pubkey
@ -189,6 +195,9 @@ to make this work.)
Identifies the path of a Identifies the path of a
.Ux Ns -domain .Ux Ns -domain
socket used to communicate with the agent. socket used to communicate with the agent.
.It Ev SSH_SK_PROVIDER
Specifies the path to a security key provider library used to interact with
hardware security keys.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-add.c,v 1.142 2019/10/31 21:19:15 djm Exp $ */ /* $OpenBSD: ssh-add.c,v 1.143 2019/10/31 21:19:56 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -77,6 +77,7 @@ static char *default_files[] = {
_PATH_SSH_CLIENT_ID_DSA, _PATH_SSH_CLIENT_ID_DSA,
#ifdef OPENSSL_HAS_ECC #ifdef OPENSSL_HAS_ECC
_PATH_SSH_CLIENT_ID_ECDSA, _PATH_SSH_CLIENT_ID_ECDSA,
_PATH_SSH_CLIENT_ID_ECDSA_SK,
#endif #endif
#endif /* WITH_OPENSSL */ #endif /* WITH_OPENSSL */
_PATH_SSH_CLIENT_ID_ED25519, _PATH_SSH_CLIENT_ID_ED25519,
@ -191,7 +192,8 @@ delete_all(int agent_fd, int qflag)
} }
static int static int
add_file(int agent_fd, const char *filename, int key_only, int qflag) add_file(int agent_fd, const char *filename, int key_only, int qflag,
const char *skprovider)
{ {
struct sshkey *private, *cert; struct sshkey *private, *cert;
char *comment = NULL; char *comment = NULL;
@ -310,8 +312,16 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
ssh_free_identitylist(idlist); ssh_free_identitylist(idlist);
} }
if (sshkey_type_plain(private->type) != KEY_ECDSA_SK)
skprovider = NULL; /* Don't send constraint for other keys */
else if (skprovider == NULL) {
fprintf(stderr, "Cannot load security key %s without "
"provider\n", filename);
goto out;
}
if ((r = ssh_add_identity_constrained(agent_fd, private, comment, if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
lifetime, confirm, maxsign, NULL)) == 0) { lifetime, confirm, maxsign, skprovider)) == 0) {
ret = 0; ret = 0;
if (!qflag) { if (!qflag) {
fprintf(stderr, "Identity added: %s (%s)\n", fprintf(stderr, "Identity added: %s (%s)\n",
@ -364,7 +374,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
sshkey_free(cert); sshkey_free(cert);
if ((r = ssh_add_identity_constrained(agent_fd, private, comment, if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
lifetime, confirm, maxsign, NULL)) != 0) { lifetime, confirm, maxsign, skprovider)) != 0) {
error("Certificate %s (%s) add failed: %s", certpath, error("Certificate %s (%s) add failed: %s", certpath,
private->cert->key_id, ssh_err(r)); private->cert->key_id, ssh_err(r));
goto out; goto out;
@ -529,13 +539,14 @@ lock_agent(int agent_fd, int lock)
} }
static int static int
do_file(int agent_fd, int deleting, int key_only, char *file, int qflag) do_file(int agent_fd, int deleting, int key_only, char *file, int qflag,
const char *skprovider)
{ {
if (deleting) { if (deleting) {
if (delete_file(agent_fd, file, key_only, qflag) == -1) if (delete_file(agent_fd, file, key_only, qflag) == -1)
return -1; return -1;
} else { } else {
if (add_file(agent_fd, file, key_only, qflag) == -1) if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1)
return -1; return -1;
} }
return 0; return 0;
@ -561,6 +572,7 @@ usage(void)
fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n"); fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n");
fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n"); fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n");
fprintf(stderr, " -T pubkey Test if ssh-agent can access matching private key.\n"); fprintf(stderr, " -T pubkey Test if ssh-agent can access matching private key.\n");
fprintf(stderr, " -S provider Specify security key provider.\n");
fprintf(stderr, " -q Be quiet after a successful operation.\n"); fprintf(stderr, " -q Be quiet after a successful operation.\n");
fprintf(stderr, " -v Be more verbose.\n"); fprintf(stderr, " -v Be more verbose.\n");
} }
@ -571,7 +583,7 @@ main(int argc, char **argv)
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
int agent_fd; int agent_fd;
char *pkcs11provider = NULL; 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;
int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
@ -600,7 +612,9 @@ main(int argc, char **argv)
exit(2); exit(2);
} }
while ((ch = getopt(argc, argv, "vklLcdDTxXE:e:M:m:qs:t:")) != -1) { skprovider = getenv("SSH_SK_PROVIDER");
while ((ch = getopt(argc, argv, "vklLcdDTxXE:e:M:m:qs:S:t:")) != -1) {
switch (ch) { switch (ch) {
case 'v': case 'v':
if (log_level == SYSLOG_LEVEL_INFO) if (log_level == SYSLOG_LEVEL_INFO)
@ -656,6 +670,9 @@ main(int argc, char **argv)
case 's': case 's':
pkcs11provider = optarg; pkcs11provider = optarg;
break; break;
case 'S':
skprovider = optarg;
break;
case 'e': case 'e':
deleting = 1; deleting = 1;
pkcs11provider = optarg; pkcs11provider = optarg;
@ -732,7 +749,7 @@ main(int argc, char **argv)
if (stat(buf, &st) == -1) if (stat(buf, &st) == -1)
continue; continue;
if (do_file(agent_fd, deleting, key_only, buf, if (do_file(agent_fd, deleting, key_only, buf,
qflag) == -1) qflag, skprovider) == -1)
ret = 1; ret = 1;
else else
count++; count++;
@ -742,7 +759,7 @@ main(int argc, char **argv)
} else { } else {
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
if (do_file(agent_fd, deleting, key_only, if (do_file(agent_fd, deleting, key_only,
argv[i], qflag) == -1) argv[i], qflag, skprovider) == -1)
ret = 1; ret = 1;
} }
} }