1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! Configuration for the `YubiHSM` backend
use super::KeyType;
use crate::{chain, prelude::*};
use abscissa_core::secret::{CloneableSecret, DebugSecret, ExposeSecret, Secret};
use serde::Deserialize;
use std::{fmt, fs, path::PathBuf, process};
use tendermint_config::net;
use yubihsm::Credentials;
use zeroize::{Zeroize, Zeroizing};
/// The (optional) `[providers.yubihsm]` config section
#[derive(Clone, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct YubihsmConfig {
/// Adapter configuration
pub adapter: AdapterConfig,
/// Authentication configuration
pub auth: AuthConfig,
/// List of signing keys in this YubiHSM
#[serde(default)]
pub keys: Vec<SigningKeyConfig>,
/// Serial number of the YubiHSM to connect to
pub serial_number: Option<String>,
/// Configuration for `yubihsm-connector` compatible HTTP server.
#[cfg(feature = "yubihsm-server")]
pub connector_server: Option<ConnectorServerConfig>,
}
/// Configuration for an individual YubiHSM
#[derive(Clone, Deserialize, Debug)]
#[serde(deny_unknown_fields, tag = "type")]
pub enum AdapterConfig {
/// Connect to the YubiHSM2 directly via USB
#[serde(rename = "usb")]
Usb {
/// Timeout when communicating with YubiHSM2
#[serde(default = "usb_timeout_ms_default")]
timeout_ms: u64,
},
/// Connect to the YubiHSM2 via `yubihsm-connector`
#[serde(rename = "http")]
Http {
/// `yubihsm-connector` configuration
addr: net::Address,
},
}
/// Configuration options for this connector
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields, untagged)]
pub enum AuthConfig {
/// Path to a separate password file
Path {
/// Authentication key ID to use to authenticate to the YubiHSM
key: u16,
/// Password file path
password_file: PathBuf,
},
/// Read password directly from the config file
String {
/// Authentication key ID to use to authenticate to the YubiHSM
key: u16,
/// Password to use to authenticate to the YubiHSM
password: Secret<Password>,
},
}
impl AuthConfig {
/// Get the `yubihsm::Credentials` for this `AuthConfig`
pub fn credentials(&self) -> Credentials {
match self {
AuthConfig::Path { key, password_file } => {
let password =
Zeroizing::new(fs::read_to_string(password_file).unwrap_or_else(|e| {
status_err!("couldn't read key from {}: {}", password_file.display(), e);
process::exit(1);
}));
// TODO(tarcieri): constant-time string trimming
let password_trimmed = password.trim_end();
Credentials::from_password(*key, password_trimmed.as_bytes())
}
AuthConfig::String { key, password } => {
Credentials::from_password(*key, password.expose_secret().0.as_bytes())
}
}
}
}
/// Password to the YubiHSM
#[derive(Clone, Deserialize, Zeroize)]
#[serde(deny_unknown_fields)]
#[zeroize(drop)]
pub struct Password(String);
impl CloneableSecret for Password {}
impl DebugSecret for Password {
fn debug_secret(f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("REDACTED PASSWORD")
}
}
/// Signing key configuration
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SigningKeyConfig {
/// Chains this signing key is authorized to be used from
pub chain_ids: Vec<chain::Id>,
/// Signing key ID
pub key: u16,
/// Type of key
#[serde(default, rename = "type")]
pub key_type: KeyType,
}
/// Default value for `AdapterConfig::Usb { timeout_ms }`
fn usb_timeout_ms_default() -> u64 {
1000
}
/// Configuration for `yubihsm-connector` compatible service
#[cfg(feature = "yubihsm-server")]
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ConnectorServerConfig {
/// Listen address to run the connector service at
pub laddr: net::Address,
/// Connect to the listen address when using `tmkms yubihsm` CLI
pub cli: Option<CliConfig>,
}
/// Overrides for when using the `tmkms yubihsm` command-line interface
#[cfg(feature = "yubihsm-server")]
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CliConfig {
/// Override the auth key to use when using the CLI. This will additionally
/// prompt for a password from the terminal.
pub auth_key: Option<u16>,
}