Pretty Good Phishing
PGP is not broken. It has long been the best framework most of us have for digital identity, and a secure means of communication.
Sadly the same cannot be said for certain popular PGP tools, nor for vast numbers of tutorials out there. The usage we enjoyed and became accustomed to for a quarter century will now lead at best to confusion, and at worst to mistakes that could defeat the entire purpose of PGP and leave users wide open to spoofing. That applies both to longstanding users who understand it well, and to the newbie who has read and understood a tutorial.
The underlying problem is that 32-bit (8 hex character) key IDs are comprehensively broken. The story of that is told at evil32.com, by (I think) the people who originally demonstrated the issue. It’s developed further since I last paid attention to it (and drew my colleagues’ attention to the need to stop using those 32-bit key IDs), in that an entire ‘shadow strong set’ has now been uploaded to the keyservers. Those imposters were revoked by the evil32 folks, but with the idea being out there, anyone could now repeat that exercise and generate their own fake identities and fake Web of Trust. And when a real malefactor does that, they’ll have the private keys, so there’ll be no-one to revoke them.
Let’s take a look at a recent sequence of events, when I rolled a release candidate for an Apache software package, and PGP-signed it. Bear in mind, this is all happening in a techie community: people who have been happily using PGP for years.
[me] Signs a software bundle, upload it with the signature to web space.
[colleague] Checks the software, comes back with a number of comments. Among them:
- Key B87F79A9 is listed as "revoked: 2016-08-16" in key server
Where does that come from? I take great care of my PGP keys, and I certainly don’t recollect revoking that one. To have revoked it, someone needs to have had access to both my private key and my passphrase, which is kind-of equivalent to having both the chip and the PIN to use my bank card (and that’s ignoring risks like someone tampering with my post on its way from the bank). This is … impossible … alarming!
Yet this is exactly what happens if you RTFM:
% gpg --verify bundle.asc gpg: Signature made Sun 16 Apr 2017 00:00:14 BST using RSA key ID B87F79A9 gpg: Can't check signature: public key not found
We don’t have the release manager’s public key ( B87F79A9 ) in our local system. You now need to retrieve the public key from a key server.% gpg --recv-key B87F79A9 gpg: requesting key B87F79A9 from HKP keyserver pgpkeys.mit.edu gpg: key B87F79A9: public key "Nick Kew <me>" imported gpg: Total number processed: 1 gpg: imported: 1
That’s a paraphrased extract from a real tutorial (which I intend to update, if noone else gets there first). It was fine when it was written, but now imports not one but two keys. Here they are:
$ gpg --list-keys B87F79A9 pub 4096R/B87F79A9 2011-01-30 uid Nick Kew <niq@apache...> uid Nick Kew (4096-bit key) <nick@webthing...> sub 4096R/862BA082 2011-01-30 pub 4096R/B87F79A9 2014-06-16 [revoked: 2016-08-16] uid Nick Kew <niq@apache...>
Both appear to be me; one is really me, the other an imposter from the evil32 set. It’s easy to see when we know what we’re looking for, but could be confusing if unexpected!
The problem goes away if we use 64-bit Key IDs, or (nowadays strongly recommended) the full 160-bit (40 character) fingerprint. It is computationally infeasible anyone could impersonate that, and indeed, they haven’t.
$ gpg --fingerprint B87F79A9 pub 4096R/B87F79A9 2011-01-30 Key fingerprint = 3CE3 BAC2 EB7B BC62 4D1D 22D8 F3B9 D88C B87F 79A9 uid Nick Kew <niq@apache...> uid Nick Kew (4096-bit key) <nick@webthing...> sub 4096R/862BA082 2011-01-30 pub 4096R/B87F79A9 2014-06-16 [revoked: 2016-08-16] Key fingerprint = C74C 8AA5 91CB 3766 9D6F 73C0 2DF2 C6E4 B87F 79A9 uid Nick Kew <niq@apache...>
The imposter’s fingerprint is completely different from mine. It’s not PGP that’s broken, it’s the use of 32-bit/8-character key IDs in our tools, our tutorials, and our minds, that’s at fault.
However, the problem is a whole lot worse than that. It’s not just my key (and everyone else in the Strong Set at the time of the evil32 demo) that has an imposter, it’s the entire WoT. Let’s see if WordPress will let me present these side-by-side if I truncate the lines a bit. The commandline used here is
$ gpg --list-sigs [fingerprint] |egrep ^sig|cut -c14-50|sort|uniq|head -5
which lists me:
010D6F3A 2012-04-11 dirk astrath (mo 02D1BC65 2011-02-07 Peter Van Eynde 0AA3BF0E 2011-02-06 Christophe De Wo 16879738 2011-02-07 Markus Reichelt 1DFBA164 2011-02-07 Bernhard Wiedema
010D6F3A 2014-08-05 dirk astrath (mo 02D1BC65 2014-08-05 Peter Van Eynde 0AA3BF0E 2014-08-05 Christophe De Wo 16879738 2014-08-05 Markus Reichelt 1DFBA164 2014-08-05 Bernhard Wiedema
The first field there is the culprit 8-hex-char Key IDs for my signatories and their evil32 doppelgangers. The only clue is in those dates, which would be easy to overlook. Otherwise we have a complete imposter WoT. Those IDs offer no more security than a checksum (such as MD5 or SHA) if used without due care, and without a chain of trust right back to the user’s own signature (which is something you probably don’t have if you’re not a geek).
There are a lot of tools and tutorials out there that need updating to prevent this becoming yet another phisher’s playground. Tools should not merely stop displaying 8-character key IDs, they shouldn’t even accept them. I don’t think mere disambiguation is enough when an innocent user might thoughtlessly just select, say, the first of competing options.
I’ve already been diving in to some of those tutorials where I have write access to update them, but the task is complicated by having to work in the context of a document that deals with more than just the one thing, and without adding too much complexity for readers. So I decided to work through the story here first!