blob: b070cc4c4f218d9b57fcd16a9ebb1995d1ce8257 [file] [log] [blame]
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package signature_test
import (
"bytes"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/proto"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/insecurecleartextkeyset"
"github.com/google/tink/go/internal/internalregistry"
"github.com/google/tink/go/internal/testing/stubkeymanager"
"github.com/google/tink/go/keyset"
"github.com/google/tink/go/mac"
"github.com/google/tink/go/monitoring"
"github.com/google/tink/go/signature"
"github.com/google/tink/go/subtle/random"
"github.com/google/tink/go/testing/fakemonitoring"
"github.com/google/tink/go/testkeyset"
"github.com/google/tink/go/testutil"
commonpb "github.com/google/tink/go/proto/common_go_proto"
tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)
func TestSignerVerifyFactory(t *testing.T) {
tinkPriv, tinkPub := newECDSAKeysetKeypair(commonpb.HashType_SHA512,
commonpb.EllipticCurveType_NIST_P521,
tinkpb.OutputPrefixType_TINK,
1)
legacyPriv, legacyPub := newECDSAKeysetKeypair(commonpb.HashType_SHA256,
commonpb.EllipticCurveType_NIST_P256,
tinkpb.OutputPrefixType_LEGACY,
2)
rawPriv, rawPub := newECDSAKeysetKeypair(commonpb.HashType_SHA512,
commonpb.EllipticCurveType_NIST_P384,
tinkpb.OutputPrefixType_RAW,
3)
crunchyPriv, crunchyPub := newECDSAKeysetKeypair(commonpb.HashType_SHA512,
commonpb.EllipticCurveType_NIST_P384,
tinkpb.OutputPrefixType_CRUNCHY,
4)
privKeys := []*tinkpb.Keyset_Key{tinkPriv, legacyPriv, rawPriv, crunchyPriv}
privKeyset := testutil.NewKeyset(privKeys[0].KeyId, privKeys)
privKeysetHandle, _ := testkeyset.NewHandle(privKeyset)
pubKeys := []*tinkpb.Keyset_Key{tinkPub, legacyPub, rawPub, crunchyPub}
pubKeyset := testutil.NewKeyset(pubKeys[0].KeyId, pubKeys)
pubKeysetHandle, err := testkeyset.NewHandle(pubKeyset)
if err != nil {
t.Fatalf("testkeyset.NewHandle(pubKeyset) err = %v, want nil", err)
}
// sign some random data
signer, err := signature.NewSigner(privKeysetHandle)
if err != nil {
t.Fatalf("signature.NewSigner(privKeysetHandle) err = %v, want nil", err)
}
data := random.GetRandomBytes(1211)
sig, err := signer.Sign(data)
if err != nil {
t.Fatalf("signer.Sign(data) err = %v, want nil", err)
}
// verify with the same set of public keys should work
verifier, err := signature.NewVerifier(pubKeysetHandle)
if err != nil {
t.Fatalf("signature.NewVerifier(pubKeysetHandle) err = %v, want nil", err)
}
if err := verifier.Verify(sig, data); err != nil {
t.Errorf("verifier.Verify(sig, data) = %v, want nil", err)
}
// verify with other key should fail
_, otherPub := newECDSAKeysetKeypair(commonpb.HashType_SHA512,
commonpb.EllipticCurveType_NIST_P521,
tinkpb.OutputPrefixType_TINK,
1)
otherPubKeys := []*tinkpb.Keyset_Key{otherPub}
otherPubKeyset := testutil.NewKeyset(otherPubKeys[0].KeyId, otherPubKeys)
otherPubKeysetHandle, err := testkeyset.NewHandle(otherPubKeyset)
if err != nil {
t.Fatalf("testkeyset.NewHandle(otherPubKeyset) err = %v, want nil", err)
}
otherVerifier, err := signature.NewVerifier(otherPubKeysetHandle)
if err != nil {
t.Fatalf("signature.NewVerifier(otherPubKeysetHandle) err = %v, want nil", err)
}
if err = otherVerifier.Verify(sig, data); err == nil {
t.Error("otherVerifier.Verify(sig, data) = nil, want not nil")
}
}
func TestPrimitiveFactoryFailsWhenKeysetHasNoPrimary(t *testing.T) {
privateKey, _ := newECDSAKeysetKeypair(commonpb.HashType_SHA512,
commonpb.EllipticCurveType_NIST_P521,
tinkpb.OutputPrefixType_TINK,
1)
privateKeysetWithoutPrimary := &tinkpb.Keyset{
Key: []*tinkpb.Keyset_Key{privateKey},
}
privateHandleWithoutPrimary, err := testkeyset.NewHandle(privateKeysetWithoutPrimary)
if err != nil {
t.Fatalf("testkeyset.NewHandle(privateKeysetWithoutPrimary) err = %v, want nil", err)
}
publicHandleWithoutPrimary, err := privateHandleWithoutPrimary.Public()
if err != nil {
t.Fatalf("privateHandleWithoutPrimary.Public() err = %v, want nil", err)
}
if _, err = signature.NewSigner(privateHandleWithoutPrimary); err == nil {
t.Errorf("signature.NewSigner(privateHandleWithoutPrimary) err = nil, want not nil")
}
if _, err = signature.NewVerifier(publicHandleWithoutPrimary); err == nil {
t.Errorf("signature.NewVerifier(publicHandleWithoutPrimary) err = nil, want not nil")
}
}
func newECDSAKeysetKeypair(hashType commonpb.HashType, curve commonpb.EllipticCurveType, outputPrefixType tinkpb.OutputPrefixType, keyID uint32) (*tinkpb.Keyset_Key, *tinkpb.Keyset_Key) {
key := testutil.NewRandomECDSAPrivateKey(hashType, curve)
serializedKey, _ := proto.Marshal(key)
keyData := testutil.NewKeyData(testutil.ECDSASignerTypeURL,
serializedKey,
tinkpb.KeyData_ASYMMETRIC_PRIVATE)
privKey := testutil.NewKey(keyData, tinkpb.KeyStatusType_ENABLED, keyID, outputPrefixType)
serializedKey, _ = proto.Marshal(key.PublicKey)
keyData = testutil.NewKeyData(testutil.ECDSAVerifierTypeURL,
serializedKey,
tinkpb.KeyData_ASYMMETRIC_PUBLIC)
pubKey := testutil.NewKey(keyData, tinkpb.KeyStatusType_ENABLED, keyID, outputPrefixType)
return privKey, pubKey
}
func TestFactoryWithInvalidPrimitiveSetType(t *testing.T) {
wrongKH, err := keyset.NewHandle(mac.HMACSHA256Tag128KeyTemplate())
if err != nil {
t.Fatalf("keyset.NewHandle(mac.HMACSHA256Tag128KeyTemplate()) err = %v, want nil", err)
}
_, err = signature.NewSigner(wrongKH)
if err == nil {
t.Error("signature.NewSigner(wrongKH) err = nil, want not nil")
}
_, err = signature.NewVerifier(wrongKH)
if err == nil {
t.Error("signature.NewVerifier(wrongKH) err = nil, want not nil")
}
}
func TestFactoryWithValidPrimitiveSetType(t *testing.T) {
goodKH, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate())
if err != nil {
t.Fatalf("keyset.NewHandle(signature.ECDSAP256KeyTemplate()) err = %v, want nil", err)
}
_, err = signature.NewSigner(goodKH)
if err != nil {
t.Fatalf("signature.NewSigner(goodKH) err = %v, want nil", err)
}
goodPublicKH, err := goodKH.Public()
if err != nil {
t.Fatalf("goodKH.Public() err = %v, want nil", err)
}
_, err = signature.NewVerifier(goodPublicKH)
if err != nil {
t.Errorf("signature.NewVerifier(goodPublicKH) err = %v, want nil", err)
}
}
func TestPrimitiveFactorySignVerifyWithoutAnnotationsDoesNothing(t *testing.T) {
defer internalregistry.ClearMonitoringClient()
client := fakemonitoring.NewClient("fake-client")
if err := internalregistry.RegisterMonitoringClient(client); err != nil {
t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err)
}
privHandle, err := keyset.NewHandle(signature.ED25519KeyTemplate())
if err != nil {
t.Fatalf("keyset.NewHandle() err = %v, want nil", err)
}
signer, err := signature.NewSigner(privHandle)
if err != nil {
t.Fatalf("signature.NewSigner() err = %v, want nil", err)
}
pubHandle, err := privHandle.Public()
if err != nil {
t.Fatalf("privHandle.Public() err = %v, want nil", err)
}
verifier, err := signature.NewVerifier(pubHandle)
if err != nil {
t.Fatalf("signature.NewVerifier() err = %v, want nil", err)
}
data := []byte("some_important_data")
sig, err := signer.Sign(data)
if err != nil {
t.Fatalf("signer.Sign() err = %v, want nil", err)
}
if err := verifier.Verify(sig, data); err != nil {
t.Fatalf("verifier.Verify() err = %v, want nil", err)
}
if len(client.Events()) != 0 {
t.Errorf("len(client.Events()) = %d, want 0", len(client.Events()))
}
if len(client.Failures()) != 0 {
t.Errorf("len(client.Failures()) = %d, want 0", len(client.Failures()))
}
}
func TestPrimitiveFactoryMonitoringWithAnnotationsLogSignVerify(t *testing.T) {
defer internalregistry.ClearMonitoringClient()
client := fakemonitoring.NewClient("fake-client")
if err := internalregistry.RegisterMonitoringClient(client); err != nil {
t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err)
}
handle, err := keyset.NewHandle(signature.ED25519KeyTemplate())
if err != nil {
t.Fatalf("keyset.NewHandle() err = %v, want nil", err)
}
buff := &bytes.Buffer{}
if err := insecurecleartextkeyset.Write(handle, keyset.NewBinaryWriter(buff)); err != nil {
t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err)
}
annotations := map[string]string{"foo": "bar"}
privHandle, err := insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations))
if err != nil {
t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err)
}
signer, err := signature.NewSigner(privHandle)
if err != nil {
t.Fatalf("signature.NewSigner() err = %v, want nil", err)
}
pubHandle, err := privHandle.Public()
if err != nil {
t.Fatalf("privHandle.Public() err = %v, want nil", err)
}
buff.Reset()
if err := insecurecleartextkeyset.Write(pubHandle, keyset.NewBinaryWriter(buff)); err != nil {
t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err)
}
pubHandle, err = insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations))
if err != nil {
t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err)
}
verifier, err := signature.NewVerifier(pubHandle)
if err != nil {
t.Fatalf("signature.NewVerifier() err = %v, want nil", err)
}
data := []byte("some_important_data")
sig, err := signer.Sign(data)
if err != nil {
t.Fatalf("signer.Sign() err = %v, want nil", err)
}
if err := verifier.Verify(sig, data); err != nil {
t.Fatalf("verifier.Verify() err = %v, want nil", err)
}
if len(client.Failures()) != 0 {
t.Errorf("len(client.Failures()) = %d, want 0", len(client.Failures()))
}
got := client.Events()
wantVerifyKeysetInfo := &monitoring.KeysetInfo{
Annotations: annotations,
PrimaryKeyID: pubHandle.KeysetInfo().GetPrimaryKeyId(),
Entries: []*monitoring.Entry{
{
KeyID: pubHandle.KeysetInfo().GetPrimaryKeyId(),
Status: monitoring.Enabled,
KeyType: "tink.Ed25519PublicKey",
KeyPrefix: "TINK",
},
},
}
wantSignKeysetInfo := &monitoring.KeysetInfo{
Annotations: annotations,
PrimaryKeyID: privHandle.KeysetInfo().GetPrimaryKeyId(),
Entries: []*monitoring.Entry{
{
KeyID: privHandle.KeysetInfo().GetPrimaryKeyId(),
Status: monitoring.Enabled,
KeyType: "tink.Ed25519PrivateKey",
KeyPrefix: "TINK",
},
},
}
want := []*fakemonitoring.LogEvent{
{
Context: monitoring.NewContext("public_key_sign", "sign", wantSignKeysetInfo),
KeyID: privHandle.KeysetInfo().GetPrimaryKeyId(),
NumBytes: len(data),
},
{
Context: monitoring.NewContext("public_key_verify", "verify", wantVerifyKeysetInfo),
KeyID: privHandle.KeysetInfo().GetPrimaryKeyId(),
NumBytes: len(data),
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("%v", diff)
}
}
type alwaysFailingSigner struct{}
func (a *alwaysFailingSigner) Sign(data []byte) ([]byte, error) { return nil, fmt.Errorf("failed") }
func TestPrimitiveFactoryMonitoringWithAnnotationsSignFailureIsLogged(t *testing.T) {
defer internalregistry.ClearMonitoringClient()
client := fakemonitoring.NewClient("fake-client")
if err := internalregistry.RegisterMonitoringClient(client); err != nil {
t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err)
}
typeURL := "TestPrimitiveFactoryMonitoringWithAnnotationsSignFailureIsLogged" + "PrivateKeyManager"
km := &stubkeymanager.StubPrivateKeyManager{
StubKeyManager: stubkeymanager.StubKeyManager{
URL: typeURL,
Prim: &alwaysFailingSigner{},
KeyData: &tinkpb.KeyData{
TypeUrl: typeURL,
Value: []byte("serialized_key"),
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE,
},
},
}
if err := registry.RegisterKeyManager(km); err != nil {
t.Fatalf("registry.RegisterKeyManager() err = %v, want nil", err)
}
template := &tinkpb.KeyTemplate{
TypeUrl: typeURL,
OutputPrefixType: tinkpb.OutputPrefixType_LEGACY,
}
kh, err := keyset.NewHandle(template)
if err != nil {
t.Fatalf("keyset.NewHandle() err = %v, want nil", err)
}
buff := &bytes.Buffer{}
if err := insecurecleartextkeyset.Write(kh, keyset.NewBinaryWriter(buff)); err != nil {
t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err)
}
annotations := map[string]string{"foo": "bar"}
privHandle, err := insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations))
if err != nil {
t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err)
}
signer, err := signature.NewSigner(privHandle)
if err != nil {
t.Fatalf("signature.NewSigner() err = %v, want nil", err)
}
if _, err := signer.Sign([]byte("some_data")); err == nil {
t.Fatalf("signer.Sign() err = nil, want error")
}
if len(client.Events()) != 0 {
t.Errorf("len(client.Events()) = %d, want 0", len(client.Events()))
}
got := client.Failures()
want := []*fakemonitoring.LogFailure{
{
Context: monitoring.NewContext(
"public_key_sign",
"sign",
monitoring.NewKeysetInfo(
annotations,
kh.KeysetInfo().GetPrimaryKeyId(),
[]*monitoring.Entry{
{
KeyID: kh.KeysetInfo().GetPrimaryKeyId(),
Status: monitoring.Enabled,
KeyType: typeURL,
KeyPrefix: "LEGACY",
},
},
),
),
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("%v", diff)
}
}
func TestPrimitiveFactoryMonitoringWithAnnotationsVerifyFailureIsLogged(t *testing.T) {
defer internalregistry.ClearMonitoringClient()
client := fakemonitoring.NewClient("fake-client")
if err := internalregistry.RegisterMonitoringClient(client); err != nil {
t.Fatalf("internalregistry.RegisterMonitoringClient() err = %v, want nil", err)
}
privHandle, err := keyset.NewHandle(signature.ED25519KeyTemplate())
if err != nil {
t.Fatalf("keyset.NewHandle() err = %v, want nil", err)
}
pubHandle, err := privHandle.Public()
if err != nil {
t.Fatalf("privHandle.Public() err = %v, want nil", err)
}
buff := &bytes.Buffer{}
annotations := map[string]string{"foo": "bar"}
if err := insecurecleartextkeyset.Write(pubHandle, keyset.NewBinaryWriter(buff)); err != nil {
t.Fatalf("insecurecleartextkeyset.Write() err = %v, want nil", err)
}
pubHandle, err = insecurecleartextkeyset.Read(keyset.NewBinaryReader(buff), keyset.WithAnnotations(annotations))
if err != nil {
t.Fatalf("insecurecleartextkeyset.Read() err = %v, want nil", err)
}
verifier, err := signature.NewVerifier(pubHandle)
if err != nil {
t.Fatalf("signature.NewVerifier() err = %v, want nil", err)
}
if err := verifier.Verify([]byte("some_invalid_signature"), []byte("some_invalid_data")); err == nil {
t.Fatalf("verifier.Verify() err = nil, want error")
}
if len(client.Events()) != 0 {
t.Errorf("len(client.Events()) = %d, want 0", len(client.Events()))
}
got := client.Failures()
want := []*fakemonitoring.LogFailure{
{
Context: monitoring.NewContext(
"public_key_verify",
"verify",
monitoring.NewKeysetInfo(
annotations,
pubHandle.KeysetInfo().GetPrimaryKeyId(),
[]*monitoring.Entry{
{
KeyID: pubHandle.KeysetInfo().GetPrimaryKeyId(),
Status: monitoring.Enabled,
KeyType: "tink.Ed25519PublicKey",
KeyPrefix: "TINK",
},
},
),
),
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("%v", diff)
}
}
func TestVerifyWithLegacyKeyDoesNotHaveSideEffectOnMessage(t *testing.T) {
privateKey, publicKey := newECDSAKeysetKeypair(commonpb.HashType_SHA256,
commonpb.EllipticCurveType_NIST_P256,
tinkpb.OutputPrefixType_LEGACY,
2)
privateKeyset := testutil.NewKeyset(privateKey.KeyId, []*tinkpb.Keyset_Key{privateKey})
privateHandle, err := testkeyset.NewHandle(privateKeyset)
if err != nil {
t.Fatalf("testkeyset.NewHandle(privateHandle) err = %v, want nil", err)
}
publicKeyset := testutil.NewKeyset(publicKey.KeyId, []*tinkpb.Keyset_Key{publicKey})
publicHandle, err := testkeyset.NewHandle(publicKeyset)
if err != nil {
t.Fatalf("testkeyset.NewHandle(publicKeyset) err = %v, want nil", err)
}
signer, err := signature.NewSigner(privateHandle)
if err != nil {
t.Fatalf("signature.NewSigner(privateHandle) err = %v, want nil", err)
}
verifier, err := signature.NewVerifier(publicHandle)
if err != nil {
t.Fatalf("signature.NewVerifier(publicHandle) err = %v, want nil", err)
}
data := []byte("data")
message := data[:3] // Let message be a slice of data.
sig, err := signer.Sign(message)
if err != nil {
t.Fatalf("signer.Sign(message) err = %v, want nil", err)
}
err = verifier.Verify(sig, message)
if err != nil {
t.Fatalf("verifier.Verify(sig, message) err = %v, want nil", err)
}
wantData := []byte("data")
if !bytes.Equal(data, wantData) {
t.Errorf("data = %q, want: %q", data, wantData)
}
}