tink_core/registry/mod.rs
1// Copyright 2020 The Tink-Rust Authors
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//! Provides a container that for each supported key type holds a corresponding `KeyManager` object,
18//! which can generate new keys or instantiate the primitive corresponding to given key.
19//!
20//! Registry is initialized at startup, and is later used to instantiate primitives for given keys
21//! or keysets. Keeping [`KeyManager`]s for all primitives in a single Registry (rather than having
22//! a separate [`KeyManager`] per primitive) enables modular construction of compound primitives
23//! from "simple" ones, e.g., AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC.
24//!
25//! Note that regular users will usually not work directly with Registry, but rather via primitive
26//! factories, which in the background query the Registry for specific [`KeyManager`]s. Registry is
27//! public though, to enable configurations with custom primitives and [`KeyManager`]s.
28
29use crate::TinkError;
30use lazy_static::lazy_static;
31use std::{
32 collections::HashMap,
33 sync::{Arc, RwLock},
34};
35
36mod kms_client;
37pub use kms_client::*;
38mod key_manager;
39pub use key_manager::*;
40mod key_templates;
41pub use key_templates::*;
42
43lazy_static! {
44 /// Global registry of key manager objects, indexed by type URL.
45 static ref KEY_MANAGERS: RwLock<HashMap<&'static str, Arc<dyn KeyManager>>> =
46 RwLock::new(HashMap::new());
47 /// Global list of KMS client objects.
48 static ref KMS_CLIENTS: RwLock<Vec<Arc<dyn KmsClient>>> = RwLock::new(Vec::new());
49}
50
51/// Error message for global key manager registry lock.
52const MERR: &str = "global KEY_MANAGERS lock poisoned";
53/// Error message for global KMS client list lock.
54const CERR: &str = "global KMS_CLIENTS lock poisoned";
55
56/// Register the given key manager. Does not allow overwrite of existing key managers.
57pub fn register_key_manager<T>(km: Arc<T>) -> Result<(), TinkError>
58where
59 T: 'static + KeyManager,
60{
61 let mut key_mgrs = KEY_MANAGERS.write().expect(MERR); // safe: lock
62
63 let type_url = km.type_url();
64 if key_mgrs.contains_key(type_url) {
65 return Err(
66 format!("registry::register_key_manager: type {type_url} already registered",).into(),
67 );
68 }
69 key_mgrs.insert(type_url, km);
70 Ok(())
71}
72
73/// Return the key manager for the given `type_url` if it exists.
74pub fn get_key_manager(type_url: &str) -> Result<Arc<dyn KeyManager>, TinkError> {
75 let key_mgrs = KEY_MANAGERS.read().expect(MERR); // safe: lock
76 let km = key_mgrs.get(type_url).ok_or_else(|| {
77 TinkError::new(&format!(
78 "registry::get_key_manager: unsupported key type: {type_url}",
79 ))
80 })?;
81 Ok(km.clone())
82}
83
84/// Generate a new [`KeyData`](tink_proto::KeyData) for the given key template.
85pub fn new_key_data(kt: &tink_proto::KeyTemplate) -> Result<tink_proto::KeyData, TinkError> {
86 get_key_manager(&kt.type_url)?.new_key_data(&kt.value)
87}
88
89/// Generate a new key for the given key template as a serialized protobuf message.
90pub fn new_key(kt: &tink_proto::KeyTemplate) -> Result<Vec<u8>, TinkError> {
91 get_key_manager(&kt.type_url)?.new_key(&kt.value)
92}
93
94/// Create a new primitive for the key given in the given [`KeyData`](tink_proto::KeyData).
95pub fn primitive_from_key_data(kd: &tink_proto::KeyData) -> Result<crate::Primitive, TinkError> {
96 primitive(&kd.type_url, &kd.value)
97}
98
99/// Create a new primitive for the given serialized key using the [`KeyManager`]
100/// identified by the given `type_url`.
101pub fn primitive(type_url: &str, sk: &[u8]) -> Result<crate::Primitive, TinkError> {
102 if sk.is_empty() {
103 return Err("registry::primitive: invalid serialized key".into());
104 }
105 get_key_manager(type_url)?.primitive(sk)
106}
107
108/// Register a new KMS client
109pub fn register_kms_client<T>(k: T)
110where
111 T: 'static + KmsClient,
112{
113 let mut kms_clients = KMS_CLIENTS.write().expect(CERR); // safe: lock
114 kms_clients.push(Arc::new(k));
115}
116
117/// Remove all registered KMS clients.
118pub fn clear_kms_clients() {
119 let mut kms_clients = KMS_CLIENTS.write().expect(CERR); // safe: lock
120 kms_clients.clear();
121}
122
123/// Fetches a [`KmsClient`] by a given URI.
124pub fn get_kms_client(key_uri: &str) -> Result<Arc<dyn KmsClient>, TinkError> {
125 let kms_clients = KMS_CLIENTS.read().expect(CERR); // safe: lock
126 for k in kms_clients.iter() {
127 if k.supported(key_uri) {
128 return Ok(k.clone());
129 }
130 }
131 Err(format!("KMS client supporting {key_uri} not found").into())
132}