From 5558d4a1770ea46d55c661ff86ebd8e1410eeed2 Mon Sep 17 00:00:00 2001 From: marin thiercelin Date: Thu, 23 Sep 2021 10:40:56 +0200 Subject: [PATCH] Fix: use verifyTime in the config time instead of Now() When decrypting message, we have to use verifyTime in the config otherwise signatures not valid at verifyTime but valid at Now() will be seen as valid. --- CHANGELOG.md | 6 ++++++ crypto/keyring_message.go | 21 +++++++++++++++++-- crypto/keyring_streaming.go | 1 + crypto/keyring_test.go | 42 +++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5d2409..fba4af9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Use the provided `verifyTime` instead of the current time when verifying embedded signatures. + ## [2.2.3] 2021-09-21 ### Changed - Keys are now generated with ZLIB as preferred compression algorithm diff --git a/crypto/keyring_message.go b/crypto/keyring_message.go index d819dad..c625061 100644 --- a/crypto/keyring_message.go +++ b/crypto/keyring_message.go @@ -5,6 +5,7 @@ import ( "crypto" "io" "io/ioutil" + "time" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/packet" @@ -190,6 +191,7 @@ func asymmetricDecrypt( encryptedIO, privateKey, verifyKey, + verifyTime, ) if err != nil { return nil, err @@ -215,7 +217,10 @@ func asymmetricDecrypt( // Core for decryption+verification (all) functions. func asymmetricDecryptStream( - encryptedIO io.Reader, privateKey *KeyRing, verifyKey *KeyRing, + encryptedIO io.Reader, + privateKey *KeyRing, + verifyKey *KeyRing, + verifyTime int64, ) (messageDetails *openpgp.MessageDetails, err error) { privKeyEntries := privateKey.entities var additionalEntries openpgp.EntityList @@ -228,7 +233,19 @@ func asymmetricDecryptStream( privKeyEntries = append(privKeyEntries, additionalEntries...) } - config := &packet.Config{Time: getTimeGenerator()} + config := &packet.Config{ + Time: func() time.Time { + if verifyTime == 0 { + /* + We default to current time while decrypting and verifying + but the caller will remove signature expiration errors later on. + See processSignatureExpiration(). + */ + return getNow() + } + return time.Unix(verifyTime, 0) + }, + } messageDetails, err = openpgp.ReadMessage(encryptedIO, privKeyEntries, nil, config) if err != nil { diff --git a/crypto/keyring_streaming.go b/crypto/keyring_streaming.go index e16be5a..215212a 100644 --- a/crypto/keyring_streaming.go +++ b/crypto/keyring_streaming.go @@ -194,6 +194,7 @@ func (keyRing *KeyRing) DecryptStream( message, keyRing, verifyKeyRing, + verifyTime, ) if err != nil { return nil, err diff --git a/crypto/keyring_test.go b/crypto/keyring_test.go index cbe27e0..a7569ed 100644 --- a/crypto/keyring_test.go +++ b/crypto/keyring_test.go @@ -3,11 +3,13 @@ package crypto import ( "crypto/ed25519" "crypto/rsa" + "errors" "testing" "github.com/stretchr/testify/assert" "github.com/ProtonMail/go-crypto/openpgp/ecdh" + "github.com/ProtonMail/gopenpgp/v2/constants" ) var testSymmetricKey []byte @@ -231,3 +233,43 @@ func TestKeyringCapabilities(t *testing.T) { assert.True(t, keyRingTestMultiple.CanVerify()) assert.True(t, keyRingTestMultiple.CanEncrypt()) } + +func TestVerificationTime(t *testing.T) { + message := NewPlainMessageFromString("Hello") + pgp.latestServerTime = 1632312383 + defer func() { + pgp.latestServerTime = testTime + }() + enc, err := keyRingTestPublic.Encrypt( + message, + keyRingTestPrivate, + ) + + if err != nil { + t.Fatalf("Encryption error: %v", err) + } + _, err = keyRingTestPrivate.Decrypt( + enc, + keyRingTestPublic, + 392039755, + ) + if err == nil { + t.Fatal("No signature error") + } + castedErr := &SignatureVerificationError{} + isType := errors.As(err, castedErr) + if !isType { + t.Fatalf("No signature error %v", err) + } + if castedErr.Status != constants.SIGNATURE_FAILED { + t.Fatalf("Wrong status %v", castedErr) + } + _, err = keyRingTestPrivate.Decrypt( + enc, + keyRingTestPublic, + 0, + ) + if err != nil { + t.Fatalf("Got an error while decrypting %v", err) + } +}