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) + } +}