16

I read man ssh-add and I don't see a flag for passing a passphrase like we have in ssh which is -p.

I tried

# the -K is for macOS's ssh-add but it's not relevant
ssh-add -q -K ~/.ssh/id_rsa <<< $passphrase

But I get the following output:

ssh_askpass: exec(/usr/X11R6/bin/ssh-askpass): No such file or directory

How can I pass a password w/o triggering a prompt

Update

Adding more context to what I'm doing, I'm creating a script to create SSH keys for me. It will generate the passphrase, the SSH key using that passphrase, and add it to the agent.

# ...
passphrase=$(generate_password)

ssh-keygen -t rsa -b 4096 -C $email -f $filename -N $passphrase -q
ssh-add -q -K $filename

Following Stephen's answer, I'm not sure how would that work. Seems like I'd had to create a temporal script and save it to disk, in order for SSH_ASKPASS to work. Any ideas?

2 Answers2

25

From the ssh-add manpage:

 DISPLAY and SSH_ASKPASS
         If ssh-add needs a passphrase, it will read the passphrase from
         the current terminal if it was run from a terminal.  If ssh-add
         does not have a terminal associated with it but DISPLAY and
         SSH_ASKPASS are set, it will execute the program specified by
         SSH_ASKPASS (by default ``ssh-askpass'') and open an X11 window
         to read the passphrase.  This is particularly useful when calling
         ssh-add from a .xsession or related script.  (Note that on some
         machines it may be necessary to redirect the input from /dev/null
         to make this work.)

So we can use this to cheat a little.

We start with no identities in the agent:

$ ssh-add -l
The agent has no identities.

So now we need a program that will supply the password:

$ cat x
#!/bin/sh
echo test123

And then convince ssh-add to use that script:

$ DISPLAY=1 SSH_ASKPASS="./x" ssh-add test < /dev/null
Identity added: test (sweh@godzilla)

And there it is:

$ ssh-add -l                                          
2048 SHA256:07qZby7TafI10LWAMSvGFreY75L/js94pFuNcbhfSC0 sweh@godzilla (RSA)

Edit to add, based on revised question:

The password could be passed as a variable, and the askpass script use that variable.

For example:

$ cat /usr/local/sbin/auto-add-key
#!/bin/sh
echo $SSH_PASS

$ SSH_PASS=test123 DISPLAY=1 SSH_ASKPASS=/usr/local/sbin/auto-add-key ssh-add test < /dev/null
Identity added: test (sweh@godzilla)

In the workflow presented you would do SSH_PASS=$passphrase to use the newly generated passphrase.

  • Possible improvement: ssh-add will endlessly loop calling the SSH_ASKPASS program if password was bad, consider making auto-add-key exit if $1 starts with Bad (full content is "Bad passphrase, try again for /path/to/key" as of OpenSSH_9.3p1) – Asmadeus Nov 25 '23 at 05:07
  • I do not understand why you would need both SSH_PASS and SSH_ASKPASS to supply the passphrase to ssh-add ? – user5359531 Mar 13 '24 at 14:29
  • @user5359531 SSH_ASKPASS points to the program to run to supply the password; SSH_PASS is used by the program to return the password. – Stephen Harris Mar 13 '24 at 15:50
6

You can use script(1) as a mini-expect.

On Linux:

{ sleep .1; echo password; } | script -q /dev/null -c 'ssh-add /path/to/identity'

On BSD:

{ sleep .1; echo password; } | script -q /dev/null ssh-add /path/to/identity

You may want to increase the delay (sleep .3 or sleep 1) if the right hand of the pipeline is slow to start. For anything more complex, use expect. Do not use sshpass since it's really no better than script and itself subject to races.

  • You're right about the flag, I don't know why that came to mind; maybe it's a different tool that takes -p as password(?) I can't remember. Anyways, you're right – Christopher Francisco Mar 08 '20 at 06:20
  • Could you break down the first part of the expression, and how the solution works? I'm not sure why the sleep call – Christopher Francisco Mar 08 '20 at 06:21
  • Yes, sshpass. See the updated answer, I think the BSD syntax works in MacOS, too. –  Mar 08 '20 at 06:21
  • The sleep is to give time to ssh-add to start, print its prompt and turn echo mode off on the pseudo-terminal created by script. Like with any pipeline, both sides of the pipeline are started in any order, and are run in parallel, at the same time. –  Mar 08 '20 at 06:23
  • For this kind of timing problems (which also badly affect sshpass), see this Q&A. –  Mar 08 '20 at 06:26
  • @ChristopherFrancisco please con/infirm if the BSD script syntax also works on MacOS as it does on FreeBSD, since I have no MacOS to test on (it should, according to the manpage). So I could correct it before leaving. Thanks. –  Mar 08 '20 at 07:31