1// Copyright 2019 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 17// Package registry provides a container that for each supported key type holds 18// a corresponding KeyManager object, which can generate new keys or 19// instantiate the primitive corresponding to given key. 20// 21// Registry is initialized at startup, and is later used to instantiate 22// primitives for given keys or keysets. Keeping KeyManagers for all primitives 23// in a single Registry (rather than having a separate KeyManager per 24// primitive) enables modular construction of compound primitives from "simple" 25// ones, e.g., AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC. 26// 27// Note that regular users will usually not work directly with Registry, but 28// rather via primitive factories, which in the background query the Registry 29// for specific KeyManagers. Registry is public though, to enable 30// configurations with custom primitives and KeyManagers. 31package registry 32 33import ( 34 "fmt" 35 "sync" 36 37 "google.golang.org/protobuf/proto" 38 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 39) 40 41var ( 42 keyManagersMu sync.RWMutex 43 keyManagers = make(map[string]KeyManager) // typeURL -> KeyManager 44 kmsClientsMu sync.RWMutex 45 kmsClients = []KMSClient{} 46) 47 48// RegisterKeyManager registers the given key manager. 49// Does not allow to overwrite existing key managers. 50func RegisterKeyManager(keyManager KeyManager) error { 51 keyManagersMu.Lock() 52 defer keyManagersMu.Unlock() 53 typeURL := keyManager.TypeURL() 54 if _, existed := keyManagers[typeURL]; existed { 55 return fmt.Errorf("registry.RegisterKeyManager: type %s already registered", typeURL) 56 } 57 keyManagers[typeURL] = keyManager 58 return nil 59} 60 61// GetKeyManager returns the key manager for the given typeURL if existed. 62func GetKeyManager(typeURL string) (KeyManager, error) { 63 keyManagersMu.RLock() 64 defer keyManagersMu.RUnlock() 65 keyManager, existed := keyManagers[typeURL] 66 if !existed { 67 return nil, fmt.Errorf("registry.GetKeyManager: unsupported key type: %s", typeURL) 68 } 69 return keyManager, nil 70} 71 72// NewKeyData generates a new KeyData for the given key template. 73func NewKeyData(template *tinkpb.KeyTemplate) (*tinkpb.KeyData, error) { 74 if template == nil { 75 return nil, fmt.Errorf("registry.NewKeyData: invalid key template") 76 } 77 keyManager, err := GetKeyManager(template.TypeUrl) 78 if err != nil { 79 return nil, err 80 } 81 return keyManager.NewKeyData(template.Value) 82} 83 84// NewKey generates a new key for the given key template. 85// 86// Deprecated: use [NewKeyData] instead. 87func NewKey(template *tinkpb.KeyTemplate) (proto.Message, error) { 88 if template == nil { 89 return nil, fmt.Errorf("registry.NewKey: invalid key template") 90 } 91 keyManager, err := GetKeyManager(template.TypeUrl) 92 if err != nil { 93 return nil, err 94 } 95 return keyManager.NewKey(template.Value) 96} 97 98// PrimitiveFromKeyData creates a new primitive for the key given in the given KeyData. 99// Note that the returned primitive does not add/remove the output prefix. 100// It is the caller's responsibility to handle this correctly, based on the key's output_prefix_type. 101func PrimitiveFromKeyData(keyData *tinkpb.KeyData) (interface{}, error) { 102 if keyData == nil { 103 return nil, fmt.Errorf("registry.PrimitiveFromKeyData: invalid key data") 104 } 105 return Primitive(keyData.TypeUrl, keyData.Value) 106} 107 108// Primitive creates a new primitive for the given serialized key using the KeyManager 109// identified by the given typeURL. 110// Note that the returned primitive does not add/remove the output prefix. 111// It is the caller's responsibility to handle this correctly, based on the key's output_prefix_type. 112func Primitive(typeURL string, serializedKey []byte) (interface{}, error) { 113 if len(serializedKey) == 0 { 114 return nil, fmt.Errorf("registry.Primitive: invalid serialized key") 115 } 116 keyManager, err := GetKeyManager(typeURL) 117 if err != nil { 118 return nil, err 119 } 120 return keyManager.Primitive(serializedKey) 121} 122 123// RegisterKMSClient is used to register a new KMS client 124func RegisterKMSClient(kmsClient KMSClient) { 125 kmsClientsMu.Lock() 126 defer kmsClientsMu.Unlock() 127 kmsClients = append(kmsClients, kmsClient) 128} 129 130// GetKMSClient fetches a KMSClient by a given URI. 131func GetKMSClient(keyURI string) (KMSClient, error) { 132 kmsClientsMu.RLock() 133 defer kmsClientsMu.RUnlock() 134 for _, kmsClient := range kmsClients { 135 if kmsClient.Supported(keyURI) { 136 return kmsClient, nil 137 } 138 } 139 return nil, fmt.Errorf("KMS client supporting %s not found", keyURI) 140} 141 142// ClearKMSClients removes all registered KMS clients. 143func ClearKMSClients() { 144 kmsClientsMu.Lock() 145 defer kmsClientsMu.Unlock() 146 kmsClients = []KMSClient{} 147} 148