Skip to content

Commit

Permalink
Reset origText in verifySignature before the retry
Browse files Browse the repository at this point in the history
This is partial fix for ProtonMail#231

Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
  • Loading branch information
DmitriyMV committed Apr 13, 2023
1 parent 2778398 commit 158eba9
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 3 deletions.
14 changes: 12 additions & 2 deletions crypto/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func verifySignature(

sig, signer, err := openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, origText, signatureReader, allowedHashes, config)

if sig != nil && signer != nil && (errors.Is(err, pgpErrors.ErrSignatureExpired) || errors.Is(err, pgpErrors.ErrKeyExpired)) {
if sig != nil && signer != nil && (errors.Is(err, pgpErrors.ErrSignatureExpired) || errors.Is(err, pgpErrors.ErrKeyExpired)) { //nolint:nestif
if verifyTime == 0 { // Expiration check disabled
err = nil
} else {
Expand All @@ -261,12 +261,22 @@ func verifySignature(
return time.Unix(verifyTime, 0)
}

seeker, ok := origText.(io.ReadSeeker)
if !ok {
return nil, errors.Wrap(err, "gopenpgp: message reader do not support seeking, cannot retry signature verification")
}

_, err = seeker.Seek(0, io.SeekStart)
if err != nil {
return nil, newSignatureFailed(errors.Wrap(err, "gopenpgp: could not rewind the data reader."))
}

_, err = signatureReader.Seek(0, io.SeekStart)
if err != nil {
return nil, newSignatureFailed(err)
}

sig, signer, err = openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, origText, signatureReader, allowedHashes, config)
sig, signer, err = openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, seeker, signatureReader, allowedHashes, config)
}
}

Expand Down
55 changes: 54 additions & 1 deletion crypto/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ package crypto

import (
"bytes"
"crypto"
"errors"
"io"
"io/ioutil"
"regexp"
"testing"
"time"

"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/ProtonMail/gopenpgp/v2/constants"
"github.com/stretchr/testify/assert"

"github.com/ProtonMail/gopenpgp/v2/constants"
)

const testMessage = "Hello world!"
Expand Down Expand Up @@ -610,3 +614,52 @@ func Test_VerifyDetachedWithDoubleContext(t *testing.T) {
// then
checkVerificationError(t, err, constants.SIGNATURE_BAD_CONTEXT)
}

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

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

cfg := &packet.Config{
Algorithm: packet.PubKeyAlgoEdDSA,
DefaultHash: crypto.SHA256,
DefaultCipher: packet.CipherAES256,
DefaultCompressionAlgo: packet.CompressionZLIB,
KeyLifetimeSecs: lifetime,
SigLifetimeSecs: lifetime,
}

entity, err := openpgp.NewEntity("John Smith", "Linux", "john.smith@example.com", cfg)
if err != nil {
t.Fatal(err)
}

key, err := NewKeyFromEntity(entity)
if err != nil {
t.Fatal(err)
}

keyRing, err := NewKeyRing(key)
if err != nil {
t.Fatal(err)
}

data := []byte("Hello, World!")
message := NewPlainMessage(data)

signature, err := keyRing.SignDetached(message)
if err != nil {
t.Fatalf("%#+v", err)
}

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)
if err != nil {
t.Fatal(err)
}
}

0 comments on commit 158eba9

Please sign in to comment.