I need to be able to GPG-sign git commits in two different Linux environments.
In a full GUI X-Window setup using the GUI-based password dialog box
In an SSH, without X-forwarding, using command-line only password entry
In both cases I need to be able to use different UID's for signing, all of which are in my keyring. The local and remote access use the same user account on a single machine, and may both be active at the same time. The computer is running openSUSE Leap 15 (4.12.14), using GnuPG 2.2.11, and libgcrypt 1.8.4. My typical remote connection uses ConnectBot v1.9.5 on Android v5.1.1, though I often also use Terminus v4.3.12 on iOS 12.1.1, and I could use a public Win 10 PC on occasion.
I do not want a 'permanent' solution which forces me to use the CLI method locally. Doing so would affect all other uses of gpg, including email.
Reading this question, I tried several variations which seemed to suggest themselves. Even though the solutions there, including the accepted one, were aimed at a permanent solution. I hoped they'd lead to a solution in my use case.
I have tried several variations of setting the pinentry-command
in my gpg-agent.conf
file.
In all cases, the gpg-connect-agent reloadagent /bye
command is executed after a change to the config file. The remote session was started fresh after any change and tested, as-is, and after each of the following commands, in sequence:
export GPG_TTY=$(tty)
unset DISPLAY
gpg-connect-agent updatestartuptty /bye
The results have been the same before and after all three commands, and are as follows:
- Using
pinentry
gives the GUI method locally - whether I am executing the command locally or remotely (The remote screen simply hangs until time-out happens for the dialog box.) - Using
pinentry-tty
forces CLI in all cases. (Remote usage prompts in the remote terminal and local usage prompts in the local terminal.) - Using
pinentry-gtk-2
duplicates the results ofpinentry
- Using
pinentry-qt
also duplicates the results ofpinentry
- Using
pinentry-curses
provides the curses box, but otherwise duplicates the results ofpinentry-tty
In all cases, if the setting results in a command-line prompt locally, all non CLI uses, such as Thunderbird, fail with an error.
I will not include the password on the command line or in a text file (no --passphrase-*
option to GnuPG).
I will not use a password-less key.
It does no good to hard code any one key as I often use several within a short span of time.
I will use a command line option, if possible, to force the correct pinentry choice. I'm not sure it's possible to pass gpg
options through git
.
I would prefer the ability to have the pinentry automatically "pick" the proper option. I would also prefer that the command line pinentry work for all commands. At the moment, however, I only need it to work in connection with git usage. (Signing is often one key while push/pull operations require a different key.) Currently, my main remote SSH client can execute custom commands at login, so a script that affects the current session/tty only would also be acceptable, though not ideal. A per-connection modification of the gpg-agent.conf
file (manually or scripted) would not be acceptable.
There was one hopeful answer for making this work on a mac. Attempting it with the above options, however, produced no different results. (I also tried ="USE_TTY=1"
, just in case it worked.)
I can work with suggestions in an effort to find a real solution (team-effort so to speak) if there are possibilities which might work but cannot be tested outside of my environment.
Current work-around
As a "fix" for my issue I've developed a work-around, which is sub-optimal, but does work. I've also made a few wrapper scripts to utilize the work-around in a semi-automated manner.
The work-around requires that I have two versions of gpg-agent.conf
, in my case gpg-agent.local
and gpg-agent.remote
, which are different in only one line. The local version has pinentry-program /usr/bin/pinentry
and the remote version has pinentry-program /usr/bin/pinentry-tty
. gpg-agent.conf
is a symlink to one of those, usually the local version. To switch to remote I execute:
rm ~/.gnupg/gpg-agent.conf
ln -s ~/.gnupg/gpg-agent.remote ~/.gnupg/gpg-agent.conf`
gpgconf --kill gpg-agent
gpg-connect-agent reloadagent /bye
gpg-connect-agent updatestartuptty /bye
Perhaps all three commands are overkill, but I've not been able to determine exactly which subset will guarantee the complete switch, and I know that all three always works.
Returning to the local version is the same process, with the local version replacing the remote version in the symlink.
The two things I do most while SSH'ed is git commit and push, so I have a wrapper script for both which will do the switch to remote conf, do the git operation, and switch the conf back to the local version so that it's ready for use from the local machine. Everything else requires that I remember to switch to remote before trying to use GPG, and switch back to local when done.
If I happen to forget the switch to remote, after a pause, I realize that nothing's happening because GPG is showing the GUI dialog on the host, and can CTRL
+C
out, do the switch and rerun the command. If I forget to return to the local version, using a command on the local machine gives me a passphrase prompt in the CLI and I can type the passphrase and then reset the config to local for the remainder of my session.
The reason I consider this work-around to be sub-optimal is that all of it is manually done. Scripts to make the switch, or wrappers around other commands which apply, and reset, the switch help, but are not handled by the system or configuration, automatically. My intervention is always required to make it happen, and to unwind what was done when I'm through, or when I switch terminal sessions.
The suggestion by user Michele to use export DBUS_SESSION_BUS_ADDRESS=/dev/null
may make a big difference in what I have to do, but will still require that I make that command a manually executed command. I can add it to my current SSH client as a "first" command, but if/when I use a different client I will still have to remember to use that command, and remember what it is.
Perhaps with my work-around, and the idea from Michele, someone else might have the solution that "just works."
gpg-connect-agent "getinfo std_session_env" /bye
, immediately after updatestartuptty, does not have DISPLAY anymore?unset DISPLAY
andDISPLAY=""
followed by updatestartuptty still listsDISPLAY=:0
as well as the correctGPG_TTY=/dev/pts/17
. Using the local terminal to 'echo "testing" /dev/pts/17` causes the message to appear on the remote terminal. Perhaps the DISPLAY remains fixed because the local machine is still logged in, and my use case requires that to be an option.DISPLAY
is not special in your case.GPG_TTY
does show the correct pts number for each shell, even beforeupdatestartuptty
, theDISPLAY
remains locked, irrespective of which shell/session is callinggpg-connect-agent
. Using the echo command from another shell confirmed that the reported pts was correct.