Skip to content

Hardware Security Module Integration with Rust: Enterprise-Grade Key Management

Published: at 06:30 AM

Hardware Security Modules (HSMs) provide the highest level of cryptographic security by storing keys in tamper-resistant hardware. This guide demonstrates building production-ready HSM integrations in Rust that leverage hardware acceleration while maintaining memory safety.

The HSM Integration Challenge

Enterprise cryptographic operations face stringent requirements:

Our Rust implementation achieves:

Architecture Overview

// HSM integration architecture
pub struct HsmManager {
    providers: Vec<Box<dyn HsmProvider>>,
    key_store: KeyStore,
    session_pool: SessionPool,
    load_balancer: HsmLoadBalancer,
    metrics: HsmMetrics,
}

// Multi-vendor HSM abstraction
#[async_trait]
pub trait HsmProvider: Send + Sync {
    async fn initialize(&mut self) -> Result<()>;
    async fn create_session(&self) -> Result<HsmSession>;
    async fn generate_key(&self, spec: &KeySpec) -> Result<KeyHandle>;
    async fn sign(&self, key: &KeyHandle, data: &[u8]) -> Result<Vec<u8>>;
    async fn encrypt(&self, key: &KeyHandle, data: &[u8]) -> Result<Vec<u8>>;
    async fn get_info(&self) -> Result<HsmInfo>;
}

// High-level key management
pub struct KeyManagementSystem {
    hsm_manager: Arc<HsmManager>,
    policy_engine: PolicyEngine,
    audit_logger: AuditLogger,
    rotation_scheduler: RotationScheduler,
}

Core Implementation

1. PKCS#11 Integration

use pkcs11::{Ctx, Flags, Mechanism, Object, Session, Slot};
use std::sync::Arc;
use tokio::sync::{Mutex, Semaphore};
use zeroize::Zeroizing;

pub struct Pkcs11Provider {
    context: Arc<Ctx>,
    slot: Slot,
    pin: Zeroizing<String>,
    session_pool: Arc<SessionPool>,
    capabilities: HsmCapabilities,
}

impl Pkcs11Provider {
    pub async fn new(config: Pkcs11Config) -> Result<Self> {
        // Load PKCS#11 library
        let context = Ctx::new(config.library_path)?;

        // Initialize
        context.initialize(None)?;

        // Find slot
        let slots = context.get_slot_list(true)?;
        let slot = slots
            .into_iter()
            .find(|s| Self::matches_criteria(s, &config.slot_criteria))
            .ok_or(Error::SlotNotFound)?;

        // Get capabilities
        let capabilities = Self::probe_capabilities(&context, slot)?;

        // Create session pool
        let session_pool = Arc::new(SessionPool::new(
            context.clone(),
            slot,
            config.max_sessions,
        ));

        Ok(Self {
            context,
            slot,
            pin: Zeroizing::new(config.pin),
            session_pool,
            capabilities,
        })
    }

    async fn create_session_internal(&self) -> Result<HsmSession> {
        let session = self.session_pool.acquire().await?;

        // Login if required
        session.login(UserType::User, &self.pin)?;

        Ok(HsmSession {
            inner: session,
            provider: self.clone(),
        })
    }
}

#[async_trait]
impl HsmProvider for Pkcs11Provider {
    async fn initialize(&mut self) -> Result<()> {
        // Already initialized in new()
        Ok(())
    }

    async fn create_session(&self) -> Result<HsmSession> {
        self.create_session_internal().await
    }

    async fn generate_key(&self, spec: &KeySpec) -> Result<KeyHandle> {
        let session = self.create_session_internal().await?;

        // Build key attributes
        let mut template = vec![
            Attribute::Class(ObjectClass::SecretKey),
            Attribute::KeyType(spec.key_type.into()),
            Attribute::Token(true),
            Attribute::Private(true),
            Attribute::Sensitive(true),
            Attribute::Extractable(false),
            Attribute::Label(spec.label.as_bytes().to_vec()),
        ];

        // Add key-specific attributes
        match &spec.algorithm {
            Algorithm::Aes(size) => {
                template.push(Attribute::ValueLen(*size / 8));
                template.push(Attribute::Encrypt(true));
                template.push(Attribute::Decrypt(true));
            }
            Algorithm::Rsa(size) => {
                template.push(Attribute::ModulusBits(*size));
                template.push(Attribute::PublicExponent(vec![0x01, 0x00, 0x01])); // 65537
                template.push(Attribute::Sign(true));
                template.push(Attribute::Verify(true));
            }
            Algorithm::EcdsaP256 => {
                template.push(Attribute::EcParams(EC_P256_PARAMS.to_vec()));
                template.push(Attribute::Sign(true));
                template.push(Attribute::Verify(true));
            }
            // ... other algorithms
        }

        // Generate key
        let mechanism = spec.algorithm.generation_mechanism();
        let key_handle = session.inner.generate_key(&mechanism, &template)?;

        // Create persistent handle
        let handle = KeyHandle {
            id: Uuid::new_v4(),
            hsm_handle: key_handle,
            algorithm: spec.algorithm.clone(),
            created_at: SystemTime::now(),
            attributes: spec.attributes.clone(),
        };

        Ok(handle)
    }

    async fn sign(&self, key: &KeyHandle, data: &[u8]) -> Result<Vec<u8>> {
        let session = self.create_session_internal().await?;

        // Get signing mechanism
        let mechanism = key.algorithm.signing_mechanism()?;

        // Initialize signing
        session.inner.sign_init(&mechanism, key.hsm_handle)?;

        // Sign data
        let signature = if data.len() > MAX_SINGLE_PART_SIZE {
            // Multi-part operation
            let mut chunks = data.chunks(CHUNK_SIZE);

            // Process all but last chunk
            for chunk in chunks.by_ref().take(chunks.len() - 1) {
                session.inner.sign_update(chunk)?;
            }

            // Final chunk
            session.inner.sign_final(chunks.last().unwrap())?
        } else {
            // Single-part operation
            session.inner.sign(data)?
        };

        Ok(signature)
    }

    async fn encrypt(&self, key: &KeyHandle, data: &[u8]) -> Result<Vec<u8>> {
        let session = self.create_session_internal().await?;

        // Generate IV if needed
        let iv = if key.algorithm.requires_iv() {
            let mut iv = vec![0u8; key.algorithm.iv_size()];
            session.inner.generate_random(&mut iv)?;
            Some(iv)
        } else {
            None
        };

        // Get encryption mechanism
        let mechanism = key.algorithm.encryption_mechanism(iv.as_deref())?;

        // Initialize encryption
        session.inner.encrypt_init(&mechanism, key.hsm_handle)?;

        // Encrypt data
        let ciphertext = if data.len() > MAX_SINGLE_PART_SIZE {
            // Multi-part operation
            let mut result = Vec::with_capacity(data.len() + 16); // Room for padding

            for chunk in data.chunks(CHUNK_SIZE) {
                let encrypted = session.inner.encrypt_update(chunk)?;
                result.extend_from_slice(&encrypted);
            }

            let final_block = session.inner.encrypt_final()?;
            result.extend_from_slice(&final_block);

            result
        } else {
            // Single-part operation
            session.inner.encrypt(data)?
        };

        // Prepend IV if used
        if let Some(iv) = iv {
            let mut result = iv;
            result.extend_from_slice(&ciphertext);
            Ok(result)
        } else {
            Ok(ciphertext)
        }
    }
}

// Session pool for connection management
pub struct SessionPool {
    context: Arc<Ctx>,
    slot: Slot,
    sessions: Arc<Mutex<Vec<Session>>>,
    semaphore: Arc<Semaphore>,
}

impl SessionPool {
    pub fn new(context: Arc<Ctx>, slot: Slot, max_sessions: usize) -> Self {
        Self {
            context,
            slot,
            sessions: Arc::new(Mutex::new(Vec::with_capacity(max_sessions))),
            semaphore: Arc::new(Semaphore::new(max_sessions)),
        }
    }

    pub async fn acquire(&self) -> Result<PooledSession> {
        // Acquire permit
        let permit = self.semaphore.acquire().await?;

        // Try to get existing session
        let session = {
            let mut sessions = self.sessions.lock().await;
            sessions.pop()
        };

        let session = match session {
            Some(s) => s,
            None => {
                // Create new session
                self.context.open_session(
                    self.slot,
                    Flags::SERIAL_SESSION | Flags::RW_SESSION,
                    None,
                    None,
                )?
            }
        };

        Ok(PooledSession {
            session,
            pool: self.clone(),
            _permit: permit,
        })
    }
}

2. Native HSM APIs

use std::ffi::{CString, c_void};
use std::os::raw::{c_char, c_int, c_ulong};

// Thales nShield Direct API
#[link(name = "nfkm")]
extern "C" {
    fn NFastApp_Connect(
        app_name: *const c_char,
        flags: c_ulong,
        apphandle: *mut *mut c_void,
    ) -> c_int;

    fn NFastApp_Transact(
        conn: *mut c_void,
        command: *const c_void,
        reply: *mut c_void,
        timeout: c_int,
    ) -> c_int;
}

pub struct ThalesProvider {
    connection: *mut c_void,
    capabilities: HsmCapabilities,
}

unsafe impl Send for ThalesProvider {}
unsafe impl Sync for ThalesProvider {}

impl ThalesProvider {
    pub async fn new(config: ThalesConfig) -> Result<Self> {
        let app_name = CString::new(config.app_name)?;
        let mut handle: *mut c_void = std::ptr::null_mut();

        // Connect to HSM
        let result = unsafe {
            NFastApp_Connect(
                app_name.as_ptr(),
                0, // flags
                &mut handle,
            )
        };

        if result != 0 {
            return Err(Error::HsmConnection(result));
        }

        // Probe capabilities
        let capabilities = Self::probe_capabilities(handle)?;

        Ok(Self {
            connection: handle,
            capabilities,
        })
    }

    async fn execute_command(&self, cmd: Command) -> Result<Reply> {
        let command_bytes = bincode::serialize(&cmd)?;
        let mut reply_buffer = vec![0u8; MAX_REPLY_SIZE];

        let result = unsafe {
            NFastApp_Transact(
                self.connection,
                command_bytes.as_ptr() as *const c_void,
                reply_buffer.as_mut_ptr() as *mut c_void,
                TIMEOUT_MS,
            )
        };

        if result != 0 {
            return Err(Error::HsmCommand(result));
        }

        let reply: Reply = bincode::deserialize(&reply_buffer)?;
        Ok(reply)
    }
}

// AWS CloudHSM SDK integration
pub struct CloudHsmProvider {
    client: CloudHsmClient,
    cluster_id: String,
    credentials: AwsCredentials,
}

impl CloudHsmProvider {
    pub async fn new(config: CloudHsmConfig) -> Result<Self> {
        let credentials = AwsCredentials::from_env()?;
        let client = CloudHsmClient::new(Region::from_str(&config.region)?);

        Ok(Self {
            client,
            cluster_id: config.cluster_id,
            credentials,
        })
    }

    async fn get_cluster_info(&self) -> Result<ClusterInfo> {
        let request = DescribeClustersRequest {
            cluster_ids: Some(vec![self.cluster_id.clone()]),
            ..Default::default()
        };

        let response = self.client.describe_clusters(request).await?;
        let cluster = response.clusters
            .and_then(|clusters| clusters.into_iter().next())
            .ok_or(Error::ClusterNotFound)?;

        Ok(ClusterInfo::from(cluster))
    }
}

3. Key Management System

use blake3::Hasher;
use dashmap::DashMap;
use serde::{Serialize, Deserialize};

pub struct KeyManagementSystem {
    hsm_manager: Arc<HsmManager>,
    key_registry: Arc<DashMap<KeyId, KeyMetadata>>,
    policy_engine: Arc<PolicyEngine>,
    audit_log: Arc<AuditLog>,
    cache: Arc<KeyCache>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyMetadata {
    pub id: KeyId,
    pub name: String,
    pub algorithm: Algorithm,
    pub purpose: KeyPurpose,
    pub state: KeyState,
    pub created_at: DateTime<Utc>,
    pub rotated_at: Option<DateTime<Utc>>,
    pub expires_at: Option<DateTime<Utc>>,
    pub hsm_handles: Vec<HsmKeyHandle>,
    pub attributes: KeyAttributes,
    pub policy: KeyPolicy,
}

impl KeyManagementSystem {
    pub async fn create_key(
        &self,
        request: CreateKeyRequest,
    ) -> Result<KeyMetadata> {
        // Validate request against policy
        self.policy_engine.validate_key_creation(&request).await?;

        // Generate unique key ID
        let key_id = self.generate_key_id(&request)?;

        // Select HSM based on policy and load
        let hsm = self.hsm_manager
            .select_hsm(&request.hsm_criteria)
            .await?;

        // Generate key on HSM
        let key_spec = KeySpec {
            algorithm: request.algorithm.clone(),
            label: format!("{}:{}", request.name, key_id),
            attributes: request.attributes.clone(),
        };

        let hsm_handle = hsm.generate_key(&key_spec).await?;

        // Create metadata
        let metadata = KeyMetadata {
            id: key_id.clone(),
            name: request.name,
            algorithm: request.algorithm,
            purpose: request.purpose,
            state: KeyState::Active,
            created_at: Utc::now(),
            rotated_at: None,
            expires_at: request.expires_at,
            hsm_handles: vec![HsmKeyHandle {
                hsm_id: hsm.id(),
                handle: hsm_handle,
                primary: true,
            }],
            attributes: request.attributes,
            policy: request.policy,
        };

        // Store metadata
        self.key_registry.insert(key_id.clone(), metadata.clone());

        // Audit log
        self.audit_log.log_key_creation(&metadata).await?;

        Ok(metadata)
    }

    pub async fn rotate_key(&self, key_id: &KeyId) -> Result<KeyMetadata> {
        // Get current key
        let current = self.key_registry
            .get(key_id)
            .ok_or(Error::KeyNotFound)?;

        // Check rotation policy
        self.policy_engine.validate_key_rotation(&current).await?;

        // Generate new key version
        let new_handle = self.generate_new_key_version(&current).await?;

        // Update metadata
        let mut updated = current.clone();
        updated.rotated_at = Some(Utc::now());
        updated.hsm_handles.push(new_handle);

        // Mark old versions for deletion after grace period
        for handle in &mut updated.hsm_handles {
            if handle.primary {
                handle.primary = false;
                handle.delete_after = Some(Utc::now() + Duration::days(7));
            }
        }

        // Mark new version as primary
        updated.hsm_handles.last_mut().unwrap().primary = true;

        // Store updated metadata
        self.key_registry.insert(key_id.clone(), updated.clone());

        // Audit log
        self.audit_log.log_key_rotation(key_id, &updated).await?;

        Ok(updated)
    }

    pub async fn use_key<F, R>(
        &self,
        key_id: &KeyId,
        operation: KeyOperation,
        f: F,
    ) -> Result<R>
    where
        F: FnOnce(&KeyHandle) -> Result<R>,
    {
        // Check cache first
        if let Some(handle) = self.cache.get(key_id).await {
            return self.execute_with_key(handle, operation, f).await;
        }

        // Get key metadata
        let metadata = self.key_registry
            .get(key_id)
            .ok_or(Error::KeyNotFound)?;

        // Validate operation against policy
        self.policy_engine
            .validate_key_usage(&metadata, &operation)
            .await?;

        // Get primary HSM handle
        let hsm_handle = metadata.hsm_handles
            .iter()
            .find(|h| h.primary)
            .ok_or(Error::NoPrimaryKey)?;

        // Get HSM connection
        let hsm = self.hsm_manager.get_hsm(&hsm_handle.hsm_id).await?;

        // Load key handle
        let key_handle = hsm.load_key(&hsm_handle.handle).await?;

        // Cache for future use
        self.cache.put(key_id.clone(), key_handle.clone()).await;

        // Execute operation
        self.execute_with_key(key_handle, operation, f).await
    }

    async fn execute_with_key<F, R>(
        &self,
        handle: Arc<KeyHandle>,
        operation: KeyOperation,
        f: F,
    ) -> Result<R>
    where
        F: FnOnce(&KeyHandle) -> Result<R>,
    {
        let start = Instant::now();

        // Execute operation
        let result = f(&handle)?;

        // Record metrics
        let duration = start.elapsed();
        self.metrics.record_operation(operation, duration, true);

        // Audit log
        self.audit_log.log_key_usage(
            &handle.id,
            operation,
            duration,
        ).await?;

        Ok(result)
    }
}

// High-performance key cache
pub struct KeyCache {
    cache: Arc<DashMap<KeyId, CachedKey>>,
    ttl: Duration,
    max_size: usize,
}

struct CachedKey {
    handle: Arc<KeyHandle>,
    loaded_at: Instant,
    last_used: AtomicU64,
    usage_count: AtomicU64,
}

impl KeyCache {
    pub async fn get(&self, key_id: &KeyId) -> Option<Arc<KeyHandle>> {
        if let Some(cached) = self.cache.get(key_id) {
            let now = Instant::now();

            // Check TTL
            if now.duration_since(cached.loaded_at) > self.ttl {
                self.cache.remove(key_id);
                return None;
            }

            // Update usage stats
            cached.last_used.store(
                now.elapsed().as_secs(),
                Ordering::Relaxed,
            );
            cached.usage_count.fetch_add(1, Ordering::Relaxed);

            Some(cached.handle.clone())
        } else {
            None
        }
    }

    pub async fn put(&self, key_id: KeyId, handle: Arc<KeyHandle>) {
        // Evict if at capacity
        if self.cache.len() >= self.max_size {
            self.evict_lru();
        }

        let cached = CachedKey {
            handle,
            loaded_at: Instant::now(),
            last_used: AtomicU64::new(0),
            usage_count: AtomicU64::new(0),
        };

        self.cache.insert(key_id, cached);
    }
}

4. Cryptographic Operations

use ring::aead::{Aad, BoundKey, Nonce, NonceSequence, SealingKey, UnboundKey};
use ring::signature::{self, KeyPair};

pub struct CryptoOperations {
    hsm_manager: Arc<HsmManager>,
    operation_cache: Arc<OperationCache>,
}

impl CryptoOperations {
    pub async fn encrypt_data(
        &self,
        key_id: &KeyId,
        plaintext: &[u8],
        aad: Option<&[u8]>,
    ) -> Result<EncryptedData> {
        let hsm = self.hsm_manager.select_hsm_for_key(key_id).await?;

        // Generate nonce
        let nonce = self.generate_nonce()?;

        // Perform encryption on HSM
        let ciphertext = hsm.encrypt_with_aad(
            key_id,
            &nonce,
            plaintext,
            aad.unwrap_or(&[]),
        ).await?;

        Ok(EncryptedData {
            key_id: key_id.clone(),
            nonce: nonce.to_vec(),
            ciphertext,
            aad: aad.map(|a| a.to_vec()),
            algorithm: Algorithm::AesGcm256,
        })
    }

    pub async fn decrypt_data(
        &self,
        encrypted: &EncryptedData,
    ) -> Result<Vec<u8>> {
        let hsm = self.hsm_manager.select_hsm_for_key(&encrypted.key_id).await?;

        // Decrypt on HSM
        let plaintext = hsm.decrypt_with_aad(
            &encrypted.key_id,
            &encrypted.nonce,
            &encrypted.ciphertext,
            encrypted.aad.as_deref().unwrap_or(&[]),
        ).await?;

        Ok(plaintext)
    }

    pub async fn sign_data(
        &self,
        key_id: &KeyId,
        data: &[u8],
        algorithm: SignatureAlgorithm,
    ) -> Result<Signature> {
        let hsm = self.hsm_manager.select_hsm_for_key(key_id).await?;

        // Hash data if required
        let to_sign = match algorithm {
            SignatureAlgorithm::RsaPkcs1Sha256 |
            SignatureAlgorithm::EcdsaP256Sha256 => {
                let mut hasher = Sha256::new();
                hasher.update(data);
                hasher.finalize().to_vec()
            }
            SignatureAlgorithm::Ed25519 => data.to_vec(),
            _ => return Err(Error::UnsupportedAlgorithm),
        };

        // Sign on HSM
        let signature_bytes = hsm.sign(key_id, &to_sign, algorithm).await?;

        Ok(Signature {
            key_id: key_id.clone(),
            algorithm,
            signature: signature_bytes,
            signed_at: SystemTime::now(),
        })
    }

    pub async fn verify_signature(
        &self,
        signature: &Signature,
        data: &[u8],
    ) -> Result<bool> {
        let hsm = self.hsm_manager.select_hsm_for_key(&signature.key_id).await?;

        // Hash data if required
        let to_verify = match signature.algorithm {
            SignatureAlgorithm::RsaPkcs1Sha256 |
            SignatureAlgorithm::EcdsaP256Sha256 => {
                let mut hasher = Sha256::new();
                hasher.update(data);
                hasher.finalize().to_vec()
            }
            SignatureAlgorithm::Ed25519 => data.to_vec(),
            _ => return Err(Error::UnsupportedAlgorithm),
        };

        // Verify on HSM
        hsm.verify(
            &signature.key_id,
            &to_verify,
            &signature.signature,
            signature.algorithm,
        ).await
    }

    pub async fn wrap_key(
        &self,
        kek_id: &KeyId, // Key Encryption Key
        target_key: &[u8],
        algorithm: KeyWrapAlgorithm,
    ) -> Result<WrappedKey> {
        let hsm = self.hsm_manager.select_hsm_for_key(kek_id).await?;

        // Wrap key on HSM
        let wrapped = hsm.wrap_key(kek_id, target_key, algorithm).await?;

        Ok(WrappedKey {
            kek_id: kek_id.clone(),
            wrapped_key: wrapped,
            algorithm,
            wrapped_at: SystemTime::now(),
        })
    }
}

// Batch operations for performance
pub struct BatchCrypto {
    hsm_manager: Arc<HsmManager>,
    batch_size: usize,
}

impl BatchCrypto {
    pub async fn batch_encrypt(
        &self,
        key_id: &KeyId,
        items: Vec<Vec<u8>>,
    ) -> Result<Vec<EncryptedData>> {
        let hsm = self.hsm_manager.select_hsm_for_key(key_id).await?;

        // Process in batches
        let mut results = Vec::with_capacity(items.len());

        for batch in items.chunks(self.batch_size) {
            let batch_results = tokio::join!(
                batch.iter().map(|item| {
                    self.encrypt_single(hsm.clone(), key_id, item)
                })
            );

            results.extend(batch_results);
        }

        Ok(results)
    }
}

5. HSM Load Balancing and Failover

use std::sync::atomic::{AtomicU64, AtomicUsize};
use tokio::time::interval;

pub struct HsmLoadBalancer {
    hsms: Vec<Arc<dyn HsmProvider>>,
    strategy: LoadBalancingStrategy,
    health_checker: HealthChecker,
    metrics: Arc<LoadBalancerMetrics>,
}

#[derive(Clone)]
pub enum LoadBalancingStrategy {
    RoundRobin { counter: Arc<AtomicUsize> },
    LeastConnections,
    WeightedRandom { weights: Vec<f64> },
    PerformanceBased,
}

impl HsmLoadBalancer {
    pub async fn select_hsm(&self) -> Result<Arc<dyn HsmProvider>> {
        // Get healthy HSMs
        let healthy_hsms = self.get_healthy_hsms().await?;

        if healthy_hsms.is_empty() {
            return Err(Error::NoHealthyHsms);
        }

        // Select based on strategy
        match &self.strategy {
            LoadBalancingStrategy::RoundRobin { counter } => {
                let index = counter.fetch_add(1, Ordering::Relaxed) % healthy_hsms.len();
                Ok(healthy_hsms[index].clone())
            }
            LoadBalancingStrategy::LeastConnections => {
                // Select HSM with least active connections
                let mut min_connections = usize::MAX;
                let mut selected = &healthy_hsms[0];

                for hsm in &healthy_hsms {
                    let connections = self.metrics.get_active_connections(hsm.id());
                    if connections < min_connections {
                        min_connections = connections;
                        selected = hsm;
                    }
                }

                Ok(selected.clone())
            }
            LoadBalancingStrategy::PerformanceBased => {
                // Select based on response time
                let mut best_score = f64::MAX;
                let mut selected = &healthy_hsms[0];

                for hsm in &healthy_hsms {
                    let score = self.calculate_performance_score(hsm).await;
                    if score < best_score {
                        best_score = score;
                        selected = hsm;
                    }
                }

                Ok(selected.clone())
            }
            _ => Ok(healthy_hsms[0].clone()),
        }
    }

    async fn calculate_performance_score(&self, hsm: &Arc<dyn HsmProvider>) -> f64 {
        let metrics = self.metrics.get_hsm_metrics(hsm.id());

        // Weight factors
        let latency_weight = 0.5;
        let throughput_weight = 0.3;
        let error_rate_weight = 0.2;

        // Calculate weighted score (lower is better)
        latency_weight * metrics.avg_latency_ms +
        throughput_weight * (1.0 / metrics.ops_per_sec) +
        error_rate_weight * metrics.error_rate
    }
}

// Health checking
pub struct HealthChecker {
    hsms: Vec<Arc<dyn HsmProvider>>,
    check_interval: Duration,
    health_status: Arc<DashMap<String, HealthStatus>>,
}

impl HealthChecker {
    pub async fn start(&self) {
        let mut interval = interval(self.check_interval);

        loop {
            interval.tick().await;

            for hsm in &self.hsms {
                let status = self.check_hsm_health(hsm).await;
                self.health_status.insert(hsm.id(), status);
            }
        }
    }

    async fn check_hsm_health(&self, hsm: &Arc<dyn HsmProvider>) -> HealthStatus {
        // Perform health check
        let start = Instant::now();

        match hsm.get_info().await {
            Ok(info) => {
                let latency = start.elapsed();

                HealthStatus {
                    healthy: true,
                    latency,
                    free_slots: info.free_slots,
                    temperature: info.temperature,
                    last_check: SystemTime::now(),
                }
            }
            Err(_) => {
                HealthStatus {
                    healthy: false,
                    latency: start.elapsed(),
                    free_slots: 0,
                    temperature: None,
                    last_check: SystemTime::now(),
                }
            }
        }
    }
}

6. Compliance and Audit

use serde_json::json;
use chrono::{DateTime, Utc};

pub struct AuditLogger {
    storage: Arc<dyn AuditStorage>,
    signer: Arc<AuditSigner>,
    buffer: Arc<Mutex<Vec<AuditEvent>>>,
}

#[derive(Debug, Serialize)]
pub struct AuditEvent {
    pub id: Uuid,
    pub timestamp: DateTime<Utc>,
    pub event_type: AuditEventType,
    pub actor: Actor,
    pub resource: Resource,
    pub action: Action,
    pub result: ActionResult,
    pub metadata: serde_json::Value,
}

impl AuditLogger {
    pub async fn log_key_operation(
        &self,
        operation: &KeyOperation,
        key_id: &KeyId,
        actor: &Actor,
        result: &OperationResult,
    ) -> Result<()> {
        let event = AuditEvent {
            id: Uuid::new_v4(),
            timestamp: Utc::now(),
            event_type: AuditEventType::KeyOperation,
            actor: actor.clone(),
            resource: Resource::Key(key_id.clone()),
            action: Action::from(operation),
            result: result.into(),
            metadata: json!({
                "operation": operation,
                "duration_ms": result.duration.as_millis(),
                "hsm_id": result.hsm_id,
            }),
        };

        // Sign event
        let signed_event = self.signer.sign_event(&event).await?;

        // Buffer for batch writing
        {
            let mut buffer = self.buffer.lock().await;
            buffer.push(signed_event);

            if buffer.len() >= BATCH_SIZE {
                self.flush_buffer(&mut buffer).await?;
            }
        }

        Ok(())
    }

    async fn flush_buffer(&self, buffer: &mut Vec<AuditEvent>) -> Result<()> {
        if buffer.is_empty() {
            return Ok(());
        }

        // Write to storage
        self.storage.write_batch(buffer).await?;

        // Clear buffer
        buffer.clear();

        Ok(())
    }
}

// FIPS compliance validation
pub struct FipsValidator {
    hsm_info: HsmInfo,
    validation_cache: Arc<DashMap<String, ValidationResult>>,
}

impl FipsValidator {
    pub async fn validate_operation(
        &self,
        operation: &CryptoOperation,
    ) -> Result<ValidationResult> {
        // Check cache
        let cache_key = self.operation_cache_key(operation);
        if let Some(cached) = self.validation_cache.get(&cache_key) {
            return Ok(cached.clone());
        }

        // Validate algorithm
        if !self.is_fips_approved_algorithm(&operation.algorithm) {
            return Ok(ValidationResult::Failed(
                "Algorithm not FIPS approved".to_string()
            ));
        }

        // Validate key size
        if !self.is_valid_key_size(&operation.algorithm, operation.key_size) {
            return Ok(ValidationResult::Failed(
                "Key size not FIPS compliant".to_string()
            ));
        }

        // Validate mode of operation
        if let Some(mode) = &operation.mode {
            if !self.is_fips_approved_mode(&operation.algorithm, mode) {
                return Ok(ValidationResult::Failed(
                    "Mode not FIPS approved".to_string()
                ));
            }
        }

        let result = ValidationResult::Passed;
        self.validation_cache.insert(cache_key, result.clone());

        Ok(result)
    }
}

Performance Benchmarks

#[cfg(test)]
mod benchmarks {
    use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId};

    fn benchmark_key_generation(c: &mut Criterion) {
        let mut group = c.benchmark_group("key_generation");

        for key_type in ["AES-256", "RSA-2048", "ECDSA-P256", "Ed25519"] {
            group.bench_with_input(
                BenchmarkId::from_parameter(key_type),
                &key_type,
                |b, &key_type| {
                    let runtime = tokio::runtime::Runtime::new().unwrap();
                    let hsm = runtime.block_on(create_test_hsm());

                    b.iter(|| {
                        runtime.block_on(async {
                            hsm.generate_key(&create_key_spec(key_type)).await
                        })
                    });
                },
            );
        }

        group.finish();
    }

    fn benchmark_signing(c: &mut Criterion) {
        let mut group = c.benchmark_group("signing");

        for data_size in [32, 256, 1024, 4096] {
            group.bench_with_input(
                BenchmarkId::from_parameter(data_size),
                &data_size,
                |b, &size| {
                    let runtime = tokio::runtime::Runtime::new().unwrap();
                    let hsm = runtime.block_on(create_test_hsm());
                    let key = runtime.block_on(create_test_key(&hsm));
                    let data = vec![0u8; size];

                    b.iter(|| {
                        runtime.block_on(async {
                            hsm.sign(&key, &data).await
                        })
                    });
                },
            );
        }

        group.finish();
    }

    fn benchmark_batch_encryption(c: &mut Criterion) {
        c.bench_function("batch_encrypt_1000", |b| {
            let runtime = tokio::runtime::Runtime::new().unwrap();
            let batch_crypto = runtime.block_on(create_test_batch_crypto());
            let items: Vec<Vec<u8>> = (0..1000)
                .map(|_| vec![0u8; 1024])
                .collect();

            b.iter(|| {
                runtime.block_on(async {
                    batch_crypto.batch_encrypt(&test_key_id(), items.clone()).await
                })
            });
        });
    }

    criterion_group!(
        benches,
        benchmark_key_generation,
        benchmark_signing,
        benchmark_batch_encryption
    );
    criterion_main!(benches);
}

Production Deployment

Configuration

# hsm-config.yaml
hsm:
  providers:
    - type: pkcs11
      name: thales-primary
      library: /opt/nfast/toolkits/pkcs11/libcknfast.so
      slot_criteria:
        label: "Production HSM 1"
      pin_source:
        type: kubernetes_secret
        name: hsm-credentials
        key: pin
      max_sessions: 100

    - type: cloudhsm
      name: aws-cloudhsm
      cluster_id: cluster-abc123
      region: us-east-1
      credentials:
        type: iam_role
        role_arn: arn:aws:iam::123456789012:role/hsm-access

    - type: azure_keyvault
      name: azure-hsm
      vault_name: production-hsm
      tenant_id: ${AZURE_TENANT_ID}

  load_balancing:
    strategy: performance_based
    health_check_interval: 30s
    failover_timeout: 5s

  performance:
    session_pool_size: 50
    operation_timeout: 10s
    batch_size: 100
    cache_ttl: 3600s

key_management:
  default_key_policy:
    algorithm: AES-256-GCM
    rotation_period: 90d
    expiration: 2y
    backup_required: true

  compliance:
    fips_mode: true
    audit_retention: 7y
    key_escrow: false

monitoring:
  metrics:
    enabled: true
    endpoint: /metrics

  alerts:
    - name: high_error_rate
      condition: error_rate > 0.01
      action: page_oncall

    - name: key_rotation_due
      condition: days_until_rotation < 7
      action: email_security_team

Docker Deployment

FROM rust:1.75-slim as builder

# Install HSM client libraries
RUN apt-get update && apt-get install -y \
    libssl-dev \
    pkg-config \
    && rm -rf /var/lib/apt/lists/*

# Copy HSM vendor libraries
COPY vendor/pkcs11 /opt/pkcs11
COPY vendor/thales /opt/nfast

# Build application
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY src ./src

RUN cargo build --release

# Runtime image
FROM debian:bookworm-slim

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    && rm -rf /var/lib/apt/lists/*

# Copy HSM libraries
COPY --from=builder /opt/pkcs11 /opt/pkcs11
COPY --from=builder /opt/nfast /opt/nfast

# Copy application
COPY --from=builder /app/target/release/hsm-service /usr/local/bin/

# Set library paths
ENV LD_LIBRARY_PATH=/opt/pkcs11/lib:/opt/nfast/lib:$LD_LIBRARY_PATH

# Security hardening
RUN useradd -r -u 1000 -s /bin/false hsm-user
USER hsm-user

EXPOSE 8443

ENTRYPOINT ["hsm-service"]

Key Takeaways

  1. Hardware Acceleration: Native HSM integration for maximum performance
  2. Multi-Vendor Support: Unified API across different HSM vendors
  3. Zero-Copy Operations: Efficient memory usage for large-scale operations
  4. Automated Key Management: Policy-driven key lifecycle management
  5. Production Ready: FIPS compliant with comprehensive audit logging

The complete implementation provides enterprise-grade HSM integration that leverages hardware security while maintaining the safety and performance benefits of Rust.

Performance Results

This implementation demonstrates that Rust can deliver high-performance HSM integration suitable for the most demanding enterprise environments.