Skip to main content

kipuka_hsm/providers/
mod.rs

1//! HSM provider registry and vendor-specific configurations.
2
3pub mod entrust;
4pub mod kryoptic;
5pub mod thales_csp;
6pub mod thales_tct;
7pub mod utimaco;
8
9use cryptoki::mechanism::MechanismType;
10use serde::Deserialize;
11
12/// Supported HSM providers.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
14pub enum HsmProvider {
15    /// Entrust nShield HSM.
16    Entrust,
17    /// Utimaco CryptoServer HSM.
18    Utimaco,
19    /// Kryoptic software token (FIPS 140-3 module).
20    Kryoptic,
21    /// Thales Luna Cloud HSM (CSP).
22    ThalesCsp,
23    /// Thales Luna Tactical (TCT).
24    ThalesTct,
25}
26
27/// Provider-specific configuration.
28#[derive(Debug, Clone)]
29pub struct HsmProviderConfig {
30    /// Provider identifier.
31    pub provider: HsmProvider,
32    /// Default PKCS#11 library path.
33    pub library_path: String,
34    /// Supported PKCS#11 mechanisms.
35    pub supported_mechanisms: Vec<MechanismType>,
36    /// Provider-specific notes and quirks.
37    pub notes: Vec<String>,
38}
39
40impl HsmProvider {
41    /// Get the default configuration for this provider.
42    pub fn config(&self) -> HsmProviderConfig {
43        match self {
44            Self::Entrust => entrust::provider_config(),
45            Self::Utimaco => utimaco::provider_config(),
46            Self::Kryoptic => kryoptic::provider_config(),
47            Self::ThalesCsp => thales_csp::provider_config(),
48            Self::ThalesTct => thales_tct::provider_config(),
49        }
50    }
51
52    /// Detect provider from PKCS#11 library info.
53    ///
54    /// This is a best-effort heuristic based on library manufacturer strings.
55    pub fn detect_from_library_info(manufacturer: &str, library_description: &str) -> Option<Self> {
56        let manufacturer_lower = manufacturer.to_lowercase();
57        let description_lower = library_description.to_lowercase();
58
59        if manufacturer_lower.contains("entrust") || manufacturer_lower.contains("ncipher") {
60            Some(Self::Entrust)
61        } else if manufacturer_lower.contains("utimaco") {
62            Some(Self::Utimaco)
63        } else if manufacturer_lower.contains("kryoptic") || description_lower.contains("kryoptic")
64        {
65            Some(Self::Kryoptic)
66        } else if manufacturer_lower.contains("thales") || manufacturer_lower.contains("safenet") {
67            // Distinguish CSP vs TCT by library path or model
68            if description_lower.contains("tactical") || description_lower.contains("tct") {
69                Some(Self::ThalesTct)
70            } else {
71                Some(Self::ThalesCsp)
72            }
73        } else {
74            None
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_provider_detection() {
85        assert_eq!(
86            HsmProvider::detect_from_library_info("nCipher Corporation Ltd", "nFast PKCS#11"),
87            Some(HsmProvider::Entrust)
88        );
89
90        assert_eq!(
91            HsmProvider::detect_from_library_info("Utimaco IS GmbH", "CryptoServer PKCS#11"),
92            Some(HsmProvider::Utimaco)
93        );
94
95        assert_eq!(
96            HsmProvider::detect_from_library_info("Thales", "Luna CSP PKCS#11"),
97            Some(HsmProvider::ThalesCsp)
98        );
99
100        assert_eq!(
101            HsmProvider::detect_from_library_info("Thales", "Luna TCT Tactical"),
102            Some(HsmProvider::ThalesTct)
103        );
104    }
105
106    #[test]
107    fn test_all_providers_have_configs() {
108        for provider in &[
109            HsmProvider::Entrust,
110            HsmProvider::Utimaco,
111            HsmProvider::Kryoptic,
112            HsmProvider::ThalesCsp,
113            HsmProvider::ThalesTct,
114        ] {
115            let config = provider.config();
116            assert!(!config.library_path.is_empty());
117            assert!(!config.supported_mechanisms.is_empty());
118        }
119    }
120}