This is another attack to spoof digital signatures specific to Enigmail.
This time, we show two more methods to spoof the signer and trust value of signatures with GnuPG that is specific to Enigmail. Again, we exploit the awkwardness of the text-based GnuPG status interface.
Many thanks also to Patrick Brunschwig, who maintains Enigmail in his spare time, and who did an amazing job responding and attending to these issues in a quick and professional manner!
We found multiple vulnerabilities in Enigmail:
CVE-2018-12019: The signature verification routine in Enigmail 18.104.22.168 interprets user ids as status/control messages and does not correctly keep track of the status of multiple signatures, which allows remote attackers to spoof arbitrary email signatures via public keys containing crafted primary user ids.
You can protect yourself:
This vulnerability is tracked under the following identifiers:
This screenshot is from Enigmail 2.0.6, and apparently shows a message with a valid signature by Patrick Brunschwig. In reality, this message was signed and sent by us using a specially crafted key.
This method allows an attacker to craft a message with a signature by an untrusted key that Enigmail shows as “trusted.” The message box will be green and the envelope will carry a red wax seal instead of a grey seal with a question mark.
Enigmail can only keep track of a single signature. Enigmail has little contextual information on the status lines, and will overwrite the signature state with the last seen signature. In particular, these status messages are relevant to the discussion:
GOODSIG [KEY_ID] [USER_ID]indicates a good signature and provides a short key id and the primary user id.
REVKEYSIGare similar to
GOODSIGbut for signatures by expired or revoked keys.
VALIDSIG [FPR] [CREATION_DATE] [TIMESTAMP] [EXPIRE_TIMESTAMP] [VERSION] [RESERVED] [PUBKEY_ALGO] [HASH_ALGO] [CLASS] [PRIMARY_KEY_FPR]provides much more information on the signature, such as creation time, long fingerprint, and the algorithms used.
Some status flags understood by Enigmail have a “trapdoor” effect in
the sense that they can only trigger setting a flag which is not
deleted afterwards. In the case of error flags that is often useful
and the safe default, but for
behaviour is actually dangerous.
We found two flaws in the way Enigmail handles status messages for multiple signatures:
REVKEYSIG, Enigmail will overwrite the signature details (fingerprint, creation time, algorithm identifiers) with the information from the first
VALIDSIG, confusing the metadata of two signatures. For example, this allows us to change the state of a signature to good, expired or revoked, by adding a second signature with an appropriate state. Enigmail will display the details of the first signature, but the state of the second.
TRUST_ULTIMATE, and the last signature is good (can be expired or revoked), then Enigmail will display the information from the first
Put together, the attacker can trick Enigmail into assigning the trust value of one signature to the details of another signature.
Simply generate two keys, and sign a message with both. Import the public keys into a new keyring, and set full trust for one of them. Sign a message first with the untrusted key, and second with the trusted key. Enigmail will display the signature from the untrusted key as trusted.
$ mkdir /tmp/trustconfusion $ gpg --homedir /tmp/trustconfusion --quick-gen-key "Dubious Key <email@example.com>" $ gpg --homedir /tmp/trustconfusion --quick-gen-key "Trusted Key <firstname.lastname@example.org>" $ gpg --homedir /tmp/trustconfusion/ --export Trusted Dubious | gpg --import $ gpg --edit-key Trusted > lsign > save $ echo 'Do you remember me?' | gpg --homedir /tmp/trustconfusion --armor --sign -u Dubious -u Trusted | gpg --status-fd 2 ... [GNUPG:] GOODSIG 848346A87AEDB69D Dubious Key <email@example.com> [GNUPG:] VALIDSIG 3A6744E8E65F3CAF3E0FB88A848346A87AEDB69D 2018-06-07 1528401495 0 4 0 1 8 00 3A6744E8E65F3CAF3E0FB88A848346A87AEDB69D [GNUPG:] TRUST_UNDEFINED 0 classic ... [GNUPG:] GOODSIG 645130A3A9C92809 Trusted Key <firstname.lastname@example.org> [GNUPG:] VALIDSIG 05B34301E7FEB1328344789E645130A3A9C92809 2018-06-07 1528401495 0 4 0 1 8 00 05B34301E7FEB1328344789E645130A3A9C92809 [GNUPG:] TRUST_FULLY 0 classic ...
To make the attack work, the victim has to import the keys generated by the attacker and trust one of them. We show below several ways to achieve this under more restrictive conditions (were the user id is more suspicious than here).
NEWSIGstatus messages can be used to do that).
This method allows an attacker to spoof arbitrary signature details and the trust status of the signature. All signature details displayed by Enigmail are under the control of the attacker. The message box will be green and the envelope will carry a red wax seal instead of a grey seal with a question mark.
This attack works due to the incomplete way Enigmail matches status messages with regular expressions.
Again, we find synergy between two unrelated weak design choices in GnuPG and Enigmail:
TRUST_FULLYbelow) GnuPG status messages like
BADSIGfrom the end of a line, ignoring the beginning.
GOODSIGstatus line, without escaping whitespace.
This enables us to inject some GnuPG status lines into Enigmail by writing them into the primary user ID of a signing key.
Note: This is a list of status lines that can be injected this way due
to incomplete regular expressions:
ENC_TO. In this attack, we only make use of
Unfortunately, we can not inject the
TRUST_* status lines through
user ids, because Enigmail expects them to be at the beginning of a
status line (here Enigmail is more strict than with
The main idea of the attack is to use a valid signature by a key with
a malicious user id that itself contains a
status line indicating an entirely different key. In this example, we
are using the details from the key of the Enigmail author.
$ gpg --status-fd 2 --quick-gen-key "GOODSIG DB1187B9DD5F693B Patrick Brunschwig <email@example.com>" ... [GNUPG:] KEY_CREATED B BF52C30EA443623C6299883FB81CB745B9100FC9 ... $ gpg --status-fd 2 --quick-gen-key "VALIDSIG 4F9F89F5505AC1D1A260631CDB1187B9DD5F693B 2018-05-31 1527721037 0 4 0 1 10 01 4F9F89F5505AC1D1A260631CDB1187B9DD5F693B" ... [GNUPG:] KEY_CREATED B 552D4E1657548BF8C4B3A5643C2AA6885649565E ... $ echo 'I am ordering a pizza.' | gpg --sign -u 552D4E1657548BF8C4B3A5643C2AA6885649565E | gpg --status-fd 2 ... [GNUPG:] GOODSIG B81CB745B9100FC9 GOODSIG DB1187B9DD5F693B Patrick Brunschwig <firstname.lastname@example.org> ... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [GNUPG:] GOODSIG 3C2AA6885649565E VALIDSIG 4F9F89F5505AC1D1A260631CDB1187B9DD5F693B 2018-05-31 1527721037 0 4 0 1 10 01 4F9F89F5505AC1D1A260631CDB1187B9DD5F693B ... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This approach is not quite right, due to the way Enigmail processes the status lines. However, with a bit of extra work, it can be modified to a functional attack.
We saw above (in “Method I: Signature status confusion”), that
Enigmail uses the signature state (
GOODSIG) of the last signature,
but the fingerprint and other information from the very first
VALIDSIG in the output.
GOODSIG with the injected user id comes before the corresponding
VALIDSIG. This means that for a successful attack, we only
need to inject a proper
VALIDSIG line in the first
GOODSIG is entirely superfluous, and we can
rely on the valid, original
GOODSIG from GnuPG to trigger the search
VALIDSIG must be injected in the primary user id of the very first
signature, because otherwise the correct
emitted by GnuPG for the first signature would be used instead.
Although we said that Enigmail matches
VALIDSIG even in the middle
of a line, it retrieves the key details from the beginning of the
line (after stripping away the first 9 characters for `VALIDSIG␣’). So
we have to repeat the required arguments at the beginning of the line.
Here is a complete, stripped-down and working example for a user id that can be used to spoof a signature in Enigmail:
x 1527763815 x x x 1 10 x 4F9F89F5505AC1D1A260631CDB1187B9DD5F693B VALIDSIG x x 0 4F9F89F5505AC1D1A260631CDB1187B9DD5F693B ^ creation ^ 40-character fingerprint ^ 40-character fingerprint ^ hash algorithm ^^^^^ matches (\w+) (.*) (\d+) ^ pubkey algorithm
There are two remaining issues:
The assumption here is that the victim has already established communication with the signer the attacker wants to spoof, and that the victim has managed the trust settings accordingly. If either of these is not true, it is easy to perform a man in the middle attack anyway.
NEWSIGboundary to clear internal data structures, and makes sure that
TRUST_*status lines are taken from the same signature context (between two
In both methods, the attacker must inject the signing key with the malicious user id into the victim’s keyring ahead of sending the spoofed message. There are many ways to do this, and the best way depends on the victim’s configuration and behaviour.
The main point about this is that in the OpenPGP community it is considered acceptable to import malicious keys into the keyring, as long as they are not assigned a trust value. In fact, the tenor is that it is unavoidable that the attacker can insert arbitrary keys into the victim’s keyring, and that alone is not considered a breach of the security model.
These are some ways to inject the key using the keyserver network:
auto-key-retrieveoption in GnuPG do all the work. The key is then downloaded and imported automatically, but the existance of the key is public knowledge.
auto-key-locate), the malicious key can be added to the payload. This way the existance of the key is hidden to the network and other users.
These are some ways to inject the key by email:
Import Key, Enigmail will ask three times if the user cancels the first two confirmation dialogues. That nagging is working in favor of the attacker.
x) with some nice looking strings, maybe we can trick the victim into accepting the key anyway? Judge for yourself by the screenshots.
It is also possible that the victim can be tricked into importing the key at the command line, for example to verify some signature of a software download. A single downloaded public key file can contain several public keys, and the malicious user id can simply be lost in the noise.
There are also new ways to inject keys, for example autocrypt. We did not explore these for this attack, because the above seem sufficient to illustrate the point.
Once the key is imported, it requires manual action by the victim to get rid of it. The victim must manually identify the key and delete it from the keyring. Until then, the victim is vulnerable to our attack.
Both methods above rely on the fact that we can get the victim to trust at least one key generated by the attacker. This key can have any user id, and is completely unrelated to the spoofed signature details. Because exchanging such keys and trusting them is the normal mode of operation for OpenPGP, this is usually not difficult to accomplish. Nevertheless, we give some helpful advice here to spur the reader’s imagination.
We start with some advice: Forensically, the victim will be able to identify the key that was used (it will be “burned”), so it is a good idea to set up a new, trusted communication channel with the victim under an innocuous user id.
In the simplest case, the attacker and the victim will exchange key signatures directly. If the victim uses the “Web of Trust” policy in GnuPG, the attacker might be able to infiltrate that.
Enthusiastic OpenPGP supporters are often happy to sign keys of strangers at international conferences at so-called “key signing parties”. The signatures are made based on a cursory inspection of international passports or identity cards, and it is unlikely that the victim is familiar with passports and id cards from all recognized nation states. Given the helpfulness of the community towards activists from non-democratic countries, a social engineering attack under an appropriate cover story might be possible.
Again, the goal here is to get the victim to sign a completely unrelated and innocuous key with a properly formed user id consisting of a name and email address. Eventually, the attacker sends the actual attack email carrying the signature by the key with the malicious user id and the signature by the trusted key. Enigmail will display the spoofed signature metadata in the former and the trust status of the latter.
Normally, we expect the victim to have the key of the spoofed signer in the local keyring (with an assigned trust value) due to previous communication. But if that is not the case, we can inject it using the above described methods.
However, the mail client is usually a long running program, and
Enigmail caches the information in the local key ring. A missing key
or stale cache can cause Enigmail to fall back to the user id in the
GOODSIG status line of the signature verification, instead of using
the user id from the key with the fingerprint in the spoofed
VALIDSIG line, defeating the attack by showing the wrong user id in
To get around this, we can add another signature by a key with the following primary user id (this must be the last signature in the message):
GOODSIG DB1187B9DD5F693B Patrick Brunschwig <email@example.com>
We inject this key along with the other malicious key as described above. Enigmail will then fall back to the provided user id in case the public key is missing from the local keyring or Enigmail’s cache.