#![allow(dead_code)]
use crate::{KeyPair, PublicKey, SecretKey, SignatureBytes, SigningError, verify};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::time::SystemTime;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum HsmError {
#[error("HSM not initialized")]
NotInitialized,
#[error("HSM connection failed: {0}")]
ConnectionFailed(String),
#[error("HSM authentication failed")]
AuthenticationFailed,
#[error("Key not found: {0}")]
KeyNotFound(String),
#[error("Key generation failed: {0}")]
KeyGenerationFailed(String),
#[error("Signing operation failed: {0}")]
SigningFailed(String),
#[error("Unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("PKCS#11 error: {0}")]
Pkcs11Error(String),
#[error("TPM error: {0}")]
TpmError(String),
#[error("Signing error: {0}")]
Signing(#[from] SigningError),
#[error("Configuration error: {0}")]
ConfigError(String),
}
pub type HsmResult<T> = Result<T, HsmError>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum KeyLifecycleState {
#[default]
Active,
Archived,
Compromised,
Revoked,
Pending,
}
impl std::fmt::Display for KeyLifecycleState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Active => write!(f, "active"),
Self::Archived => write!(f, "archived"),
Self::Compromised => write!(f, "compromised"),
Self::Revoked => write!(f, "revoked"),
Self::Pending => write!(f, "pending"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditEventType {
KeyGenerated,
KeyImported,
KeyExported,
SignOperation,
KeyDeleted,
KeyStateChanged,
Authentication,
ConfigChange,
HealthCheck,
}
impl std::fmt::Display for AuditEventType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::KeyGenerated => write!(f, "key_generated"),
Self::KeyImported => write!(f, "key_imported"),
Self::KeyExported => write!(f, "key_exported"),
Self::SignOperation => write!(f, "sign_operation"),
Self::KeyDeleted => write!(f, "key_deleted"),
Self::KeyStateChanged => write!(f, "key_state_changed"),
Self::Authentication => write!(f, "authentication"),
Self::ConfigChange => write!(f, "config_change"),
Self::HealthCheck => write!(f, "health_check"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEntry {
pub timestamp: u64,
pub event_type: AuditEventType,
pub provider: String,
pub key_id: Option<String>,
pub success: bool,
pub error: Option<String>,
pub metadata: HashMap<String, String>,
}
impl AuditEntry {
pub fn new(event_type: AuditEventType, provider: impl Into<String>) -> Self {
Self {
timestamp: SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
event_type,
provider: provider.into(),
key_id: None,
success: true,
error: None,
metadata: HashMap::new(),
}
}
pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
self.key_id = Some(key_id.into());
self
}
pub fn with_error(mut self, error: impl Into<String>) -> Self {
self.success = false;
self.error = Some(error.into());
self
}
pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthStatus {
pub provider: String,
pub healthy: bool,
pub last_check: u64,
pub response_time_ms: u64,
pub error: Option<String>,
pub metrics: HashMap<String, String>,
}
impl HealthStatus {
pub fn new(provider: impl Into<String>, healthy: bool) -> Self {
Self {
provider: provider.into(),
healthy,
last_check: SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
response_time_ms: 0,
error: None,
metrics: HashMap::new(),
}
}
pub fn with_response_time(mut self, ms: u64) -> Self {
self.response_time_ms = ms;
self
}
pub fn with_error(mut self, error: impl Into<String>) -> Self {
self.error = Some(error.into());
self.healthy = false;
self
}
pub fn with_metric(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metrics.insert(key.into(), value.into());
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct KeyId(pub String);
impl KeyId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
}
impl std::fmt::Display for KeyId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyMetadata {
pub id: KeyId,
pub label: String,
pub algorithm: String,
pub created_at: u64,
pub exportable: bool,
pub state: KeyLifecycleState,
pub version: u32,
pub last_used: Option<u64>,
pub last_rotated: Option<u64>,
pub operation_count: u64,
pub attributes: HashMap<String, String>,
}
impl KeyMetadata {
pub fn new(id: KeyId, label: impl Into<String>) -> Self {
Self {
id,
label: label.into(),
algorithm: "Ed25519".to_string(),
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
exportable: false,
state: KeyLifecycleState::Active,
version: 1,
last_used: None,
last_rotated: None,
operation_count: 0,
attributes: HashMap::new(),
}
}
pub fn with_exportable(mut self, exportable: bool) -> Self {
self.exportable = exportable;
self
}
pub fn with_state(mut self, state: KeyLifecycleState) -> Self {
self.state = state;
self
}
pub fn with_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.attributes.insert(key.into(), value.into());
self
}
pub fn record_usage(&mut self) {
self.operation_count += 1;
self.last_used = Some(
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
);
}
pub fn mark_rotated(&mut self) {
self.version += 1;
self.last_rotated = Some(
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
);
}
pub fn is_usable(&self) -> bool {
matches!(self.state, KeyLifecycleState::Active)
}
}
pub trait SigningProvider: Send + Sync {
fn name(&self) -> &str;
fn is_available(&self) -> bool;
fn generate_key(&self, label: &str) -> HsmResult<KeyId>;
fn import_key(&self, label: &str, secret_key: &SecretKey) -> HsmResult<KeyId>;
fn get_public_key(&self, key_id: &KeyId) -> HsmResult<PublicKey>;
fn sign(&self, key_id: &KeyId, message: &[u8]) -> HsmResult<SignatureBytes>;
fn verify(
&self,
public_key: &PublicKey,
message: &[u8],
signature: &SignatureBytes,
) -> HsmResult<()> {
verify(public_key, message, signature).map_err(HsmError::from)
}
fn list_keys(&self) -> HsmResult<Vec<KeyMetadata>>;
fn delete_key(&self, key_id: &KeyId) -> HsmResult<()>;
fn key_exists(&self, key_id: &KeyId) -> bool;
fn export_key(&self, key_id: &KeyId) -> HsmResult<SecretKey> {
let _ = key_id;
Err(HsmError::UnsupportedOperation(
"Key export not supported by this provider".to_string(),
))
}
fn get_key_metadata(&self, key_id: &KeyId) -> HsmResult<KeyMetadata> {
let keys = self.list_keys()?;
keys.into_iter()
.find(|k| k.id == *key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))
}
fn update_key_state(&self, key_id: &KeyId, state: KeyLifecycleState) -> HsmResult<()> {
let _ = (key_id, state);
Err(HsmError::UnsupportedOperation(
"Key state updates not supported by this provider".to_string(),
))
}
fn health_check(&self) -> HsmResult<HealthStatus> {
let start = SystemTime::now();
let healthy = self.is_available();
let elapsed = start.elapsed().unwrap_or_default().as_millis() as u64;
Ok(HealthStatus::new(self.name(), healthy).with_response_time(elapsed))
}
fn batch_sign(&self, key_id: &KeyId, messages: &[&[u8]]) -> HsmResult<Vec<SignatureBytes>> {
messages.iter().map(|msg| self.sign(key_id, msg)).collect()
}
fn get_audit_log(&self, limit: usize) -> HsmResult<Vec<AuditEntry>> {
let _ = limit;
Err(HsmError::UnsupportedOperation(
"Audit log not supported by this provider".to_string(),
))
}
fn rotate_key(&self, key_id: &KeyId, new_label: &str) -> HsmResult<KeyId> {
self.update_key_state(key_id, KeyLifecycleState::Archived)?;
self.generate_key(new_label)
}
}
pub struct SoftwareProvider {
keys: RwLock<HashMap<KeyId, (KeyPair, KeyMetadata)>>,
allow_export: bool,
audit_log: RwLock<Vec<AuditEntry>>,
}
impl Default for SoftwareProvider {
fn default() -> Self {
Self::new()
}
}
impl SoftwareProvider {
pub fn new() -> Self {
Self {
keys: RwLock::new(HashMap::new()),
allow_export: true,
audit_log: RwLock::new(Vec::new()),
}
}
pub fn new_non_exportable() -> Self {
Self {
keys: RwLock::new(HashMap::new()),
allow_export: false,
audit_log: RwLock::new(Vec::new()),
}
}
fn log_audit(&self, entry: AuditEntry) {
let mut log = self.audit_log.write().unwrap();
log.push(entry);
if log.len() > 10_000 {
log.drain(0..1000);
}
}
fn next_key_id(&self) -> KeyId {
let keys = self.keys.read().unwrap();
let mut id = keys.len();
loop {
let key_id = KeyId::new(format!("sw-key-{}", id));
if !keys.contains_key(&key_id) {
return key_id;
}
id += 1;
}
}
}
impl SigningProvider for SoftwareProvider {
fn name(&self) -> &str {
"Software"
}
fn is_available(&self) -> bool {
true
}
#[allow(clippy::redundant_closure_call)]
fn generate_key(&self, label: &str) -> HsmResult<KeyId> {
let result: HsmResult<KeyId> = (|| {
let key_pair = KeyPair::generate();
let key_id = self.next_key_id();
let metadata =
KeyMetadata::new(key_id.clone(), label).with_exportable(self.allow_export);
let mut keys = self.keys.write().unwrap();
keys.insert(key_id.clone(), (key_pair, metadata));
Ok(key_id.clone())
})();
let entry = match &result {
Ok(key_id) => AuditEntry::new(AuditEventType::KeyGenerated, self.name())
.with_key_id(key_id.to_string())
.with_metadata("label", label),
Err(e) => {
AuditEntry::new(AuditEventType::KeyGenerated, self.name()).with_error(e.to_string())
}
};
self.log_audit(entry);
result
}
fn import_key(&self, label: &str, secret_key: &SecretKey) -> HsmResult<KeyId> {
let result: HsmResult<KeyId> = (|| {
let key_pair = KeyPair::from_secret_key(secret_key)?;
let key_id = self.next_key_id();
let metadata =
KeyMetadata::new(key_id.clone(), label).with_exportable(self.allow_export);
let mut keys = self.keys.write().unwrap();
keys.insert(key_id.clone(), (key_pair, metadata));
Ok(key_id.clone())
})();
let entry = match &result {
Ok(key_id) => AuditEntry::new(AuditEventType::KeyImported, self.name())
.with_key_id(key_id.to_string())
.with_metadata("label", label),
Err(e) => {
AuditEntry::new(AuditEventType::KeyImported, self.name()).with_error(e.to_string())
}
};
self.log_audit(entry);
result
}
fn get_public_key(&self, key_id: &KeyId) -> HsmResult<PublicKey> {
let keys = self.keys.read().unwrap();
let (key_pair, _) = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
Ok(key_pair.public_key())
}
fn sign(&self, key_id: &KeyId, message: &[u8]) -> HsmResult<SignatureBytes> {
let result = (|| {
let mut keys = self.keys.write().unwrap();
let (key_pair, metadata) = keys
.get_mut(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
if !metadata.is_usable() {
return Err(HsmError::UnsupportedOperation(format!(
"Key {} is in state '{}' and cannot be used for signing",
key_id, metadata.state
)));
}
metadata.record_usage();
Ok(key_pair.sign(message))
})();
let entry = match &result {
Ok(_) => AuditEntry::new(AuditEventType::SignOperation, self.name())
.with_key_id(key_id.to_string())
.with_metadata("message_len", message.len().to_string()),
Err(e) => AuditEntry::new(AuditEventType::SignOperation, self.name())
.with_key_id(key_id.to_string())
.with_error(e.to_string()),
};
self.log_audit(entry);
result
}
fn list_keys(&self) -> HsmResult<Vec<KeyMetadata>> {
let keys = self.keys.read().unwrap();
Ok(keys.values().map(|(_, meta)| meta.clone()).collect())
}
fn delete_key(&self, key_id: &KeyId) -> HsmResult<()> {
let result: HsmResult<()> = (|| {
let mut keys = self.keys.write().unwrap();
keys.remove(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
Ok(())
})();
let entry = match &result {
Ok(_) => AuditEntry::new(AuditEventType::KeyDeleted, self.name())
.with_key_id(key_id.to_string()),
Err(e) => AuditEntry::new(AuditEventType::KeyDeleted, self.name())
.with_key_id(key_id.to_string())
.with_error(e.to_string()),
};
self.log_audit(entry);
result
}
fn key_exists(&self, key_id: &KeyId) -> bool {
let keys = self.keys.read().unwrap();
keys.contains_key(key_id)
}
fn export_key(&self, key_id: &KeyId) -> HsmResult<SecretKey> {
let result = (|| {
let keys = self.keys.read().unwrap();
let (key_pair, metadata) = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
if !metadata.exportable {
return Err(HsmError::UnsupportedOperation(
"Key is not exportable".to_string(),
));
}
Ok(key_pair.secret_key())
})();
let entry = match &result {
Ok(_) => AuditEntry::new(AuditEventType::KeyExported, self.name())
.with_key_id(key_id.to_string()),
Err(e) => AuditEntry::new(AuditEventType::KeyExported, self.name())
.with_key_id(key_id.to_string())
.with_error(e.to_string()),
};
self.log_audit(entry);
result
}
fn update_key_state(&self, key_id: &KeyId, state: KeyLifecycleState) -> HsmResult<()> {
let result: HsmResult<KeyLifecycleState> = (|| {
let mut keys = self.keys.write().unwrap();
let (_, metadata) = keys
.get_mut(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
let old_state = metadata.state;
metadata.state = state;
Ok(old_state)
})();
let entry = match &result {
Ok(old_state) => AuditEntry::new(AuditEventType::KeyStateChanged, self.name())
.with_key_id(key_id.to_string())
.with_metadata("old_state", old_state.to_string())
.with_metadata("new_state", state.to_string()),
Err(e) => AuditEntry::new(AuditEventType::KeyStateChanged, self.name())
.with_key_id(key_id.to_string())
.with_error(e.to_string()),
};
self.log_audit(entry);
result.map(|_| ())
}
fn get_audit_log(&self, limit: usize) -> HsmResult<Vec<AuditEntry>> {
let log = self.audit_log.read().unwrap();
let len = log.len();
let start = len.saturating_sub(limit);
Ok(log[start..].to_vec())
}
}
#[derive(Debug, Clone)]
pub struct Pkcs11Config {
pub library_path: String,
pub slot_id: u64,
pub pin: String,
pub token_label: Option<String>,
}
impl Pkcs11Config {
pub fn new(library_path: impl Into<String>, slot_id: u64, pin: impl Into<String>) -> Self {
Self {
library_path: library_path.into(),
slot_id,
pin: pin.into(),
token_label: None,
}
}
pub fn with_token_label(mut self, label: impl Into<String>) -> Self {
self.token_label = Some(label.into());
self
}
}
pub struct Pkcs11Provider {
config: Pkcs11Config,
initialized: bool,
}
impl Pkcs11Provider {
pub fn new(config: Pkcs11Config) -> Self {
Self {
config,
initialized: false,
}
}
pub fn initialize(&mut self) -> HsmResult<()> {
if self.config.library_path.is_empty() {
return Err(HsmError::ConfigError(
"PKCS#11 library path is empty".to_string(),
));
}
self.initialized = true;
Ok(())
}
pub fn finalize(&mut self) -> HsmResult<()> {
self.initialized = false;
Ok(())
}
}
impl SigningProvider for Pkcs11Provider {
fn name(&self) -> &str {
"PKCS#11 HSM"
}
fn is_available(&self) -> bool {
self.initialized
}
fn generate_key(&self, label: &str) -> HsmResult<KeyId> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::Pkcs11Error(format!(
"PKCS#11 key generation not implemented for label: {}",
label
)))
}
fn import_key(&self, label: &str, _secret_key: &SecretKey) -> HsmResult<KeyId> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::Pkcs11Error(format!(
"PKCS#11 key import not implemented for label: {}",
label
)))
}
fn get_public_key(&self, key_id: &KeyId) -> HsmResult<PublicKey> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::Pkcs11Error(format!(
"PKCS#11 get_public_key not implemented for key: {}",
key_id
)))
}
fn sign(&self, key_id: &KeyId, _message: &[u8]) -> HsmResult<SignatureBytes> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::Pkcs11Error(format!(
"PKCS#11 signing not implemented for key: {}",
key_id
)))
}
fn list_keys(&self) -> HsmResult<Vec<KeyMetadata>> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Ok(Vec::new())
}
fn delete_key(&self, key_id: &KeyId) -> HsmResult<()> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::Pkcs11Error(format!(
"PKCS#11 key deletion not implemented for key: {}",
key_id
)))
}
fn key_exists(&self, _key_id: &KeyId) -> bool {
false
}
}
#[derive(Debug, Clone)]
pub struct TpmConfig {
pub tcti: String,
pub owner_auth: Option<String>,
pub hierarchy: TpmHierarchy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TpmHierarchy {
#[default]
Owner,
Endorsement,
Platform,
}
impl TpmConfig {
pub fn device(path: impl Into<String>) -> Self {
Self {
tcti: format!("device:{}", path.into()),
owner_auth: None,
hierarchy: TpmHierarchy::Owner,
}
}
pub fn simulator(host: &str, port: u16) -> Self {
Self {
tcti: format!("mssim:host={},port={}", host, port),
owner_auth: None,
hierarchy: TpmHierarchy::Owner,
}
}
pub fn with_owner_auth(mut self, auth: impl Into<String>) -> Self {
self.owner_auth = Some(auth.into());
self
}
pub fn with_hierarchy(mut self, hierarchy: TpmHierarchy) -> Self {
self.hierarchy = hierarchy;
self
}
}
pub struct TpmProvider {
config: TpmConfig,
initialized: bool,
}
impl TpmProvider {
pub fn new(config: TpmConfig) -> Self {
Self {
config,
initialized: false,
}
}
pub fn initialize(&mut self) -> HsmResult<()> {
if self.config.tcti.is_empty() {
return Err(HsmError::ConfigError("TPM TCTI is empty".to_string()));
}
self.initialized = true;
Ok(())
}
pub fn finalize(&mut self) -> HsmResult<()> {
self.initialized = false;
Ok(())
}
}
impl SigningProvider for TpmProvider {
fn name(&self) -> &str {
"TPM 2.0"
}
fn is_available(&self) -> bool {
self.initialized
}
fn generate_key(&self, label: &str) -> HsmResult<KeyId> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::TpmError(format!(
"TPM key generation not implemented for label: {}",
label
)))
}
fn import_key(&self, label: &str, _secret_key: &SecretKey) -> HsmResult<KeyId> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::TpmError(format!(
"TPM key import not implemented for label: {}",
label
)))
}
fn get_public_key(&self, key_id: &KeyId) -> HsmResult<PublicKey> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::TpmError(format!(
"TPM get_public_key not implemented for key: {}",
key_id
)))
}
fn sign(&self, key_id: &KeyId, _message: &[u8]) -> HsmResult<SignatureBytes> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::TpmError(format!(
"TPM signing not implemented for key: {}",
key_id
)))
}
fn list_keys(&self) -> HsmResult<Vec<KeyMetadata>> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Ok(Vec::new())
}
fn delete_key(&self, key_id: &KeyId) -> HsmResult<()> {
if !self.initialized {
return Err(HsmError::NotInitialized);
}
Err(HsmError::TpmError(format!(
"TPM key deletion not implemented for key: {}",
key_id
)))
}
fn key_exists(&self, _key_id: &KeyId) -> bool {
false
}
}
pub struct HsmManager {
providers: RwLock<Vec<Arc<dyn SigningProvider>>>,
default_provider: usize,
}
impl Default for HsmManager {
fn default() -> Self {
Self::new()
}
}
impl HsmManager {
pub fn new() -> Self {
let software = Arc::new(SoftwareProvider::new()) as Arc<dyn SigningProvider>;
Self {
providers: RwLock::new(vec![software]),
default_provider: 0,
}
}
pub fn add_provider(&self, provider: Arc<dyn SigningProvider>) -> usize {
let mut providers = self.providers.write().unwrap();
let index = providers.len();
providers.push(provider);
index
}
pub fn set_default_provider(&mut self, index: usize) -> HsmResult<()> {
let providers = self.providers.read().unwrap();
if index >= providers.len() {
return Err(HsmError::ConfigError(format!(
"Invalid provider index: {}",
index
)));
}
drop(providers);
self.default_provider = index;
Ok(())
}
pub fn default_provider(&self) -> Arc<dyn SigningProvider> {
let providers = self.providers.read().unwrap();
providers[self.default_provider].clone()
}
pub fn provider(&self, index: usize) -> Option<Arc<dyn SigningProvider>> {
let providers = self.providers.read().unwrap();
providers.get(index).cloned()
}
pub fn list_providers(&self) -> Vec<String> {
let providers = self.providers.read().unwrap();
providers.iter().map(|p| p.name().to_string()).collect()
}
pub fn generate_key(&self, label: &str) -> HsmResult<KeyId> {
self.default_provider().generate_key(label)
}
pub fn import_key(&self, label: &str, secret_key: &SecretKey) -> HsmResult<KeyId> {
self.default_provider().import_key(label, secret_key)
}
pub fn sign(&self, key_id: &KeyId, message: &[u8]) -> HsmResult<SignatureBytes> {
self.default_provider().sign(key_id, message)
}
pub fn get_public_key(&self, key_id: &KeyId) -> HsmResult<PublicKey> {
self.default_provider().get_public_key(key_id)
}
pub fn verify(
&self,
public_key: &PublicKey,
message: &[u8],
signature: &SignatureBytes,
) -> HsmResult<()> {
self.default_provider()
.verify(public_key, message, signature)
}
}
pub struct HsmManagerBuilder {
providers: Vec<Arc<dyn SigningProvider>>,
default_index: usize,
}
impl Default for HsmManagerBuilder {
fn default() -> Self {
Self::new()
}
}
impl HsmManagerBuilder {
pub fn new() -> Self {
Self {
providers: Vec::new(),
default_index: 0,
}
}
pub fn with_software(mut self) -> Self {
let provider = Arc::new(SoftwareProvider::new()) as Arc<dyn SigningProvider>;
self.providers.push(provider);
self
}
pub fn with_pkcs11(mut self, config: Pkcs11Config) -> Self {
let provider = Arc::new(Pkcs11Provider::new(config)) as Arc<dyn SigningProvider>;
self.providers.push(provider);
self
}
pub fn with_tpm(mut self, config: TpmConfig) -> Self {
let provider = Arc::new(TpmProvider::new(config)) as Arc<dyn SigningProvider>;
self.providers.push(provider);
self
}
pub fn with_default(mut self, index: usize) -> Self {
self.default_index = index;
self
}
pub fn build(self) -> HsmResult<HsmManager> {
if self.providers.is_empty() {
return Err(HsmError::ConfigError("No providers configured".to_string()));
}
if self.default_index >= self.providers.len() {
return Err(HsmError::ConfigError(format!(
"Invalid default index: {}",
self.default_index
)));
}
Ok(HsmManager {
providers: RwLock::new(self.providers),
default_provider: self.default_index,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_software_provider_lifecycle() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("test-key").unwrap();
assert!(provider.key_exists(&key_id));
let public_key = provider.get_public_key(&key_id).unwrap();
assert_eq!(public_key.len(), 32);
let message = b"Hello, HSM!";
let signature = provider.sign(&key_id, message).unwrap();
provider.verify(&public_key, message, &signature).unwrap();
let keys = provider.list_keys().unwrap();
assert_eq!(keys.len(), 1);
assert_eq!(keys[0].label, "test-key");
let secret = provider.export_key(&key_id).unwrap();
assert_eq!(secret.len(), 32);
provider.delete_key(&key_id).unwrap();
assert!(!provider.key_exists(&key_id));
}
#[test]
fn test_software_provider_import() {
let provider = SoftwareProvider::new();
let original = KeyPair::generate();
let secret = original.secret_key();
let public = original.public_key();
let key_id = provider.import_key("imported", &secret).unwrap();
let imported_public = provider.get_public_key(&key_id).unwrap();
assert_eq!(public, imported_public);
let message = b"Test message";
let signature = provider.sign(&key_id, message).unwrap();
provider.verify(&public, message, &signature).unwrap();
}
#[test]
fn test_non_exportable_keys() {
let provider = SoftwareProvider::new_non_exportable();
let key_id = provider.generate_key("secure-key").unwrap();
let result = provider.export_key(&key_id);
assert!(result.is_err());
assert!(matches!(
result.unwrap_err(),
HsmError::UnsupportedOperation(_)
));
}
#[test]
fn test_hsm_manager() {
let manager = HsmManager::new();
let key_id = manager.generate_key("manager-key").unwrap();
let public_key = manager.get_public_key(&key_id).unwrap();
let message = b"Manager test";
let signature = manager.sign(&key_id, message).unwrap();
manager.verify(&public_key, message, &signature).unwrap();
}
#[test]
fn test_hsm_manager_builder() {
let manager = HsmManagerBuilder::new()
.with_software()
.with_default(0)
.build()
.unwrap();
let providers = manager.list_providers();
assert_eq!(providers.len(), 1);
assert_eq!(providers[0], "Software");
}
#[test]
fn test_pkcs11_provider_not_initialized() {
let config = Pkcs11Config::new("/path/to/pkcs11.so", 0, "1234");
let provider = Pkcs11Provider::new(config);
let result = provider.generate_key("test");
assert!(matches!(result.unwrap_err(), HsmError::NotInitialized));
}
#[test]
fn test_tpm_provider_not_initialized() {
let config = TpmConfig::device("/dev/tpm0");
let provider = TpmProvider::new(config);
let result = provider.generate_key("test");
assert!(matches!(result.unwrap_err(), HsmError::NotInitialized));
}
#[test]
fn test_key_metadata() {
let key_id = KeyId::new("test-123");
let metadata = KeyMetadata::new(key_id.clone(), "My Key")
.with_exportable(true)
.with_attribute("purpose", "signing");
assert_eq!(metadata.id, key_id);
assert_eq!(metadata.label, "My Key");
assert!(metadata.exportable);
assert_eq!(
metadata.attributes.get("purpose"),
Some(&"signing".to_string())
);
}
#[test]
fn test_key_lifecycle_states() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("test-key").unwrap();
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.state, KeyLifecycleState::Active);
assert!(metadata.is_usable());
provider
.update_key_state(&key_id, KeyLifecycleState::Archived)
.unwrap();
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.state, KeyLifecycleState::Archived);
assert!(!metadata.is_usable());
provider
.update_key_state(&key_id, KeyLifecycleState::Revoked)
.unwrap();
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.state, KeyLifecycleState::Revoked);
assert!(!metadata.is_usable());
}
#[test]
fn test_revoked_key_cannot_sign() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("test-key").unwrap();
let message = b"test message";
provider.sign(&key_id, message).unwrap();
provider
.update_key_state(&key_id, KeyLifecycleState::Revoked)
.unwrap();
let result = provider.sign(&key_id, message);
assert!(result.is_err());
}
#[test]
fn test_key_usage_tracking() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("test-key").unwrap();
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.operation_count, 0);
assert!(metadata.last_used.is_none());
for i in 0..5 {
provider.sign(&key_id, &[i]).unwrap();
}
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.operation_count, 5);
assert!(metadata.last_used.is_some());
}
#[test]
fn test_audit_logging() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("test-key").unwrap();
provider.sign(&key_id, b"test").unwrap();
provider.delete_key(&key_id).unwrap();
let log = provider.get_audit_log(10).unwrap();
assert_eq!(log.len(), 3);
assert!(matches!(log[0].event_type, AuditEventType::KeyGenerated));
assert!(log[0].success);
assert!(matches!(log[1].event_type, AuditEventType::SignOperation));
assert!(log[1].success);
assert!(matches!(log[2].event_type, AuditEventType::KeyDeleted));
assert!(log[2].success);
}
#[test]
fn test_audit_log_limit() {
let provider = SoftwareProvider::new();
for i in 0..20 {
provider.generate_key(&format!("key-{}", i)).unwrap();
}
let log = provider.get_audit_log(5).unwrap();
assert_eq!(log.len(), 5);
for entry in &log {
assert!(matches!(entry.event_type, AuditEventType::KeyGenerated));
}
}
#[test]
fn test_health_check() {
let provider = SoftwareProvider::new();
let health = provider.health_check().unwrap();
assert!(health.healthy);
assert_eq!(health.provider, "Software");
assert!(health.response_time_ms < 1000); }
#[test]
fn test_batch_signing() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("batch-key").unwrap();
let messages: Vec<&[u8]> = vec![b"msg1", b"msg2", b"msg3", b"msg4", b"msg5"];
let signatures = provider.batch_sign(&key_id, &messages).unwrap();
assert_eq!(signatures.len(), messages.len());
let public_key = provider.get_public_key(&key_id).unwrap();
for (i, sig) in signatures.iter().enumerate() {
provider.verify(&public_key, messages[i], sig).unwrap();
}
}
#[test]
fn test_key_rotation() {
let provider = SoftwareProvider::new();
let old_key_id = provider.generate_key("old-key").unwrap();
let new_key_id = provider.rotate_key(&old_key_id, "new-key").unwrap();
let old_metadata = provider.get_key_metadata(&old_key_id).unwrap();
assert_eq!(old_metadata.state, KeyLifecycleState::Archived);
let new_metadata = provider.get_key_metadata(&new_key_id).unwrap();
assert_eq!(new_metadata.state, KeyLifecycleState::Active);
assert!(new_metadata.is_usable());
provider.sign(&new_key_id, b"test").unwrap();
let result = provider.sign(&old_key_id, b"test");
assert!(result.is_err());
}
#[test]
fn test_key_versioning() {
let provider = SoftwareProvider::new();
let key_id = provider.generate_key("versioned-key").unwrap();
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.version, 1);
assert!(metadata.last_rotated.is_none());
let mut keys = provider.keys.write().unwrap();
let (_, meta) = keys.get_mut(&key_id).unwrap();
meta.mark_rotated();
drop(keys);
let metadata = provider.get_key_metadata(&key_id).unwrap();
assert_eq!(metadata.version, 2);
assert!(metadata.last_rotated.is_some());
}
#[test]
fn test_lifecycle_state_display() {
assert_eq!(KeyLifecycleState::Active.to_string(), "active");
assert_eq!(KeyLifecycleState::Archived.to_string(), "archived");
assert_eq!(KeyLifecycleState::Compromised.to_string(), "compromised");
assert_eq!(KeyLifecycleState::Revoked.to_string(), "revoked");
assert_eq!(KeyLifecycleState::Pending.to_string(), "pending");
}
#[test]
fn test_audit_entry_builder() {
let entry = AuditEntry::new(AuditEventType::KeyGenerated, "TestProvider")
.with_key_id("test-key-123")
.with_metadata("label", "test-label")
.with_metadata("algorithm", "Ed25519");
assert!(matches!(entry.event_type, AuditEventType::KeyGenerated));
assert_eq!(entry.provider, "TestProvider");
assert_eq!(entry.key_id, Some("test-key-123".to_string()));
assert!(entry.success);
assert_eq!(entry.metadata.get("label"), Some(&"test-label".to_string()));
}
#[test]
fn test_health_status_builder() {
let status = HealthStatus::new("TestProvider", true)
.with_response_time(42)
.with_metric("connections", "5")
.with_metric("keys", "10");
assert_eq!(status.provider, "TestProvider");
assert!(status.healthy);
assert_eq!(status.response_time_ms, 42);
assert_eq!(status.metrics.get("connections"), Some(&"5".to_string()));
assert_eq!(status.metrics.get("keys"), Some(&"10".to_string()));
}
#[test]
fn test_failed_operations_audit() {
let provider = SoftwareProvider::new();
let key_id = KeyId::new("nonexistent");
let _ = provider.sign(&key_id, b"test");
let log = provider.get_audit_log(10).unwrap();
assert!(!log.is_empty());
let last_entry = &log[log.len() - 1];
assert!(!last_entry.success);
assert!(last_entry.error.is_some());
}
}