Fix parsing issue of AEAD encrypted messages.

In pgpMessage.SeparateKeyAndData(), the parsing would
ignore AEAD encrypted data packets. Which would result
in a split message with a nil data packet.
We add support for AEAD encrypted data packets.
This also affects `NewPGPSplitMessageFromArmored` and `NewPGPSplitMessage`.
This commit is contained in:
marin thiercelin 2022-01-10 14:24:08 +01:00
parent 3aafa3c549
commit 1a2e569373
No known key found for this signature in database
GPG key ID: 117C025B1F21B2C6
3 changed files with 96 additions and 56 deletions

View file

@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Fixed
- Fixed bug with `NewPGPSplitMessageFromArmored(armored)` and `PGPMessage.SeparateKeyAndData()`.
Those functions didn't parse AEAD encrypted messages correctly (eg messages encrypted with the latest versions of gnupg.), resulting in a nil `DataPacket`.
## [2.4.0] 2021-12-21 ## [2.4.0] 2021-12-21
### Added ### Added

View file

@ -333,7 +333,6 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
// For info on each, see: https://golang.org/pkg/runtime/#MemStats // For info on each, see: https://golang.org/pkg/runtime/#MemStats
packets := packet.NewReader(bytes.NewReader(msg.Data)) packets := packet.NewReader(bytes.NewReader(msg.Data))
outSplit = &PGPSplitMessage{} outSplit = &PGPSplitMessage{}
gcCounter := 0
// Store encrypted key and symmetrically encrypted packet separately // Store encrypted key and symmetrically encrypted packet separately
var encryptedKey *packet.EncryptedKey var encryptedKey *packet.EncryptedKey
@ -345,13 +344,38 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
} }
switch p := p.(type) { switch p := p.(type) {
case *packet.EncryptedKey: case *packet.EncryptedKey:
// TODO: add support for multiple keypackets
if encryptedKey != nil && encryptedKey.Key != nil { if encryptedKey != nil && encryptedKey.Key != nil {
break break
} }
encryptedKey = p encryptedKey = p
case *packet.SymmetricallyEncrypted: case *packet.SymmetricallyEncrypted:
// TODO: add support for multiple keypackets outSplit.DataPacket, err = readPacketContents(p.Contents, estimatedLength, garbageCollector)
if err != nil {
return nil, err
}
case *packet.AEADEncrypted:
outSplit.DataPacket, err = readPacketContents(p.Contents, estimatedLength, garbageCollector)
if err != nil {
return nil, err
}
}
}
if encryptedKey == nil {
return nil, errors.New("gopenpgp: packets don't include an encrypted key packet")
}
var buf bytes.Buffer
if err := encryptedKey.Serialize(&buf); err != nil {
return nil, errors.Wrap(err, "gopenpgp: cannot serialize encrypted key")
}
outSplit.KeyPacket = buf.Bytes()
return outSplit, nil
}
func readPacketContents(contents io.Reader, estimatedLength int, garbageCollector int) ([]byte, error) {
gcCounter := 0
var b bytes.Buffer var b bytes.Buffer
// 2^16 is an estimation of the size difference between input and output, the size difference is most probably // 2^16 is an estimation of the size difference between input and output, the size difference is most probably
// 16 bytes at a maximum though. // 16 bytes at a maximum though.
@ -370,7 +394,7 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
actualLength := 1 actualLength := 1
block := make([]byte, 128) block := make([]byte, 128)
for { for {
n, err := p.Contents.Read(block) n, err := contents.Read(block)
if goerrors.Is(err, io.EOF) { if goerrors.Is(err, io.EOF) {
break break
} }
@ -406,20 +430,7 @@ func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int)
symEncryptedData[4] = byte(actualLength >> 8) symEncryptedData[4] = byte(actualLength >> 8)
symEncryptedData[5] = byte(actualLength) symEncryptedData[5] = byte(actualLength)
} }
outSplit.DataPacket = symEncryptedData return symEncryptedData, nil
}
}
if encryptedKey == nil {
return nil, errors.New("gopenpgp: packets don't include an encrypted key packet")
}
var buf bytes.Buffer
if err := encryptedKey.Serialize(&buf); err != nil {
return nil, errors.Wrap(err, "gopenpgp: cannot serialize encrypted key")
}
outSplit.KeyPacket = buf.Bytes()
return outSplit, nil
} }
// GetBinary returns the unarmored binary content of the signature as a []byte. // GetBinary returns the unarmored binary content of the signature as a []byte.

View file

@ -439,3 +439,26 @@ func TestMessageGetArmoredWithEmptyHeaders(t *testing.T) {
assert.NotContains(t, armored, "Version") assert.NotContains(t, armored, "Version")
assert.NotContains(t, armored, "Comment") assert.NotContains(t, armored, "Comment")
} }
func TestPGPSplitMessageFromArmoredWithAEAD(t *testing.T) {
var message = `-----BEGIN PGP MESSAGE-----
hF4DJDxTg/yg6TkSAQdA3Ogzuxwz7IdSRCh81gdYuB0bKqkYDs7EksOkYJ7eUnMw
FsRNg+X3KbCj9j747An4J7V8trghOIN00dlpuR77wELS79XHoP55qmyVyPzmTXdx
1F8BCQIQyGCAxAA1ppydoBVp7ithTEl2bU72tbOsLCFY8TBamG6t3jfqJpO2lz+G
M0xNgvwIDrAQsN35VGw72I/FvWJ0VG3rpBKgFp5nPK0NblRomXTRRfoNgSoVUcxU
vA==
=YNf2
-----END PGP MESSAGE-----
`
split, err := NewPGPSplitMessageFromArmored(message)
if err != nil {
t.Errorf("Couldn't parse split message: %v", err)
}
if split.KeyPacket == nil {
t.Error("Key packet was nil")
}
if split.DataPacket == nil {
t.Error("Data packet was nil")
}
}