Closed jvehent closed 3 years ago
Ping @rsc & @agl who wrote the code according to git blame. Let me know if I can help test further!
Can I do anything to help with the resolution of this issue? It's blocking some of my users...
I took a peek at it, but this is my first dive into RFC4880 so some things are still unclear to me.
Looking at the yubikey stub in the secring, if I skip the first 272 bytes, I get directly to the S2K value, which is set to 0xff
:
$ hexdump -s 272 -C 000015-005.secret_key
00000110 ff 00 65 00 47 4e 55 02 10 d2 76 00 01 24 01 02 |..e.GNU...v..$..|
00000120 00 00 00 00 00 00 01 00 00 |.........|
00000129
0xff
indicates an encrypted private key. In the code [1], (pk *PrivateKey) parse()
tries to read the next byte to guess the encryption algorithm, but that next byte is set to 00
which doesn't map to any valid cipher.
Then, entering s2k.Parse()
, the following 2 bytes are read (0x6500
), and the second byte (0x00
) is used in s2k.HashIdToHash()
. But 0
is not a valid hash id, and the function returns error openpgp: unsupported feature: hash for S2K function: 0
. The error is silenced is openpgp.ReadKeyRing
[2].
I could do the analysis, but I'm afraid writing a patch is beyond my understand of the OpenPGP standard at this point...
[1] https://github.com/golang/crypto/blob/master/openpgp/packet/private_key.go#L67-L80 [2] https://github.com/golang/crypto/blob/master/openpgp/keys.go#L258
The hexdump from @jvehent is an example of a gnupg extension S2K type, which can be identified by the 65
(101
in decimal, rfc4480#section-3.7.1 denotes 100-110
as "Private/Experimental") followed by the 47 4e 55
(GNU
in ASCII). The 02
byte after that signifies that the stub is for "gnu-divert-to-card" S2K (01
signifies a "gnu-dummy" S2K as in #13605).
Per the accepted #44226 proposal and due to lack of maintenance, the golang.org/x/crypto/openpgp package is now frozen and deprecated. No new changes will be accepted except for security fixes. The package will not be removed.
If this is a security issue, please email security@golang.org and we will assess it and provide a fix.
If you're looking for alternatives, consider the crypto/ed25519 package for simple signatures, golang.org/x/mod/sumdb/note for inline signatures, or filippo.io/age for encryption. You can read a summary of OpenPGP issues and alternatives here.
If you are required to interoperate with OpenPGP systems and need a maintained package, we suggest considering one of multiple community forks of golang.org/x/crypto/openpgp. We don't endorse any specific one.
When a GPG secring contains a smartcard stub, the openpgp package fails to read the keyring correctly and does not return an error. A call to
openpgp.ReadKeyRing()
will returns the entities that precedes the stub, excluding the entity located right before the stub.For example, if a secring contains 3 entities and the smartcard stub is in position 3, then
openpgp.ReadKeyRing()
will only return the first entity. The second entity and the stub are ignored. No error is returned.Steps to reproduce:
1. Create a keyring with two regular 1024 bits RSA keys
2. Import a smartcard stub from a yubikey into the keyring
3. Attempt to read the entities in the keyring. Only the first entity is returned.
source code: