use std::sync::Arc;
use std::{collections::HashMap, sync::RwLock};
#[cfg(feature = "hsm")]
use log::{debug, error, info, trace};
use rpki::crypto::{
signer::KeyError, KeyIdentifier, PublicKey, PublicKeyFormat, Signature,
SignatureAlgorithm, Signer, SigningError,
};
use crate::commons::{
crypto::{
dispatch::{
signerinfo::SignerMapper, signerprovider::SignerProvider,
},
signers::error::SignerError,
SignerHandle,
},
error::Error,
KrillResult,
};
#[cfg(feature = "hsm")]
use crate::commons::crypto::dispatch::error::ErrorString;
#[derive(Debug)]
pub struct SignerRouter {
default_signer: Arc<SignerProvider>,
one_off_signer: Arc<SignerProvider>,
signer_mapper: Option<Arc<SignerMapper>>,
active_signers: RwLock<HashMap<SignerHandle, Arc<SignerProvider>>>,
#[cfg(feature = "hsm")]
pending_signers: RwLock<Vec<Arc<SignerProvider>>>,
}
impl SignerRouter {
pub fn build(
signer_mapper: Option<Arc<SignerMapper>>,
mut signers: Vec<SignerProvider>,
) -> KrillResult<Self> {
let active_signers = RwLock::new(HashMap::new());
let mut default_signer: Option<Arc<SignerProvider>> = None;
let mut one_off_signer: Option<Arc<SignerProvider>> = None;
let mut all_signers = Vec::new();
for signer in signers.drain(..) {
let signer = Arc::new(signer);
if signer.is_default_signer() {
Self::set_once(&mut default_signer, signer.clone()).map_err(
|_| {
Error::ConfigError(
"There must only be one default signer"
.to_string(),
)
},
)?;
} else if signer.is_one_off_signer() {
Self::set_once(&mut one_off_signer, signer.clone()).map_err(
|_| {
Error::ConfigError(
"There must only be one one-off signer"
.to_string(),
)
},
)?;
}
all_signers.push(signer.clone());
}
let default_signer = default_signer.unwrap();
#[cfg(feature = "hsm")]
let pending_signers = RwLock::new(all_signers);
Ok(SignerRouter {
default_signer: default_signer.clone(),
one_off_signer: one_off_signer
.unwrap_or_else(|| default_signer.clone()),
active_signers,
#[cfg(feature = "hsm")]
pending_signers,
signer_mapper,
})
}
pub fn get_mapper(&self) -> Option<Arc<SignerMapper>> {
self.signer_mapper.clone()
}
pub fn get_active_signers(
&self,
) -> HashMap<SignerHandle, Arc<SignerProvider>> {
self.active_signers.read().unwrap().clone()
}
fn get_signer_for_key(
&self,
key_id: &KeyIdentifier,
) -> Result<Arc<SignerProvider>, SignerError> {
match &self.signer_mapper {
None => Ok(self.default_signer.clone()),
Some(mapper) => {
let signer_handle = mapper
.get_signer_for_key(key_id)
.map_err(|_| SignerError::KeyNotFound)?;
let signer = self
.active_signers
.read()
.unwrap()
.get(&signer_handle)
.cloned();
signer.ok_or(SignerError::KeyNotFound)
}
}
}
fn set_once(
to_be_set: &mut Option<Arc<SignerProvider>>,
new_value: Arc<SignerProvider>,
) -> Result<(), ()> {
let old_value = to_be_set.replace(new_value);
if old_value.is_some() {
Err(())
} else {
Ok(())
}
}
pub fn import_key(
&self,
pem: &str,
) -> Result<KeyIdentifier, SignerError> {
self.bind_ready_signers();
self.default_signer.import_key(pem)
}
}
#[cfg(feature = "hsm")]
enum IdentifyResult {
Unavailable,
Corrupt,
Identified(SignerHandle),
Unusable,
Unidentified,
}
#[cfg(feature = "hsm")]
enum RegisterResult {
NotReady,
ReadyVerified(SignerHandle),
ReadyUnusable(String),
}
#[cfg(not(feature = "hsm"))]
impl SignerRouter {
fn bind_ready_signers(&self) {}
}
#[cfg(feature = "hsm")]
impl SignerRouter {
fn bind_ready_signers(&self) {
if let Err(err) = self.do_ready_signer_binding() {
error!("Internal error: Unable to bind ready signers: {err}");
}
}
fn do_ready_signer_binding(&self) -> Result<(), String> {
let num_pending_signers = self.pending_signers.read().unwrap().len();
if num_pending_signers > 0 {
trace!(
"Attempting to bind {num_pending_signers} pending signers"
);
let candidate_handles = self.get_candidate_signer_handles()?;
trace!(
"{} signers were previously registered",
candidate_handles.len()
);
let mut pending_signers = self.pending_signers.write().unwrap();
let mut abort_flag = false;
pending_signers.retain(|signer_provider| -> bool {
if abort_flag {
return true;
}
let signer_name = signer_provider.get_name().to_string();
self.identify_signer(signer_provider, &candidate_handles)
.and_then(|verify_result| match verify_result {
IdentifyResult::Unavailable => {
trace!("Signer '{signer_name}' is unavailable");
Ok(true)
}
IdentifyResult::Identified(signer_handle) => {
self.active_signers
.write()
.unwrap()
.insert(signer_handle, signer_provider.clone());
info!("Signer '{signer_name}' is ready for use");
Ok(false)
}
IdentifyResult::Unidentified => {
self.register_new_signer(signer_provider)
.map(|register_result| match register_result {
RegisterResult::NotReady => {
trace!("Signer '{signer_name}' is not ready");
true
}
RegisterResult::ReadyVerified(signer_handle) => {
self.active_signers
.write()
.unwrap()
.insert(signer_handle, signer_provider.clone());
info!("Signer '{signer_name}' is ready for use");
false
}
RegisterResult::ReadyUnusable(err) => {
error!(
"Signer '{signer_name}' could not be registered: signer is not usable: {err}"
);
false
}
})
}
IdentifyResult::Unusable => {
error!("Signer '{signer_name}' could not be identified: signer is not usable");
Ok(false)
}
IdentifyResult::Corrupt => {
Err(ErrorString::new("Internal error: invalid handle"))
}
})
.unwrap_or_else(|err| {
error!("Signer '{}' could not be bound: {}. Aborting.", signer_name, *err);
abort_flag = true;
true
})
});
}
Ok(())
}
fn get_candidate_signer_handles(
&self,
) -> Result<Vec<SignerHandle>, String> {
self.signer_mapper
.as_ref()
.unwrap()
.get_signer_handles()
.map_err(|err| format!("Failed to get signer handles: {err}"))
}
fn identify_signer(
&self,
signer_provider: &Arc<SignerProvider>,
candidate_handles: &[SignerHandle],
) -> Result<IdentifyResult, ErrorString> {
let config_signer_name = signer_provider.get_name().to_string();
let mut ordered_candidate_handles = Vec::new();
for candidate_handle in candidate_handles {
let stored_signer_name = self
.signer_mapper
.as_ref()
.unwrap()
.get_signer_name(candidate_handle)?;
if stored_signer_name == config_signer_name {
ordered_candidate_handles.insert(0, candidate_handle);
} else {
ordered_candidate_handles.push(candidate_handle);
}
}
for candidate_handle in ordered_candidate_handles {
let res = self.is_signer_identified_by_handle(
signer_provider,
candidate_handle,
)?;
match res {
IdentifyResult::Unidentified => {
continue;
}
IdentifyResult::Corrupt => {
continue;
}
IdentifyResult::Unavailable
| IdentifyResult::Unusable
| IdentifyResult::Identified(_) => {
return Ok(res);
}
}
}
Ok(IdentifyResult::Unidentified)
}
fn is_signer_identified_by_handle(
&self,
signer_provider: &Arc<SignerProvider>,
candidate_handle: &SignerHandle,
) -> Result<IdentifyResult, ErrorString> {
let handle_name = self
.signer_mapper
.as_ref()
.unwrap()
.get_signer_name(candidate_handle)?;
let signer_name = signer_provider.get_name().to_string();
trace!(
"Attempting to identify signer '{signer_name}' using identity key stored for signer '{handle_name}'"
);
let public_key = match self
.signer_mapper
.as_ref()
.unwrap()
.get_signer_public_key(candidate_handle)
{
Ok(res) => Ok(res),
Err(err) => match err {
crate::commons::error::Error::SignerError(err) => {
error!(
"Internal error: Identity public key for signer '{handle_name}' is invalid: {err}"
);
return Ok(IdentifyResult::Corrupt);
}
err => Err(err),
},
}?;
let signer_private_key_id = self
.signer_mapper
.as_ref()
.unwrap()
.get_signer_private_key_internal_id(candidate_handle)?;
let challenge = "Krill signer verification challenge".as_bytes();
let signature = match signer_provider
.sign_registration_challenge(&signer_private_key_id, challenge)
{
Err(SignerError::TemporarilyUnavailable) => {
debug!("Signer '{signer_name}' could not be contacted");
return Ok(IdentifyResult::Unavailable);
}
Err(SignerError::KeyNotFound) => {
debug!(
"Signer '{signer_name}' not matched: private key id '{signer_private_key_id}' not found"
);
return Ok(IdentifyResult::Unidentified);
}
Err(err) => {
error!("Signer '{signer_name}' is unusable: {err}");
return Ok(IdentifyResult::Unusable);
}
Ok(res) => res,
};
if public_key.verify(challenge, &signature).is_ok() {
debug!("Signer '{signer_name}' is ready and known, binding");
let signer_info = signer_provider
.get_info()
.unwrap_or_else(|| "No signer info".to_string());
signer_provider.set_handle(candidate_handle.clone());
if let Err(err) = self
.signer_mapper
.as_ref()
.unwrap()
.change_signer_name(candidate_handle, &signer_name)
{
error!(
"Internal error: Failed to change name of signer to '{signer_name}': {err}"
);
}
if let Err(err) = self
.signer_mapper
.as_ref()
.unwrap()
.change_signer_info(candidate_handle, &signer_info)
{
error!(
"Internal error: Failed to change info for signer '{signer_name}' to '{signer_info}': {err}"
);
}
debug!(
"Signer '{signer_name}' bound to signer mapper handle '{candidate_handle}'"
);
} else {
debug!(
"Signer '{signer_name}' not matched: incorrect signature created with private key '{signer_private_key_id}'"
);
}
Ok(IdentifyResult::Identified(candidate_handle.clone()))
}
fn register_new_signer(
&self,
signer_provider: &Arc<SignerProvider>,
) -> Result<RegisterResult, ErrorString> {
let signer_name = signer_provider.get_name().to_string();
trace!("Attempting to register signer '{signer_name}'");
let (public_key, signer_private_key_id) =
match signer_provider.create_registration_key() {
Err(SignerError::TemporarilyUnavailable) => {
return Ok(RegisterResult::NotReady)
}
Err(err) => {
return Ok(RegisterResult::ReadyUnusable(err.to_string()))
}
Ok(res) => res,
};
let challenge = "Krill signer verification challenge".as_bytes();
let signature = match signer_provider
.sign_registration_challenge(&signer_private_key_id, challenge)
{
Err(SignerError::TemporarilyUnavailable) => {
return Ok(RegisterResult::NotReady)
}
Err(err) => {
return Ok(RegisterResult::ReadyUnusable(err.to_string()))
}
Ok(res) => res,
};
if public_key.verify(challenge, &signature).is_err() {
return Ok(RegisterResult::ReadyUnusable(
"Challenge signature is invalid".to_string(),
));
}
debug!("Signer '{signer_name}' is ready and new, binding");
let signer_info = signer_provider
.get_info()
.unwrap_or_else(|| "No signer info".to_string());
let signer_handle = self.signer_mapper.as_ref().unwrap().add_signer(
&signer_name,
&signer_info,
&public_key,
&signer_private_key_id,
)?;
signer_provider.set_handle(signer_handle.clone());
debug!(
"Signer '{signer_name}' bound to signer handle '{signer_handle}'"
);
Ok(RegisterResult::ReadyVerified(signer_handle))
}
}
impl Signer for SignerRouter {
type KeyId = KeyIdentifier;
type Error = SignerError;
fn create_key(
&self,
algorithm: PublicKeyFormat,
) -> Result<Self::KeyId, Self::Error> {
self.bind_ready_signers();
self.default_signer.create_key(algorithm)
}
fn get_key_info(
&self,
key_id: &KeyIdentifier,
) -> Result<PublicKey, KeyError<Self::Error>> {
self.bind_ready_signers();
self.get_signer_for_key(key_id)?.get_key_info(key_id)
}
fn destroy_key(
&self,
key_id: &KeyIdentifier,
) -> Result<(), KeyError<Self::Error>> {
self.bind_ready_signers();
self.get_signer_for_key(key_id)?.destroy_key(key_id)
}
fn sign<Alg: SignatureAlgorithm, D: AsRef<[u8]> + ?Sized>(
&self,
key_id: &KeyIdentifier,
algorithm: Alg,
data: &D,
) -> Result<Signature<Alg>, SigningError<Self::Error>> {
self.bind_ready_signers();
self.get_signer_for_key(key_id)?
.sign(key_id, algorithm, data)
}
fn sign_one_off<Alg: SignatureAlgorithm, D: AsRef<[u8]> + ?Sized>(
&self,
algorithm: Alg,
data: &D,
) -> Result<(Signature<Alg>, PublicKey), Self::Error> {
self.bind_ready_signers();
self.one_off_signer.sign_one_off(algorithm, data)
}
fn rand(&self, target: &mut [u8]) -> Result<(), Self::Error> {
self.bind_ready_signers();
openssl::rand::rand_bytes(target).map_err(SignerError::OpenSslError)
}
}
#[cfg(all(test, feature = "hsm"))]
pub mod tests {
use std::slice;
use rpki::crypto::RpkiSignatureAlgorithm;
use crate::{
commons::crypto::{
dispatch::signerprovider::SignerFlags,
signers::mocksigner::{
CreateRegistrationKeyErrorCb, FnIdx, MockSigner,
MockSignerCallCounts, SignRegistrationChallengeErrorCb,
},
},
commons::test,
};
use super::*;
fn create_signer_router(
all_signers: &[Arc<SignerProvider>],
signer_mapper: Arc<SignerMapper>,
) -> SignerRouter {
SignerRouter {
default_signer: all_signers[0].clone(),
one_off_signer: all_signers[0].clone(),
signer_mapper: Some(signer_mapper),
active_signers: RwLock::new(HashMap::new()),
pending_signers: RwLock::new(all_signers.to_vec()),
}
}
#[test]
pub fn verify_that_a_usable_signer_is_registered_and_can_be_used() {
test::test_in_memory(|storage_uri| {
#[allow(non_snake_case)]
let DEF_SIG_ALG = RpkiSignatureAlgorithm::default();
let call_counts = Arc::new(MockSignerCallCounts::new());
let signer_mapper =
Arc::new(SignerMapper::build(storage_uri).unwrap());
let mock_signer = MockSigner::new(
"mock signer",
signer_mapper.clone(),
call_counts.clone(),
None,
None,
);
let mock_signer = Arc::new(SignerProvider::Mock(
SignerFlags::default(),
mock_signer,
));
let router = create_signer_router(
slice::from_ref(&mock_signer),
signer_mapper.clone(),
);
assert_eq!(0, signer_mapper.get_signer_handles().unwrap().len());
assert_eq!(0, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(0, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(0, call_counts.get(FnIdx::GetInfo));
assert_eq!(0, call_counts.get(FnIdx::SetHandle));
assert_eq!(0, call_counts.get(FnIdx::CreateKey));
assert_eq!(0, call_counts.get(FnIdx::Sign));
assert_eq!(0, call_counts.get(FnIdx::DestroyKey));
let mut out_buf: [u8; 1] = [0; 1];
router.rand(&mut out_buf).unwrap();
assert_eq!(1, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(1, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(1, call_counts.get(FnIdx::GetInfo));
assert_eq!(1, call_counts.get(FnIdx::SetHandle));
assert_eq!(1, signer_mapper.get_signer_handles().unwrap().len());
router.rand(&mut out_buf).unwrap();
let key_identifier =
router.create_key(PublicKeyFormat::Rsa).unwrap();
assert!(signer_mapper
.get_signer_for_key(&key_identifier)
.is_ok());
assert_eq!(1, call_counts.get(FnIdx::CreateKey));
router.sign(&key_identifier, DEF_SIG_ALG, &out_buf).unwrap();
assert_eq!(1, call_counts.get(FnIdx::Sign));
let router = create_signer_router(
slice::from_ref(&mock_signer),
signer_mapper.clone(),
);
router.sign(&key_identifier, DEF_SIG_ALG, &out_buf).unwrap();
assert_eq!(1, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(2, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(2, call_counts.get(FnIdx::GetInfo));
assert_eq!(2, call_counts.get(FnIdx::SetHandle));
assert_eq!(2, call_counts.get(FnIdx::Sign));
router.destroy_key(&key_identifier).unwrap();
assert_eq!(1, call_counts.get(FnIdx::DestroyKey));
let err = router.sign(
&key_identifier,
RpkiSignatureAlgorithm::default(),
&out_buf,
);
assert!(matches!(
err,
Err(SigningError::Signer(SignerError::KeyNotFound))
));
assert_eq!(2, call_counts.get(FnIdx::Sign));
mock_signer.wipe_all_keys();
let key_identifier =
router.create_key(PublicKeyFormat::Rsa).unwrap();
router.sign(&key_identifier, DEF_SIG_ALG, &out_buf).unwrap();
assert_eq!(1, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(2, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(2, call_counts.get(FnIdx::CreateKey));
assert_eq!(3, call_counts.get(FnIdx::Sign));
let router =
create_signer_router(&[mock_signer], signer_mapper.clone());
let err = router.sign(&key_identifier, DEF_SIG_ALG, &out_buf);
assert!(matches!(
err,
Err(SigningError::Signer(SignerError::KeyNotFound))
));
assert_eq!(2, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(4, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(3, call_counts.get(FnIdx::GetInfo));
assert_eq!(3, call_counts.get(FnIdx::SetHandle));
assert_eq!(3, call_counts.get(FnIdx::Sign));
assert_eq!(2, signer_mapper.get_signer_handles().unwrap().len());
});
}
#[test]
pub fn verify_that_unusable_signers_are_neither_registered_nor_retried() {
fn perm_unusable(
_: &MockSignerCallCounts,
) -> Result<(), SignerError> {
Err(SignerError::PermanentlyUnusable)
}
fn internal_error(
_: &MockSignerCallCounts,
) -> Result<(), SignerError> {
Err(SignerError::Other("internal error".to_string()))
}
fn temp_unavail(_: &MockSignerCallCounts) -> Result<(), SignerError> {
Err(SignerError::TemporarilyUnavailable)
}
fn create_broken_signer(
signer_mapper: Arc<SignerMapper>,
call_counts: Arc<MockSignerCallCounts>,
create_registration_key_error_cb: Option<
CreateRegistrationKeyErrorCb,
>,
sign_registration_challenge_error_cb: Option<
SignRegistrationChallengeErrorCb,
>,
) -> Arc<SignerProvider> {
Arc::new(SignerProvider::Mock(
SignerFlags::default(),
MockSigner::new(
"broken mock signer",
signer_mapper,
call_counts,
create_registration_key_error_cb,
sign_registration_challenge_error_cb,
),
))
}
fn create_broken_signers(
sm: Arc<SignerMapper>,
cc: Arc<MockSignerCallCounts>,
) -> Vec<Arc<SignerProvider>> {
vec![
create_broken_signer(
sm.clone(),
cc.clone(),
Some(perm_unusable),
None,
),
create_broken_signer(
sm.clone(),
cc.clone(),
Some(internal_error),
None,
),
create_broken_signer(
sm.clone(),
cc.clone(),
Some(temp_unavail),
None,
),
create_broken_signer(
sm.clone(),
cc.clone(),
None,
Some(perm_unusable),
),
create_broken_signer(
sm.clone(),
cc.clone(),
None,
Some(internal_error),
),
create_broken_signer(sm, cc, None, Some(temp_unavail)),
]
}
test::test_in_memory(|storage_uri| {
let call_counts = Arc::new(MockSignerCallCounts::new());
let signer_mapper =
Arc::new(SignerMapper::build(storage_uri).unwrap());
let broken_signers = create_broken_signers(
signer_mapper.clone(),
call_counts.clone(),
);
let router = create_signer_router(
broken_signers.as_slice(),
signer_mapper.clone(),
);
assert_eq!(0, signer_mapper.get_signer_handles().unwrap().len());
let mut rand_out: [u8; 1] = [0; 1];
router.rand(&mut rand_out).unwrap();
assert_eq!(6, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(3, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(0, signer_mapper.get_signer_handles().unwrap().len());
router.rand(&mut rand_out).unwrap();
assert_eq!(6 + 2, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(
3 + 1,
call_counts.get(FnIdx::SignRegistrationChallenge)
);
assert_eq!(0, signer_mapper.get_signer_handles().unwrap().len());
});
}
#[test]
pub fn verify_that_temporarily_unavailable_signers_are_registered_when_available(
) {
fn temp_unavail(
call_counts: &MockSignerCallCounts,
) -> Result<(), SignerError> {
if call_counts.get(FnIdx::CreateRegistrationKey) == 1 {
Err(SignerError::TemporarilyUnavailable)
} else {
Ok(())
}
}
test::test_in_memory(|storage_uri| {
let call_counts = Arc::new(MockSignerCallCounts::new());
let signer_mapper =
Arc::new(SignerMapper::build(storage_uri).unwrap());
let temp_unavail_signer = Arc::new(SignerProvider::Mock(
SignerFlags::default(),
MockSigner::new(
"mock temporararily unavailable signer",
signer_mapper.clone(),
call_counts.clone(),
Some(temp_unavail),
None,
),
));
let router = create_signer_router(
&[temp_unavail_signer],
signer_mapper.clone(),
);
assert_eq!(0, signer_mapper.get_signer_handles().unwrap().len());
let mut rand_out: [u8; 1] = [0; 1];
router.rand(&mut rand_out).unwrap();
assert_eq!(1, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(0, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(0, signer_mapper.get_signer_handles().unwrap().len());
router.rand(&mut rand_out).unwrap();
assert_eq!(2, call_counts.get(FnIdx::CreateRegistrationKey));
assert_eq!(1, call_counts.get(FnIdx::SignRegistrationChallenge));
assert_eq!(1, signer_mapper.get_signer_handles().unwrap().len());
});
}
}