mod ed25519;
use signatory::ed25519::{PublicKey, Signature};
use std::{collections::BTreeMap, sync::RwLock};
use subtle_encoding;
use tendermint::public_keys::ConsensusKey;
use config::provider::ProviderConfig;
use error::{KmsError, KmsErrorKind::*};
#[cfg(feature = "yubihsm")]
use self::ed25519::yubihsm;
use self::ed25519::{softsign, Signer};
pub type SecretKeyEncoding = subtle_encoding::Base64;
lazy_static! {
static ref GLOBAL_KEYRING: RwLock<KeyRing> = RwLock::new(KeyRing(BTreeMap::default()));
}
pub struct KeyRing(BTreeMap<PublicKey, Signer>);
impl KeyRing {
pub fn load_from_config(config: &ProviderConfig) -> Result<(), KmsError> {
let mut keyring = GLOBAL_KEYRING.write().unwrap();
if !keyring.0.is_empty() {
info!("[keyring:*] Clearing keyring");
keyring.0.clear();
}
#[cfg(feature = "softsign")]
softsign::init(&mut keyring, &config.softsign)?;
#[cfg(feature = "yubihsm")]
yubihsm::init(&mut keyring, &config.yubihsm)?;
if keyring.0.is_empty() {
fail!(ConfigError, "no signing keys configured!")
} else {
Ok(())
}
}
pub(super) fn add(&mut self, public_key: PublicKey, signer: Signer) -> Result<(), KmsError> {
info!(
"[keyring:{}:{}] added validator key {}",
signer.provider_name,
signer.key_id,
ConsensusKey::from(public_key)
);
if let Some(other) = self.0.insert(public_key, signer) {
fail!(
InvalidKey,
"duplicate key {}: already registered as {}:{}",
ConsensusKey::from(public_key),
other.provider_name,
other.key_id
)
} else {
Ok(())
}
}
pub fn default_pubkey() -> Result<PublicKey, KmsError> {
let keyring = GLOBAL_KEYRING.read().unwrap();
let mut keys = keyring.0.keys();
if keys.len() == 1 {
Ok(*keys.next().unwrap())
} else {
fail!(InvalidKey, "expected only one key in keyring");
}
}
pub fn sign(public_key: Option<&PublicKey>, msg: &[u8]) -> Result<Signature, KmsError> {
let keyring = GLOBAL_KEYRING.read().unwrap();
let signer: &Signer = match public_key {
Some(public_key) => keyring.0.get(public_key).ok_or_else(|| {
err!(
InvalidKey,
"not in keyring: {}",
ConsensusKey::from(*public_key)
)
})?,
None => {
let mut vals = keyring.0.values();
if vals.len() > 1 {
fail!(SigningError, "expected only one key in keyring");
} else {
vals.next()
.ok_or_else(|| err!(InvalidKey, "could not get only signer"))?
}
}
};
signer.sign(msg)
}
}