1// Copyright 2022 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package internalregistry 18 19import ( 20 "fmt" 21 "io" 22 "sync" 23 24 "google.golang.org/protobuf/proto" 25 "github.com/google/tink/go/core/registry" 26 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 27) 28 29var ( 30 derivableKeyManagersMu sync.RWMutex 31 32 // derivableKeyManagers is the set of all key managers allowed to derive keys. 33 // It is keyed by the key manager's type URL, i.e. typeURL -> true. All type 34 // URLs in this map correspond to key managers that are 35 // - in the registry and 36 // - implement key derivation. 37 // 38 // This exists because of Golang's weak type system and the desire to keep key 39 // derivation non-public. If we do not explicitly restrict derivable key 40 // managers, users would be able to register any custom key manager that 41 // implements DeriveKey() and be able to derive keys with it, even without 42 // access to this library, internalregistry. 43 derivableKeyManagers = make(map[string]bool) 44) 45 46// AllowKeyDerivation adds the type URL to derivableKeyManagers if the 47// corresponding key manager is in the registry and implements key derivation. 48func AllowKeyDerivation(typeURL string) error { 49 km, err := registry.GetKeyManager(typeURL) 50 if err != nil { 51 return err 52 } 53 if _, ok := km.(DerivableKeyManager); !ok { 54 return fmt.Errorf("key manager for type %s does not implement key derivation", typeURL) 55 } 56 derivableKeyManagersMu.Lock() 57 derivableKeyManagers[typeURL] = true 58 derivableKeyManagersMu.Unlock() 59 return nil 60} 61 62// CanDeriveKeys returns true if typeURL is in derivableKeyManagers. 63func CanDeriveKeys(typeURL string) bool { 64 derivableKeyManagersMu.Lock() 65 defer derivableKeyManagersMu.Unlock() 66 return derivableKeyManagers[typeURL] 67} 68 69// DeriveKey derives a new key from template and pseudorandomness. 70func DeriveKey(keyTemplate *tinkpb.KeyTemplate, pseudorandomness io.Reader) (*tinkpb.KeyData, error) { 71 if !CanDeriveKeys(keyTemplate.GetTypeUrl()) { 72 return nil, fmt.Errorf("key manager for type %s is not allowed to derive keys", keyTemplate.GetTypeUrl()) 73 } 74 km, err := registry.GetKeyManager(keyTemplate.GetTypeUrl()) 75 if err != nil { 76 return nil, err 77 } 78 keyManager, ok := km.(DerivableKeyManager) 79 if !ok { 80 return nil, fmt.Errorf("key manager for type %s does not implement key derivation", keyTemplate.GetTypeUrl()) 81 } 82 key, err := keyManager.DeriveKey(keyTemplate.GetValue(), pseudorandomness) 83 if err != nil { 84 return nil, err 85 } 86 serializedKey, err := proto.Marshal(key) 87 if err != nil { 88 return nil, fmt.Errorf("failed to serialize derived key: %v", err) 89 } 90 return &tinkpb.KeyData{ 91 TypeUrl: keyTemplate.GetTypeUrl(), 92 Value: serializedKey, 93 KeyMaterialType: keyManager.KeyMaterialType(), 94 }, nil 95} 96