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 67fa7316..069b57af 100644 --- a/openpgp/packet/encrypted_key.go +++ b/openpgp/packet/encrypted_key.go @@ -463,17 +463,17 @@ func SerializeEncryptedKeyWithHiddenOption(w io.Writer, pub *PublicKey, cipherFu return SerializeEncryptedKeyAEADwithHiddenOption(w, pub, cipherFunc, config.AEAD() != nil, key, hidden, config) } -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 } @@ -483,16 +483,12 @@ func (e *EncryptedKey) ProxyTransform(proxyParam []byte, forwarderKeyId, forward copy(copiedWrappedKey, wrappedKey) transformed = &EncryptedKey{ - KeyId: forwardeeKeyId, - Algo: e.Algo, + 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 } @@ -641,27 +637,60 @@ func serializeEncryptedKeyAEAD(w io.Writer, rand io.Reader, header [10]byte, pub return err } +<<<<<<< HEAD func checksumKeyMaterial(key []byte) uint16 { var checksum uint16 for _, v := range key { checksum += uint16(v) +======= +func (e *EncryptedKey) ProxyTransform(instance ForwardingInstance) (transformed *EncryptedKey, err error) { + if e.Algo != PubKeyAlgoECDH { + return nil, errors.InvalidArgumentError("invalid PKESK") +>>>>>>> edf1961 (Use fingerprints instead of KeyIDs) } return checksum } +<<<<<<< HEAD func decodeChecksumKey(msg []byte) (key []byte, err error) { key = msg[:len(msg)-2] expectedChecksum := uint16(msg[len(msg)-2])<<8 | uint16(msg[len(msg)-1]) checksum := checksumKeyMaterial(key) if checksum != expectedChecksum { err = errors.StructuralError("session key checksum is incorrect") +======= + if e.KeyId != 0 && e.KeyId != instance.GetForwarderKeyId() { + return nil, errors.InvalidArgumentError("invalid key id in PKESK") +>>>>>>> edf1961 (Use fingerprints instead of KeyIDs) } return } +<<<<<<< HEAD func encodeChecksumKey(buffer []byte, key []byte) { copy(buffer, key) checksum := checksumKeyMaterial(key) buffer[len(key)] = byte(checksum >> 8) buffer[len(key)+1] = byte(checksum) } +======= + ephemeral := e.encryptedMPI1.Bytes() + transformedEphemeral, err := ecdh.ProxyTransform(ephemeral, instance.ProxyParameter) + if err != nil { + return nil, err + } + + wrappedKey := e.encryptedMPI2.Bytes() + copiedWrappedKey := make([]byte, len(wrappedKey)) + copy(copiedWrappedKey, wrappedKey) + + transformed = &EncryptedKey{ + KeyId: instance.getForwardeeKeyIdOrZero(e.KeyId), + Algo: e.Algo, + encryptedMPI1: encoding.NewMPI(transformedEphemeral), + encryptedMPI2: encoding.NewOID(copiedWrappedKey), + } + + return transformed, nil +} +>>>>>>> edf1961 (Use fingerprints instead of KeyIDs) 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