-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (go version)?
go version go1.9.2 linux/amd64
Does this issue reproduce with the latest release?
Yes, including a fresh git clone of x/crypto.
What operating system and processor architecture are you using (go env)?
Nothing but the finest Debian GNU/Linux has to offer
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/paultag/go"
GORACE=""
GOROOT="/usr/lib/go-1.9"
GOTOOLDIR="/usr/lib/go-1.9/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build475381706=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
What did you do?
Try to parse an exported GnuPG secret cryptoblob, with a subkey that does not have private key material (such as a hardware token, or a subkey that isn't present on that machine)
What did you expect to see?
A wonderful cryptoblob that I can use to post screeds to my local mailing lists.
What did you see instead?
openpgp: unsupported feature: hash for S2K function: 0
More details
When GnuPG exports the secret chunks of a key, it will also export the subkey private material. This will come as wholly uninteresting to everyone involved, I'm sure.
However, the interesting part is when that subkey does not have a private component associated with it (e.g. a hardware token, or subkey that has a key on another machine), it is marked "offline".
From the GPG manpage:
-K List the specified secret keys. If no keys are specified, then
all known secret keys are listed. A # after the initial tags
sec or ssb means that the secret key or subkey is currently not
usable. We also say that this key has been taken offline (for
example, a primary key can be taken offline by exported the key
using the command --export-secret-subkeys). A > after these
tags indicate that the key is stored on a smartcard. See also
--list-keys.
So, I made a key, and added a subkey with the golang.org/x/crypto/openpgp library, and discarded the subkey privatekey material (since gpg can't know if that's stored somewhere real or not), and imported that into the keyring.
I then added a new key and let it keep the key material.
$ gpg -K
sec rsa4096 2017-12-23 [SC] [expires: 2018-12-23]
AAC04B92503C27027E9FA3727456ABE798DA7527
uid [ultimate] foo bar don't use me <example@example.com>
ssb# rsa2048 2017-12-23 [S] [expires: 2017-12-24]
ssb rsa2048 2017-12-23 [S] [expires: 2018-12-23]
And, now the interesting part of --list-packets:
[other packets that aren't germane to my point]
:secret sub key packet:
version 4, algo 1, created 1513992502, expires 0
pkey[0]: [2048 bits]
pkey[1]: [17 bits]
gnu-dummy S2K, algo: 0, simple checksum, hash: 0
protect IV:
keyid: C3A17CA0B9DFF1E5
[other packets that aren't germane to my point]
:secret sub key packet:
version 4, algo 1, created 1513993077, expires 0
pkey[0]: [2048 bits]
pkey[1]: [17 bits]
iter+salt S2K, algo: 7, SHA1 protection, hash: 2, salt: 87557FFC8163000E
protect count: 65011712 (255)
protect IV: 8e db a3 af 4e 71 11 5a e5 d7 48 97 40 e3 a6 c9
skey[2]: [v4 protected]
keyid: 26E9A61F6F84F502
Now, on the real subkey packet, it has an S2K packet that looks legit, and the "offline" key has a "gnu-dummy" subkey on it. Neat!
Seems like it's exporting shim (and empty) secret packets for the keys it doesn't have the private half to, which would explain why it's coming up with anyone doing stuff with Yubikeys.
This is a really wackado thing for GnuPG to do, and I'm kinda creeped out that it does this rather than just outputting the public key packet. I'm sure there's a totally plausible and mature reason to do this rather than it being easier to make a custom secret packet type.
I guess the behavior of /x/crypto/openpgp ought to be ignoring the gnu-dummy packets, pull the public key material out of it, and go on about your day, but it's apparently trying to validate what seems to this one humble engineer as a batshit value.
If it didn't crash there, it would for sure blow up when it tried to read the actual private key material, so maybe this is better? Who can know.
Here's another bug report that I think is related, and I posted there, until I thought to file it here, too.