// 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) } }