Pin entry
Private Keys
I regularly use gpg and ssh keys during the day, from signing git commits, encrypting sensitive messages to email and authenticating with servers. I regularly use gpg via Enignmail and the Thunderbird GUI and from the command line in zsh. I was having a couple of issues with the default ubuntu 16.04 setup for managing keys.
- gnome-keyring-agent was not always handling encrypted private keys correctly resulting in some scripts failing to authenticate with an error message
too many authentication attempts
even thoughssh-add -l
showed the correct keys where available. - using
ssh
,ssh-add
fromgpg2
from the command line when a password was requested to decrypt a key a GUI dialog would pop up disrupting my focus.
Ideally a terminal based password entry would present itself when working in a terminal and a GUI dialog present itself when working with a desktop app. A solution would also have to fix the too many authentication attempts
error.
gpg-agent
The gpg-agent
is a good candidate, it is a daemon to manage secret keys similar the ssh-agent
or the gnome-keyring-daemon
. It’s used by gpg2
and can be used as an agent for ssh. gpg-agent
has numerous pinentry programs that allow gpg to read passphrases in a secure manner, there are GUI and terminal based programs and the gpg-agent
can be configured to use different pinentry programs.
I updated GnuPG to the latest version using https://gist.github.com/vt0r/a2f8c0bcb1400131ff51
My .zshrc
contains the following:
# gpg
#
GPG_TTY=$(tty)
export GPG_TTY
# gpg as ssh-agent
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi
# let pinentry know which console to display in for ssh-agent
# https://www.gnupg.org/documentation/manuals/gnupg/Common-Problems.html
update-start-up-tty(){
echo UPDATESTARTUPTTY | gpg-connect-agent > /dev/null
}
# let gpg-agent know which pinentry program to use
update-pinentry-app(){
echo "term" > /tmp/pinentry-app
}
# add zsh hook to exec above function before every command execution
autoload -U add-zsh-hook
zsh-preexec(){
update-start-up-tty
update-pinentry-app
}
add-zsh-hook preexec zsh-preexec
# similar to `ssh-add -D` but works with gpg-agent
ssh-delete(){
grep -o ^[A-Z0-9]* ~/.gnupg/sshcontrol | xargs -I% rm ~/.gnupg/private-keys-v1.d/%.key
echo '' > ~/.gnupg/sshcontrol
}
Next a simple shim for pinentry is needed, when invoked it selects either a terminal pinentry program or a GUI pinentry program based on contents of /tmp/pinentry-app
#!/bin/bash
#
# http://askubuntu.com/questions/858347/disable-gnome-from-asking-passphrase-in-gui-when-using-ssh-and-gpg-from-terminal#858947
#
# Configuration -- adjust these to your liking
PINENTRY_TERMINAL=/usr/bin/pinentry-curses
PINENTRY_X11=/usr/bin/pinentry-x11
# if /tmp/pinentry-app is "x11" then use gui
if [ $(cat /tmp/pinentry-app) = "x11" ]; then
exec "$PINENTRY_X11" "$@"
else
exec "$PINENTRY_TERMINAL" "$@"
fi
This needs to be linked to pinentry so it is used as our default pinentry program.
ln -s ~/bin/pinentry /usr/local/bin/pinentry -f
The gpg-agent
needs ssh enabled and then stopped, it’ll automatically restart when needed.
echo 'enable-ssh-support' >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Next the GUI applications using GnuPG need configured, in my case Thunderbird Enigmail.
First another simple shim is created ~/bin/gpg2-thunderbird
, this time for gpg2
, which tells gpg-agent
to use the GUI pinentry.
#!/bin/sh
echo "x11" > /tmp/pinentry-app
exec "/usr/local/bin/gpg2" "$@"
Then Thunderbird > Enigmail > Preferences > Basic > Files and Directories > Override with
is updated with the location of the gpg2
shim.
Success!
I now have my desired private key management setup how I want it. A terminal based pinentry when working in the terminal and a GUI based pinentry when working from a GUI.