Mailing List Archive

Accessing SSH key path using SSH_ASKPASS and passwordstore
Hello,

With the introduction of SSH_ASKPASS_REQUIRE in version 8.4, I've set
up a script for SSH_ASKPASS to query my local passwordstore
(https://www.passwordstore.org/) vault to retrieve the password for a
given key. This works for ssh-add as well as ssh (configured with
AddKeysToAgent set to 'yes'). My workflow effectively transforms into
entering the password for the GPG key used to encrypt my vault for any
given key. It works especially well now that I don't have to alter
DISPLAY and confuse gpg's pin input inference. Thanks for that
enhancement!

The tricky part here is the way I have to figure out which key is
being unlocked. I was initially only working with ssh-add, so it
seemed trivial to just deal with the input to a script acting as a
wrapper and feed that to the askpass script as an environment
variable. When I realized I could also take advantage of
AddKeysToAgent and simply call ssh, I had to change my strategy given
that the path to the key being unlocked does not appear to get passed
separately to my script; rather it's just given a prompt that happens
to contain the path to the key. Using this knowledge I just have my
script infer the path using sed.

This strategy works, but I noticed that when you call ssh (with
AddKeysToAgent set to 'yes') vs ssh-add, the prompts are slightly
different:

$ ssh user@host
Enter passphrase for key '/home/user/.ssh/id_ed25519_somekey':

$ ssh-add /home/user/.ssh/id_ed25519_somekey
Enter passphrase for /home/user/.ssh/id_ed25519_somekey:

Notice the single quotes around the path in the prompt when calling
ssh. I'm not sure if that's a bug with regard to consistency. I was
able to modify the regex to account for this difference, but overall I
wondered if this couldn't be improved. For my usage, it would be great
to receive the path to the key as another askpass argument.
Alternatively I could also envision accessing this information as an
environment variable.

I understand that my use-case may diverge too greatly from the
original intentions for this component, but I thought I'd ask anyway
in case I'm either doing something wrong or missing out on another
feature. What I have currently works, but I fear it leaves me prone to
breaking changes later on.

I've included my askpass script below. Also just to note, I'm running
on Arch, but I've confirmed these behaviors in the GitHub repo.

Thanks,
John

pass-askpass.sh
---
#!/usr/bin/env bash
# This translates "Enter passphrase for
/home/user/.ssh/id_ed25519_somekey:" to "id_ed25519_somekey"
# It also accounts for the case where the path is surrounded by single
quotes in the prompt
key_filename="$(echo "$1" | sed -e "s/^.*\/\(.*\)'*:.*$/\1/")"

# Assume we store all our keys in one folder in pass, and they are all
uniquely identifiable
# This will result in a prompt for my GPG key password to retrieve the
SSH key password
pass "${PASS_SSH_FOLDER:-SSH}/${key_filename}" | head -n1
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: Accessing SSH key path using SSH_ASKPASS and passwordstore [ In reply to ]
On Mon, 5 Oct 2020, John Heatherington wrote:

> Hello,
>
> With the introduction of SSH_ASKPASS_REQUIRE in version 8.4, I've set
> up a script for SSH_ASKPASS to query my local passwordstore
> (https://www.passwordstore.org/) vault to retrieve the password for a
> given key. This works for ssh-add as well as ssh (configured with
> AddKeysToAgent set to 'yes'). My workflow effectively transforms into
> entering the password for the GPG key used to encrypt my vault for any
> given key. It works especially well now that I don't have to alter
> DISPLAY and confuse gpg's pin input inference. Thanks for that
> enhancement!
>
> The tricky part here is the way I have to figure out which key is
> being unlocked. I was initially only working with ssh-add, so it
> seemed trivial to just deal with the input to a script acting as a
> wrapper and feed that to the askpass script as an environment
> variable. When I realized I could also take advantage of
> AddKeysToAgent and simply call ssh, I had to change my strategy given
> that the path to the key being unlocked does not appear to get passed
> separately to my script; rather it's just given a prompt that happens
> to contain the path to the key. Using this knowledge I just have my
> script infer the path using sed.
>
> This strategy works, but I noticed that when you call ssh (with
> AddKeysToAgent set to 'yes') vs ssh-add, the prompts are slightly
> different:
>
> $ ssh user@host
> Enter passphrase for key '/home/user/.ssh/id_ed25519_somekey':
>
> $ ssh-add /home/user/.ssh/id_ed25519_somekey
> Enter passphrase for /home/user/.ssh/id_ed25519_somekey:
>
> Notice the single quotes around the path in the prompt when calling
> ssh. I'm not sure if that's a bug with regard to consistency. I was
> able to modify the regex to account for this difference, but overall I
> wondered if this couldn't be improved. For my usage, it would be great
> to receive the path to the key as another askpass argument.
> Alternatively I could also envision accessing this information as an
> environment variable.

Unfortunately the askpass convention is pretty old and baked-in to
too many places to change radically. OTOH we could certainly harmonise
the prompts, e.g.

diff --git a/ssh-add.c b/ssh-add.c
index 0ce989f..2a0b207 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -228,8 +228,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
const char *skprovider)
{
struct sshkey *private, *cert;
- char *comment = NULL;
- char msg[1024], *certpath = NULL;
+ char *comment = NULL, *msg = NULL, *certpath = NULL;
int r, fd, ret = -1;
size_t i;
u_int32_t left;
@@ -282,7 +281,8 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
if (private == NULL) {
/* clear passphrase since it did not work */
clear_pass();
- snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ",
+ free(msg);
+ xasprintf(&msg, "Enter passphrase for key '%s%s': ",
filename, confirm ? " (will confirm each use)" : "");
for (;;) {
pass = read_passphrase(msg, RP_ALLOW_STDIN);
@@ -298,11 +298,13 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
fail_load:
clear_pass();
sshbuf_free(keyblob);
+ free(msg);
return -1;
}
clear_pass();
- snprintf(msg, sizeof msg,
- "Bad passphrase, try again for %s%s: ", filename,
+ free(msg);
+ xasprintf(&msg,
+ "Bad passphrase, try again for '%s%s': ", filename,
confirm ? " (will confirm each use)" : "");
}
}
@@ -435,6 +437,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag,
free(certpath);
free(comment);
sshkey_free(private);
+ free(msg);

return ret;
}
diff --git a/sshconnect2.c b/sshconnect2.c
index 2aca328..149eb11 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1503,7 +1503,7 @@ static struct sshkey *
load_identity_file(Identity *id)
{
struct sshkey *private = NULL;
- char prompt[300], *passphrase, *comment;
+ char *prompt = NULL, *passphrase, *comment;
int r, quit = 0, i;
struct stat st;

@@ -1512,8 +1512,7 @@ load_identity_file(Identity *id)
id->filename, strerror(errno));
return NULL;
}
- snprintf(prompt, sizeof prompt,
- "Enter passphrase for key '%.100s': ", id->filename);
+ xasprintf(&prompt, "Enter passphrase for key '%s': ", id->filename);
for (i = 0; i <= options.number_of_password_prompts; i++) {
if (i == 0)
passphrase = "";
@@ -1568,6 +1567,7 @@ load_identity_file(Identity *id)
if (private != NULL || quit)
break;
}
+ free(prompt);
return private;
}

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: Accessing SSH key path using SSH_ASKPASS and passwordstore [ In reply to ]
On Tue, 6 Oct 2020, Damien Miller wrote:

> Unfortunately the askpass convention is pretty old and baked-in to
> too many places to change radically. OTOH we could certainly harmonise

In kwalletcli, I just use the full prompt string as “key”.

(This does something like the thing the OP described, except
for storing/retrieving the passwords from the KDE 3/4/5 wallet.)

bye,
//mirabilos
--
tarent solutions GmbH
Rochusstraße 2-4, D-53123 Bonn • http://www.tarent.de/
Tel: +49 228 54881-393 • Fax: +49 228 54881-235
HRB 5168 (AG Bonn) • USt-ID (VAT): DE122264941
Geschäftsführer: Dr. Stefan Barth, Kai Ebenrett, Boris Esser, Alexander Steeg

*************************************************

Mit unserem Consulting bieten wir Unternehmen maßgeschneiderte Angebote in
Form von Beratung, Trainings sowie Workshops in den Bereichen
Softwaretechnologie, IT Strategie und Architektur, Innovation und Umsetzung
sowie Agile Organisation.

Besuchen Sie uns auf https://www.tarent.de/consulting .
Wir freuen uns auf Ihren Kontakt.

*************************************************
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: Accessing SSH key path using SSH_ASKPASS and passwordstore [ In reply to ]
On Tue, 6 Oct 2020, Damien Miller wrote:

> Unfortunately the askpass convention is pretty old and baked-in to
> too many places to change radically. OTOH we could certainly harmonise

The unified prompt will work well enough for my purposes, and it lets
me keep my vault hierarchy clean, so that seems like a good change to
me.

Also I noticed my script's regex is not quite right. Should be:
"s/^.*\/\(.*[^']\)'\{0,1\}:.*$/\1/"

On Tue, Oct 6, 2020 at 10:07 AM Thorsten Glaser <t.glaser@tarent.de> wrote:

> In kwalletcli, I just use the full prompt string as “key”.
>
> (This does something like the thing the OP described, except
> for storing/retrieving the passwords from the KDE 3/4/5 wallet.)

Now that you mention it, that kind of turns things around in my mind.
It doesn't work too well with pass to have extraneous information in
the hierarchy if you still wish to peruse it in the CLI, but if the
prompts generated by the ssh tools could be toggled to a more machine
readable format ("key:/path/to/key" or something) through some sort of
configuration option, it would prevent having to change the API in a
drastic way but still enable interesting automation by ingesting the
entire prompt.

Considering my situation, however, it's probably not justified since I
can handle everything with a one-liner in my script. I just thought
I'd bring it up in case it's more relevant to interoperability in the
future. For now I'm pretty happy with the prompts being consistent as
per Damien's changeset.

Thanks,
John
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev