use crate::TinkError;
use lazy_static::lazy_static;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
mod kms_client;
pub use kms_client::*;
mod key_manager;
pub use key_manager::*;
mod key_templates;
pub use key_templates::*;
lazy_static! {
static ref KEY_MANAGERS: RwLock<HashMap<&'static str, Arc<dyn KeyManager>>> =
RwLock::new(HashMap::new());
static ref KMS_CLIENTS: RwLock<Vec<Arc<dyn KmsClient>>> = RwLock::new(Vec::new());
}
const MERR: &str = "global KEY_MANAGERS lock poisoned";
const CERR: &str = "global KMS_CLIENTS lock poisoned";
pub fn register_key_manager<T>(km: Arc<T>) -> Result<(), TinkError>
where
T: 'static + KeyManager,
{
let mut key_mgrs = KEY_MANAGERS.write().expect(MERR);
let type_url = km.type_url();
if key_mgrs.contains_key(type_url) {
return Err(
format!("registry::register_key_manager: type {type_url} already registered",).into(),
);
}
key_mgrs.insert(type_url, km);
Ok(())
}
pub fn get_key_manager(type_url: &str) -> Result<Arc<dyn KeyManager>, TinkError> {
let key_mgrs = KEY_MANAGERS.read().expect(MERR); let km = key_mgrs.get(type_url).ok_or_else(|| {
TinkError::new(&format!(
"registry::get_key_manager: unsupported key type: {type_url}",
))
})?;
Ok(km.clone())
}
pub fn new_key_data(kt: &tink_proto::KeyTemplate) -> Result<tink_proto::KeyData, TinkError> {
get_key_manager(&kt.type_url)?.new_key_data(&kt.value)
}
pub fn new_key(kt: &tink_proto::KeyTemplate) -> Result<Vec<u8>, TinkError> {
get_key_manager(&kt.type_url)?.new_key(&kt.value)
}
pub fn primitive_from_key_data(kd: &tink_proto::KeyData) -> Result<crate::Primitive, TinkError> {
primitive(&kd.type_url, &kd.value)
}
pub fn primitive(type_url: &str, sk: &[u8]) -> Result<crate::Primitive, TinkError> {
if sk.is_empty() {
return Err("registry::primitive: invalid serialized key".into());
}
get_key_manager(type_url)?.primitive(sk)
}
pub fn register_kms_client<T>(k: T)
where
T: 'static + KmsClient,
{
let mut kms_clients = KMS_CLIENTS.write().expect(CERR); kms_clients.push(Arc::new(k));
}
pub fn clear_kms_clients() {
let mut kms_clients = KMS_CLIENTS.write().expect(CERR); kms_clients.clear();
}
pub fn get_kms_client(key_uri: &str) -> Result<Arc<dyn KmsClient>, TinkError> {
let kms_clients = KMS_CLIENTS.read().expect(CERR); for k in kms_clients.iter() {
if k.supported(key_uri) {
return Ok(k.clone());
}
}
Err(format!("KMS client supporting {key_uri} not found").into())
}