Skip to content

Commit

Permalink
Use fingerprints instead of KeyIDs
Browse files Browse the repository at this point in the history
  • Loading branch information
wussler authored and lubux committed Oct 1, 2024
1 parent 348b81d commit c602a74
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 32 deletions.
20 changes: 7 additions & 13 deletions openpgp/forwarding.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
16 changes: 6 additions & 10 deletions openpgp/forwarding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}
Expand Down
47 changes: 38 additions & 9 deletions openpgp/packet/encrypted_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}

Expand Down Expand Up @@ -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)
36 changes: 36 additions & 0 deletions openpgp/packet/forwarding.go
Original file line number Diff line number Diff line change
@@ -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")
}
}

0 comments on commit c602a74

Please sign in to comment.