| // Copyright 2022 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 internalregistry_test |
| |
| import ( |
| "bytes" |
| "errors" |
| "sync" |
| "testing" |
| |
| "google.golang.org/protobuf/proto" |
| "github.com/google/tink/go/aead" |
| "github.com/google/tink/go/core/registry" |
| "github.com/google/tink/go/internal/internalregistry" |
| "github.com/google/tink/go/internal/testing/stubkeymanager" |
| "github.com/google/tink/go/subtle/random" |
| gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto" |
| tinkpb "github.com/google/tink/go/proto/tink_go_proto" |
| ) |
| |
| const ( |
| typeURLRoot = "TestDeriveKeyFails" |
| unregisteredKMTypeURL = typeURLRoot + "UnregisteredKeyManager" |
| notDerivableKMTypeURL = typeURLRoot + "NotDerivableKeyManager" |
| failingKMTypeURL = typeURLRoot + "FailingKeyManager" |
| ) |
| |
| var once sync.Once |
| |
| func mustRegisterBadKeyManagers(t *testing.T) { |
| t.Helper() |
| // The registry does not allow a key manager to be registered more than once. |
| once.Do(func() { |
| notDerivableKM := &stubkeymanager.StubKeyManager{URL: notDerivableKMTypeURL} |
| if err := registry.RegisterKeyManager(notDerivableKM); err != nil { |
| t.Fatalf("registry.RegisterKeyManager() err = %v, want nil", err) |
| } |
| |
| failingKM := &stubkeymanager.StubDerivableKeyManager{ |
| StubKeyManager: stubkeymanager.StubKeyManager{ |
| URL: failingKMTypeURL, |
| }, |
| DerErr: errors.New("failing"), |
| } |
| if err := registry.RegisterKeyManager(failingKM); err != nil { |
| t.Fatalf("registry.RegisterKeyManager() err = %v, want nil", err) |
| } |
| }) |
| } |
| |
| func TestDerivableKeyManagers(t *testing.T) { |
| mustRegisterBadKeyManagers(t) |
| for _, typeURL := range []string{ |
| aead.AES128GCMKeyTemplate().GetTypeUrl(), |
| aead.AES256GCMKeyTemplate().GetTypeUrl(), |
| failingKMTypeURL, |
| } { |
| t.Run(typeURL, func(t *testing.T) { |
| if err := internalregistry.AllowKeyDerivation(typeURL); err != nil { |
| t.Fatalf("internalregistry.AllowKeyDerivation() err = %v, want nil", err) |
| } |
| if !internalregistry.CanDeriveKeys(typeURL) { |
| t.Errorf("internalregistry.CanDeriveKeys() = false, want true") |
| } |
| }) |
| } |
| } |
| |
| func TestDerivableKeyManagersRejectsInvalidInputs(t *testing.T) { |
| mustRegisterBadKeyManagers(t) |
| for _, typeURL := range []string{ |
| "", |
| unregisteredKMTypeURL, |
| notDerivableKMTypeURL, |
| } { |
| t.Run(typeURL, func(t *testing.T) { |
| if err := internalregistry.AllowKeyDerivation(typeURL); err == nil { |
| t.Error("internalregistry.AllowKeyDerivation() err = nil, want non-nil") |
| } |
| if internalregistry.CanDeriveKeys(typeURL) { |
| t.Errorf("internalregistry.CanDeriveKeys() = true, want false") |
| } |
| }) |
| } |
| } |
| |
| func TestDeriveKey(t *testing.T) { |
| for _, test := range []struct { |
| name string |
| keyTemplate *tinkpb.KeyTemplate |
| keySize uint32 |
| keyMaterialType tinkpb.KeyData_KeyMaterialType |
| }{ |
| { |
| name: "AES-128-GCM", |
| keyTemplate: aead.AES128GCMKeyTemplate(), |
| keySize: 16, |
| keyMaterialType: tinkpb.KeyData_SYMMETRIC, |
| }, |
| { |
| name: "AES-256-GCM", |
| keyTemplate: aead.AES256GCMKeyTemplate(), |
| keySize: 32, |
| keyMaterialType: tinkpb.KeyData_SYMMETRIC, |
| }, |
| } { |
| t.Run(test.name, func(t *testing.T) { |
| buf := bytes.NewBuffer(random.GetRandomBytes(test.keySize)) |
| keyData, err := internalregistry.DeriveKey(test.keyTemplate, buf) |
| if err != nil { |
| t.Fatalf("internalregistry.DeriveKey() err = %v, want nil", err) |
| } |
| if got, want := keyData.GetTypeUrl(), test.keyTemplate.GetTypeUrl(); got != want { |
| t.Errorf("TypeUrl = %s, want %s", got, want) |
| } |
| key := &gcmpb.AesGcmKey{} |
| if err := proto.Unmarshal(keyData.GetValue(), key); err != nil { |
| t.Errorf("proto.Unmarshal() err = %v, want nil", err) |
| } |
| if got, want := len(key.GetKeyValue()), int(test.keySize); got != want { |
| t.Errorf("len(KeyValue) = %d, want %d", got, want) |
| } |
| if got, want := keyData.GetKeyMaterialType(), test.keyMaterialType; got != want { |
| t.Errorf("KeyMaterialType = %s, want %s", got, want) |
| } |
| }) |
| } |
| } |
| |
| func TestDeriveKeyFails(t *testing.T) { |
| mustRegisterBadKeyManagers(t) |
| rand := random.GetRandomBytes(32) |
| for _, test := range []struct { |
| name string |
| keyTemplate *tinkpb.KeyTemplate |
| randLen uint32 |
| }{ |
| { |
| name: "not enough randomness", |
| keyTemplate: aead.AES128GCMKeyTemplate(), |
| randLen: 15}, |
| { |
| name: "nil key template", |
| randLen: 32}, |
| { |
| name: "derivation-disallowed but registered key manager", |
| keyTemplate: aead.AES128CTRHMACSHA256KeyTemplate(), |
| randLen: 32, |
| }, |
| { |
| name: "derivation-allowed but unregistered key manager", |
| keyTemplate: &tinkpb.KeyTemplate{ |
| TypeUrl: unregisteredKMTypeURL, |
| Value: rand, |
| OutputPrefixType: tinkpb.OutputPrefixType_TINK, |
| }, |
| randLen: 32, |
| }, |
| { |
| "does not implement DerivableKeyManager", |
| &tinkpb.KeyTemplate{ |
| TypeUrl: notDerivableKMTypeURL, |
| Value: rand, |
| OutputPrefixType: tinkpb.OutputPrefixType_TINK, |
| }, |
| 32, |
| }, |
| { |
| "key manager with failing DeriveKey()", |
| &tinkpb.KeyTemplate{ |
| TypeUrl: failingKMTypeURL, |
| Value: rand, |
| OutputPrefixType: tinkpb.OutputPrefixType_TINK, |
| }, |
| 32, |
| }, |
| } { |
| t.Run(test.name, func(t *testing.T) { |
| buf := bytes.NewBuffer(random.GetRandomBytes(test.randLen)) |
| if _, err := internalregistry.DeriveKey(test.keyTemplate, buf); err == nil { |
| t.Error("internalregistry.DeriveKey() err = nil, want non-nil") |
| } |
| }) |
| } |
| } |