diff --git a/Cargo.lock b/Cargo.lock index 7f61effb..563d1d5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "autocfg" version = "1.3.0" @@ -651,6 +657,7 @@ dependencies = [ name = "nethsm_pkcs11" version = "1.4.1" dependencies = [ + "arc-swap", "base64ct", "config_file", "cryptoki-sys", diff --git a/pkcs11/Cargo.toml b/pkcs11/Cargo.toml index 0101fbfe..0862b7c1 100644 --- a/pkcs11/Cargo.toml +++ b/pkcs11/Cargo.toml @@ -36,6 +36,7 @@ digest = { default-features = false, version = "0.10" } rayon = "1.8.0" syslog = "6.1.0" thiserror = "1.0.63" +arc-swap = "1.7.1" config_file = { path = "config_file" } diff --git a/pkcs11/src/api/mod.rs b/pkcs11/src/api/mod.rs index 5fe65e55..7ad2858b 100644 --- a/pkcs11/src/api/mod.rs +++ b/pkcs11/src/api/mod.rs @@ -13,12 +13,12 @@ pub mod sign; pub mod token; pub mod verify; -use std::ptr::addr_of_mut; use std::sync::atomic::Ordering; +use std::{ptr::addr_of_mut, sync::Arc}; use crate::{ backend::events::{fetch_slots_state, EventsManager}, - data::{self, DEVICE, DEVICE_INIT, EVENTS_MANAGER, THREADS_ALLOWED, TOKENS_STATE}, + data::{self, DEVICE, EVENTS_MANAGER, THREADS_ALLOWED, TOKENS_STATE}, defs, utils::padded_str, }; @@ -44,27 +44,18 @@ pub extern "C" fn C_GetFunctionList( pub extern "C" fn C_Initialize(pInitArgs: CK_VOID_PTR) -> CK_RV { trace!("C_Initialize() called with args: {:?}", pInitArgs); - let mut result = Ok(()); - - DEVICE_INIT.call_once(|| { - let res = crate::config::initialization::initialize(); - match res { - Ok(device) => { - _ = DEVICE.set(device); - } - Err(err) => result = Err(err), + let res = crate::config::initialization::initialize(); + let device = match res { + Ok(device) => { + let arced = Arc::new(device); + DEVICE.store(Some(arced.clone())); + arced } - }); - - match result { - Ok(()) => {} Err(err) => { error!("NetHSM PKCS#11: Failed to initialize configuration: {err}"); return cryptoki_sys::CKR_FUNCTION_FAILED; } - } - - let device = DEVICE.get().expect("Device was just initializated"); + }; // we force the initialization of the lazy static here if device.slots.is_empty() { @@ -118,6 +109,7 @@ pub extern "C" fn C_Finalize(pReserved: CK_VOID_PTR) -> CK_RV { if !pReserved.is_null() { return cryptoki_sys::CKR_ARGUMENTS_BAD; } + DEVICE.store(None); EVENTS_MANAGER.write().unwrap().finalized = true; cryptoki_sys::CKR_OK diff --git a/pkcs11/src/api/object.rs b/pkcs11/src/api/object.rs index 3ed3568f..a56b002d 100644 --- a/pkcs11/src/api/object.rs +++ b/pkcs11/src/api/object.rs @@ -229,7 +229,7 @@ pub extern "C" fn C_SetAttributeValue( } }; - let Some(device) = DEVICE.get() else { + let Some(device) = DEVICE.load_full() else { error!("Initialization was not performed or failed"); return cryptoki_sys::CKR_CRYPTOKI_NOT_INITIALIZED; }; diff --git a/pkcs11/src/api/token.rs b/pkcs11/src/api/token.rs index 87c6183a..0206ebe2 100644 --- a/pkcs11/src/api/token.rs +++ b/pkcs11/src/api/token.rs @@ -31,7 +31,7 @@ pub extern "C" fn C_GetSlotList( return cryptoki_sys::CKR_ARGUMENTS_BAD; } - let Some(device) = DEVICE.get() else { + let Some(device) = DEVICE.load_full() else { error!("Initialization was not performed or failed"); return cryptoki_sys::CKR_CRYPTOKI_NOT_INITIALIZED; }; diff --git a/pkcs11/src/backend/events.rs b/pkcs11/src/backend/events.rs index 75e7df97..6255a356 100644 --- a/pkcs11/src/backend/events.rs +++ b/pkcs11/src/backend/events.rs @@ -36,7 +36,7 @@ pub fn update_slot_state(slot_id: CK_SLOT_ID, present: bool) { } pub fn fetch_slots_state() -> Result<(), cryptoki_sys::CK_RV> { - let Some(device) = DEVICE.get() else { + let Some(device) = DEVICE.load_full() else { error!("Initialization was not performed or failed"); return Err(cryptoki_sys::CKR_CRYPTOKI_NOT_INITIALIZED); }; diff --git a/pkcs11/src/backend/key.rs b/pkcs11/src/backend/key.rs index 6e9d756d..a68eebbc 100644 --- a/pkcs11/src/backend/key.rs +++ b/pkcs11/src/backend/key.rs @@ -169,7 +169,7 @@ fn upload_certificate( } }; - let Some(device) = DEVICE.get() else { + let Some(device) = DEVICE.load_full() else { error!("Initialization was not performed or failed"); return Err(Error::LibraryNotInitialized); }; diff --git a/pkcs11/src/backend/slot.rs b/pkcs11/src/backend/slot.rs index ff7bc4f7..c01dd42a 100644 --- a/pkcs11/src/backend/slot.rs +++ b/pkcs11/src/backend/slot.rs @@ -4,7 +4,7 @@ use crate::{config::device::Slot, data::DEVICE}; use log::error; pub fn get_slot(slot_id: usize) -> Result, cryptoki_sys::CK_RV> { - let Some(device) = DEVICE.get() else { + let Some(device) = DEVICE.load_full() else { error!("Initialization was not performed or failed"); return Err(cryptoki_sys::CKR_CRYPTOKI_NOT_INITIALIZED); }; @@ -19,13 +19,11 @@ pub fn get_slot(slot_id: usize) -> Result, cryptoki_sys::CK_RV> { #[cfg(test)] pub fn init_for_tests() { use std::ptr; - use std::sync::Once; use crate::api::C_Initialize; - static ONCE: Once = Once::new(); - ONCE.call_once(|| { + if DEVICE.load().is_none() { std::env::set_var("P11NETHSM_CONFIG_FILE", "../p11nethsm.conf"); assert_eq!(C_Initialize(ptr::null_mut()), cryptoki_sys::CKR_OK); - }) + } } diff --git a/pkcs11/src/config/initialization.rs b/pkcs11/src/config/initialization.rs index 4505a25e..44ae6e82 100644 --- a/pkcs11/src/config/initialization.rs +++ b/pkcs11/src/config/initialization.rs @@ -62,7 +62,7 @@ pub fn initialize_with_configs( pub fn initialize() -> Result { rustls::crypto::ring::default_provider() .install_default() - .unwrap(); + .ok(); initialize_with_configs(config_files()) } diff --git a/pkcs11/src/data.rs b/pkcs11/src/data.rs index 028d44de..9c136ac9 100644 --- a/pkcs11/src/data.rs +++ b/pkcs11/src/data.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; -use std::sync::{atomic::AtomicBool, Mutex, Once, OnceLock, RwLock}; +use std::sync::{atomic::AtomicBool, Mutex, RwLock}; use crate::backend::events::EventsManager; use crate::{api, backend::session::SessionManager, config::device::Device}; +use arc_swap::ArcSwapOption; use cryptoki_sys::{CK_FUNCTION_LIST, CK_SLOT_ID, CK_VERSION}; use lazy_static::lazy_static; @@ -12,9 +13,7 @@ pub const DEVICE_VERSION: CK_VERSION = CK_VERSION { minor: 40, }; -/// A separate DEVICE_INIT is required because `OnceLock::get_or_try_insert` is unstable -pub static DEVICE_INIT: Once = Once::new(); -pub static DEVICE: OnceLock = OnceLock::new(); +pub static DEVICE: ArcSwapOption = ArcSwapOption::const_empty(); lazy_static! { pub static ref SESSION_MANAGER : Mutex = Mutex::new(SessionManager::new());