Page MenuHome GnuPG

Agent required for symmetric operation causes encrypted partitions to fail to mount
Closed, WontfixPublic

Description

With the release of GnuPG-2.1 the agent is always required, also for symmetric
operation.
This breaks LUKS encryption if symmetrically encrypted keyfiles are used for
LUKS, as the agent can't write its S.* file(s) to the system's filesystem at
this early stage of the boot process. Thus gpg fails to do the symmetric
decryption of the keyfile and opening a LUKS partition fails.

My wish is for GnuPG to either provide an option or other means to not rely on
its agent for at least a symmetric decryption operation.

Details

Version
2.1.15

Event Timeline

ftiede added projects: Feature Request, gnupg.
ftiede added a subscriber: ftiede.

How do you supply the passphrase? Modern GnuPG uses the gpg-agent to ask for
passphrases.

Also note that 'S.gpg-agent' is not a file, but a socket. Nothing is written
there, it is merely used for interprocess communication. Are you sure that
there is no writable location that can be used to create the sockets?

Please tell us more about your setup. What operating system are you using, how
is GnuPG used in the LUKS setup?

pinentry is used to enter the passphrase, during bootup pinentry-curses is in
use, after the GUI has started, a graphical version is used.

The major problem is that the gpg-agent tries to write to the root filesystem
when gpg is called to supply the key-material to LUKS. This fails with modern
GnuPG, stable GnuPG doesn't have this issue.

I am using Gentoo Linux AMD64 stable as operating system which stabilised
gnupg-2.1.15 a few days ago for general use.
In my LUKS setup GnuPG is used to symmetrically encrypt/decrypt a file
consisting the random data which in turn is the key for the LUKS partition in
question. So GnuPG does the part of requiring a secret for a required file to
get to the data in question, like a PIN to a credit card, both are worthless
without the other.

The process is roughly this:
The kernel starts and init (no systemd) proceeds to one step prior to checking
all to-be-mounted filesystems.
Now one or more partitions are found to be LUKS-encrypted with gpg-encrypted
keyfiles.
For each partition with such a gpg-encrypted keyfile gpg is called to decrypt
the keyfile and pass it to cryptsetup.
After all partitions have either been decrypted, the regular filesystem checks
are performed and filesystems are mounted as specified by /etc/fstab.

The crucial part is that up to the last step in the process the root filesystem
is still read-only and the agent's default location for the socket
(/root/.gnupg) doesn't allow creation of the socket.

Since my disk encryption relies on being able to enter the keyfile's passphrase
prior to being able to write to the root filesystem, I'm currently stuck with
GnuPG-2.0, which doesn't need its agent (contrary to its man-page, btw).

If you want to use the pinentry mechanism you need the agent in GnuPG 2.1.
There is no way around that. You need to find a writable place for GnuPG to
bind its sockets to.

Note that this is not an "issue", it is an improvement. GnuPG has been split up
into several components, a process called compartmentalization. The agent is no
longer optional.

Ah, no. I don't _want_ to use pinentry, it's just what happens with GnuPG-2.0,
given that pinentry is installed and GnuPG is able to find it at that point. I
can very well live with the basic (blind) prompt from GnuPG-1.x (I think
pinentry's habit of displaying * characters for each passphrase character typed
is also _not_ an improvement). So, I'm using pinentry, because I don't have the
choice not to do so.

And, honestly, I find changing an application's behaviour such way it doesn't
work anymore like it did for years without even an option to get at least part
of the old behaviour back - I'm talking _only_ symmetric _de_cryption here, for
everything else I'm fine with the agent - is not really an "improvement".

I understand there has been considerable time invested in discussing and
evaluating options here, but this decision renders GnuPG worthless for a step of
security I've had and now I need to look up alternatives, with the tradeoff of
them being probably less thoroughly scrutinized, esp. in their implementation of
the cryptography part. Also not an "improvement".

You need to find a writable place for GnuPG 2.1 to bind its sockets to. If you
do, you can also use the smart card daemon. Using a smart card to store could
increase the security of your setup considerably. Also, I consider this an
integration issue, so talking to your distribution makes more sense imho.

Otoh, if GnuPG 1.4 fits your needs, you could continue to use that. It will be
maintained forever for compatibility with older PGP versions.

I'm working on a solution for this problem, but since gpg-agent does now ignore
--no-use-standard-socket, how do I tell the agent daemon on commandline where to
create its socket?

Set the environment variable GNUPGHOME to the desired location.

What about cases where a local (/root/.gnupg) config is required to decrypt the
files?
I honestly don't know about SmartCards and stuff, but doesn't setting GNUPGHOME
also hide other GnuPG configuration?

That doesn't work then of course, unless the configuration is copied over to the
new GNUPGHOME.

Another option would be to create directories or links to directories
/run/user/0 or /var/run/user/0. If those exist, gnupg will create the sockets
there.

I've tried - unfortunately the gpg-binary doesn't try that on its own, so i
still have to extend the pre-fs-mount-magic happening during boot, but at least
it spares me thinking about how to tell the agent where to create its socket.
Modifying configs wouldn't be a good idea here, IMHO, as usually user-created
configs are there for a reason.

I've tried

What did you try?

  • unfortunately the gpg-binary doesn't try that on its own

What is it that which of the gpg binaries does not try?

To be absolutely precise:

  1. Log in as a test user with an existing ~/.gnupg and some (empty) keyrings
  2. Lock write access to ~/.gnupg with 'chmod 0500 ~/.gnupg'
  3. Create /run/user/<id> as root, chown and chmod it to be owned by that user

with write permission.

  1. Run 'gpg -q -d <symmetrically encrypted file>' as that user (which is

precisely what needs to work at this point. - It does _not_ work

  1. Run 'gpg-agent --daemon' as that user.
  2. Retry step 4. - Now it _does_ work.

So: gpg-agent can figure out to put its socket into /run/user/$(id -u) and
subsequent calls to gpg will find the agent socket there. But calling gpg
without starting the agent manually does not perform this magic.

Try running "gpgconf --create-socketdir" after step 3.

If gpg does not create this directory when it is trying to start an agent, but
gpg-agent does, then I guess that is a bug. But to be honest, this is easily
one of my least favorite features of GnuPG, and I have no opinion whatsoever
regarding its design.

gpgconf --create-socketdir made no difference, the agent still has to be started
manually, and honestly, even the gpgconf step is one step more than I think
absolutely necessary to make it work.

You simply can't run gpg on a read-only home directory. That is not just a
matter of socket files but of lock files and tracking a lot of other things.

For symmetric-only encryption the agent is used to calibrate the KDF
interations, it might be possible to a chnage gpg to take the iteration count
from the command line.

Try this:

echo hello | \
gpg -ac --pinentry-mode loopback --passphrase abc --s2k-count 17659904

By giving the S1K count (iterations) there is no need to ask gpg-agent. I have
used --passphrase for easier testing; --passphrase-fd should work as well.

To get the suggested iteration count for your box, use
gpg-connect-agent 'getinfo s2k_count' /bye

Figuring out required iteration counts is not necessary as the only operation
performed while GNUPGHOME is still unwritable is decryption.

--passphrase-fd 0 with --pinentry-mode loopback does indeed work without the
agent but requires a potentially unsafe password entry to be programmed around
the call which is also probably not the best option. --pinentry-mode ask
requires the agent again.

marcus claimed this task.
marcus added a subscriber: marcus.

Werner indicated that the current behaviour is intentional.