Skip to content

Commit

Permalink
Cleanup fixed time and allow using time offset for crypto operations
Browse files Browse the repository at this point in the history
  • Loading branch information
KaQuMiQ committed May 9, 2023
1 parent d37f4eb commit 7dc9328
Show file tree
Hide file tree
Showing 19 changed files with 119 additions and 113 deletions.
4 changes: 2 additions & 2 deletions crypto/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (keyRing *KeyRing) newAttachmentProcessor(

config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Time: getTimeGenerator(),
Time: GetTime,
}

reader, writer := io.Pipe()
Expand Down Expand Up @@ -163,7 +163,7 @@ func (keyRing *KeyRing) DecryptAttachment(message *PGPSplitMessage) (*PlainMessa

encryptedReader := io.MultiReader(keyReader, dataReader)

config := &packet.Config{Time: getTimeGenerator()}
config := &packet.Config{Time: GetTime}

md, err := openpgp.ReadMessage(encryptedReader, privKeyEntries, nil, config)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion crypto/attachment_manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (keyRing *KeyRing) NewManualAttachmentProcessor(
// encryption config
config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Time: getTimeGenerator(),
Time: GetTime,
}

// goroutine that reads the key packet
Expand Down
14 changes: 8 additions & 6 deletions crypto/attachment_manual_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (
)

func TestManualAttachmentProcessor(t *testing.T) {
pgp.latestServerTime = 1615394034
defer func() { pgp.latestServerTime = testTime }()
defer SetFixedTime(testTime)
SetFixedTime(1615394034)

passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS")
pk, err := NewKeyFromArmored(readTestFile("att_key", false))
if err != nil {
Expand Down Expand Up @@ -86,8 +87,8 @@ func TestManualAttachmentProcessor(t *testing.T) {
}

func TestManualAttachmentProcessorNotEnoughBuffer(t *testing.T) {
pgp.latestServerTime = 1615394034
defer func() { pgp.latestServerTime = testTime }()
defer SetFixedTime(testTime)
SetFixedTime(1615394034)
passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS")
pk, err := NewKeyFromArmored(readTestFile("att_key", false))
if err != nil {
Expand Down Expand Up @@ -141,8 +142,9 @@ func TestManualAttachmentProcessorNotEnoughBuffer(t *testing.T) {
}

func TestManualAttachmentProcessorEmptyBuffer(t *testing.T) {
pgp.latestServerTime = 1615394034
defer func() { pgp.latestServerTime = testTime }()
defer SetFixedTime(testTime)
SetFixedTime(1615394034)

passphrase := []byte("wUMuF/lkDPYWH/0ZqqY8kJKw7YJg6kS")
pk, err := NewKeyFromArmored(readTestFile("att_key", false))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion crypto/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func readTestFile(name string, trimNewlines bool) string {
}

func init() {
UpdateTime(testTime) // 2019-05-13T13:37:07+00:00
SetFixedTime(testTime) // 2019-05-13T13:37:07+00:00

initGenerateKeys()
initArmoredKeys()
Expand Down
12 changes: 6 additions & 6 deletions crypto/gopenpgp.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import "sync"
// GopenPGP is used as a "namespace" for many of the functions in this package.
// It is a struct that keeps track of time skew between server and client.
type GopenPGP struct {
latestServerTime int64
generationOffset int64
lock *sync.RWMutex
fixedTime int64
timeOffset int64
lock *sync.RWMutex
}

var pgp = GopenPGP{
latestServerTime: 0,
generationOffset: 0,
lock: &sync.RWMutex{},
fixedTime: 0,
timeOffset: 0,
lock: &sync.RWMutex{},
}

// clone returns a clone of the byte slice. Internal function used to make sure
Expand Down
12 changes: 6 additions & 6 deletions crypto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,26 +264,26 @@ func (key *Key) GetPublicKey() (b []byte, err error) {

// CanVerify returns true if any of the subkeys can be used for verification.
func (key *Key) CanVerify() bool {
_, canVerify := key.entity.SigningKey(getNow())
_, canVerify := key.entity.SigningKey(GetTime())
return canVerify
}

// CanEncrypt returns true if any of the subkeys can be used for encryption.
func (key *Key) CanEncrypt() bool {
_, canEncrypt := key.entity.EncryptionKey(getNow())
_, canEncrypt := key.entity.EncryptionKey(GetTime())
return canEncrypt
}

// IsExpired checks whether the key is expired.
func (key *Key) IsExpired() bool {
i := key.entity.PrimaryIdentity()
return key.entity.PrimaryKey.KeyExpired(i.SelfSignature, getNow()) || // primary key has expired
i.SelfSignature.SigExpired(getNow()) // user ID self-signature has expired
return key.entity.PrimaryKey.KeyExpired(i.SelfSignature, GetTime()) || // primary key has expired
i.SelfSignature.SigExpired(GetTime()) // user ID self-signature has expired
}

// IsRevoked checks whether the key or the primary identity has a valid revocation signature.
func (key *Key) IsRevoked() bool {
return key.entity.Revoked(getNow()) || key.entity.PrimaryIdentity().Revoked(getNow())
return key.entity.Revoked(GetTime()) || key.entity.PrimaryIdentity().Revoked(GetTime())
}

// IsPrivate returns true if the key is private.
Expand Down Expand Up @@ -447,7 +447,7 @@ func generateKey(
cfg := &packet.Config{
Algorithm: packet.PubKeyAlgoRSA,
RSABits: bits,
Time: getKeyGenerationTimeGenerator(),
Time: GetTime,
DefaultHash: crypto.SHA256,
DefaultCipher: packet.CipherAES256,
DefaultCompressionAlgo: packet.CompressionZLIB,
Expand Down
26 changes: 22 additions & 4 deletions crypto/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,26 @@ func TestIsExpired(t *testing.T) {
assert.Exactly(t, true, futureKey.IsExpired())
}

func TestGeneratedWithOffset(t *testing.T) {
defer SetFixedTime(testTime)
SetFixedTime(0)
defer SetTimeOffset(0)
var timeOffset int64 = 30
SetTimeOffset(timeOffset)

// generate key with offset
keyTestRSA, err := GenerateKey(keyTestName, keyTestDomain, "rsa", 1024)
if err != nil {
panic("Cannot generate RSA key:" + err.Error())
}

// Bring back offset to zero
SetTimeOffset(0)

// Verify if key was generated with offset but lower by 1 sec to compensate time passing in test
assert.GreaterOrEqual(t, keyTestRSA.entity.PrimaryKey.CreationTime.Unix(), GetUnixTime()+timeOffset-1)
}

func TestGenerateKeyWithPrimes(t *testing.T) {
prime1, _ := base64.StdEncoding.DecodeString(
"/thF8zjjk6fFx/y9NId35NFx8JTA7jvHEl+gI0dp9dIl9trmeZb+ESZ8f7bNXUmTI8j271kyenlrVJiqwqk80Q==")
Expand Down Expand Up @@ -418,10 +438,8 @@ func TestKeyCapabilities(t *testing.T) {
}

func TestRevokedKeyCapabilities(t *testing.T) {
pgp.latestServerTime = 1632219895
defer func() {
pgp.latestServerTime = testTime
}()
defer SetFixedTime(testTime)
SetFixedTime(1632219895)

revokedKey, err := NewKeyFromArmored(readTestFile("key_revoked", false))
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions crypto/keyring_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func asymmetricEncryptStream(
) (encryptWriter io.WriteCloser, err error) {
config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Time: getTimeGenerator(),
Time: GetTime,
}

if compress {
Expand Down Expand Up @@ -337,7 +337,7 @@ func asymmetricDecryptStream(
but the caller will remove signature expiration errors later on.
See processSignatureExpiration().
*/
return getNow()
return GetTime()
}
return time.Unix(verifyTime, 0)
},
Expand Down
2 changes: 1 addition & 1 deletion crypto/keyring_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (keyRing *KeyRing) EncryptSessionKey(sk *SessionKey) ([]byte, error) {

pubKeys := make([]*packet.PublicKey, 0, len(keyRing.entities))
for _, e := range keyRing.entities {
encryptionKey, ok := e.EncryptionKey(getNow())
encryptionKey, ok := e.EncryptionKey(GetTime())
if !ok {
return nil, errors.New("gopenpgp: encryption key is unavailable for key id " + strconv.FormatUint(e.PrimaryKey.KeyId, 16))
}
Expand Down
7 changes: 3 additions & 4 deletions crypto/keyring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,10 @@ func TestKeyringCapabilities(t *testing.T) {
}

func TestVerificationTime(t *testing.T) {
defer SetFixedTime(testTime)
SetFixedTime(1632312383)
message := NewPlainMessageFromString("Hello")
pgp.latestServerTime = 1632312383
defer func() {
pgp.latestServerTime = testTime
}()

enc, err := keyRingTestPublic.Encrypt(
message,
keyRingTestPrivate,
Expand Down
10 changes: 4 additions & 6 deletions crypto/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,8 @@ func TestBinaryMessageEncryption(t *testing.T) {
}

func TestIssue11(t *testing.T) {
pgp.latestServerTime = 1559655272
defer func() {
pgp.latestServerTime = testTime
}()
defer SetFixedTime(testTime)
SetFixedTime(1559655272)

var issue11Password = []byte("1234")

Expand Down Expand Up @@ -258,8 +256,8 @@ func TestIssue11(t *testing.T) {
}

func TestDummy(t *testing.T) {
pgp.latestServerTime = 1636644417
defer func() { pgp.latestServerTime = testTime }()
defer SetFixedTime(testTime)
SetFixedTime(1636644417)

dummyKey, err := NewKeyFromArmored(readTestFile("key_dummy", false))
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion crypto/mime.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ func parseMIME(
if err != nil {
return nil, nil, nil, errors.Wrap(err, "gopenpgp: error in reading message")
}
config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: getTimeGenerator()}
config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Time: GetTime,
}

h := textproto.MIMEHeader(mm.Header)
mmBodyData, err := ioutil.ReadAll(mm.Body)
Expand Down
5 changes: 3 additions & 2 deletions crypto/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func EncryptSessionKeyWithPassword(sk *SessionKey, password []byte) ([]byte, err

config := &packet.Config{
DefaultCipher: cf,
Time: GetTime,
}

err = packet.SerializeSymmetricKeyEncryptedReuseKey(outbuf, sk.Key, password, config)
Expand All @@ -109,7 +110,7 @@ func passwordEncrypt(message *PlainMessage, password []byte) ([]byte, error) {

config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Time: getTimeGenerator(),
Time: GetTime,
}

hints := &openpgp.FileHints{
Expand Down Expand Up @@ -148,7 +149,7 @@ func passwordDecrypt(encryptedIO io.Reader, password []byte) (*PlainMessage, err
}

config := &packet.Config{
Time: getTimeGenerator(),
Time: GetTime,
}

var emptyKeyRing openpgp.EntityList
Expand Down
9 changes: 6 additions & 3 deletions crypto/sessionkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ func (sk *SessionKey) GetBase64Key() string {

// RandomToken generates a random token with the specified key size.
func RandomToken(size int) ([]byte, error) {
config := &packet.Config{DefaultCipher: packet.CipherAES256}
config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Time: GetTime,
}
symKey := make([]byte, size)
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in generating random token")
Expand Down Expand Up @@ -225,7 +228,7 @@ func encryptStreamWithSessionKey(
}

config := &packet.Config{
Time: getTimeGenerator(),
Time: GetTime,
DefaultCipher: dc,
}

Expand Down Expand Up @@ -426,7 +429,7 @@ func decryptStreamWithSessionKey(
}

config := &packet.Config{
Time: getTimeGenerator(),
Time: GetTime,
}

if verificationContext != nil {
Expand Down
2 changes: 1 addition & 1 deletion crypto/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func signMessageDetached(
) (*PGPSignature, error) {
config := &packet.Config{
DefaultHash: crypto.SHA512,
Time: getTimeGenerator(),
Time: GetTime,
}

signEntity, err := signKeyRing.getSigningEntity()
Expand Down
35 changes: 14 additions & 21 deletions crypto/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,11 @@ func TestVerifyBinDetachedSig(t *testing.T) {
}

func Test_KeyRing_GetVerifiedSignatureTimestampSuccess(t *testing.T) {
message := NewPlainMessageFromString(testMessage)
defer SetFixedTime(testTime)
var time int64 = 1600000000
pgp.latestServerTime = time
defer func() {
pgp.latestServerTime = testTime
}()
SetFixedTime(time)
message := NewPlainMessageFromString(testMessage)

signature, err := keyRingTestPrivate.SignDetached(message)
if err != nil {
t.Errorf("Got an error while generating the signature: %v", err)
Expand All @@ -159,12 +158,10 @@ func Test_KeyRing_GetVerifiedSignatureTimestampSuccess(t *testing.T) {
}

func Test_KeyRing_GetVerifiedSignatureTimestampWithContext(t *testing.T) {
message := NewPlainMessageFromString(testMessage)
defer SetFixedTime(testTime)
var time int64 = 1600000000
pgp.latestServerTime = time
defer func() {
pgp.latestServerTime = testTime
}()
SetFixedTime(time)
message := NewPlainMessageFromString(testMessage)
var testContext = "test-context"
signature, err := keyRingTestPrivate.SignDetachedWithContext(message, NewSigningContext(testContext, true))
if err != nil {
Expand Down Expand Up @@ -259,12 +256,10 @@ func getTimestampOfIssuer(signature *PGPSignature, keyID uint64) int64 {
}

func Test_KeyRing_GetVerifiedSignatureTimestampError(t *testing.T) {
message := NewPlainMessageFromString(testMessage)
defer SetFixedTime(testTime)
var time int64 = 1600000000
pgp.latestServerTime = time
defer func() {
pgp.latestServerTime = testTime
}()
SetFixedTime(time)
message := NewPlainMessageFromString(testMessage)
signature, err := keyRingTestPrivate.SignDetached(message)
if err != nil {
t.Errorf("Got an error while generating the signature: %v", err)
Expand Down Expand Up @@ -616,12 +611,13 @@ func Test_VerifyDetachedWithDoubleContext(t *testing.T) {
}

func Test_verifySignaturExpire(t *testing.T) {
defer func(t int64) { pgp.latestServerTime = t }(pgp.latestServerTime)
pgp.latestServerTime = 0
defer SetFixedTime(testTime)
SetFixedTime(0)

const lifetime = uint32(time.Hour / time.Second)

cfg := &packet.Config{
Time: GetTime,
Algorithm: packet.PubKeyAlgoEdDSA,
DefaultHash: crypto.SHA256,
DefaultCipher: packet.CipherAES256,
Expand Down Expand Up @@ -655,10 +651,7 @@ func Test_verifySignaturExpire(t *testing.T) {

sig := NewPGPSignature(signature.GetBinary())

// packet.PublicKey.KeyExpired will return false here because PublicKey CreationTime has
// nanosecond precision, while pgpcrypto.GetUnixTime() has only second precision.
// Adjust the check time to be in the future to ensure that the key is not expired.
err = keyRing.VerifyDetached(message, sig, GetUnixTime()+1)
err = keyRing.VerifyDetached(message, sig, GetUnixTime())
if err != nil {
t.Fatal(err)
}
Expand Down
Loading

0 comments on commit 7dc9328

Please sign in to comment.