Skip to main content

kipuka/config/
hsm.rs

1//! HSM / PKCS#11 configuration.
2//!
3//! The `[hsm]` section configures hardware security module access via
4//! the PKCS#11 API.  When present, CA private keys referenced by
5//! `pkcs11_uri` in `[[ca]]` entries are accessed through this HSM.
6//!
7//! Supported HSM providers:
8//!
9//! | Provider | Description |
10//! |----------|-------------|
11//! | `entrust` | Entrust nShield (nCipher) |
12//! | `utimaco` | Utimaco SecurityServer |
13//! | `kryoptic` | Kryoptic software PKCS#11 (dev/test) |
14//! | `thales_csp` | Thales CipherTrust Platform (Luna CSP) |
15//! | `thales_tct` | Thales Luna Network HSM (TCT) |
16
17use serde::Deserialize;
18
19/// HSM provider identifier.
20///
21/// Each provider corresponds to a specific PKCS#11 middleware library
22/// and may require provider-specific initialization parameters.
23#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
24#[serde(rename_all = "lowercase")]
25pub enum HsmProvider {
26    Entrust,
27    Utimaco,
28    Kryoptic,
29    #[serde(rename = "thales_csp")]
30    ThalesCsp,
31    #[serde(rename = "thales_tct")]
32    ThalesTct,
33}
34
35/// `[hsm]` section — PKCS#11 HSM configuration.
36///
37/// ```toml
38/// [hsm]
39/// provider = "entrust"
40/// library_path = "/opt/nfast/toolkits/pkcs11/libcknfast.so"
41/// pin = "env:KIPUKA_HSM_PIN"
42/// slot_id = 0
43/// ```
44#[derive(Debug, Clone, Deserialize)]
45#[serde(deny_unknown_fields)]
46pub struct HsmConfig {
47    /// HSM middleware provider.
48    pub provider: HsmProvider,
49
50    /// Absolute path to the PKCS#11 shared library (`.so` / `.dylib` / `.dll`).
51    pub library_path: String,
52
53    /// PKCS#11 user PIN for session login.
54    ///
55    /// Supports `"env:VAR_NAME"` syntax to read the PIN from an
56    /// environment variable at startup, avoiding plaintext storage
57    /// in the config file.
58    #[serde(default)]
59    pub pin: String,
60
61    /// PKCS#11 slot ID to use.
62    ///
63    /// When absent, the first available slot is used.
64    pub slot_id: Option<u64>,
65
66    /// PKCS#11 token label (alternative to `slot_id`).
67    ///
68    /// When both `slot_id` and `token_label` are set, `slot_id` takes
69    /// precedence.
70    pub token_label: Option<String>,
71
72    /// PKCS#11 URI for advanced key identification.
73    ///
74    /// Example: `"pkcs11:token=kipuka;object=ca-key;type=private"`
75    ///
76    /// This is a template for CA keys; per-CA `pkcs11_uri` in `[[ca]]`
77    /// overrides this when present.
78    pub pkcs11_uri: Option<String>,
79
80    /// Maximum concurrent PKCS#11 sessions.
81    ///
82    /// Limits the number of simultaneous signing operations to avoid
83    /// exhausting HSM session resources.  Default: 8.
84    #[serde(default = "default_max_sessions")]
85    pub max_sessions: usize,
86}
87
88fn default_max_sessions() -> usize {
89    8
90}
91
92impl HsmConfig {
93    /// Resolve the HSM PIN, expanding `"env:VAR_NAME"` references.
94    pub fn resolve_pin(&self) -> std::result::Result<String, String> {
95        if let Some(var_name) = self.pin.strip_prefix("env:") {
96            std::env::var(var_name)
97                .map_err(|_| format!("[hsm].pin references env var {var_name:?} which is not set"))
98        } else {
99            Ok(self.pin.clone())
100        }
101    }
102}