pinentry emacs features need documentation
Open, NormalPublic

Description

pinentry 0.9.5 added a pinentry-emacs program and an "INSIDE_EMACS" fallback
mode, but those features and mechanisms do not appear to be documented anywhere
in doc/pinentry.texi (or anywhere in doc).

When i try to run pinentry-emacs manually to test it out (even from within M-x
shell), i get a terse and inexplicable failure:

0 $ ./emacs/pinentry-emacs
stat: No such file or directory
1 $

There is also no indication in the documentation of what i need to do to my
emacs installation to make sure that it works correctly.

Given the lack of documentation, the opaque failure modes, and the vague concern
about abuse of INSIDE_EMACS from non-emacs environments i've currently disabled
those features in the pinentry 0.9.5-2 upload to debian.

If the documentation and failure modes are clarified, i'm happy to re-enable
them in debian, and potentially to add a new pinentry-emacs package if there's
reason to think that would be desirable.

Details

Version
0.9.5
dkg set Version to 0.9.5.Jul 7 2015, 9:01 PM
dkg added projects: pinentry, Bug Report.
dkg added a subscriber: dkg.
neal added a subscriber: neal.Jul 8 2015, 3:12 PM

pinentry-emacs does not need to be distributed. You just need to distribute the
usual pinentry programs with emacs support. Similar to the fallback-curses
mode, if these programs see that INSIDE_EMACS is set AND they can talk to an
emacs instance with the pinentry module loaded, then they speak the emacs
protocol. Otherwise, they do their usual thing.

I'll update the documentation in the near future.

What abuse of INSIDE_EMACS are you referring to?

Thanks

dkg added a comment.Jul 8 2015, 4:42 PM

If pinentry-emacs doesn't need to be distributed, why do we even have it as a
separate target (emacs/pinentry-emacs) that is enabled by default?

my concern about abuse of INSIDE_EMACS is as i said "vague" -- sorry, i hope
it's not FUD! here's a rough sketch:

pinentry is a sensitive program. its job is to protect sensitive data (secret
key material, passphrases) from unintended use. each hook that we put into
pinentry to allow an attacker to probe its contents, or to execute commands, or
to control the UI/UX of what is presented to the user, is another hook that can
be used to violate the protection we want gpg-agent to afford its users.

Consider an attacker who has access only to the gpg-agent socket, and to one
other socket on the system. If they can convince gpg-agent to talk to them on
that one other socket by setting INSIDE_EMACS during a communication to
gpg-agent, this seems like a risk. furthermore, it's an unnecessary risk for
users who have no intention of interacting with gpg-agent through emacs in this
way. (e.g. users of emacs under X11 sessions may prefer to use a graphical
agent, or users of emacs from a terminal may prefer pinentry-curses). it's not
clear if there's a way to tell gpg-agent at runtime to avoid this additional
communications vector either.

neal added a comment.Jul 14 2015, 2:05 PM

The security issue with emacs pinentry is that emacs is handling the passphrase
and it isn't very careful with it. For instance, try typing C-h l
(view-lossage) in emacs. This will show you your recent keystrokes. Emacs is
also a huge program (operating system?), which doesn't provide any isolation to
speak of. So, having it handle the passphrase adds a huge chunk of code to the
user's trusted computing base. Because of this concern, emacs doesn't enable
this by default (the user has to add pinentry-start to his or her .emacs files).

Emacs support in pinentry of course adds some complexity to pinentry and a
minuscule amount of additional complexity to gpg agent (it needs to pass through
a few more environment variables).

You propose an attack in which an attacker has access to the gpg-agent socket
and some other socket. pinentry is wired to use /tmp/emacs<UID>/pinentry. So I
guess this is the other socket that you mean. Note: before using it, pinentry
makes sure that the socket is owned by UID.

As far as I can see there are two weaknesses. First, the attacker can try to
brute force the password. This is a minor problem, I think, but worth
addressing given the recent efforts to prevent this type of attack. Based on
how unlikely and difficult this attack is, I think the best thing to do is for
gpg-agent to rate limit pinentry. Second, the attacker could exploit a weakness
in the gpg-agent/pinentry API. My sense here is that there are probably easier
attack vectors. As Werner likes to say: there are many local exploits. Once
the attacker has your UID, he or she can just ptrace your gpg-agent or copy your
private key (assuming it is saved on disk).

I propose the following:

  • Add a command line option to pinentry that disables emacs support
  • Change gpg-agent to support passing command line options to pinentry
  • Rate limit password attempts by pinentry.
  • Document pinentry-emacs and related functionality in the pinentry manual.

Is this reasonable?

neal added a comment.Jul 28 2015, 11:53 AM

I've added some documentation. Let me know if it needs further improvement.
Thanks.

neal added a comment.Jul 28 2015, 2:09 PM

The documentation part of this bug should now be resolved. There are three
other issues. I've opened separate issues in the tracker for them.

neal added a comment.Jul 28 2015, 2:10 PM

Duplicate of T2058

neal added a comment.Jul 28 2015, 2:10 PM

Duplicate of T2059

neal closed this task as "Resolved".Aug 24 2015, 4:35 PM
neal claimed this task.
ueno added a subscriber: ueno.Feb 22 2016, 3:18 AM

Thanks for writing this up, Neal. However, I found the claim a bit
inaccurate by now. I am attaching a proposed fix for this.

Emacs keeps all key presses buffered.
(You can see the recent key presses by typing @code{C-h l}
(@code{view-lossage}) in emacs.)

This is not the case with the common `read-passwd' function, which
clears the log on every key press. See:
http://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/subr.el#n2126

Because of this concern, Emacs doesn't
enable this by default (the user has to run @code{(pinentry-start)},
e.g., from his or her @code{.emacs} file, explicitly).

This is no longer true. Emacs checks the allow-emacs-pinentry option
of gpg-agent, and start it if desired.

Further, Emacs is a huge program,
which doesn't provide any process isolation to speak of. As such,
having it handle the passphrase adds a huge chunk of code to the
user's trusted computing base.

Yes. However, all official packages on elpa.gnu.org are digitally
signed and supposed to work courteously. Users can still use unsigned
or 3rd party packages, but I think it is similar to the situation
where distribution packages are used.

In conclusion, I would say the Emacs pinentry provides the same level
of security as the current pinentry-gtk2 (as long as the
implementation is sane). My only concern was that Emacs `read-passwd'
is implemented in Elisp and thus cannot use secure memory. However,
it is also true for pinentry-gtk2, which uses the default GtkEntry
now.

neal added a comment.Feb 22 2016, 11:32 AM

@ueno: This is reasonable. Thanks for the explanation. Do you happen to know
approximately what version started to enable these protections?

dkg added a comment.Feb 12 2017, 8:36 PM

So i'm left a little confused here about what the resolution is. neal added
documentation, but ueno suggested it was wrong and contributed a patch for it.
However, that patch hasn't been applied.

Some additional questions about pinentry-emacs and INSIDE_EMACS that came up in
discussion over on https://bugs.debian.org/854797:

    What's the best way to debug a problem when emacs pinentry
    isn't working?  do we look at gpg?  gpg-agent?  pinentry? emacs itself?
    all of those places?  What happens when the user has two separate
    instances of emacs running?  What if there's an instance of emacs
    running and someone uses tramp to connect to a remote ssh server, and
    gpg-agent is providing the ssh-agent interface?  What if someone uses
    ssh from *outside* of emacs and it talks to a gpg-agent that was
    auto-launched from within an emacs session?  What about when there's an
    instance of emacs running in a graphical session on a machine where the
    same user is also logged into the machine via ssh, and they're using a
    different graphical session?  how does pinentry-emacs interact with
    emacs --daemon and multiple emacsclient instances?

Another few questions:

Why does emacs use /tmp/emacs$UID for the ephemeral socket instead of

/run/user/$UID ?

If OPTION allow-pinentry-emacs is set, but the emacs process isn't

repsonsive (or nothing is listening at all) should pinentry do a second layer of
fallback, e.g. to curses?

kai edited the task description. (Show Details)Tue, Apr 4, 2:54 PM
kai removed a project: Duplicate.