1use crate::error::{HsmError, HsmResult};
4use cryptoki::context::{CInitializeArgs, Pkcs11};
5use std::path::Path;
6use std::sync::{Arc, Mutex};
7
8#[derive(Clone)]
13pub struct Pkcs11Context {
14 inner: Arc<Mutex<Option<Pkcs11>>>,
15}
16
17impl Pkcs11Context {
18 pub fn new(library_path: impl AsRef<Path>) -> HsmResult<Self> {
28 let path = library_path.as_ref();
29
30 tracing::debug!("Loading PKCS#11 library from {}", path.display());
31
32 let pkcs11 = Pkcs11::new(path).map_err(|e| {
33 HsmError::LibraryLoad(format!("Failed to load {}: {}", path.display(), e))
34 })?;
35
36 pkcs11
38 .initialize(CInitializeArgs::OsThreads)
39 .map_err(|e| HsmError::LibraryLoad(format!("C_Initialize failed: {e}")))?;
40
41 tracing::info!("PKCS#11 library initialized: {}", path.display());
42
43 Ok(Self {
44 inner: Arc::new(Mutex::new(Some(pkcs11))),
45 })
46 }
47
48 pub fn with_pkcs11<F, R>(&self, f: F) -> HsmResult<R>
57 where
58 F: FnOnce(&Pkcs11) -> HsmResult<R>,
59 {
60 let guard = self.inner.lock().expect("Pkcs11Context mutex poisoned");
61 let pkcs11 = guard.as_ref().ok_or_else(|| {
62 HsmError::LibraryLoad("HSM not initialized (placeholder context)".into())
63 })?;
64 f(pkcs11)
65 }
66
67 pub fn library_info(&self) -> HsmResult<String> {
69 self.with_pkcs11(|pkcs11| {
70 let info = pkcs11
71 .get_library_info()
72 .map_err(|e| HsmError::LibraryLoad(format!("Failed to get library info: {e}")))?;
73 Ok(format!(
74 "Library: {} v{}.{}",
75 info.library_description(),
76 info.cryptoki_version().major(),
77 info.cryptoki_version().minor()
78 ))
79 })
80 }
81
82 pub fn placeholder() -> Self {
86 Self {
87 inner: Arc::new(Mutex::new(None)),
88 }
89 }
90}
91
92impl Drop for Pkcs11Context {
93 fn drop(&mut self) {
94 tracing::debug!("PKCS#11 context dropped");
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 #[ignore = "requires PKCS#11 library"]
106 fn test_context_creation() {
107 let result = Pkcs11Context::new("/usr/local/lib/softhsm/libsofthsm2.so");
109 assert!(result.is_ok() || matches!(result, Err(HsmError::LibraryLoad(_))));
110 }
111}