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}