use std::sync::Arc;
use std::{collections::HashMap, sync::RwLock};
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(())
}
}
}
#[cfg(feature = "hsm")]
enum IdentifyResult {
Unavailable,
Corrupt,
Identified(SignerHandle),
Unusable,
Unidentified,
}
#[cfg(feature = "hsm")]
enum RegisterResult {
NotReady,
ReadyVerified(SignerHandle),
ReadyUnusable,
}
#[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 {} pending signers", num_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 '{}' is unavailable", signer_name);
Ok(true)
}
IdentifyResult::Identified(signer_handle) => {
self.active_signers
.write()
.unwrap()
.insert(signer_handle, signer_provider.clone());
info!("Signer '{}' is ready for use", signer_name);
Ok(false)
}
IdentifyResult::Unidentified => {
self.register_new_signer(signer_provider)
.map(|register_result| match register_result {
RegisterResult::NotReady => {
trace!("Signer '{}' is not ready", signer_name);
true
}
RegisterResult::ReadyVerified(signer_handle) => {
self.active_signers
.write()
.unwrap()
.insert(signer_handle, signer_provider.clone());
info!("Signer '{}' is ready for use", signer_name);
false
}
RegisterResult::ReadyUnusable => {
warn!("Signer '{}' could not be registered: signer is not usable", signer_name);
false
}
})
}
IdentifyResult::Unusable => {
warn!("Signer '{}' could not be identified: signer is not usable", signer_name);
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 '{}' using identity key stored for signer '{}'",
signer_name,
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 '{}' is invalid: {}",
handle_name, 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 '{}' could not be contacted", signer_name);
return Ok(IdentifyResult::Unavailable);
}
Err(SignerError::KeyNotFound) => {
debug!(
"Signer '{}' not matched: private key id '{}' not found",
signer_name, signer_private_key_id
);
return Ok(IdentifyResult::Unidentified);
}
Err(err) => {
error!("Signer '{}' is unusable: {}", signer_name, err);
return Ok(IdentifyResult::Unusable);
}
Ok(res) => res,
};
if public_key.verify(challenge, &signature).is_ok() {
debug!("Signer '{}' is ready and known, binding", signer_name);
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 '{}' to '{}': {}",
signer_name, signer_info, err
);
}
debug!(
"Signer '{}' bound to signer mapper handle '{}'",
signer_name, candidate_handle
);
} else {
debug!(
"Signer '{}' not matched: incorrect signature created with private key '{}'",
signer_name, 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(_) => return Ok(RegisterResult::ReadyUnusable),
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(_) => return Ok(RegisterResult::ReadyUnusable),
Ok(res) => res,
};
if public_key.verify(challenge, &signature).is_err() {
error!("Signer '{}' challenge signature is invalid", signer_name);
return Ok(RegisterResult::ReadyUnusable);
}
debug!("Signer '{}' is ready and new, binding", signer_name);
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 '{}' bound to signer handle '{}'", signer_name, 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 rpki::crypto::RpkiSignatureAlgorithm;
use crate::{
commons::crypto::{
dispatch::signerprovider::SignerFlags,
signers::mocksigner::{
CreateRegistrationKeyErrorCb, FnIdx, MockSigner, MockSignerCallCounts, SignRegistrationChallengeErrorCb,
},
},
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_under_tmp(|d| {
#[allow(non_snake_case)]
let DEF_SIG_ALG = RpkiSignatureAlgorithm::default();
let call_counts = Arc::new(MockSignerCallCounts::new());
let signer_mapper = Arc::new(SignerMapper::build(&d).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(&[mock_signer.clone()], 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(&[mock_signer.clone()], 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_under_tmp(|d| {
let call_counts = Arc::new(MockSignerCallCounts::new());
let signer_mapper = Arc::new(SignerMapper::build(&d).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_under_tmp(|d| {
let call_counts = Arc::new(MockSignerCallCounts::new());
let signer_mapper = Arc::new(SignerMapper::build(&d).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());
});
}
}