Signing files with GPG from within a snap

It was brought to my attention that the “sign document” feature of libreoffice doesn’t work with the snap, so I filed bug #1772683 and started looking into it.

TL;DR: I haven’t got it working yet, the following is a brain dump of my investigation and a call for suggestions.

libreoffice uses libgpgmepp which is a C++ wrapper for libgpgme. When signing a document with a given private key, it essentially executes the following (simplified for readability):

gpg --batch --sign --detach -u $KEYID -- $DOCUMENT

By default, gpg searches for keys under $HOME/.gnupg (which in a snap is e.g. ~/snap/libreoffice/current/.gnupg), so we need to either set the GNUPGHOME environment variable or pass the --homedir option to set that to ~/.gnupg.

There’s a gpg-keys interface that should allow acces to private keys under ~/.gnupg, let’s add the plug and connect it after installation (not auto-connected).

/usr/bin/gpg is in the core snap, which was built on xenial, so it is version 1 of gpg. If running on, say, a bionic host, /usr/bin/gpg is version 2, and the two versions store the keys in different, incompatible formats. So let’s add gnupg2 to the stage packages and explicitly invoke /usr/bin/gpg2:

gpg: failed to create temporary file '/home/osomon/.gnupg/.#lk0xXXXXXXXXXXXXXXXX.bribon.YYYY': Permission denied
gpg: can't connect to the agent: Permission denied

It looks like searching for a running agent requires creating temporary files under ~/.gnupg/. The gpg-keys interface will need updating. Let’s switch to devmode for now to move forward:

gpg: failed to start agent '/usr/bin/gpg-agent': No such file or directory
gpg: can't connect to the agent: No such file or directory

gpg is trying to start gpg-agent, despite the fact that it’s already running on the host. That’s because the version of gpg2 in xenial looks for the agent’s socket at ~/.gnupg/S.gpg-agent (i.e. in the same directory where the keys live, overridable with --homedir), whereas more recent versions of gpg2 (like the one in my bionic host) create the socket at /run/user/1000/gnupg/S.gpg-agent. If we point --homedir to /run/user/1000/gnupg the socket will be found, but the keys won’t… (also note that the gpg-keys interface will need to be updated to allow talking to that socket).

At this point I tried building a gnupg2 part from source with a recent version (tried several tags in the 2.2 and 2.1 series), but all the versions I tried would either not build without patches, or would require build dependencies (libgpg-error, libgcrypt, libassuan, libksba) in versions greater than what’s available in xenial.

That’s where I stand at the moment. With a bit of effort I could probably convince snapcraft to build a recent version of gpg2 on xenial with all associated dependencies, and hopefully that would be enough to make the whole thing work (including a couple of additions to the gpg-keys interface that I already mentioned). That would work on a bionic host, but not on xenial because of gpg version discrepancies. And probably not on other distros either, for the same reason. Perhaps a gpg part with a wrapper that detects the version of gpg on the host and acts accordingly?

Suggestions welcome!


I’m working to make the GPG signing feature of a Git frontend snap works.

History for interfaces/builtin/gpg_keys.go - snapcore/snapd

GPG signing not possible · Issue #7 · Lin-Buo-Ren/git-cola-snap

@Lin-Buo-Ren, it’s not immediately obvious to me what that pull request has to do with fixing GPG in snaps, can you elaborate?

I have no idea why my URL History for interfaces/builtin/gpg_keys.go - snapcore/snapd’s preview turned out to be that PR, please disregard it.

Is anyone working on this issue at the moment? The gpg-keys interface is a bit useless in its current state.

We’d need:

  • Access to the gpg-agent socket in /run/user/…
  • Permission to write lock files into ~/.gnupg. This is probably not necessary if gpg is invoked with --lock-never. I think this is safe for just encrypting/read-only operations.

Is this even desirable or should any such apps just use classic confinement?

Consider the following apparmor policy addition:

# allow accessing gpg-agent
owner /run/user/[0-9]*/gnupg/S.gpg-agent wr,

# gpg creates lockfiles by default, even if it cannot write to the db
owner @{HOME}/.gnupg/.#lk* rwk,

This gives me usable gpg in strict confinement. I guess I’ll PR the change to snapd for further discussion.

See related PR:

@oSoMoN, et al: I investigated this a bit. Please see