keymgr: Require callers to specify which keystore to insert keys in.

The caller uses `KeystoreSelector` to specify which keystore to insert
the new key into (only `KeystoreSelector::Id` and
`KeystoreSelector::Default` are supported for `insert`).

The ability to insert keys in a particular keystore will come in handy
when we implement the key management CLI (the CLI will have an option
for specifying the keystore to access/modify).
This commit is contained in:
Gabriela Moldovan 2023-07-18 14:21:36 +01:00
parent 6ec1b55938
commit 0b20806213
No known key found for this signature in database
GPG Key ID: 3946E0ADE72BAC99
3 changed files with 34 additions and 28 deletions

View File

@ -7,3 +7,5 @@ BREAKING: `KeyMgr::new` takes an extra argument (the default keystore)
ADDED: `KeystoreSelector`
BREAKING: `KeystoreError` now has a `boxed` function
ADDED: an `id` function to `Keystore` trait
BREAKING: `KeyMgr::insert` now takes an additional
`selector: KeystoreSelector` argument

View File

@ -8,7 +8,7 @@
//! removed, because the dummy implementations must have the same API as their fully-featured
//! counterparts.
use crate::{KeystoreError, Result};
use crate::{KeystoreError, KeystoreSelector, Result};
use tor_error::HasKind;
use fs_mistrust::Mistrust;
@ -88,7 +88,7 @@ impl KeyMgr {
/// A dummy `insert` implementation that always fails.
///
/// This function always returns an error.
pub fn insert<K>(&self, _: K, _: &dyn Any) -> Result<()> {
pub fn insert<K>(&self, _: K, _: &dyn Any, _: KeystoreSelector) -> Result<()> {
Err(Box::new(Error))
}

View File

@ -3,7 +3,9 @@
//! The [`KeyMgr`] reads from (and writes to) a number of key stores. The key stores all implement
//! [`Keystore`].
use crate::{EncodableKey, KeySpecifier, Keystore, KeystoreError, Result, ToEncodableKey};
use crate::{
EncodableKey, KeySpecifier, Keystore, KeystoreError, KeystoreSelector, Result, ToEncodableKey,
};
use std::iter;
use tor_error::{internal, HasKind};
@ -94,38 +96,40 @@ impl KeyMgr {
Ok(None)
}
/// Insert the specified key intro the appropriate key store.
/// Insert `key` into the [`Keystore`] specified by `selector`.
///
/// If the key bundle of this `key` exists in one of the key stores, the key is inserted
/// there. Otherwise, the key is inserted into the first key store.
/// This function can only be used with [`KeystoreSelector::Default`] and
/// [`KeystoreSelector::Id`]. It returns an error if the specified `selector`
/// is not supported.
///
/// If the key already exists, it is overwritten.
///
// TODO HSS: would it be useful for this API to return a Result<Option<K>> here (i.e. the old key)?
// TODO HSS (#903): define what "key bundle" means
pub fn insert<K: ToEncodableKey>(&self, key: K, key_spec: &dyn KeySpecifier) -> Result<()> {
// TODO HSS: maybe we should designate an explicit 'primary' store instead of implicitly
// preferring the first one.
let primary_store = match self.key_stores.first() {
Some(store) => store,
None => return Err(internal!("no key stores configured").into()),
};
pub fn insert<K: ToEncodableKey>(
&self,
key: K,
key_spec: &dyn KeySpecifier,
selector: KeystoreSelector,
) -> Result<()> {
let key = key.to_encodable_key();
let store = self
.key_stores
.iter()
.find_map(|s| match s.has_key_bundle(key_spec) {
Ok(true) => Some(Ok(s)),
Ok(false) => None,
Err(e) => Some(Err(e)),
})
.transpose()?
// None of the stores has the key bundle of key_spec, so we insert the key into the first
// store.
.unwrap_or(primary_store);
store.insert(&key, key_spec, K::Key::key_type())
match selector {
KeystoreSelector::Id(keystore_id) => {
let Some(keystore) = self.find_keystore(keystore_id) else {
return Err(KeyMgrError::KeystoreNotFound(keystore_id).boxed());
};
keystore.insert(&key, key_spec, K::Key::key_type())
}
KeystoreSelector::Default => {
self.default_store
.insert(&key, key_spec, K::Key::key_type())
}
KeystoreSelector::All => Err(KeyMgrError::UnsupportedKeystoreSelector {
op: "insert",
selector,
}
.boxed()),
}
}
/// Remove the specified key.