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