silly business

GPG Could've Been Good and Cool but Instead We Have This

I had heard of GPG/PGP (same thing, as it turns out) for years and I heard it was hard and unpopular so I never investigated it independently. However, I needed to learn how to sign and encrypt things with it for work at some point and I learned the basics, and more recently I noticed that GitHub will allow you to verify commits with GPG.

So, I decided, why not start signing my commits? That would be cool and at least useful in my imagination where someone might want to prove that I was really the author of some commit.

I generated a GPG key and configured git to use it. So far, things were as straightforward as things ever were with gpg, which is to say, I don't know why gpg --export --armor $KEY_ID is the incantation to see a public key, but besides --armor being an objectively strange flag to mean "output the key as text," everything was normal and went smoothly. I made a commit and a pop-up appeared for me to unlock my GPG key to sign the commit. Success.

Satisfied, I signed off for the night.

The next day, on a different computer, I realized I had left some changes to my Emacs config on my desktop, that I wanted to use. I sshed to my desktop and staged the changes, wrote my commit message and then.. my prompt hung.

I'll spare you the ensuing confusion and drama. It turns out, that upon adding my GPG key to my git config, I had involved something called gpg-agent in my git commit flow. gpg-agent's task is apparently managing access to secrets known to GPG on the local system, and to present me with a prompt in order to type in my password and unlock my GPG key, and then presumably to cache that for the duration of my session and allow git or whatever to use it to sign or decrypt things.

However, for reasons unbeknownst to me, gpg-agent has a static configuration and if you have a GUI installed at all, it always presents a GUI password prompt. If you have a GUI installed and you've connected over SSH, tough shit! It just hangs forever. You can reconfigure and restart it to get a TTY-friendly PIN input prompt, but then it'll fail to work in GUI sessions.

What really kills me about this is that it doesn't seem to be that hard to detect what kind of session the user is using. I could be wrong – if there's anything I've learned about software it's that we are forever underestimating the complexity involved – but certainly this is the only software that has ever caused me to encounter this particular problem.

That said, this was a fairly straightforward problem to solve with a little searching around. I am not sure of the best way to detect a TTY session, but at least for my case, I solved the problem with a script, adapted from some SuperUser/StackOverflow answers, and saved to /usr/local/bin/pinentry-auto:

  #!/usr/bin/sh
  bin=/usr/local/bin
  pe=$bin/pinentry-qt
  if test "$XDG_SESSION_TYPE" = "tty"; then
      pe=$bin/pinentry-tty
  fi

  exec $pe "$@"

and then a bit of configuration; in ~/.gnupg/gpg-agent.conf:

 pinentry-program /usr/local/bin/pinentry-auto

This solution works for me1 and I'm on my way. And just looking for an XDG variable in the environment seems reasonable enough to me (it is a standard after all, for desktops, where one might encounter this problem) but what do I know?

I just have to wonder, if this is what GPG's UX is like, how anybody ever expected GPG to catch on at all? Among normies, obviously – GPG clearly caught on enough among computer scientists and software professionals that someone is out there using it, and it's useful and entrenched enough that I will continue to use it.

I mean, I realize I'm really, really late to the "GPG usability is bad" party but damn.. sometimes you have to experience it for yourself to really get it.

That said, I don't really know of a good replacement for GPG 😅 so I guess I should quit bitching and start contributing, right??

I need a drink.

Footnotes


1

If you're trying to use this example, you'll need to gpgconf --kill gpg-agent to put the changes to ~/.gnupg/gpg-agent.conf into effect.