diff options
Diffstat (limited to 'dsse/verify_test.go')
-rw-r--r-- | dsse/verify_test.go | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/dsse/verify_test.go b/dsse/verify_test.go new file mode 100644 index 0000000..14db088 --- /dev/null +++ b/dsse/verify_test.go @@ -0,0 +1,382 @@ +package dsse + +import ( + "context" + "crypto" + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEnvelopeVerifier_Verify_HandlesNil(t *testing.T) { + verifier, err := NewEnvelopeVerifier(&mockVerifier{}) + assert.NoError(t, err) + + acceptedKeys, err := verifier.Verify(context.TODO(), nil) + assert.Empty(t, acceptedKeys) + assert.EqualError(t, err, "cannot verify a nil envelope") +} + +type mockVerifier struct { + returnErr error +} + +func (m *mockVerifier) Verify(ctx context.Context, data, sig []byte) error { + if m.returnErr != nil { + return m.returnErr + } + return nil +} + +func (m *mockVerifier) KeyID() (string, error) { + return "mock", errors.New("Unsupported keyid") +} + +func (m *mockVerifier) Public() crypto.PublicKey { + return "mock-public" +} + +// Test against the example in the protocol specification: +// https://github.com/secure-systems-lab/dsse/blob/master/protocol.md +func TestVerify(t *testing.T) { + var keyID = "test key 123" + var payloadType = "http://example.com/HelloWorld" + + e := Envelope{ + Payload: "aGVsbG8gd29ybGQ=", + PayloadType: payloadType, + Signatures: []Signature{ + { + KeyID: keyID, + Sig: "Cc3RkvYsLhlaFVd+d6FPx4ZClhqW4ZT0rnCYAfv6/ckoGdwT7g/blWNpOBuL/tZhRiVFaglOGTU8GEjm4aEaNA==", + }, + }, + } + + ev, err := NewEnvelopeVerifier(&mockVerifier{}) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := ev.Verify(context.TODO(), &e) + + // Now verify + assert.Nil(t, err, "unexpected error") + assert.Len(t, acceptedKeys, 1, "unexpected keys") + assert.Equal(t, acceptedKeys[0].KeyID, "", "unexpected keyid") + + // Now try an error + ev, err = NewEnvelopeVerifier(&mockVerifier{returnErr: errors.New("uh oh")}) + assert.Nil(t, err, "unexpected error") + _, err = ev.Verify(context.TODO(), &e) + + // Now verify + assert.Error(t, err) + +} + +func TestVerifyOneProvider(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var ns nilSignerVerifier + signer, err := NewEnvelopeSigner(ns) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(ns) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "unexpected error") + assert.Len(t, acceptedKeys, 1, "unexpected keys") + assert.Equal(t, acceptedKeys[0].KeyID, "nil", "unexpected keyid") +} + +func TestVerifyMultipleProvider(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var ns nilSignerVerifier + var null nullSignerVerifier + signer, err := NewEnvelopeSigner(ns, null) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(ns, null) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "unexpected error") + assert.Len(t, acceptedKeys, 2, "unexpected keys") +} + +func TestVerifyMultipleProviderThreshold(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var ns nilSignerVerifier + var null nullSignerVerifier + signer, err := NewEnvelopeSigner(ns, null) + assert.Nil(t, err) + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewMultiEnvelopeVerifier(2, ns, null) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "unexpected error") + assert.Len(t, acceptedKeys, 2, "unexpected keys") +} + +func TestVerifyMultipleProviderThresholdErr(t *testing.T) { + var ns nilSignerVerifier + var null nullSignerVerifier + _, err := NewMultiEnvelopeVerifier(3, ns, null) + assert.Equal(t, errThreshold, err, "wrong error") + _, err = NewMultiEnvelopeVerifier(0, ns, null) + assert.Equal(t, errThreshold, err, "wrong error") +} + +func TestVerifyErr(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var errsv errSignerVerifier + signer, err := NewEnvelopeSigner(errsv) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(errsv) + assert.Nil(t, err, "unexpected error") + _, err = verifier.Verify(context.TODO(), env) + assert.Equal(t, errVerify, err, "wrong error") +} + +func TestBadVerifier(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var badv badverifier + signer, err := NewEnvelopeSigner(badv) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(badv) + assert.Nil(t, err, "unexpected error") + _, err = verifier.Verify(context.TODO(), env) + assert.NotNil(t, err, "expected error") +} + +func TestVerifyNoSig(t *testing.T) { + var badv badverifier + verifier, err := NewEnvelopeVerifier(badv) + assert.Nil(t, err, "unexpected error") + + env := &Envelope{} + + _, err = verifier.Verify(context.TODO(), env) + assert.Equal(t, ErrNoSignature, err, "wrong error") +} + +func TestVerifyBadBase64(t *testing.T) { + var badv badverifier + verifier, err := NewEnvelopeVerifier(badv) + assert.Nil(t, err, "unexpected error") + + expectedErr := fmt.Errorf("unable to base64 decode payload (is payload in the right format?)") + + t.Run("Payload", func(t *testing.T) { + env := &Envelope{ + Payload: "Not base 64", + Signatures: []Signature{ + {}, + }, + } + + _, err := verifier.Verify(context.TODO(), env) + assert.IsType(t, expectedErr, err, "wrong error") + }) + + t.Run("Signature", func(t *testing.T) { + env := &Envelope{ + Payload: "cGF5bG9hZAo=", + Signatures: []Signature{ + { + Sig: "not base 64", + }, + }, + } + + _, err := verifier.Verify(context.TODO(), env) + assert.IsType(t, expectedErr, err, "wrong error") + }) +} + +func TestVerifyNoMatch(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + + var ns nilSignerVerifier + var null nullSignerVerifier + verifier, err := NewEnvelopeVerifier(ns, null) + assert.Nil(t, err, "unexpected error") + + env := &Envelope{ + PayloadType: payloadType, + Payload: "cGF5bG9hZAo=", + Signatures: []Signature{ + { + KeyID: "not found", + Sig: "cGF5bG9hZAo=", + }, + }, + } + + _, err = verifier.Verify(context.TODO(), env) + assert.NotNil(t, err, "expected error") +} + +type interceptSignerVerifier struct { + keyID string + verifyRes bool + verifyCalled bool +} + +func (i *interceptSignerVerifier) Sign(ctx context.Context, data []byte) ([]byte, error) { + return data, nil +} + +func (i *interceptSignerVerifier) Verify(ctx context.Context, data, sig []byte) error { + i.verifyCalled = true + + if i.verifyRes { + return nil + } + return errVerify +} + +func (i *interceptSignerVerifier) KeyID() (string, error) { + return i.keyID, nil +} + +func (i *interceptSignerVerifier) Public() crypto.PublicKey { + return "intercept-public" +} + +func TestVerifyOneFail(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var s1 = &interceptSignerVerifier{ + keyID: "i1", + verifyRes: true, + } + var s2 = &interceptSignerVerifier{ + keyID: "i2", + verifyRes: false, + } + signer, err := NewEnvelopeSigner(s1, s2) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(s1, s2) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "expected error") + assert.True(t, s1.verifyCalled, "verify not called") + assert.True(t, s2.verifyCalled, "verify not called") + assert.Len(t, acceptedKeys, 1, "unexpected keys") + assert.Equal(t, acceptedKeys[0].KeyID, "i1", "unexpected keyid") +} + +func TestVerifySameKeyID(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var s1 = &interceptSignerVerifier{ + keyID: "i1", + verifyRes: true, + } + var s2 = &interceptSignerVerifier{ + keyID: "i1", + verifyRes: true, + } + signer, err := NewEnvelopeSigner(s1, s2) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(s1, s2) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "expected error") + assert.True(t, s1.verifyCalled, "verify not called") + assert.True(t, s2.verifyCalled, "verify not called") + assert.Len(t, acceptedKeys, 1, "unexpected keys") + assert.Equal(t, acceptedKeys[0].KeyID, "i1", "unexpected keyid") +} + +func TestVerifyEmptyKeyID(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + + var s1 = &interceptSignerVerifier{ + keyID: "", + verifyRes: true, + } + + var s2 = &interceptSignerVerifier{ + keyID: "", + verifyRes: true, + } + + signer, err := NewEnvelopeSigner(s1, s2) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(s1, s2) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "expected error") + assert.Len(t, acceptedKeys, 1, "unexpected keys") + assert.Equal(t, acceptedKeys[0].KeyID, "", "unexpected keyid") +} + +func TestVerifyPublicKeyID(t *testing.T) { + var payloadType = "http://example.com/HelloWorld" + var payload = "hello world" + var keyID = "SHA256:f4AuBLdH4Lj/dIuwAUXXebzoI9B/cJ4iSQ3/qByIl4M" + + var s1 = &ecdsaSignerVerifier{ + keyID: "", + key: newEcdsaKey(), + } + + var s2 = &ecdsaSignerVerifier{ + keyID: "", + key: newEcdsaKey(), + } + + signer, err := NewEnvelopeSigner(s1, s2) + assert.Nil(t, err, "unexpected error") + + env, err := signer.SignPayload(context.TODO(), payloadType, []byte(payload)) + assert.Nil(t, err, "sign failed") + + verifier, err := NewEnvelopeVerifier(s1, s2) + assert.Nil(t, err, "unexpected error") + acceptedKeys, err := verifier.Verify(context.TODO(), env) + assert.Nil(t, err, "expected error") + assert.Len(t, acceptedKeys, 1, "unexpected keys") + assert.Equal(t, acceptedKeys[0].KeyID, keyID, "unexpected keyid") +} |