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.pgp
Here is the executed command to generate the GPG key:
> relic pgp-generate -k default -n "pouet" -t "gcloud" > /tmp/mykey.pgp
The 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 identities
We'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/pouet
So 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?
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
Here is the executed command to generate the GPG key:
The public key generated by the V8
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/openpgpwithgolang.org/x/crypto/openpgpincmdline/token/newpgpkeycmd.go, and this approach successfully serialized the key.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.However in the
github.com/ProtonMail/go-crypto/openpgpimplementation, the serialize function only serializes SignaturesAfterward, 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.
The generated key after the patch
And the sign-pgp works properly
So we have two question: