From aa22c20e0c36c2fc610cfcc793b0d14079c38814 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sun, 20 Jan 2019 22:03:29 +0000 Subject: [PATCH] upstream: add option to test whether keys in an agent are usable, by performing a signature and a verification using each key "ssh-add -T pubkey [...]" work by markus@, ok djm@ OpenBSD-Commit-ID: 931b888a600b6a883f65375bd5f73a4776c6d19b --- ssh-add.1 | 14 +++++++++++--- ssh-add.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/ssh-add.1 b/ssh-add.1 index d5da9279c..35ab04426 100644 --- a/ssh-add.1 +++ b/ssh-add.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-add.1,v 1.66 2017/08/29 13:05:58 jmc Exp $ +.\" $OpenBSD: ssh-add.1,v 1.67 2019/01/20 22:03:29 djm Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -35,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: August 29 2017 $ +.Dd $Mdocdate: January 20 2019 $ .Dt SSH-ADD 1 .Os .Sh NAME @@ -43,7 +43,7 @@ .Nd adds private key identities to the authentication agent .Sh SYNOPSIS .Nm ssh-add -.Op Fl cDdkLlqXx +.Op Fl cDdkLlqTXx .Op Fl E Ar fingerprint_hash .Op Fl t Ar life .Op Ar @@ -51,6 +51,10 @@ .Fl s Ar pkcs11 .Nm ssh-add .Fl e Ar pkcs11 +.Nm ssh-add +.Fl T +.Ar pubkey +.Op Ar ... .Sh DESCRIPTION .Nm adds private key identities to the authentication agent, @@ -131,6 +135,10 @@ Be quiet after a successful operation. .It Fl s Ar pkcs11 Add keys provided by the PKCS#11 shared library .Ar pkcs11 . +.It Fl T Ar pubkey Op Ar ... +Tests whether the private keys that correspond to the specified +.Ar pubkey +files are usable by performing sign and verify operations on each. .It Fl t Ar life Set a maximum lifetime when adding identities to an agent. The lifetime may be specified in seconds or in a time format diff --git a/ssh-add.c b/ssh-add.c index 50165e7d6..eb2552ad5 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.136 2018/09/19 02:03:02 djm Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.137 2019/01/20 22:03:29 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -417,6 +417,40 @@ update_card(int agent_fd, int add, const char *id, int qflag) return ret; } +static int +test_key(int agent_fd, const char *filename) +{ + struct sshkey *key = NULL; + u_char *sig = NULL; + size_t slen = 0; + int r, ret = -1; + char data[1024]; + + if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { + error("Couldn't read public key %s: %s", filename, ssh_err(r)); + return -1; + } + arc4random_buf(data, sizeof(data)); + if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), + NULL, 0)) != 0) { + error("Agent signature failed for %s: %s", + filename, ssh_err(r)); + goto done; + } + if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), + NULL, 0)) != 0) { + error("Signature verification failed for %s: %s", + filename, ssh_err(r)); + goto done; + } + /* success */ + ret = 0; + done: + free(sig); + sshkey_free(key); + return ret; +} + static int list_identities(int agent_fd, int do_fp) { @@ -524,6 +558,7 @@ usage(void) fprintf(stderr, " -X Unlock agent.\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, " -T pubkey Test if ssh-agent can access matching private key.\n"); fprintf(stderr, " -q Be quiet after a successful operation.\n"); } @@ -535,7 +570,7 @@ main(int argc, char **argv) int agent_fd; char *pkcs11provider = NULL; int r, i, ch, deleting = 0, ret = 0, key_only = 0; - int xflag = 0, lflag = 0, Dflag = 0, qflag = 0; + int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; ssh_malloc_init(); /* must be called before any mallocs */ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ @@ -559,7 +594,7 @@ main(int argc, char **argv) exit(2); } - while ((ch = getopt(argc, argv, "klLcdDxXE:e:M:m:qs:t:")) != -1) { + while ((ch = getopt(argc, argv, "klLcdDTxXE:e:M:m:qs:t:")) != -1) { switch (ch) { case 'E': fingerprint_hash = ssh_digest_alg_by_name(optarg); @@ -623,6 +658,9 @@ main(int argc, char **argv) case 'q': qflag = 1; break; + case 'T': + Tflag = 1; + break; default: usage(); ret = 1; @@ -648,6 +686,14 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (Tflag) { + if (argc <= 0) + fatal("no keys to test"); + for (r = i = 0; i < argc; i++) + r |= test_key(agent_fd, argv[i]); + ret = r == 0 ? 0 : 1; + goto done; + } if (pkcs11provider != NULL) { if (update_card(agent_fd, !deleting, pkcs11provider, qflag) == -1)