Page MenuHome GnuPG

gpg --sign fails when LC_ALL=C, the signing key's primary user ID is not US ASCII, and we fall back to curses
Open, LowPublic

Description

consider:

export GNUPGHOME=$(mktemp -d)
gpg --quick-gen-key 'Test Usér <tester@example.org>'
echo test > test.txt
gpgconf --kill gpg-agent
LC_ALL=C DISPLAY= DBUS_SESSION_BUS_ADDRESS= gpg --default-key tester@example.org --sign test.txt

The final step here fails with:

gpg: signing failed: A locale function failed

This is an issue on debian because sbuild apparently sets LC_ALL=C during its final signing stage.

Event Timeline

dkg created this object in space S1 Public.

fwiw, i've also opened a bug for sbuild asking it to not force the locale into non-UTF-8: https://bugs.debian.org/866023

note that the problem here is related to the choice of pinentry, and also whether gpg-agent is already running. the issue appears to be in pinentry-curses, or in the curses fallback for other pinentry implementations.

What behavior do you expect in this case?

Users expect to be able to make signatures (or to fail to make signatures) reliably and understandably. the fact that some pinentries fail in some obscure combinations of circumstances makes the process of making signatures unreliable and incomprehensible.

If a pinentry is tasked with displaying a prompt to the user that it doesn't feel capable of displaying properly, it can still receive data from the user (granted, the context with which it prompts the user will be less "correct").

So i think the pinentry has two choices:

  • it can go ahead and prompt the user with whatever translation of the message it is capable of displaying, while acknowledging that the prompt is likely to be ill-formed.
  • it can decline to show the requested prompt to the user, but instead show a message to the user explaining why it is not asking the user for a passphrase even though it wanted to. This should include some sort of suggestion about how the user could fix it.

The third option, which is what pinentry is doing right now, is:

  • failing to prompt the user at all, and passing back a cryptic error message to the upper layer stack.

I think that either of the first two options would be better than the current behavior.

I am not sure I agree with the “cryptic error message” bit. I would think anyone knowledgeable enough to play with LC_ALL (or any other LC_* variable) should understand what “a locale function failed” means and conclude that maybe the best way to fix the problem is to leave LC_ALL alone.

In the case where the user did not modify LC_ALL himself, but used a tool that did it without his knowing, then I would say the problem lies entirely within that tool.