Merge pull request #217 from ProtonMail/feat/signature-notation-data
Add API to add context to detached signatures
This commit is contained in:
commit
5718d2a524
10 changed files with 614 additions and 19 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
|
@ -5,13 +5,23 @@ 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
|
||||
# Changed
|
||||
|
||||
### Added
|
||||
- API for adding context to detached signatures:
|
||||
```go
|
||||
sig, err := keyRing.SignDetachedWithContext(message, context)
|
||||
```
|
||||
- API to verify the context of detached signatures:
|
||||
```go
|
||||
err := keyRing.VerifyDetachedWithContext(message, signature, verifyTime, verificationContext)
|
||||
```
|
||||
### Changed
|
||||
- Update `github.com/ProtonMail/go-crypto` to the latest version
|
||||
- More strictly verify detached signatures: reject detached signatures from revoked and expired keys.
|
||||
- In `GetVerifiedSignatureTimestamp`, use the new `VerifyDetachedSignatureAndHash` function to get the verified signature, instead of parsing the signature packets manually to get the timestamp.
|
||||
|
||||
## [2.5.2] 2022-01-25
|
||||
# Changed
|
||||
### Changed
|
||||
- Update `github.com/ProtonMail/go-crypto` to the latest version
|
||||
|
||||
## [2.5.1] 2022-01-24
|
||||
|
|
|
|||
3
constants/context.go
Normal file
3
constants/context.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
package constants
|
||||
|
||||
const SignatureContextName = "context@proton.ch"
|
||||
|
|
@ -62,12 +62,26 @@ func (keyRing *KeyRing) Decrypt(
|
|||
|
||||
// SignDetached generates and returns a PGPSignature for a given PlainMessage.
|
||||
func (keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, error) {
|
||||
return keyRing.SignDetachedWithContext(message, nil)
|
||||
}
|
||||
|
||||
// SignDetachedWithContext generates and returns a PGPSignature for a given PlainMessage.
|
||||
// If a context is provided, it is added to the signature as notation data
|
||||
// with the name set in `constants.SignatureContextName`.
|
||||
func (keyRing *KeyRing) SignDetachedWithContext(message *PlainMessage, context *SigningContext) (*PGPSignature, error) {
|
||||
signEntity, err := keyRing.getSigningEntity()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &packet.Config{DefaultHash: crypto.SHA512, Time: getTimeGenerator()}
|
||||
var signatureNotations []*packet.Notation
|
||||
if context != nil {
|
||||
signatureNotations = []*packet.Notation{context.getNotation()}
|
||||
}
|
||||
config := &packet.Config{
|
||||
DefaultHash: crypto.SHA512,
|
||||
Time: getTimeGenerator(),
|
||||
SignatureNotations: signatureNotations,
|
||||
}
|
||||
var outBuf bytes.Buffer
|
||||
if message.IsBinary() {
|
||||
err = openpgp.DetachSign(&outBuf, signEntity, message.NewReader(), config)
|
||||
|
|
@ -89,6 +103,22 @@ func (keyRing *KeyRing) VerifyDetached(message *PlainMessage, signature *PGPSign
|
|||
message.NewReader(),
|
||||
signature.GetBinary(),
|
||||
verifyTime,
|
||||
nil,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyDetachedWithContext verifies a PlainMessage with a detached PGPSignature
|
||||
// and returns a SignatureVerificationError if fails.
|
||||
// If a context is provided, it verifies that the signature is valid in the given context, using
|
||||
// the signature notation with name the name set in `constants.SignatureContextName`.
|
||||
func (keyRing *KeyRing) VerifyDetachedWithContext(message *PlainMessage, signature *PGPSignature, verifyTime int64, verificationContext *VerificationContext) error {
|
||||
_, err := verifySignature(
|
||||
keyRing.entities,
|
||||
message.NewReader(),
|
||||
signature.GetBinary(),
|
||||
verifyTime,
|
||||
verificationContext,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -132,6 +162,31 @@ func (keyRing *KeyRing) GetVerifiedSignatureTimestamp(message *PlainMessage, sig
|
|||
message.NewReader(),
|
||||
signature.GetBinary(),
|
||||
verifyTime,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sigPacket.CreationTime.Unix(), nil
|
||||
}
|
||||
|
||||
// GetVerifiedSignatureTimestampWithContext verifies a PlainMessage with a detached PGPSignature
|
||||
// returns the creation time of the signature if it succeeds
|
||||
// and returns a SignatureVerificationError if fails.
|
||||
// If a context is provided, it verifies that the signature is valid in the given context, using
|
||||
// the signature notation with name the name set in `constants.SignatureContextName`.
|
||||
func (keyRing *KeyRing) GetVerifiedSignatureTimestampWithContext(
|
||||
message *PlainMessage,
|
||||
signature *PGPSignature,
|
||||
verifyTime int64,
|
||||
verificationContext *VerificationContext,
|
||||
) (int64, error) {
|
||||
sigPacket, err := verifySignature(
|
||||
keyRing.entities,
|
||||
message.NewReader(),
|
||||
signature.GetBinary(),
|
||||
verifyTime,
|
||||
verificationContext,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -329,6 +329,27 @@ func (keyRing *KeyRing) VerifyDetachedStream(
|
|||
message,
|
||||
signature.GetBinary(),
|
||||
verifyTime,
|
||||
nil,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyDetachedStreamWithContext verifies a message reader with a detached PGPSignature
|
||||
// and returns a SignatureVerificationError if fails.
|
||||
// If a context is provided, it verifies that the signature is valid in the given context, using
|
||||
// the signature notations.
|
||||
func (keyRing *KeyRing) VerifyDetachedStreamWithContext(
|
||||
message Reader,
|
||||
signature *PGPSignature,
|
||||
verifyTime int64,
|
||||
verificationContext *VerificationContext,
|
||||
) error {
|
||||
_, err := verifySignature(
|
||||
keyRing.entities,
|
||||
message,
|
||||
signature.GetBinary(),
|
||||
verifyTime,
|
||||
verificationContext,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,8 +118,96 @@ func verifyDetailsSignature(md *openpgp.MessageDetails, verifierKey *KeyRing) er
|
|||
return nil
|
||||
}
|
||||
|
||||
// SigningContext gives the context that will be
|
||||
// included in the signature's notation data.
|
||||
type SigningContext struct {
|
||||
Value string
|
||||
IsCritical bool
|
||||
}
|
||||
|
||||
// NewSigningContext creates a new signing context.
|
||||
// The value is set to the notation data.
|
||||
// isCritical controls whether the notation is flagged as a critical packet.
|
||||
func NewSigningContext(value string, isCritical bool) *SigningContext {
|
||||
return &SigningContext{Value: value, IsCritical: isCritical}
|
||||
}
|
||||
|
||||
func (context *SigningContext) getNotation() *packet.Notation {
|
||||
return &packet.Notation{
|
||||
Name: constants.SignatureContextName,
|
||||
Value: []byte(context.Value),
|
||||
IsCritical: context.IsCritical,
|
||||
IsHumanReadable: true,
|
||||
}
|
||||
}
|
||||
|
||||
// VerificationContext gives the context that will be
|
||||
// used to verify the signature.
|
||||
type VerificationContext struct {
|
||||
Value string
|
||||
IsRequired bool
|
||||
RequiredAfter int64
|
||||
}
|
||||
|
||||
// NewVerificationContext creates a new verification context.
|
||||
// The value is checked against the signature's notation data.
|
||||
// If isRequired is false, the signature is allowed to have no context set.
|
||||
// If requiredAfter is != 0, the signature is allowed to have no context set if it
|
||||
// was created before the unix time set in requiredAfter.
|
||||
func NewVerificationContext(value string, isRequired bool, requiredAfter int64) *VerificationContext {
|
||||
return &VerificationContext{
|
||||
Value: value,
|
||||
IsRequired: isRequired,
|
||||
RequiredAfter: requiredAfter,
|
||||
}
|
||||
}
|
||||
|
||||
func (context *VerificationContext) isRequiredAtTime(signatureTime time.Time) bool {
|
||||
return context.IsRequired &&
|
||||
(context.RequiredAfter == 0 || signatureTime.After(time.Unix(context.RequiredAfter, 0)))
|
||||
}
|
||||
|
||||
func findContext(notations []*packet.Notation) (string, error) {
|
||||
context := ""
|
||||
for _, notation := range notations {
|
||||
if notation.Name == constants.SignatureContextName {
|
||||
if context != "" {
|
||||
return "", errors.New("gopenpgp: signature has multiple context notations")
|
||||
}
|
||||
if !notation.IsHumanReadable {
|
||||
return "", errors.New("gopenpgp: context notation was not set as human-readable")
|
||||
}
|
||||
context = string(notation.Value)
|
||||
}
|
||||
}
|
||||
return context, nil
|
||||
}
|
||||
|
||||
func (context *VerificationContext) verifyContext(sig *packet.Signature) error {
|
||||
signatureContext, err := findContext(sig.Notations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if signatureContext != context.Value {
|
||||
contextRequired := context.isRequiredAtTime(sig.CreationTime)
|
||||
if contextRequired {
|
||||
return errors.New("gopenpgp: signature did not have the required context")
|
||||
} else if signatureContext != "" {
|
||||
return errors.New("gopenpgp: signature had a wrong context")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifySignature verifies if a signature is valid with the entity list.
|
||||
func verifySignature(pubKeyEntries openpgp.EntityList, origText io.Reader, signature []byte, verifyTime int64) (*packet.Signature, error) {
|
||||
func verifySignature(
|
||||
pubKeyEntries openpgp.EntityList,
|
||||
origText io.Reader,
|
||||
signature []byte,
|
||||
verifyTime int64,
|
||||
verificationContext *VerificationContext,
|
||||
) (*packet.Signature, error) {
|
||||
config := &packet.Config{}
|
||||
if verifyTime == 0 {
|
||||
config.Time = func() time.Time {
|
||||
|
|
@ -130,32 +218,43 @@ func verifySignature(pubKeyEntries openpgp.EntityList, origText io.Reader, signa
|
|||
return time.Unix(verifyTime+internal.CreationTimeOffset, 0)
|
||||
}
|
||||
}
|
||||
|
||||
if verificationContext != nil {
|
||||
config.KnownNotations = map[string]bool{constants.SignatureContextName: true}
|
||||
}
|
||||
signatureReader := bytes.NewReader(signature)
|
||||
|
||||
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 verifyTime == 0 { // Expiration check disabled
|
||||
return sig, nil
|
||||
}
|
||||
err = nil
|
||||
} else {
|
||||
// Maybe the creation time offset pushed it over the edge
|
||||
// Retry with the actual verification time
|
||||
config.Time = func() time.Time {
|
||||
return time.Unix(verifyTime, 0)
|
||||
}
|
||||
|
||||
// Maybe the creation time offset pushed it over the edge
|
||||
// Retry with the actual verification time
|
||||
config.Time = func() time.Time {
|
||||
return time.Unix(verifyTime, 0)
|
||||
}
|
||||
_, err = signatureReader.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, newSignatureFailed()
|
||||
}
|
||||
|
||||
_, err = signatureReader.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, newSignatureFailed()
|
||||
sig, signer, err = openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, origText, signatureReader, allowedHashes, config)
|
||||
}
|
||||
|
||||
sig, signer, err = openpgp.VerifyDetachedSignatureAndHash(pubKeyEntries, origText, signatureReader, allowedHashes, config)
|
||||
}
|
||||
|
||||
if err != nil || sig == nil || signer == nil {
|
||||
return nil, newSignatureFailed()
|
||||
}
|
||||
|
||||
if verificationContext != nil {
|
||||
err := verificationContext.verifyContext(sig)
|
||||
if err != nil {
|
||||
return nil, newSignatureFailed()
|
||||
}
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const testMessage = "Hello world!"
|
||||
|
||||
const signedPlainText = "Signed message\n"
|
||||
|
||||
var textSignature, binSignature *PGPSignature
|
||||
|
|
@ -119,7 +121,7 @@ func TestVerifyBinDetachedSig(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_KeyRing_GetVerifiedSignatureTimestampSuccess(t *testing.T) {
|
||||
message := NewPlainMessageFromString("Hello world!")
|
||||
message := NewPlainMessageFromString(testMessage)
|
||||
var time int64 = 1600000000
|
||||
pgp.latestServerTime = time
|
||||
defer func() {
|
||||
|
|
@ -218,7 +220,7 @@ func getTimestampOfIssuer(signature *PGPSignature, keyID uint64) int64 {
|
|||
}
|
||||
|
||||
func Test_KeyRing_GetVerifiedSignatureTimestampError(t *testing.T) {
|
||||
message := NewPlainMessageFromString("Hello world!")
|
||||
message := NewPlainMessageFromString(testMessage)
|
||||
var time int64 = 1600000000
|
||||
pgp.latestServerTime = time
|
||||
defer func() {
|
||||
|
|
@ -234,3 +236,352 @@ func Test_KeyRing_GetVerifiedSignatureTimestampError(t *testing.T) {
|
|||
t.Errorf("Expected an error while parsing the creation time of a wrong signature, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SignDetachedWithNonCriticalContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
context := NewSigningContext(
|
||||
"test-context",
|
||||
false,
|
||||
)
|
||||
// when
|
||||
signature, err := keyRingTestPrivate.SignDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
context,
|
||||
)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p, err := packet.Read(bytes.NewReader(signature.Data))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, ok := p.(*packet.Signature)
|
||||
if !ok {
|
||||
t.Fatal("Packet was not a signature")
|
||||
}
|
||||
notations := sig.Notations
|
||||
if len(notations) != 1 {
|
||||
t.Fatal("Wrong number of notations")
|
||||
}
|
||||
notation := notations[0]
|
||||
if notation.Name != constants.SignatureContextName {
|
||||
t.Fatalf("Expected notation name to be %s, got %s", constants.SignatureContextName, notation.Name)
|
||||
}
|
||||
if string(notation.Value) != context.Value {
|
||||
t.Fatalf("Expected notation value to be %s, got %s", context.Value, notation.Value)
|
||||
}
|
||||
if notation.IsCritical {
|
||||
t.Fatal("Expected notation to be non critical")
|
||||
}
|
||||
if !notation.IsHumanReadable {
|
||||
t.Fatal("Expected notation to be human readable")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SignDetachedWithCriticalContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
context := NewSigningContext(
|
||||
"test-context",
|
||||
true,
|
||||
)
|
||||
// when
|
||||
signature, err := keyRingTestPrivate.SignDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
context,
|
||||
)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p, err := packet.Read(bytes.NewReader(signature.Data))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, ok := p.(*packet.Signature)
|
||||
if !ok {
|
||||
t.Fatal("Packet was not a signature")
|
||||
}
|
||||
notations := sig.Notations
|
||||
if len(notations) != 1 {
|
||||
t.Fatal("Wrong number of notations")
|
||||
}
|
||||
notation := notations[0]
|
||||
if notation.Name != constants.SignatureContextName {
|
||||
t.Fatalf("Expected notation name to be %s, got %s", constants.SignatureContextName, notation.Name)
|
||||
}
|
||||
if string(notation.Value) != context.Value {
|
||||
t.Fatalf("Expected notation value to be %s, got %s", context.Value, notation.Value)
|
||||
}
|
||||
if !notation.IsCritical {
|
||||
t.Fatal("Expected notation to be critical")
|
||||
}
|
||||
if !notation.IsHumanReadable {
|
||||
t.Fatal("Expected notation to be human readable")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithUnknownCriticalContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/critical_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetached(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
)
|
||||
// then
|
||||
if err == nil || !errors.Is(err, newSignatureFailed()) {
|
||||
t.Fatalf("Expected a verification error")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithUnKnownNonCriticalContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/non_critical_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetached(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no verification error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithKnownCriticalContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/critical_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"test-context",
|
||||
false,
|
||||
0,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no verification error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithWrongContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/critical_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"another-test-context",
|
||||
false,
|
||||
0,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err == nil || !errors.Is(err, newSignatureFailed()) {
|
||||
t.Fatalf("Expected a verification error")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithMissingNonRequiredContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"test-context",
|
||||
false,
|
||||
0,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no verification error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithMissingRequiredContext(t *testing.T) {
|
||||
// given
|
||||
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"test-context",
|
||||
true,
|
||||
0,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err == nil || !errors.Is(err, newSignatureFailed()) {
|
||||
t.Fatalf("Expected a verification error")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithMissingRequiredContextBeforeCutoff(t *testing.T) {
|
||||
// given
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p, err := packet.Read(bytes.NewReader(sig.Data))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sigPacket, ok := p.(*packet.Signature)
|
||||
if !ok {
|
||||
t.Fatal("Packet was not a signature")
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"test-context",
|
||||
true,
|
||||
sigPacket.CreationTime.Unix()+10000,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no verification error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithMissingRequiredContextAfterCutoff(t *testing.T) {
|
||||
// given
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/no_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p, err := packet.Read(bytes.NewReader(sig.Data))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sigPacket, ok := p.(*packet.Signature)
|
||||
if !ok {
|
||||
t.Fatal("Packet was not a signature")
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"test-context",
|
||||
true,
|
||||
sigPacket.CreationTime.Unix()-10000,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err == nil || !errors.Is(err, newSignatureFailed()) {
|
||||
t.Fatalf("Expected a verification error")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifyDetachedWithDoubleContext(t *testing.T) {
|
||||
// given
|
||||
signatureArmored, err := ioutil.ReadFile("testdata/signature/double_critical_context_detached_sig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := NewPGPSignatureFromArmored(string(signatureArmored))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verificationContext := NewVerificationContext(
|
||||
"test-context",
|
||||
true,
|
||||
0,
|
||||
)
|
||||
// when
|
||||
err = keyRingTestPublic.VerifyDetachedWithContext(
|
||||
NewPlainMessage([]byte(testMessage)),
|
||||
sig,
|
||||
0,
|
||||
verificationContext,
|
||||
)
|
||||
// then
|
||||
if err == nil || !errors.Is(err, newSignatureFailed()) {
|
||||
t.Fatalf("Expected a verification error")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
crypto/testdata/signature/critical_context_detached_sig
vendored
Normal file
14
crypto/testdata/signature/critical_context_detached_sig
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GopenPGP 2.5.2
|
||||
Comment: https://gopenpgp.org
|
||||
|
||||
wsCaBAABCgBOBQJkBdTjCZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k
|
||||
JpSAAAAAABEADGNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0AACmMwgAmhVy
|
||||
MIOgqeidOgNUQrOren3m53sA48dO0xmSRMd1HZa4uv5gDDisl+j98l7iawpvnQ1m
|
||||
GqMvvrxyCV66h3W1efjGCW8lbGMKjaSZL4iUteRrAYCfsBq2l7yMDqFn+Kqns9f5
|
||||
c29eh5mSxiGtmJsGSoJVFw7ZfDS+QpIw1yEsdYcyKLqdxmFS5pNQwY8uGuCrPaya
|
||||
4iHLP52kGRt9pTSQTf8flwjb1bjTTJ/dOd3C2AVXtH7NmOgtLeLuc2bT6WKJFPwd
|
||||
BYgCnD0r/6bcRqzqdhcV2lK3WtG1AitH0kKweXhPbtv9OGD36//04zGAeZY7BK8+
|
||||
4J2lzLNX+pYtHPbnRw==
|
||||
=XIJE
|
||||
-----END PGP SIGNATURE-----
|
||||
15
crypto/testdata/signature/double_critical_context_detached_sig
vendored
Normal file
15
crypto/testdata/signature/double_critical_context_detached_sig
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GopenPGP 2.5.2
|
||||
Comment: https://gopenpgp.org
|
||||
|
||||
wsDDBAABCgB3BQJkBd5+CZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k
|
||||
JpSAAAAAABEADGNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0KJSAAAAAABEA
|
||||
DmNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0LTIAAGnMB/9Z9Bd0z9Q6gvBB
|
||||
xxh2v/p9PleBwytUbUMaPrL4gzRsfsKF/9kShY9ZCYpzFeTVtTHGG2C8rEiCPLev
|
||||
01xr3wxVq5N8iyyF9H839qwsAKomkNrqpuAtHHF76uE/vpnqRLQ+2eCiTyOh/BSH
|
||||
syizwNBRaYeVtabZVXGW5ofWFoq/sgmO4Pr63hPiTmhFbIWDOZVadN1rHOVaLBPW
|
||||
mlcxb7vK2FUdcyIpwsQMH9ReDNe2FiCLy/lTWyKFYO43/6VnzHtd5Gn1MXLm2tuN
|
||||
zMTEGii2WFPH8u0e6sQCcmkhJS44J8y2MFv6BKrZKcRpZfzOLPzktBvFg7Q9Pvo3
|
||||
1qxluPe5
|
||||
=KiYX
|
||||
-----END PGP SIGNATURE-----
|
||||
13
crypto/testdata/signature/no_context_detached_sig
vendored
Normal file
13
crypto/testdata/signature/no_context_detached_sig
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GopenPGP 2.5.2
|
||||
Comment: https://gopenpgp.org
|
||||
|
||||
wsBzBAABCgAnBQJkBdkOCZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k
|
||||
AAAwOgf/U+wgABHyfI6Bd/1xPdUyy3FTaEY+Nj8NYi/PKez66OmLubgMEj0DfD7M
|
||||
2P4SL3ZR0Y9iEtCKpncvLtlvA0sss0SZMaXH0bpJZS62cc98gLBuhE9mP1aWUu1u
|
||||
+1AKVIvJKzhJC+MjKrVwMO03JrEb97ZDJylqoF2UvTeQomIY6qo5l4khDeZRVgsn
|
||||
wqmq7+FLGHG75bhrW4dSOCKrNdKwodml/3l4/R8OPhRL6882egXfBtF0i0yhnX2s
|
||||
4watN2OKQE8b9gfkrDWp0vA/hLLXx8IdIiuAkj55Dj6ciVXy6fTfKqcK4/IIX4MO
|
||||
y5KD4MLQbmTja5KoK82mavsbhwXM7A==
|
||||
=k4Xq
|
||||
-----END PGP SIGNATURE-----
|
||||
14
crypto/testdata/signature/non_critical_context_detached_sig
vendored
Normal file
14
crypto/testdata/signature/non_critical_context_detached_sig
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GopenPGP 2.5.2
|
||||
Comment: https://gopenpgp.org
|
||||
|
||||
wsCaBAABCgBOBQJkBdcDCZA+tiWe3yHfJBYhBG6LoimwzMr2li+XlT62JZ7fId8k
|
||||
JhSAAAAAABEADGNvbnRleHRAcHJvdG9uLmNodGVzdC1jb250ZXh0AAAWswgAmtfD
|
||||
vf7yNlc2umZ4p8ddlcQGhkpwQgiTuaYIeJytAytPtzzSAuMUcACeBCXCTt9iXaak
|
||||
ImnZULdBW6T5n/o5zVTVO5yGniOeswpXqERnp+Qmsowjd5fU+XRBnkx0cSVIrVo5
|
||||
tB4gf5nxAnojusQekELnNINd8nXrWYHiDFM+aos+pTxqzWlcJv32LtQ4yuxWSzIL
|
||||
9dJMIpqL+1jk2QI6E+6iTM6NkwNhYjJ7emMGJXyzPmXj4pmpJ1lYo50uHRlwirnI
|
||||
VXcOkUKUwGdibnCjUv+XFoG7Qv2ilDuk/TxTKSjW7ajGjv6KAOde/pOtmpiwcWKi
|
||||
OzIkiswXw5vOtLkrew==
|
||||
=Ub8I
|
||||
-----END PGP SIGNATURE-----
|
||||
Loading…
Add table
Add a link
Reference in a new issue