xref: /aosp_15_r20/external/tink/go/core/registry/registry.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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