kipuka_hsm/lib.rs
1//! PKCS#11 HSM abstraction with ML-DSA and ML-KEM support.
2//!
3//! This crate provides a high-level interface to PKCS#11 Hardware Security Modules (HSMs)
4//! with full support for:
5//!
6//! - **Classical algorithms**: RSA (2048/3072/4096), ECDSA (P-256/P-384/P-521)
7//! - **Post-quantum algorithms**: ML-DSA (FIPS 204), ML-KEM (FIPS 203)
8//! - **Key wrapping**: AES Key Wrap (RFC 3394), RSAES-OAEP
9//! - **NIAP CA PP compliance**: FCS_CKM.1 key generation requirements
10//!
11//! # Supported Providers
12//!
13//! - Entrust nShield
14//! - Utimaco CryptoServer
15//! - Kryoptic (software token)
16//! - Thales Luna Cloud HSM (CSP)
17//! - Thales Luna Tactical (TCT)
18//!
19//! # Post-Quantum Cryptography
20//!
21//! PQC mechanisms (ML-DSA, ML-KEM) are vendor-specific until PKCS#11 v3.2 standardization.
22//! Each provider configuration includes vendor-specific mechanism IDs via `PqcMechanismIds`.
23//!
24//! When HSM does not support PQC, the library can fall back to software implementations
25//! using `synta-certificate`.
26//!
27//! # Architecture
28//!
29//! ```text
30//! ┌─────────────────────────────────────────────────────────┐
31//! │ Application Layer │
32//! │ (kipuka EST server) │
33//! └─────────────────────────────────────────────────────────┘
34//! │
35//! ▼
36//! ┌─────────────────────────────────────────────────────────┐
37//! │ kipuka-hsm crate │
38//! │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
39//! │ │ HsmKeyPair │ │ HsmSigner │ │ HsmSlot │ │
40//! │ └──────────────┘ └──────────────┘ └──────────────┘ │
41//! │ │ │ │ │
42//! │ └──────────────┴──────────────────┘ │
43//! │ │ │
44//! │ ┌────────▼────────┐ │
45//! │ │ Pkcs11Context │ │
46//! │ └────────┬────────┘ │
47//! └───────────────────────────┼──────────────────────────────┘
48//! │
49//! ▼
50//! ┌─────────────────────────────────────────────────────────┐
51//! │ cryptoki crate │
52//! │ (Rust PKCS#11 bindings) │
53//! └─────────────────────────────────────────────────────────┘
54//! │
55//! ▼
56//! ┌─────────────────────────────────────────────────────────┐
57//! │ Vendor PKCS#11 Library (.so/.dll) │
58//! │ (Entrust, Utimaco, Kryoptic, Thales CSP/TCT) │
59//! └─────────────────────────────────────────────────────────┘
60//! │
61//! ▼
62//! ┌─────────────────────────────────────────────────────────┐
63//! │ Hardware Security Module │
64//! │ (Physical HSM or software token) │
65//! └─────────────────────────────────────────────────────────┘
66//! ```
67//!
68//! # Example Usage
69//!
70//! ```rust,no_run
71//! use kipuka_hsm::{
72//! HsmSlot, HsmKeyPair, KeyAlgorithm, EcdsaCurve,
73//! Pkcs11Context, sign_ecdsa,
74//! providers::HsmProvider,
75//! key::PqcMechanismIds,
76//! };
77//!
78//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
79//! // Initialize PKCS#11 library
80//! let provider = HsmProvider::Kryoptic;
81//! let config = provider.config();
82//! let context = Pkcs11Context::new(&config.library_path)?;
83//!
84//! // Find HSM slot
85//! let slot = HsmSlot::find_first_slot(&context)?;
86//!
87//! // Generate ECDSA P-256 key pair
88//! let pqc_mechanisms = PqcMechanismIds::default();
89//! let key = HsmKeyPair::generate(
90//! &slot,
91//! KeyAlgorithm::Ecdsa(EcdsaCurve::P256),
92//! "my-signing-key",
93//! &[0x01, 0x02, 0x03], // CKA_ID
94//! &config,
95//! &pqc_mechanisms,
96//! )?;
97//!
98//! // Sign a message digest
99//! let digest = [0u8; 32]; // SHA-256 digest
100//! let signature = sign_ecdsa(&key, &digest)?;
101//! # Ok(())
102//! # }
103//! ```
104//!
105//! # ML-DSA Example
106//!
107//! ```rust,no_run
108//! use kipuka_hsm::{
109//! HsmSlot, HsmKeyPair, KeyAlgorithm, MlDsaLevel,
110//! Pkcs11Context, sign_ml_dsa,
111//! providers::HsmProvider,
112//! key::PqcMechanismIds,
113//! };
114//!
115//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
116//! let provider = HsmProvider::Kryoptic;
117//! let config = provider.config();
118//! let context = Pkcs11Context::new(&config.library_path)?;
119//! let slot = HsmSlot::find_first_slot(&context)?;
120//!
121//! // Configure vendor-specific PQC mechanism IDs
122//! let pqc_mechanisms = PqcMechanismIds {
123//! ml_dsa_keygen: Some(0x8000_0001),
124//! ml_dsa_65: Some(0x8000_0003),
125//! ..Default::default()
126//! };
127//!
128//! // Generate ML-DSA-65 key pair
129//! let key = HsmKeyPair::generate(
130//! &slot,
131//! KeyAlgorithm::MlDsa(MlDsaLevel::L3),
132//! "ml-dsa-signing-key",
133//! &[0x04, 0x05, 0x06],
134//! &config,
135//! &pqc_mechanisms,
136//! )?;
137//!
138//! // Sign a message (ML-DSA hashes internally)
139//! let message = b"Hello, post-quantum world!";
140//! let signature = sign_ml_dsa(&key, message, MlDsaLevel::L3, &pqc_mechanisms)?;
141//! # Ok(())
142//! # }
143//! ```
144
145// Core modules
146pub mod error;
147pub mod key;
148pub mod pkcs11;
149pub mod sign;
150pub mod slot;
151
152// Provider registry
153pub mod providers;
154
155// Re-exports for convenience
156pub use error::{HsmError, HsmResult};
157pub use key::{EcdsaCurve, HsmKeyPair, KeyAlgorithm, MlDsaLevel, MlKemLevel, PqcMechanismIds};
158pub use pkcs11::Pkcs11Context;
159pub use providers::HsmProvider;
160pub use sign::{
161 DefaultHsmSigner, HsmSigner, RsaHashAlgorithm, SoftwarePqcFallback, sign_ecdsa, sign_ml_dsa,
162 sign_rsa_pkcs1, sign_rsa_pss,
163};
164pub use slot::HsmSlot;
165
166/// High-level HSM context wrapping PKCS#11 initialization and provider config.
167///
168/// Used by `AppState` to hold the HSM connection for the server lifetime.
169pub struct HsmContext {
170 pub context: Pkcs11Context,
171 pub provider: HsmProvider,
172}
173
174impl HsmContext {
175 pub fn new(context: Pkcs11Context, provider: HsmProvider) -> Self {
176 Self { context, provider }
177 }
178
179 pub fn placeholder() -> Self {
180 Self {
181 context: Pkcs11Context::placeholder(),
182 provider: HsmProvider::Kryoptic,
183 }
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_module_structure() {
193 // Smoke test to ensure all modules compile and link
194 let _provider = HsmProvider::Kryoptic;
195 let _config = _provider.config();
196 assert!(!_config.library_path.is_empty());
197 }
198
199 #[test]
200 fn test_pqc_mechanism_ids() {
201 let ids = PqcMechanismIds::default();
202 assert!(ids.ml_dsa_keygen.is_some());
203 assert!(ids.ml_kem_keygen.is_some());
204 }
205
206 #[test]
207 fn test_key_algorithms() {
208 let rsa = KeyAlgorithm::Rsa(2048);
209 let ecdsa = KeyAlgorithm::Ecdsa(EcdsaCurve::P256);
210 let ml_dsa = KeyAlgorithm::MlDsa(MlDsaLevel::L3);
211 let ml_kem = KeyAlgorithm::MlKem(MlKemLevel::L3);
212
213 // Just verify they construct
214 assert!(matches!(rsa, KeyAlgorithm::Rsa(2048)));
215 assert!(matches!(ecdsa, KeyAlgorithm::Ecdsa(_)));
216 assert!(matches!(ml_dsa, KeyAlgorithm::MlDsa(_)));
217 assert!(matches!(ml_kem, KeyAlgorithm::MlKem(_)));
218 }
219}