From 08c6691a8454520189842e1519414eeaea0a4deb Mon Sep 17 00:00:00 2001 From: Aron Wussler Date: Wed, 22 Mar 2023 10:27:55 +0100 Subject: [PATCH] Use fingerprints instead of KeyIDs --- openpgp/forwarding.go | 20 +++++++----------- openpgp/forwarding_test.go | 16 ++++++--------- openpgp/packet/encrypted_key.go | 12 ++++------- openpgp/packet/forwarding.go | 36 +++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 openpgp/packet/forwarding.go diff --git a/openpgp/forwarding.go b/openpgp/forwarding.go index c201b03d..d4291f8e 100644 --- a/openpgp/forwarding.go +++ b/openpgp/forwarding.go @@ -11,20 +11,13 @@ import ( "github.com/ProtonMail/go-crypto/openpgp/packet" ) -// ForwardingInstance represents a single forwarding instance (mapping IDs to a Proxy Param) -type ForwardingInstance struct { - ForwarderKeyId uint64 - ForwardeeKeyId uint64 - ProxyParameter []byte -} - // NewForwardingEntity generates a new forwardee key and derives the proxy parameters from the entity e. // If strict, it will return an error if encryption-capable non-revoked subkeys with a wrong algorithm are found, // instead of ignoring them func (e *Entity) NewForwardingEntity( name, comment, email string, config *packet.Config, strict bool, ) ( - forwardeeKey *Entity, instances []ForwardingInstance, err error, + forwardeeKey *Entity, instances []packet.ForwardingInstance, err error, ) { if e.PrimaryKey.Version != 4 { return nil, nil, errors.InvalidArgumentError("unsupported key version") @@ -64,7 +57,7 @@ func (e *Entity) NewForwardingEntity( } // Init empty instances - instances = []ForwardingInstance{} + instances = []packet.ForwardingInstance{} // Handle all forwarder subkeys for _, forwarderSubKey := range e.Subkeys { @@ -105,8 +98,9 @@ func (e *Entity) NewForwardingEntity( return nil, nil, goerrors.New("wrong forwarding sub key generation") } - instance := ForwardingInstance{ - ForwarderKeyId: forwarderSubKey.PublicKey.KeyId, + instance := packet.ForwardingInstance{ + KeyVersion: 4, + ForwarderFingerprint: forwarderSubKey.PublicKey.Fingerprint, } instance.ProxyParameter, err = ecdh.DeriveProxyParam(forwarderEcdhKey, forwardeeEcdhKey) @@ -135,8 +129,8 @@ func (e *Entity) NewForwardingEntity( return nil, nil, err } - // Set ID after changing the KDF - instance.ForwardeeKeyId = forwardeeSubKey.PublicKey.KeyId + // Extract fingerprint after changing the KDF + instance.ForwardeeFingerprint = forwardeeSubKey.PublicKey.Fingerprint // 0x04 - This key may be used to encrypt communications. forwardeeSubKey.Sig.FlagEncryptCommunications = false diff --git a/openpgp/forwarding_test.go b/openpgp/forwarding_test.go index 3241a794..c03dd8c5 100644 --- a/openpgp/forwarding_test.go +++ b/openpgp/forwarding_test.go @@ -89,12 +89,12 @@ func TestForwardingFull(t *testing.T) { t.Fatalf("invalid number of instances, expected 1 got %d", len(instances)) } - if instances[0].ForwarderKeyId != bobEntity.Subkeys[0].PublicKey.KeyId { - t.Fatalf("invalid forwarder key ID, expected: %x, got: %x", bobEntity.Subkeys[0].PublicKey.KeyId, instances[0].ForwarderKeyId) + if bytes.Compare(instances[0].ForwarderFingerprint, bobEntity.Subkeys[0].PublicKey.Fingerprint) != 0 { + t.Fatalf("invalid forwarder key ID, expected: %x, got: %x", bobEntity.Subkeys[0].PublicKey.Fingerprint, instances[0].ForwarderFingerprint) } - if instances[0].ForwardeeKeyId != charlesEntity.Subkeys[0].PublicKey.KeyId { - t.Fatalf("invalid forwardee key ID, expected: %x, got: %x", charlesEntity.Subkeys[0].PublicKey.KeyId, instances[0].ForwardeeKeyId) + if bytes.Compare(instances[0].ForwardeeFingerprint, charlesEntity.Subkeys[0].PublicKey.Fingerprint) != 0 { + t.Fatalf("invalid forwardee key ID, expected: %x, got: %x", charlesEntity.Subkeys[0].PublicKey.Fingerprint, instances[0].ForwardeeFingerprint) } // Encrypt message @@ -166,7 +166,7 @@ func TestForwardingFull(t *testing.T) { } } -func transformTestMessage(t *testing.T, encrypted []byte, instance ForwardingInstance) []byte { +func transformTestMessage(t *testing.T, encrypted []byte, instance packet.ForwardingInstance) []byte { bytesReader := bytes.NewReader(encrypted) packets := packet.NewReader(bytesReader) splitPoint := int64(0) @@ -183,11 +183,7 @@ Loop: } switch p := p.(type) { case *packet.EncryptedKey: - tp, err := p.ProxyTransform( - instance.ProxyParameter, - instance.ForwarderKeyId, - instance.ForwardeeKeyId, - ) + tp, err := p.ProxyTransform(instance) if err != nil { t.Fatalf("error transforming PKESK: %s", err) } diff --git a/openpgp/packet/encrypted_key.go b/openpgp/packet/encrypted_key.go index e6553a39..1754d029 100644 --- a/openpgp/packet/encrypted_key.go +++ b/openpgp/packet/encrypted_key.go @@ -338,17 +338,17 @@ func serializeEncryptedKeyAEAD(w io.Writer, rand io.Reader, header [10]byte, pub return err } -func (e *EncryptedKey) ProxyTransform(proxyParam []byte, forwarderKeyId, forwardeeKeyId uint64) (transformed *EncryptedKey, err error) { +func (e *EncryptedKey) ProxyTransform(instance ForwardingInstance) (transformed *EncryptedKey, err error) { if e.Algo != PubKeyAlgoECDH { return nil, errors.InvalidArgumentError("invalid PKESK") } - if e.KeyId != 0 && e.KeyId != forwarderKeyId { + if e.KeyId != 0 && e.KeyId != instance.GetForwarderKeyId() { return nil, errors.InvalidArgumentError("invalid key id in PKESK") } ephemeral := e.encryptedMPI1.Bytes() - transformedEphemeral, err := ecdh.ProxyTransform(ephemeral, proxyParam) + transformedEphemeral, err := ecdh.ProxyTransform(ephemeral, instance.ProxyParameter) if err != nil { return nil, err } @@ -358,15 +358,11 @@ func (e *EncryptedKey) ProxyTransform(proxyParam []byte, forwarderKeyId, forward copy(copiedWrappedKey, wrappedKey) transformed = &EncryptedKey{ - KeyId: forwardeeKeyId, + KeyId: instance.getForwardeeKeyIdOrZero(e.KeyId), Algo: e.Algo, encryptedMPI1: encoding.NewMPI(transformedEphemeral), encryptedMPI2: encoding.NewOID(copiedWrappedKey), } - if e.KeyId == 0 { - e.KeyId = 0 - } - return transformed, nil } \ No newline at end of file diff --git a/openpgp/packet/forwarding.go b/openpgp/packet/forwarding.go new file mode 100644 index 00000000..50b4de44 --- /dev/null +++ b/openpgp/packet/forwarding.go @@ -0,0 +1,36 @@ +package packet + +import "encoding/binary" + +// ForwardingInstance represents a single forwarding instance (mapping IDs to a Proxy Param) +type ForwardingInstance struct { + KeyVersion int + ForwarderFingerprint []byte + ForwardeeFingerprint []byte + ProxyParameter []byte +} + +func (f *ForwardingInstance) GetForwarderKeyId() uint64 { + return computeForwardingKeyId(f.ForwarderFingerprint, f.KeyVersion) +} + +func (f *ForwardingInstance) GetForwardeeKeyId() uint64 { + return computeForwardingKeyId(f.ForwardeeFingerprint, f.KeyVersion) +} + +func (f *ForwardingInstance) getForwardeeKeyIdOrZero(originalKeyId uint64) uint64 { + if originalKeyId == 0 { + return 0 + } + + return f.GetForwardeeKeyId() +} + +func computeForwardingKeyId(fingerprint []byte, version int) uint64 { + switch version { + case 4: + return binary.BigEndian.Uint64(fingerprint[12:20]) + default: + panic("invalid pgp key version") + } +} \ No newline at end of file