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
//! Configuration for the `YubiHSM` backend

use crate::chain;
use abscissa::secret::{CloneableSecret, DebugSecret, ExposeSecret, Secret};
use serde::Deserialize;
use tendermint::net;
use yubihsm::Credentials;
use zeroize::Zeroize;

/// 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)]
pub struct AuthConfig {
    /// Authentication key ID to use to authenticate to the YubiHSM
    pub key: u16,

    /// Password to use to authenticate to the YubiHSM
    // TODO: allow password to be read from an external password-file
    pub password: Secret<Password>,
}

impl AuthConfig {
    /// Get the `yubihsm::Credentials` for this `AuthConfig`
    pub fn credentials(&self) -> Credentials {
        Credentials::from_password(self.key, self.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() -> &'static 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,
}

/// 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>,
}