From 9ec011c88727eb078cbc96271f13d1dfec78071c Mon Sep 17 00:00:00 2001 From: knQzx <75641500+knQzx@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:04:44 +0200 Subject: [PATCH] reject too short decrypted session key --- openpgp/packet/encrypted_key.go | 6 +++ openpgp/packet/encrypted_key_security_test.go | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 openpgp/packet/encrypted_key_security_test.go diff --git a/openpgp/packet/encrypted_key.go b/openpgp/packet/encrypted_key.go index c544d0f0..dab70557 100644 --- a/openpgp/packet/encrypted_key.go +++ b/openpgp/packet/encrypted_key.go @@ -215,12 +215,18 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: keyOffset := 0 if e.Version < 6 { + if len(b) < 3 { + return errors.StructuralError("v3 session key is too short") + } e.CipherFunc = CipherFunction(b[0]) keyOffset = 1 if !e.CipherFunc.IsSupported() { return errors.UnsupportedError("unsupported encryption function") } } + if len(b[keyOffset:]) < 2 { + return errors.StructuralError("session key is too short") + } key, err = decodeChecksumKey(b[keyOffset:]) case PubKeyAlgoX25519, PubKeyAlgoX448, PubKeyAlgoMlkem768X25519, PubKeyAlgoMlkem1024X448: if e.Version < 6 { diff --git a/openpgp/packet/encrypted_key_security_test.go b/openpgp/packet/encrypted_key_security_test.go new file mode 100644 index 00000000..8b265224 --- /dev/null +++ b/openpgp/packet/encrypted_key_security_test.go @@ -0,0 +1,45 @@ +package packet + +import ( + "crypto" + "crypto/rsa" + "io" + "testing" + + "github.com/ProtonMail/go-crypto/openpgp/internal/encoding" +) + +type emptySessionKeyDecrypter struct { + pub *rsa.PublicKey +} + +func (d emptySessionKeyDecrypter) Public() crypto.PublicKey { + return d.pub +} + +func (d emptySessionKeyDecrypter) Decrypt(io.Reader, []byte, crypto.DecrypterOpts) ([]byte, error) { + return []byte{}, nil +} + +func TestDecryptEmptySessionKeyNoPanic(t *testing.T) { + pub := &encryptedKeyPub + priv := &PrivateKey{ + PublicKey: PublicKey{ + PubKeyAlgo: PubKeyAlgoRSA, + KeyId: 0, + }, + PrivateKey: emptySessionKeyDecrypter{pub}, + } + + e := &EncryptedKey{ + Version: 3, + KeyId: 0, + Algo: PubKeyAlgoRSA, + encryptedMPI1: encoding.NewMPI(pub.N.Bytes()), + } + + err := e.Decrypt(priv, nil) + if err == nil { + t.Fatal("expected an error for empty decrypted session key, got nil") + } +}