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}