-
Notifications
You must be signed in to change notification settings - Fork 51
Description
Hello Guys!
First, thanks for this awesome project! You rock!
We've discovered a notable issue with the pgp-generate command in v8. When generating a public GPG key, the serialized key unexpectedly lacks the signature section, which consequently results in an invalid public key. Here is the configuration used
tokens:
gcloud:
type: gcloud
keys:
default:
token: gcloud
id: projects/sandbox/locations/global/keyRings/testing/cryptoKeys/relic/cryptoKeyVersions/4
pgpcertificate: /tmp/mykey.pgpHere is the executed command to generate the GPG key:
> relic pgp-generate -k default -n "pouet" -t "gcloud" > /tmp/mykey.pgpThe public key generated by the V8
> gpg --list-packets /tmp/mykey.gpg
# off=0 ctb=c6 tag=6 hlen=3 plen=525 new-ctb
:public key packet:
version 4, algo 1, created 1732617837, expires 0
pkey[0]: [4096 bits]
pkey[1]: [17 bits]
keyid: 3BBEB9F6CC4EBE49
# off=528 ctb=cd tag=13 hlen=2 plen=5 new-ctb
:user ID packet: "pouet"And when we try to sign using the key, we encounter this signing error.
$> relic sign-pgp -s -u default -b /tmp/pouet --digest-algo SHA-512
ERROR: openpgp: invalid data: entity without any identitiesWe've attempted resolving this by replacing github.com/ProtonMail/go-crypto/openpgp with golang.org/x/crypto/openpgp in cmdline/token/newpgpkeycmd.go, and this approach successfully serialized the key.
package token
import (
...
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/packet"
...
)# off=0 ctb=c6 tag=6 hlen=3 plen=525 new-ctb
:public key packet:
version 4, algo 1, created 1732618389, expires 0
pkey[0]: [4096 bits]
pkey[1]: [17 bits]
keyid: 847B069B51CE53F9
# off=528 ctb=cd tag=13 hlen=2 plen=5 new-ctb
:user ID packet: "pouet"
# off=535 ctb=c2 tag=2 hlen=3 plen=546 new-ctb
:signature packet: algo 1, keyid 847B069B51CE53F9
version 4, created 1732618389, md5len 0, sigclass 0x13
digest algo 10, begin of digest 49 51
hashed subpkt 2 len 4 (sig created 2024-11-26)
hashed subpkt 16 len 8 (issuer key ID 847B069B51CE53F9)
hashed subpkt 27 len 1 (key flags: 03)
hashed subpkt 25 len 1 (primary user ID)
data: [4096 bits]
While investigating the serialization differences between ProtonMail and the deprecated OpenPGP from Golang Crypto, I discovered a significant distinction; In golang.org/x/crypto/openpgp, the Serialize method of the entity explicitly serializes the SelfSigned signature of identities.
//File: https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.29.0:openpgp/keys.go
func (e *Entity) Serialize(w io.Writer) error {
...
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return err
}
err = ident.SelfSignature.Serialize(w) // <= SelfSignature Serialize
if err != nil {
return err
}
for _, sig := range ident.Signatures {
err = sig.Serialize(w)
if err != nil {
return err
}
}
}
...
}However in the github.com/ProtonMail/go-crypto/openpgp implementation, the serialize function only serializes Signatures
//File: https://github.com/ProtonMail/go-crypto/blob/5521d835096caef67f37fdad5bdc8f276d999747/openpgp/keys.go
func (e *Entity) Serialize(w io.Writer) error {
...
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return err
}
for _, sig := range ident.Signatures {
err = sig.Serialize(w)
if err != nil {
return err
}
}
}
...
}Afterward, we updated the makeKey function within cmdline/token/newpgpkeycmd go by adding the SelfSignatures to the Signatures variable within Entity, and the key was subsequently generated properly.
//File: https://github.com/sassoftware/relic/blob/master/cmdline/token/newpgpkeycmd.go
func makeKey(key token.Key, uids []*packet.UserId) (*openpgp.Entity, error) {
...
entity.Identities[uid.Id] = &openpgp.Identity{
Name: uid.Name,
UserId: uid,
SelfSignature: sig,
Signatures: []*packet.Signature{sig}, // <= Addition
}
...
}The generated key after the patch
# off=0 ctb=c6 tag=6 hlen=3 plen=525 new-ctb
:public key packet:
version 4, algo 1, created 1732619542, expires 0
pkey[0]: [4096 bits]
pkey[1]: [17 bits]
keyid: EACC6CEE13FAE20B
# off=528 ctb=cd tag=13 hlen=2 plen=5 new-ctb
:user ID packet: "pouet"
# off=535 ctb=c2 tag=2 hlen=3 plen=569 new-ctb
:signature packet: algo 1, keyid EACC6CEE13FAE20B
version 4, created 1732619542, md5len 0, sigclass 0x13
digest algo 10, begin of digest 3d 95
hashed subpkt 2 len 4 (sig created 2024-11-26)
hashed subpkt 16 len 8 (issuer key ID EACC6CEE13FAE20B)
hashed subpkt 33 len 21 (issuer fpr v4 09908E29E0DB49F16C76CAEFEACC6CEE13FAE20B)
hashed subpkt 27 len 1 (key flags: 03)
hashed subpkt 25 len 1 (primary user ID)
data: [4095 bits]
And the sign-pgp works properly
> relic sign-pgp -s -u default -b /tmp/pouet --digest-algo SHA-512 > /tmp/pouet.asc
Signed /tmp/pouetSo we have two question:
- Is this behavior expected on your side? Do you want us to open a PR that adds the identity signature to the Signatures?
- We've also noticed that the pub signature hash is explicitly set to SHA512 within the pgp-generate. Is it possible to auto-detect the pub hash based on the private key, or at least provide a flag that allows users to specify the hash from the command line?