cryptoki/context/
mod.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Pkcs11 context and initialization types
4
5/// Directly get the PKCS #11 operation from the context structure and check for null pointers.
6/// Note that this macro depends on the get_pkcs11_func! macro.
7macro_rules! get_pkcs11 {
8    ($pkcs11:expr, $func_name:ident) => {
9        (get_pkcs11_func!($pkcs11, $func_name).ok_or(crate::error::Error::NullFunctionPointer)?)
10    };
11}
12
13/// Same as get_pkcs11! but does not attempt to apply '?' syntactic sugar.
14/// Suitable only if the caller can't return a Result.
15macro_rules! get_pkcs11_func {
16    ($pkcs11:expr, $func_name:ident) => {
17        ($pkcs11.impl_.get_function_list().$func_name)
18    };
19}
20
21mod general_purpose;
22mod info;
23mod locking;
24mod session_management;
25mod slot_token_management;
26
27pub use general_purpose::*;
28pub use info::*;
29pub use locking::*;
30
31use crate::error::{Error, Result, Rv};
32
33use log::error;
34use std::fmt;
35use std::mem;
36use std::path::Path;
37use std::ptr;
38use std::sync::Arc;
39use std::sync::RwLock;
40
41/// Enum for various function lists
42/// Each following is super-set of the previous one with overlapping start so we store them
43/// in the largest one so we can reference also potentially NULL/non-existing functions
44#[derive(Debug)]
45enum FunctionList {
46    /// PKCS #11 2.40 CK_FUNCTION_LIST
47    V2(cryptoki_sys::CK_FUNCTION_LIST_3_0),
48    /// PKCS #11 3.0 CK_FUNCTION_LIST_3_0
49    V3_0(cryptoki_sys::CK_FUNCTION_LIST_3_0),
50    // TODO when PKCS #11 3.2 will be imported, change the above to 3_2 too!
51    // PKCS #11 3.2 CK_FUNCTION_LIST_3_2
52    //V3_2(cryptoki_sys::CK_FUNCTION_LIST_3_2),
53}
54
55// Implementation of Pkcs11 class that can be enclosed in a single Arc
56pub(crate) struct Pkcs11Impl {
57    // Even if this field is never read, it is needed for the pointers in function_list to remain
58    // valid.
59    _pkcs11_lib: cryptoki_sys::Pkcs11,
60    function_list: FunctionList,
61}
62
63impl fmt::Debug for Pkcs11Impl {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        f.debug_struct("Pkcs11Impl")
66            .field("function_list", &self.function_list)
67            .finish()
68    }
69}
70
71impl Pkcs11Impl {
72    #[inline(always)]
73    pub(crate) fn get_function_list(&self) -> cryptoki_sys::CK_FUNCTION_LIST_3_0 {
74        match self.function_list {
75            FunctionList::V2(l) => l,
76            FunctionList::V3_0(l) => l,
77        }
78    }
79
80    // Private finalize call
81    #[inline(always)]
82    fn finalize(&self) -> Result<()> {
83        unsafe {
84            Rv::from(self
85                .get_function_list()
86                .C_Finalize
87                .ok_or(Error::NullFunctionPointer)?(
88                ptr::null_mut()
89            ))
90            .into_result(Function::Finalize)
91        }
92    }
93}
94
95impl Drop for Pkcs11Impl {
96    fn drop(&mut self) {
97        if let Err(e) = self.finalize() {
98            error!("Failed to finalize: {}", e);
99        }
100    }
101}
102
103/// Main PKCS11 context. Should usually be unique per application.
104#[derive(Clone, Debug)]
105pub struct Pkcs11 {
106    pub(crate) impl_: Arc<Pkcs11Impl>,
107    initialized: Arc<RwLock<bool>>,
108}
109
110impl Pkcs11 {
111    /// Instantiate a new context from the path of a PKCS11 dynamic library implementation.
112    pub fn new<P>(filename: P) -> Result<Self>
113    where
114        P: AsRef<Path>,
115    {
116        unsafe {
117            let pkcs11_lib =
118                cryptoki_sys::Pkcs11::new(filename.as_ref()).map_err(Error::LibraryLoading)?;
119            Self::_new(pkcs11_lib)
120        }
121    }
122
123    /// Instantiate a new context from current executable, the PKCS11 implementation is contained in the current executable
124    pub fn new_from_self() -> Result<Self> {
125        unsafe {
126            #[cfg(not(windows))]
127            let this_lib = libloading::os::unix::Library::this();
128            #[cfg(windows)]
129            let this_lib = libloading::os::windows::Library::this()?;
130            let pkcs11_lib = cryptoki_sys::Pkcs11::from_library(this_lib)?;
131            Self::_new(pkcs11_lib)
132        }
133    }
134
135    unsafe fn _new(pkcs11_lib: cryptoki_sys::Pkcs11) -> Result<Self> {
136        /* First try the 3.0 API to get default interface. It might have some more functions than
137         * the 2.4 API */
138        let mut interface = mem::MaybeUninit::uninit();
139        if pkcs11_lib.C_GetInterface.is_ok() {
140            Rv::from(pkcs11_lib.C_GetInterface(
141                ptr::null_mut(),
142                ptr::null_mut(),
143                interface.as_mut_ptr(),
144                0,
145            ))
146            .into_result(Function::GetInterface)?;
147            if !interface.as_ptr().is_null() {
148                let ifce_ptr: *mut cryptoki_sys::CK_INTERFACE = *interface.as_ptr();
149                let ifce: cryptoki_sys::CK_INTERFACE = *ifce_ptr;
150
151                let list_ptr: *mut cryptoki_sys::CK_FUNCTION_LIST =
152                    ifce.pFunctionList as *mut cryptoki_sys::CK_FUNCTION_LIST;
153                let list: cryptoki_sys::CK_FUNCTION_LIST = *list_ptr;
154                if list.version.major >= 3 {
155                    let list30_ptr: *mut cryptoki_sys::CK_FUNCTION_LIST_3_0 =
156                        ifce.pFunctionList as *mut cryptoki_sys::CK_FUNCTION_LIST_3_0;
157                    return Ok(Pkcs11 {
158                        impl_: Arc::new(Pkcs11Impl {
159                            _pkcs11_lib: pkcs11_lib,
160                            function_list: FunctionList::V3_0(*list30_ptr),
161                        }),
162                        initialized: Arc::new(RwLock::new(false)),
163                    });
164                }
165                /* fall back to the 2.* API */
166            }
167        }
168
169        let mut list = mem::MaybeUninit::uninit();
170
171        Rv::from(pkcs11_lib.C_GetFunctionList(list.as_mut_ptr()))
172            .into_result(Function::GetFunctionList)?;
173
174        let list_ptr = *list.as_ptr();
175
176        Ok(Pkcs11 {
177            impl_: Arc::new(Pkcs11Impl {
178                _pkcs11_lib: pkcs11_lib,
179                function_list: FunctionList::V2(v2tov3(*list_ptr)),
180            }),
181            initialized: Arc::new(RwLock::new(false)),
182        })
183    }
184
185    /// Initialize the PKCS11 library
186    pub fn initialize(&self, init_args: CInitializeArgs) -> Result<()> {
187        let mut init_lock = self
188            .initialized
189            .as_ref()
190            .write()
191            .expect("lock not to be poisoned");
192        if *init_lock {
193            Err(Error::AlreadyInitialized)?
194        }
195        initialize(self, init_args).map(|_| *init_lock = true)
196    }
197
198    /// Check whether the PKCS11 library has been initialized
199    pub fn is_initialized(&self) -> bool {
200        *self
201            .initialized
202            .as_ref()
203            .read()
204            .expect("lock not to be poisoned")
205    }
206
207    /// Finalize the PKCS11 library. Indicates that the application no longer needs to use PKCS11.
208    /// The library is also automatically finalized on drop.
209    pub fn finalize(self) {}
210
211    /// Returns the information about the library
212    pub fn get_library_info(&self) -> Result<Info> {
213        get_library_info(self)
214    }
215
216    /// Check whether a given PKCS11 spec-defined function is supported by this implementation
217    pub fn is_fn_supported(&self, function: Function) -> bool {
218        is_fn_supported(self, function)
219    }
220}
221
222/// This would be great to be From/Into, but it would have to live inside of the cryptoki-sys
223fn v2tov3(f: cryptoki_sys::CK_FUNCTION_LIST) -> cryptoki_sys::CK_FUNCTION_LIST_3_0 {
224    cryptoki_sys::CK_FUNCTION_LIST_3_0 {
225        version: f.version,
226        C_Initialize: f.C_Initialize,
227        C_Finalize: f.C_Finalize,
228        C_GetInfo: f.C_GetInfo,
229        C_GetFunctionList: f.C_GetFunctionList,
230        C_GetSlotList: f.C_GetSlotList,
231        C_GetSlotInfo: f.C_GetSlotInfo,
232        C_GetTokenInfo: f.C_GetTokenInfo,
233        C_GetMechanismList: f.C_GetMechanismList,
234        C_GetMechanismInfo: f.C_GetMechanismInfo,
235        C_InitToken: f.C_InitToken,
236        C_InitPIN: f.C_InitPIN,
237        C_SetPIN: f.C_SetPIN,
238        C_OpenSession: f.C_OpenSession,
239        C_CloseSession: f.C_CloseSession,
240        C_CloseAllSessions: f.C_CloseAllSessions,
241        C_GetSessionInfo: f.C_GetSessionInfo,
242        C_GetOperationState: f.C_GetOperationState,
243        C_SetOperationState: f.C_SetOperationState,
244        C_Login: f.C_Login,
245        C_Logout: f.C_Logout,
246        C_CreateObject: f.C_CreateObject,
247        C_CopyObject: f.C_CopyObject,
248        C_DestroyObject: f.C_DestroyObject,
249        C_GetObjectSize: f.C_GetObjectSize,
250        C_GetAttributeValue: f.C_GetAttributeValue,
251        C_SetAttributeValue: f.C_SetAttributeValue,
252        C_FindObjectsInit: f.C_FindObjectsInit,
253        C_FindObjects: f.C_FindObjects,
254        C_FindObjectsFinal: f.C_FindObjectsFinal,
255        C_EncryptInit: f.C_EncryptInit,
256        C_Encrypt: f.C_Encrypt,
257        C_EncryptUpdate: f.C_EncryptUpdate,
258        C_EncryptFinal: f.C_EncryptFinal,
259        C_DecryptInit: f.C_DecryptInit,
260        C_Decrypt: f.C_Decrypt,
261        C_DecryptUpdate: f.C_DecryptUpdate,
262        C_DecryptFinal: f.C_DecryptFinal,
263        C_DigestInit: f.C_DigestInit,
264        C_Digest: f.C_Digest,
265        C_DigestUpdate: f.C_DigestUpdate,
266        C_DigestKey: f.C_DigestKey,
267        C_DigestFinal: f.C_DigestFinal,
268        C_SignInit: f.C_SignInit,
269        C_Sign: f.C_Sign,
270        C_SignUpdate: f.C_SignUpdate,
271        C_SignFinal: f.C_SignFinal,
272        C_SignRecoverInit: f.C_SignRecoverInit,
273        C_SignRecover: f.C_SignRecover,
274        C_VerifyInit: f.C_VerifyInit,
275        C_Verify: f.C_Verify,
276        C_VerifyUpdate: f.C_VerifyUpdate,
277        C_VerifyFinal: f.C_VerifyFinal,
278        C_VerifyRecoverInit: f.C_VerifyRecoverInit,
279        C_VerifyRecover: f.C_VerifyRecover,
280        C_DigestEncryptUpdate: f.C_DigestEncryptUpdate,
281        C_DecryptDigestUpdate: f.C_DecryptDigestUpdate,
282        C_SignEncryptUpdate: f.C_SignEncryptUpdate,
283        C_DecryptVerifyUpdate: f.C_DecryptVerifyUpdate,
284        C_GenerateKey: f.C_GenerateKey,
285        C_GenerateKeyPair: f.C_GenerateKeyPair,
286        C_WrapKey: f.C_WrapKey,
287        C_UnwrapKey: f.C_UnwrapKey,
288        C_DeriveKey: f.C_DeriveKey,
289        C_SeedRandom: f.C_SeedRandom,
290        C_GenerateRandom: f.C_GenerateRandom,
291        C_GetFunctionStatus: f.C_GetFunctionStatus,
292        C_CancelFunction: f.C_CancelFunction,
293        C_WaitForSlotEvent: f.C_WaitForSlotEvent,
294        C_GetInterfaceList: None,
295        C_GetInterface: None,
296        C_LoginUser: None,
297        C_SessionCancel: None,
298        C_MessageEncryptInit: None,
299        C_EncryptMessage: None,
300        C_EncryptMessageBegin: None,
301        C_EncryptMessageNext: None,
302        C_MessageEncryptFinal: None,
303        C_MessageDecryptInit: None,
304        C_DecryptMessage: None,
305        C_DecryptMessageBegin: None,
306        C_DecryptMessageNext: None,
307        C_MessageDecryptFinal: None,
308        C_MessageSignInit: None,
309        C_SignMessage: None,
310        C_SignMessageBegin: None,
311        C_SignMessageNext: None,
312        C_MessageSignFinal: None,
313        C_MessageVerifyInit: None,
314        C_VerifyMessage: None,
315        C_VerifyMessageBegin: None,
316        C_VerifyMessageNext: None,
317        C_MessageVerifyFinal: None,
318    }
319}