chie_crypto/
pkcs11.rs

1// ! PKCS#11 provider implementation for HSM integration.
2//!
3//! This module provides a comprehensive PKCS#11 interface for Hardware Security Module
4//! (HSM) integration. It includes both a mock provider for testing and the interface
5//! for real PKCS#11 library integration.
6//!
7//! # Architecture
8//!
9//! - `Pkcs11Provider`: Main provider implementation
10//! - `Pkcs11Session`: Session management with login/logout
11//! - `Pkcs11MockProvider`: Software mock for testing without hardware
12//!
13//! # Supported Operations
14//!
15//! - Key generation (Ed25519 key pairs)
16//! - Key import/export
17//! - Digital signatures
18//! - Key discovery and listing
19//! - Session management
20//! - PIN-based authentication
21//!
22//! # Example
23//!
24//! ```
25//! use chie_crypto::pkcs11::{Pkcs11MockProvider, Pkcs11Session};
26//! use chie_crypto::hsm::SigningProvider;
27//!
28//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
29//! // Create a mock provider for testing
30//! let mut provider = Pkcs11MockProvider::new();
31//! provider.initialize()?;
32//! provider.open_session(true, Some("1234"))?;
33//!
34//! // Generate a key
35//! let key_id = provider.generate_key("test-key")?;
36//!
37//! // Sign a message
38//! let message = b"Hello, PKCS#11!";
39//! let signature = provider.sign(&key_id, message)?;
40//!
41//! // Verify the signature
42//! let pub_key = provider.get_public_key(&key_id)?;
43//! provider.verify(&pub_key, message, &signature)?;
44//! # Ok(())
45//! # }
46//! ```
47
48#![allow(dead_code)]
49
50use crate::hsm::{
51    AuditEntry, AuditEventType, HealthStatus, HsmError, HsmResult, KeyId, KeyLifecycleState,
52    KeyMetadata, SigningProvider,
53};
54use crate::signing::{KeyPair, PublicKey, SecretKey, SignatureBytes};
55use std::collections::HashMap;
56use std::sync::{Arc, Mutex};
57use std::time::SystemTime;
58
59/// PKCS#11 session state.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum SessionState {
62    /// Session is closed
63    Closed,
64    /// Session is open but not logged in (read-only public session)
65    ReadOnly,
66    /// Session is open and logged in (read-write)
67    ReadWrite,
68}
69
70/// PKCS#11 session handle.
71///
72/// Represents an active session with a PKCS#11 token.
73#[derive(Debug)]
74pub struct Pkcs11Session {
75    /// Session ID
76    session_id: u64,
77    /// Current state
78    state: SessionState,
79    /// Slot ID this session is connected to
80    slot_id: u64,
81    /// Login state
82    logged_in: bool,
83}
84
85impl Pkcs11Session {
86    /// Create a new session.
87    pub fn new(session_id: u64, slot_id: u64, read_write: bool) -> Self {
88        Self {
89            session_id,
90            state: if read_write {
91                SessionState::ReadWrite
92            } else {
93                SessionState::ReadOnly
94            },
95            slot_id,
96            logged_in: false,
97        }
98    }
99
100    /// Get session ID.
101    pub fn id(&self) -> u64 {
102        self.session_id
103    }
104
105    /// Get slot ID.
106    pub fn slot_id(&self) -> u64 {
107        self.slot_id
108    }
109
110    /// Check if logged in.
111    pub fn is_logged_in(&self) -> bool {
112        self.logged_in
113    }
114
115    /// Check if session is read-write.
116    pub fn is_read_write(&self) -> bool {
117        matches!(self.state, SessionState::ReadWrite)
118    }
119
120    /// Login to the session.
121    pub fn login(&mut self, _pin: &str) -> HsmResult<()> {
122        if self.state == SessionState::Closed {
123            return Err(HsmError::Pkcs11Error("Session is closed".to_string()));
124        }
125        self.logged_in = true;
126        Ok(())
127    }
128
129    /// Logout from the session.
130    pub fn logout(&mut self) -> HsmResult<()> {
131        self.logged_in = false;
132        Ok(())
133    }
134
135    /// Close the session.
136    pub fn close(&mut self) -> HsmResult<()> {
137        self.state = SessionState::Closed;
138        self.logged_in = false;
139        Ok(())
140    }
141}
142
143/// Object stored in PKCS#11 token.
144#[derive(Clone)]
145struct Pkcs11Object {
146    /// Object handle (unique identifier)
147    handle: u64,
148    /// Object label
149    label: String,
150    /// Key pair (for key objects)
151    keypair: Option<KeyPair>,
152    /// Public key only (for public key objects)
153    public_key: Option<PublicKey>,
154    /// Object attributes
155    attributes: HashMap<String, Vec<u8>>,
156    /// Creation timestamp
157    created_at: u64,
158}
159
160impl Pkcs11Object {
161    /// Create a new key pair object.
162    fn new_keypair(handle: u64, label: String, keypair: KeyPair) -> Self {
163        Self {
164            handle,
165            label,
166            keypair: Some(keypair),
167            public_key: None,
168            attributes: HashMap::new(),
169            created_at: SystemTime::now()
170                .duration_since(SystemTime::UNIX_EPOCH)
171                .unwrap_or_default()
172                .as_secs(),
173        }
174    }
175
176    /// Get the key ID.
177    fn key_id(&self) -> KeyId {
178        KeyId::new(format!("pkcs11:{}", self.handle))
179    }
180
181    /// Get key metadata.
182    fn to_metadata(&self) -> KeyMetadata {
183        KeyMetadata {
184            id: self.key_id(),
185            label: self.label.clone(),
186            algorithm: "Ed25519".to_string(),
187            created_at: self.created_at,
188            exportable: false,
189            state: KeyLifecycleState::Active,
190            version: 1,
191            last_used: None,
192            last_rotated: None,
193            operation_count: 0,
194            attributes: HashMap::new(),
195        }
196    }
197}
198
199/// Mock PKCS#11 provider for testing.
200///
201/// This is a software implementation that mimics PKCS#11 behavior without
202/// requiring actual HSM hardware. It's suitable for:
203/// - Unit testing
204/// - Integration testing
205/// - Development environments
206/// - CI/CD pipelines
207///
208/// # Security Note
209///
210/// This mock provider stores keys in memory and should NOT be used in production.
211/// For production deployments, use a real PKCS#11 provider with hardware HSMs.
212#[derive(Clone)]
213pub struct Pkcs11MockProvider {
214    /// Slot ID
215    slot_id: u64,
216    /// Objects stored in the token
217    objects: Arc<Mutex<HashMap<u64, Pkcs11Object>>>,
218    /// Next object handle
219    next_handle: Arc<Mutex<u64>>,
220    /// Current session
221    session: Arc<Mutex<Option<Pkcs11Session>>>,
222    /// Audit log
223    audit_log: Arc<Mutex<Vec<AuditEntry>>>,
224    /// Initialized flag
225    initialized: bool,
226}
227
228impl Pkcs11MockProvider {
229    /// Create a new mock provider.
230    pub fn new() -> Self {
231        Self {
232            slot_id: 0,
233            objects: Arc::new(Mutex::new(HashMap::new())),
234            next_handle: Arc::new(Mutex::new(1)),
235            session: Arc::new(Mutex::new(None)),
236            audit_log: Arc::new(Mutex::new(Vec::new())),
237            initialized: false,
238        }
239    }
240
241    /// Create a new mock provider with specific slot ID.
242    pub fn with_slot(slot_id: u64) -> Self {
243        let mut provider = Self::new();
244        provider.slot_id = slot_id;
245        provider
246    }
247
248    /// Initialize the provider.
249    pub fn initialize(&mut self) -> HsmResult<()> {
250        if self.initialized {
251            return Err(HsmError::Pkcs11Error(
252                "Provider already initialized".to_string(),
253            ));
254        }
255
256        self.initialized = true;
257
258        // Log initialization
259        let entry = AuditEntry::new(AuditEventType::Authentication, "PKCS#11 Mock");
260        self.audit_log.lock().unwrap().push(entry);
261
262        Ok(())
263    }
264
265    /// Finalize the provider.
266    pub fn finalize(&mut self) -> HsmResult<()> {
267        // Close any open session
268        if let Some(mut session) = self.session.lock().unwrap().take() {
269            session.close()?;
270        }
271
272        self.initialized = false;
273        Ok(())
274    }
275
276    /// Open a new session.
277    pub fn open_session(&self, read_write: bool, pin: Option<&str>) -> HsmResult<u64> {
278        if !self.initialized {
279            return Err(HsmError::NotInitialized);
280        }
281
282        let mut session_guard = self.session.lock().unwrap();
283
284        // Check if a session already exists
285        if session_guard.is_some() {
286            return Err(HsmError::Pkcs11Error("Session already open".to_string()));
287        }
288
289        // Create new session
290        let session_id = rand::random::<u64>();
291        let mut session = Pkcs11Session::new(session_id, self.slot_id, read_write);
292
293        // Login if PIN provided
294        if let Some(pin) = pin {
295            session.login(pin)?;
296        }
297
298        *session_guard = Some(session);
299
300        Ok(session_id)
301    }
302
303    /// Close the current session.
304    pub fn close_session(&self) -> HsmResult<()> {
305        let mut session_guard = self.session.lock().unwrap();
306
307        if let Some(mut session) = session_guard.take() {
308            session.close()?;
309        }
310
311        Ok(())
312    }
313
314    /// Get the current session.
315    fn get_session(&self) -> HsmResult<()> {
316        let session_guard = self.session.lock().unwrap();
317
318        if session_guard.is_none() {
319            return Err(HsmError::Pkcs11Error("No active session".to_string()));
320        }
321
322        Ok(())
323    }
324
325    /// Allocate a new object handle.
326    fn next_handle(&self) -> u64 {
327        let mut handle = self.next_handle.lock().unwrap();
328        let current = *handle;
329        *handle += 1;
330        current
331    }
332
333    /// Log an audit event.
334    fn log_audit(&self, entry: AuditEntry) {
335        self.audit_log.lock().unwrap().push(entry);
336    }
337
338    /// Get object by handle.
339    fn get_object(&self, handle: u64) -> HsmResult<Pkcs11Object> {
340        let objects = self.objects.lock().unwrap();
341        objects
342            .get(&handle)
343            .cloned()
344            .ok_or_else(|| HsmError::KeyNotFound(format!("Handle: {}", handle)))
345    }
346
347    /// Parse key ID to extract handle.
348    fn parse_key_id(&self, key_id: &KeyId) -> HsmResult<u64> {
349        let id_str = &key_id.0;
350        if !id_str.starts_with("pkcs11:") {
351            return Err(HsmError::KeyNotFound(format!(
352                "Invalid key ID format: {}",
353                id_str
354            )));
355        }
356
357        id_str[7..]
358            .parse()
359            .map_err(|_| HsmError::KeyNotFound(format!("Invalid key ID: {}", id_str)))
360    }
361}
362
363impl Default for Pkcs11MockProvider {
364    fn default() -> Self {
365        Self::new()
366    }
367}
368
369impl SigningProvider for Pkcs11MockProvider {
370    fn name(&self) -> &str {
371        "PKCS#11 Mock Provider"
372    }
373
374    fn is_available(&self) -> bool {
375        self.initialized
376    }
377
378    fn generate_key(&self, label: &str) -> HsmResult<KeyId> {
379        self.get_session()?;
380
381        // Generate Ed25519 key pair
382        let keypair = KeyPair::generate();
383
384        // Allocate handle
385        let handle = self.next_handle();
386
387        // Create object
388        let object = Pkcs11Object::new_keypair(handle, label.to_string(), keypair);
389        let key_id = object.key_id();
390
391        // Store object
392        self.objects.lock().unwrap().insert(handle, object);
393
394        // Log audit event
395        let entry = AuditEntry::new(AuditEventType::KeyGenerated, self.name())
396            .with_key_id(key_id.to_string())
397            .with_metadata("label", label);
398        self.log_audit(entry);
399
400        Ok(key_id)
401    }
402
403    fn import_key(&self, label: &str, secret_key: &SecretKey) -> HsmResult<KeyId> {
404        self.get_session()?;
405
406        // Create key pair from secret key
407        let keypair = KeyPair::from_secret_key(secret_key)?;
408
409        // Allocate handle
410        let handle = self.next_handle();
411
412        // Create object
413        let object = Pkcs11Object::new_keypair(handle, label.to_string(), keypair);
414        let key_id = object.key_id();
415
416        // Store object
417        self.objects.lock().unwrap().insert(handle, object);
418
419        // Log audit event
420        let entry = AuditEntry::new(AuditEventType::KeyImported, self.name())
421            .with_key_id(key_id.to_string())
422            .with_metadata("label", label);
423        self.log_audit(entry);
424
425        Ok(key_id)
426    }
427
428    fn get_public_key(&self, key_id: &KeyId) -> HsmResult<PublicKey> {
429        self.get_session()?;
430
431        let handle = self.parse_key_id(key_id)?;
432        let object = self.get_object(handle)?;
433
434        object
435            .keypair
436            .as_ref()
437            .map(|kp| kp.public_key())
438            .or(object.public_key)
439            .ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))
440    }
441
442    fn sign(&self, key_id: &KeyId, message: &[u8]) -> HsmResult<SignatureBytes> {
443        self.get_session()?;
444
445        let handle = self.parse_key_id(key_id)?;
446        let object = self.get_object(handle)?;
447
448        let keypair = object
449            .keypair
450            .as_ref()
451            .ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
452
453        // Sign the message
454        let signature = keypair.sign(message);
455
456        // Log audit event
457        let entry = AuditEntry::new(AuditEventType::SignOperation, self.name())
458            .with_key_id(key_id.to_string());
459        self.log_audit(entry);
460
461        Ok(signature)
462    }
463
464    fn list_keys(&self) -> HsmResult<Vec<KeyMetadata>> {
465        self.get_session()?;
466
467        let objects = self.objects.lock().unwrap();
468        let keys = objects.values().map(|obj| obj.to_metadata()).collect();
469
470        Ok(keys)
471    }
472
473    fn delete_key(&self, key_id: &KeyId) -> HsmResult<()> {
474        self.get_session()?;
475
476        let handle = self.parse_key_id(key_id)?;
477
478        self.objects
479            .lock()
480            .unwrap()
481            .remove(&handle)
482            .ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
483
484        // Log audit event
485        let entry = AuditEntry::new(AuditEventType::KeyDeleted, self.name())
486            .with_key_id(key_id.to_string());
487        self.log_audit(entry);
488
489        Ok(())
490    }
491
492    fn key_exists(&self, key_id: &KeyId) -> bool {
493        if self.get_session().is_err() {
494            return false;
495        }
496
497        let Ok(handle) = self.parse_key_id(key_id) else {
498            return false;
499        };
500
501        self.objects.lock().unwrap().contains_key(&handle)
502    }
503
504    fn health_check(&self) -> HsmResult<HealthStatus> {
505        let status = HealthStatus::new(self.name(), self.initialized)
506            .with_response_time(1)
507            .with_metric(
508                "objects_count",
509                self.objects.lock().unwrap().len().to_string(),
510            )
511            .with_metric("slot_id", self.slot_id.to_string());
512
513        Ok(status)
514    }
515
516    fn get_audit_log(&self, limit: usize) -> HsmResult<Vec<AuditEntry>> {
517        let log = self.audit_log.lock().unwrap();
518        let len = log.len();
519        let start = len.saturating_sub(limit);
520        Ok(log[start..].to_vec())
521    }
522}
523
524#[cfg(test)]
525mod tests {
526    use super::*;
527    use crate::verify;
528
529    #[test]
530    fn test_mock_provider_initialization() {
531        let mut provider = Pkcs11MockProvider::new();
532        assert!(!provider.is_available());
533
534        provider.initialize().unwrap();
535        assert!(provider.is_available());
536
537        provider.finalize().unwrap();
538        assert!(!provider.is_available());
539    }
540
541    #[test]
542    fn test_double_initialization_fails() {
543        let mut provider = Pkcs11MockProvider::new();
544        provider.initialize().unwrap();
545        assert!(provider.initialize().is_err());
546    }
547
548    #[test]
549    fn test_session_management() {
550        let mut provider = Pkcs11MockProvider::new();
551        provider.initialize().unwrap();
552
553        // Open session
554        let session_id = provider.open_session(true, Some("1234")).unwrap();
555        assert!(session_id > 0);
556
557        // Cannot open another session
558        assert!(provider.open_session(true, None).is_err());
559
560        // Close session
561        provider.close_session().unwrap();
562
563        // Can open new session after closing
564        provider.open_session(false, None).unwrap();
565    }
566
567    #[test]
568    fn test_key_generation() {
569        let mut provider = Pkcs11MockProvider::new();
570        provider.initialize().unwrap();
571        provider.open_session(true, Some("1234")).unwrap();
572
573        let key_id = provider.generate_key("test-key").unwrap();
574        assert!(key_id.0.starts_with("pkcs11:"));
575        assert!(provider.key_exists(&key_id));
576    }
577
578    #[test]
579    fn test_key_import() {
580        let mut provider = Pkcs11MockProvider::new();
581        provider.initialize().unwrap();
582        provider.open_session(true, Some("1234")).unwrap();
583
584        let keypair = KeyPair::generate();
585        let key_id = provider
586            .import_key("imported-key", &keypair.secret_key())
587            .unwrap();
588
589        assert!(provider.key_exists(&key_id));
590        let pub_key = provider.get_public_key(&key_id).unwrap();
591        assert_eq!(pub_key, keypair.public_key());
592    }
593
594    #[test]
595    fn test_signing() {
596        let mut provider = Pkcs11MockProvider::new();
597        provider.initialize().unwrap();
598        provider.open_session(true, Some("1234")).unwrap();
599
600        let key_id = provider.generate_key("signing-key").unwrap();
601        let message = b"Test message for PKCS#11";
602
603        let signature = provider.sign(&key_id, message).unwrap();
604        let pub_key = provider.get_public_key(&key_id).unwrap();
605
606        assert!(verify(&pub_key, message, &signature).is_ok());
607    }
608
609    #[test]
610    fn test_list_keys() {
611        let mut provider = Pkcs11MockProvider::new();
612        provider.initialize().unwrap();
613        provider.open_session(true, Some("1234")).unwrap();
614
615        assert_eq!(provider.list_keys().unwrap().len(), 0);
616
617        provider.generate_key("key1").unwrap();
618        provider.generate_key("key2").unwrap();
619        provider.generate_key("key3").unwrap();
620
621        let keys = provider.list_keys().unwrap();
622        assert_eq!(keys.len(), 3);
623
624        let labels: Vec<_> = keys.iter().map(|k| k.label.as_str()).collect();
625        assert!(labels.contains(&"key1"));
626        assert!(labels.contains(&"key2"));
627        assert!(labels.contains(&"key3"));
628    }
629
630    #[test]
631    fn test_delete_key() {
632        let mut provider = Pkcs11MockProvider::new();
633        provider.initialize().unwrap();
634        provider.open_session(true, Some("1234")).unwrap();
635
636        let key_id = provider.generate_key("delete-me").unwrap();
637        assert!(provider.key_exists(&key_id));
638
639        provider.delete_key(&key_id).unwrap();
640        assert!(!provider.key_exists(&key_id));
641
642        // Deleting again should fail
643        assert!(provider.delete_key(&key_id).is_err());
644    }
645
646    #[test]
647    fn test_operations_without_session_fail() {
648        let mut provider = Pkcs11MockProvider::new();
649        provider.initialize().unwrap();
650
651        // No session opened
652        assert!(provider.generate_key("key").is_err());
653        assert!(provider.list_keys().is_err());
654    }
655
656    #[test]
657    fn test_operations_without_initialization_fail() {
658        let provider = Pkcs11MockProvider::new();
659
660        assert!(!provider.is_available());
661        assert!(provider.open_session(true, None).is_err());
662    }
663
664    #[test]
665    fn test_get_nonexistent_key() {
666        let mut provider = Pkcs11MockProvider::new();
667        provider.initialize().unwrap();
668        provider.open_session(true, Some("1234")).unwrap();
669
670        let fake_key_id = KeyId::new("pkcs11:999999");
671        assert!(!provider.key_exists(&fake_key_id));
672        assert!(provider.get_public_key(&fake_key_id).is_err());
673        assert!(provider.delete_key(&fake_key_id).is_err());
674    }
675
676    #[test]
677    fn test_health_status() {
678        let mut provider = Pkcs11MockProvider::new();
679        provider.initialize().unwrap();
680
681        let health = provider.health_check().unwrap();
682        assert!(health.healthy);
683        assert_eq!(health.provider, "PKCS#11 Mock Provider");
684    }
685
686    #[test]
687    fn test_audit_logging() {
688        let mut provider = Pkcs11MockProvider::new();
689        provider.initialize().unwrap();
690        provider.open_session(true, Some("1234")).unwrap();
691
692        // Should have initialization entry
693        assert!(!provider.get_audit_log(100).unwrap().is_empty());
694
695        let initial_count = provider.get_audit_log(100).unwrap().len();
696
697        provider.generate_key("audit-test").unwrap();
698
699        let log = provider.get_audit_log(100).unwrap();
700        assert_eq!(log.len(), initial_count + 1);
701
702        let last_entry = log.last().unwrap();
703        assert!(matches!(
704            last_entry.event_type,
705            AuditEventType::KeyGenerated
706        ));
707        assert!(last_entry.success);
708    }
709
710    #[test]
711    fn test_audit_log_limit() {
712        let mut provider = Pkcs11MockProvider::new();
713        provider.initialize().unwrap();
714        provider.open_session(true, Some("1234")).unwrap();
715
716        // Generate multiple keys
717        for i in 0..10 {
718            provider.generate_key(&format!("key{}", i)).unwrap();
719        }
720
721        // Get last 5 entries
722        let log = provider.get_audit_log(5).unwrap();
723        assert_eq!(log.len(), 5);
724    }
725}