no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / security / manager / ssl / osclientcerts / src / lib.rs
blob8806e616b4b21a2252c9c4e7b7b4631e876e5fc9
1 /* -*- Mode: rust; rust-indent-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #![allow(non_snake_case)]
8 extern crate byteorder;
9 #[cfg(any(target_os = "macos", target_os = "ios"))]
10 #[macro_use]
11 extern crate core_foundation;
12 extern crate env_logger;
13 #[cfg(any(target_os = "macos", target_os = "ios"))]
14 #[macro_use]
15 extern crate lazy_static;
16 #[cfg(target_os = "macos")]
17 extern crate libloading;
18 #[macro_use]
19 extern crate log;
20 extern crate pkcs11_bindings;
21 #[macro_use]
22 extern crate rsclientcerts;
23 extern crate sha2;
24 #[cfg(target_os = "windows")]
25 extern crate winapi;
27 use pkcs11_bindings::*;
28 use rsclientcerts::manager::{ManagerProxy, SlotType};
29 use std::ffi::CStr;
30 use std::sync::Mutex;
31 use std::thread;
33 #[cfg(any(target_os = "macos", target_os = "ios"))]
34 mod backend_macos;
35 #[cfg(target_os = "windows")]
36 mod backend_windows;
38 #[cfg(any(target_os = "macos", target_os = "ios"))]
39 use crate::backend_macos::Backend;
40 #[cfg(target_os = "windows")]
41 use crate::backend_windows::Backend;
43 struct ModuleState {
44     manager_proxy: ManagerProxy,
45     mechanisms: Vec<CK_MECHANISM_TYPE>,
48 /// The singleton `ModuleState` that handles state with respect to PKCS #11. Only one thread
49 /// may use it at a time, but there is no restriction on which threads may use it. However, as
50 /// OS APIs being used are not necessarily thread-safe (e.g. they may be using
51 /// thread-local-storage), the `ManagerProxy` of the `ModuleState` forwards calls from any
52 /// thread to a single thread where the real `Manager` does the actual work.
53 static MODULE_STATE: Mutex<Option<ModuleState>> = Mutex::new(None);
55 // Obtaining a handle on the manager proxy is a two-step process. First the mutex must be locked,
56 // which (if successful), results in a mutex guard object. We must then get a mutable refence to the
57 // underlying manager proxy (if set - otherwise we return an error). This can't happen all in one
58 // macro without dropping a reference that needs to live long enough for this to be safe. In
59 // practice, this looks like:
60 //   let mut module_state_guard = try_to_get_module_state_guard!();
61 //   let manager = module_state_guard_to_manager!(module_state_guard);
62 macro_rules! try_to_get_module_state_guard {
63     () => {
64         match MODULE_STATE.lock() {
65             Ok(maybe_module_state) => maybe_module_state,
66             Err(poison_error) => {
67                 log_with_thread_id!(
68                     error,
69                     "previous thread panicked acquiring manager lock: {}",
70                     poison_error
71                 );
72                 return CKR_DEVICE_ERROR;
73             }
74         }
75     };
78 macro_rules! module_state_guard_to_manager {
79     ($module_state_guard:ident) => {
80         match $module_state_guard.as_mut() {
81             Some(module_state) => &mut module_state.manager_proxy,
82             None => {
83                 log_with_thread_id!(error, "module state expected to be set, but it is not");
84                 return CKR_DEVICE_ERROR;
85             }
86         }
87     };
90 macro_rules! module_state_guard_to_mechanisms {
91     ($module_state_guard:ident) => {
92         match $module_state_guard.as_ref() {
93             Some(module_state) => &module_state.mechanisms,
94             None => {
95                 log_with_thread_id!(error, "module state expected to be set, but it is not");
96                 return CKR_DEVICE_ERROR;
97             }
98         }
99     };
102 // Helper macro to prefix log messages with the current thread ID.
103 macro_rules! log_with_thread_id {
104     ($log_level:ident, $($message:expr),*) => {
105         $log_level!("{:?} {}", thread::current().id(), format_args!($($message),*));
106     };
109 /// This gets called to initialize the module. For this implementation, this consists of
110 /// instantiating the `ManagerProxy`.
111 extern "C" fn C_Initialize(pInitArgs: CK_VOID_PTR) -> CK_RV {
112     // This will fail if this has already been called, but this isn't a problem because either way,
113     // logging has been initialized.
114     let _ = env_logger::try_init();
116     if pInitArgs.is_null() {
117         return CKR_DEVICE_ERROR;
118     }
119     let init_args_ptr = unsafe { (*(pInitArgs as CK_C_INITIALIZE_ARGS_PTR)).pReserved };
120     if init_args_ptr.is_null() {
121         return CKR_DEVICE_ERROR;
122     }
123     let init_args_cstr = unsafe { CStr::from_ptr(init_args_ptr as *mut std::os::raw::c_char) };
124     let init_args = match init_args_cstr.to_str() {
125         Ok(init_args) => init_args,
126         Err(_) => return CKR_DEVICE_ERROR,
127     };
128     let mechanisms = if init_args == "RSA-PSS" {
129         vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
130     } else {
131         vec![CKM_ECDSA, CKM_RSA_PKCS]
132     };
133     let mut module_state_guard = try_to_get_module_state_guard!();
134     let manager_proxy = match ManagerProxy::new(Backend {}) {
135         Ok(p) => p,
136         Err(e) => {
137             log_with_thread_id!(error, "C_Initialize: ManagerProxy: {}", e);
138             return CKR_DEVICE_ERROR;
139         }
140     };
141     match module_state_guard.replace(ModuleState {
142         manager_proxy,
143         mechanisms,
144     }) {
145         Some(_unexpected_previous_module_state) => {
146             #[cfg(any(target_os = "macos", target_os = "ios"))]
147             {
148                 log_with_thread_id!(info, "C_Initialize: module state previously set (this is expected on macOS - replacing it)");
149             }
150             #[cfg(target_os = "windows")]
151             {
152                 log_with_thread_id!(
153                     warn,
154                     "C_Initialize: module state unexpectedly previously set (replacing it)"
155                 );
156             }
157         }
158         None => {}
159     }
160     log_with_thread_id!(debug, "C_Initialize: CKR_OK");
161     CKR_OK
164 extern "C" fn C_Finalize(_pReserved: CK_VOID_PTR) -> CK_RV {
165     let mut module_state_guard = try_to_get_module_state_guard!();
166     let manager = module_state_guard_to_manager!(module_state_guard);
167     match manager.stop() {
168         Ok(()) => {
169             log_with_thread_id!(debug, "C_Finalize: CKR_OK");
170             CKR_OK
171         }
172         Err(e) => {
173             log_with_thread_id!(error, "C_Finalize: CKR_DEVICE_ERROR: {}", e);
174             CKR_DEVICE_ERROR
175         }
176     }
179 // The specification mandates that these strings be padded with spaces to the appropriate length.
180 // Since the length of fixed-size arrays in rust is part of the type, the compiler enforces that
181 // these byte strings are of the correct length.
182 const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Corporation             ";
183 const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"OS Client Cert Module           ";
185 /// This gets called to gather some information about the module. In particular, this implementation
186 /// supports (portions of) cryptoki (PKCS #11) version 2.2.
187 extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV {
188     if pInfo.is_null() {
189         log_with_thread_id!(error, "C_GetInfo: CKR_ARGUMENTS_BAD");
190         return CKR_ARGUMENTS_BAD;
191     }
192     log_with_thread_id!(debug, "C_GetInfo: CKR_OK");
193     let mut info = CK_INFO::default();
194     info.cryptokiVersion.major = 2;
195     info.cryptokiVersion.minor = 2;
196     info.manufacturerID = *MANUFACTURER_ID_BYTES;
197     info.libraryDescription = *LIBRARY_DESCRIPTION_BYTES;
198     unsafe {
199         *pInfo = info;
200     }
201     CKR_OK
204 /// This module has one slot.
205 const SLOT_COUNT: CK_ULONG = 1;
206 const SLOT_ID: CK_SLOT_ID = 1;
208 /// This gets called twice: once with a null `pSlotList` to get the number of slots (returned via
209 /// `pulCount`) and a second time to get the ID for each slot.
210 extern "C" fn C_GetSlotList(
211     _tokenPresent: CK_BBOOL,
212     pSlotList: CK_SLOT_ID_PTR,
213     pulCount: CK_ULONG_PTR,
214 ) -> CK_RV {
215     if pulCount.is_null() {
216         log_with_thread_id!(error, "C_GetSlotList: CKR_ARGUMENTS_BAD");
217         return CKR_ARGUMENTS_BAD;
218     }
219     if !pSlotList.is_null() {
220         if unsafe { *pulCount } < SLOT_COUNT {
221             log_with_thread_id!(error, "C_GetSlotList: CKR_BUFFER_TOO_SMALL");
222             return CKR_BUFFER_TOO_SMALL;
223         }
224         unsafe {
225             *pSlotList = SLOT_ID;
226         }
227     };
228     unsafe {
229         *pulCount = SLOT_COUNT;
230     }
231     log_with_thread_id!(debug, "C_GetSlotList: CKR_OK");
232     CKR_OK
235 const SLOT_DESCRIPTION_BYTES: &[u8; 64] =
236     b"OS Client Cert Slot                                             ";
238 /// This gets called to obtain information about slots. In this implementation, the token is
239 /// always present in the singular slot.
240 extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV {
241     if slotID != SLOT_ID || pInfo.is_null() {
242         log_with_thread_id!(error, "C_GetSlotInfo: CKR_ARGUMENTS_BAD");
243         return CKR_ARGUMENTS_BAD;
244     }
245     let slot_info = CK_SLOT_INFO {
246         slotDescription: *SLOT_DESCRIPTION_BYTES,
247         manufacturerID: *MANUFACTURER_ID_BYTES,
248         flags: CKF_TOKEN_PRESENT,
249         hardwareVersion: CK_VERSION::default(),
250         firmwareVersion: CK_VERSION::default(),
251     };
252     unsafe {
253         *pInfo = slot_info;
254     }
255     log_with_thread_id!(debug, "C_GetSlotInfo: CKR_OK");
256     CKR_OK
259 const TOKEN_LABEL_BYTES: &[u8; 32] = b"OS Client Cert Token            ";
260 const TOKEN_MODEL_BYTES: &[u8; 16] = b"osclientcerts   ";
261 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
263 /// This gets called to obtain some information about tokens. This implementation has one slot,
264 /// so it has one token. This information is primarily for display purposes.
265 extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV {
266     if slotID != SLOT_ID || pInfo.is_null() {
267         log_with_thread_id!(error, "C_GetTokenInfo: CKR_ARGUMENTS_BAD");
268         return CKR_ARGUMENTS_BAD;
269     }
270     let mut token_info = CK_TOKEN_INFO::default();
271     token_info.label = *TOKEN_LABEL_BYTES;
272     token_info.manufacturerID = *MANUFACTURER_ID_BYTES;
273     token_info.model = *TOKEN_MODEL_BYTES;
274     token_info.serialNumber = *TOKEN_SERIAL_NUMBER_BYTES;
275     unsafe {
276         *pInfo = token_info;
277     }
278     log_with_thread_id!(debug, "C_GetTokenInfo: CKR_OK");
279     CKR_OK
282 /// This gets called to determine what mechanisms a slot supports. The singular slot supports
283 /// ECDSA and RSA PKCS1. Depending on the configuration the module was loaded with, it may also
284 /// support RSA PSS.
285 extern "C" fn C_GetMechanismList(
286     slotID: CK_SLOT_ID,
287     pMechanismList: CK_MECHANISM_TYPE_PTR,
288     pulCount: CK_ULONG_PTR,
289 ) -> CK_RV {
290     if slotID != SLOT_ID || pulCount.is_null() {
291         log_with_thread_id!(error, "C_GetMechanismList: CKR_ARGUMENTS_BAD");
292         return CKR_ARGUMENTS_BAD;
293     }
294     let module_state_guard = try_to_get_module_state_guard!();
295     let mechanisms = module_state_guard_to_mechanisms!(module_state_guard);
296     if !pMechanismList.is_null() {
297         if unsafe { *pulCount as usize } < mechanisms.len() {
298             log_with_thread_id!(error, "C_GetMechanismList: CKR_ARGUMENTS_BAD");
299             return CKR_ARGUMENTS_BAD;
300         }
301         for (i, mechanism) in mechanisms.iter().enumerate() {
302             unsafe {
303                 *pMechanismList.add(i) = *mechanism;
304             }
305         }
306     }
307     unsafe {
308         *pulCount = mechanisms.len() as CK_ULONG;
309     }
310     log_with_thread_id!(debug, "C_GetMechanismList: CKR_OK");
311     CKR_OK
314 extern "C" fn C_GetMechanismInfo(
315     _slotID: CK_SLOT_ID,
316     _type: CK_MECHANISM_TYPE,
317     _pInfo: CK_MECHANISM_INFO_PTR,
318 ) -> CK_RV {
319     log_with_thread_id!(error, "C_GetMechanismInfo: CKR_FUNCTION_NOT_SUPPORTED");
320     CKR_FUNCTION_NOT_SUPPORTED
323 extern "C" fn C_InitToken(
324     _slotID: CK_SLOT_ID,
325     _pPin: CK_UTF8CHAR_PTR,
326     _ulPinLen: CK_ULONG,
327     _pLabel: CK_UTF8CHAR_PTR,
328 ) -> CK_RV {
329     log_with_thread_id!(error, "C_InitToken: CKR_FUNCTION_NOT_SUPPORTED");
330     CKR_FUNCTION_NOT_SUPPORTED
333 extern "C" fn C_InitPIN(
334     _hSession: CK_SESSION_HANDLE,
335     _pPin: CK_UTF8CHAR_PTR,
336     _ulPinLen: CK_ULONG,
337 ) -> CK_RV {
338     log_with_thread_id!(error, "C_InitPIN: CKR_FUNCTION_NOT_SUPPORTED");
339     CKR_FUNCTION_NOT_SUPPORTED
342 extern "C" fn C_SetPIN(
343     _hSession: CK_SESSION_HANDLE,
344     _pOldPin: CK_UTF8CHAR_PTR,
345     _ulOldLen: CK_ULONG,
346     _pNewPin: CK_UTF8CHAR_PTR,
347     _ulNewLen: CK_ULONG,
348 ) -> CK_RV {
349     log_with_thread_id!(error, "C_SetPIN: CKR_FUNCTION_NOT_SUPPORTED");
350     CKR_FUNCTION_NOT_SUPPORTED
353 /// This gets called to create a new session. This module defers to the `ManagerProxy` to implement
354 /// this.
355 extern "C" fn C_OpenSession(
356     slotID: CK_SLOT_ID,
357     _flags: CK_FLAGS,
358     _pApplication: CK_VOID_PTR,
359     _Notify: CK_NOTIFY,
360     phSession: CK_SESSION_HANDLE_PTR,
361 ) -> CK_RV {
362     if slotID != SLOT_ID || phSession.is_null() {
363         log_with_thread_id!(error, "C_OpenSession: CKR_ARGUMENTS_BAD");
364         return CKR_ARGUMENTS_BAD;
365     }
366     let mut module_state_guard = try_to_get_module_state_guard!();
367     let manager = module_state_guard_to_manager!(module_state_guard);
368     // The "modern"/"legacy" slot distinction still exists in ipcclientcerts,
369     // which shares some library code with this module, to allow for a more
370     // nuanced notion of whether or not e.g. RSA-PSS is supported.
371     let session_handle = match manager.open_session(SlotType::Modern) {
372         Ok(session_handle) => session_handle,
373         Err(e) => {
374             log_with_thread_id!(error, "C_OpenSession: open_session failed: {}", e);
375             return CKR_DEVICE_ERROR;
376         }
377     };
378     unsafe {
379         *phSession = session_handle;
380     }
381     log_with_thread_id!(debug, "C_OpenSession: CKR_OK");
382     CKR_OK
385 /// This gets called to close a session. This is handled by the `ManagerProxy`.
386 extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV {
387     let mut module_state_guard = try_to_get_module_state_guard!();
388     let manager = module_state_guard_to_manager!(module_state_guard);
389     if manager.close_session(hSession).is_err() {
390         log_with_thread_id!(error, "C_CloseSession: CKR_SESSION_HANDLE_INVALID");
391         return CKR_SESSION_HANDLE_INVALID;
392     }
393     log_with_thread_id!(debug, "C_CloseSession: CKR_OK");
394     CKR_OK
397 /// This gets called to close all open sessions at once. This is handled by the `ManagerProxy`.
398 extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV {
399     if slotID != SLOT_ID {
400         log_with_thread_id!(error, "C_CloseAllSessions: CKR_ARGUMENTS_BAD");
401         return CKR_ARGUMENTS_BAD;
402     }
403     let mut module_state_guard = try_to_get_module_state_guard!();
404     let manager = module_state_guard_to_manager!(module_state_guard);
405     match manager.close_all_sessions(SlotType::Modern) {
406         Ok(()) => {
407             log_with_thread_id!(debug, "C_CloseAllSessions: CKR_OK");
408             CKR_OK
409         }
410         Err(e) => {
411             log_with_thread_id!(
412                 error,
413                 "C_CloseAllSessions: close_all_sessions failed: {}",
414                 e
415             );
416             CKR_DEVICE_ERROR
417         }
418     }
421 extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV {
422     log_with_thread_id!(error, "C_GetSessionInfo: CKR_FUNCTION_NOT_SUPPORTED");
423     CKR_FUNCTION_NOT_SUPPORTED
426 extern "C" fn C_GetOperationState(
427     _hSession: CK_SESSION_HANDLE,
428     _pOperationState: CK_BYTE_PTR,
429     _pulOperationStateLen: CK_ULONG_PTR,
430 ) -> CK_RV {
431     log_with_thread_id!(error, "C_GetOperationState: CKR_FUNCTION_NOT_SUPPORTED");
432     CKR_FUNCTION_NOT_SUPPORTED
435 extern "C" fn C_SetOperationState(
436     _hSession: CK_SESSION_HANDLE,
437     _pOperationState: CK_BYTE_PTR,
438     _ulOperationStateLen: CK_ULONG,
439     _hEncryptionKey: CK_OBJECT_HANDLE,
440     _hAuthenticationKey: CK_OBJECT_HANDLE,
441 ) -> CK_RV {
442     log_with_thread_id!(error, "C_SetOperationState: CKR_FUNCTION_NOT_SUPPORTED");
443     CKR_FUNCTION_NOT_SUPPORTED
446 extern "C" fn C_Login(
447     _hSession: CK_SESSION_HANDLE,
448     _userType: CK_USER_TYPE,
449     _pPin: CK_UTF8CHAR_PTR,
450     _ulPinLen: CK_ULONG,
451 ) -> CK_RV {
452     log_with_thread_id!(error, "C_Login: CKR_FUNCTION_NOT_SUPPORTED");
453     CKR_FUNCTION_NOT_SUPPORTED
456 /// This gets called to log out and drop any authenticated resources. Because this module does not
457 /// hold on to authenticated resources, this module "implements" this by doing nothing and
458 /// returning a success result.
459 extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV {
460     log_with_thread_id!(debug, "C_Logout: CKR_OK");
461     CKR_OK
464 extern "C" fn C_CreateObject(
465     _hSession: CK_SESSION_HANDLE,
466     _pTemplate: CK_ATTRIBUTE_PTR,
467     _ulCount: CK_ULONG,
468     _phObject: CK_OBJECT_HANDLE_PTR,
469 ) -> CK_RV {
470     log_with_thread_id!(error, "C_CreateObject: CKR_FUNCTION_NOT_SUPPORTED");
471     CKR_FUNCTION_NOT_SUPPORTED
474 extern "C" fn C_CopyObject(
475     _hSession: CK_SESSION_HANDLE,
476     _hObject: CK_OBJECT_HANDLE,
477     _pTemplate: CK_ATTRIBUTE_PTR,
478     _ulCount: CK_ULONG,
479     _phNewObject: CK_OBJECT_HANDLE_PTR,
480 ) -> CK_RV {
481     log_with_thread_id!(error, "C_CopyObject: CKR_FUNCTION_NOT_SUPPORTED");
482     CKR_FUNCTION_NOT_SUPPORTED
485 extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV {
486     log_with_thread_id!(error, "C_DestroyObject: CKR_FUNCTION_NOT_SUPPORTED");
487     CKR_FUNCTION_NOT_SUPPORTED
490 extern "C" fn C_GetObjectSize(
491     _hSession: CK_SESSION_HANDLE,
492     _hObject: CK_OBJECT_HANDLE,
493     _pulSize: CK_ULONG_PTR,
494 ) -> CK_RV {
495     log_with_thread_id!(error, "C_GetObjectSize: CKR_FUNCTION_NOT_SUPPORTED");
496     CKR_FUNCTION_NOT_SUPPORTED
499 /// This gets called to obtain the values of a number of attributes of an object identified by the
500 /// given handle. This module implements this by requesting that the `ManagerProxy` find the object
501 /// and attempt to get the value of each attribute. If a specified attribute is not defined on the
502 /// object, the length of that attribute is set to -1 to indicate that it is not available.
503 /// This gets called twice: once to obtain the lengths of the attributes and again to get the
504 /// values.
505 extern "C" fn C_GetAttributeValue(
506     _hSession: CK_SESSION_HANDLE,
507     hObject: CK_OBJECT_HANDLE,
508     pTemplate: CK_ATTRIBUTE_PTR,
509     ulCount: CK_ULONG,
510 ) -> CK_RV {
511     if pTemplate.is_null() {
512         log_with_thread_id!(error, "C_GetAttributeValue: CKR_ARGUMENTS_BAD");
513         return CKR_ARGUMENTS_BAD;
514     }
515     let mut attr_types = Vec::with_capacity(ulCount as usize);
516     for i in 0..ulCount as usize {
517         let attr = unsafe { &*pTemplate.add(i) };
518         attr_types.push(attr.type_);
519     }
520     let mut module_state_guard = try_to_get_module_state_guard!();
521     let manager = module_state_guard_to_manager!(module_state_guard);
522     let values = match manager.get_attributes(hObject, attr_types) {
523         Ok(values) => values,
524         Err(e) => {
525             log_with_thread_id!(error, "C_GetAttributeValue: CKR_ARGUMENTS_BAD ({})", e);
526             return CKR_ARGUMENTS_BAD;
527         }
528     };
529     if values.len() != ulCount as usize {
530         log_with_thread_id!(
531             error,
532             "C_GetAttributeValue: manager.get_attributes didn't return the right number of values"
533         );
534         return CKR_DEVICE_ERROR;
535     }
536     for (i, value) in values.iter().enumerate().take(ulCount as usize) {
537         let attr = unsafe { &mut *pTemplate.add(i) };
538         if let Some(attr_value) = value {
539             if attr.pValue.is_null() {
540                 attr.ulValueLen = attr_value.len() as CK_ULONG;
541             } else {
542                 let ptr: *mut u8 = attr.pValue as *mut u8;
543                 if attr_value.len() != attr.ulValueLen as usize {
544                     log_with_thread_id!(error, "C_GetAttributeValue: incorrect attr size");
545                     return CKR_ARGUMENTS_BAD;
546                 }
547                 unsafe {
548                     std::ptr::copy_nonoverlapping(attr_value.as_ptr(), ptr, attr_value.len());
549                 }
550             }
551         } else {
552             attr.ulValueLen = (0 - 1) as CK_ULONG;
553         }
554     }
555     log_with_thread_id!(debug, "C_GetAttributeValue: CKR_OK");
556     CKR_OK
559 extern "C" fn C_SetAttributeValue(
560     _hSession: CK_SESSION_HANDLE,
561     _hObject: CK_OBJECT_HANDLE,
562     _pTemplate: CK_ATTRIBUTE_PTR,
563     _ulCount: CK_ULONG,
564 ) -> CK_RV {
565     log_with_thread_id!(error, "C_SetAttributeValue: CKR_FUNCTION_NOT_SUPPORTED");
566     CKR_FUNCTION_NOT_SUPPORTED
569 fn trace_attr(prefix: &str, attr: &CK_ATTRIBUTE) {
570     let typ = match unsafe_packed_field_access!(attr.type_) {
571         CKA_CLASS => "CKA_CLASS".to_string(),
572         CKA_TOKEN => "CKA_TOKEN".to_string(),
573         CKA_LABEL => "CKA_LABEL".to_string(),
574         CKA_ID => "CKA_ID".to_string(),
575         CKA_VALUE => "CKA_VALUE".to_string(),
576         CKA_ISSUER => "CKA_ISSUER".to_string(),
577         CKA_SERIAL_NUMBER => "CKA_SERIAL_NUMBER".to_string(),
578         CKA_SUBJECT => "CKA_SUBJECT".to_string(),
579         CKA_PRIVATE => "CKA_PRIVATE".to_string(),
580         CKA_KEY_TYPE => "CKA_KEY_TYPE".to_string(),
581         CKA_MODULUS => "CKA_MODULUS".to_string(),
582         CKA_EC_PARAMS => "CKA_EC_PARAMS".to_string(),
583         _ => format!("0x{:x}", unsafe_packed_field_access!(attr.type_)),
584     };
585     let value =
586         unsafe { std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize) };
587     log_with_thread_id!(
588         trace,
589         "{}CK_ATTRIBUTE {{ type: {}, pValue: {:?}, ulValueLen: {} }}",
590         prefix,
591         typ,
592         value,
593         unsafe_packed_field_access!(attr.ulValueLen)
594     );
597 const RELEVANT_ATTRIBUTES: &[CK_ATTRIBUTE_TYPE] = &[
598     CKA_CLASS,
599     CKA_EC_PARAMS,
600     CKA_ID,
601     CKA_ISSUER,
602     CKA_KEY_TYPE,
603     CKA_LABEL,
604     CKA_MODULUS,
605     CKA_PRIVATE,
606     CKA_SERIAL_NUMBER,
607     CKA_SUBJECT,
608     CKA_TOKEN,
609     CKA_VALUE,
612 /// This gets called to initialize a search for objects matching a given list of attributes. This
613 /// module implements this by gathering the attributes and passing them to the `ManagerProxy` to
614 /// start the search.
615 extern "C" fn C_FindObjectsInit(
616     hSession: CK_SESSION_HANDLE,
617     pTemplate: CK_ATTRIBUTE_PTR,
618     ulCount: CK_ULONG,
619 ) -> CK_RV {
620     if pTemplate.is_null() {
621         log_with_thread_id!(error, "C_FindObjectsInit: CKR_ARGUMENTS_BAD");
622         return CKR_ARGUMENTS_BAD;
623     }
624     let mut attrs = Vec::new();
625     log_with_thread_id!(trace, "C_FindObjectsInit:");
626     for i in 0..ulCount as usize {
627         let attr = unsafe { &*pTemplate.add(i) };
628         trace_attr("  ", attr);
629         // Copy out the attribute type to avoid making a reference to an unaligned field.
630         let attr_type = attr.type_;
631         if !RELEVANT_ATTRIBUTES.contains(&attr_type) {
632             log_with_thread_id!(
633                 debug,
634                 "C_FindObjectsInit: irrelevant attribute, returning CKR_ATTRIBUTE_TYPE_INVALID"
635             );
636             return CKR_ATTRIBUTE_TYPE_INVALID;
637         }
638         let slice = unsafe {
639             std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize)
640         };
641         attrs.push((attr_type, slice.to_owned()));
642     }
643     let mut module_state_guard = try_to_get_module_state_guard!();
644     let manager = module_state_guard_to_manager!(module_state_guard);
645     match manager.start_search(hSession, attrs) {
646         Ok(()) => {}
647         Err(e) => {
648             log_with_thread_id!(error, "C_FindObjectsInit: CKR_ARGUMENTS_BAD: {}", e);
649             return CKR_ARGUMENTS_BAD;
650         }
651     }
652     log_with_thread_id!(debug, "C_FindObjectsInit: CKR_OK");
653     CKR_OK
656 /// This gets called after `C_FindObjectsInit` to get the results of a search. This module
657 /// implements this by looking up the search in the `ManagerProxy` and copying out the matching
658 /// object handles.
659 extern "C" fn C_FindObjects(
660     hSession: CK_SESSION_HANDLE,
661     phObject: CK_OBJECT_HANDLE_PTR,
662     ulMaxObjectCount: CK_ULONG,
663     pulObjectCount: CK_ULONG_PTR,
664 ) -> CK_RV {
665     if phObject.is_null() || pulObjectCount.is_null() || ulMaxObjectCount == 0 {
666         log_with_thread_id!(error, "C_FindObjects: CKR_ARGUMENTS_BAD");
667         return CKR_ARGUMENTS_BAD;
668     }
669     let mut module_state_guard = try_to_get_module_state_guard!();
670     let manager = module_state_guard_to_manager!(module_state_guard);
671     let handles = match manager.search(hSession, ulMaxObjectCount as usize) {
672         Ok(handles) => handles,
673         Err(e) => {
674             log_with_thread_id!(error, "C_FindObjects: CKR_ARGUMENTS_BAD: {}", e);
675             return CKR_ARGUMENTS_BAD;
676         }
677     };
678     log_with_thread_id!(debug, "C_FindObjects: found handles {:?}", handles);
679     if handles.len() > ulMaxObjectCount as usize {
680         log_with_thread_id!(error, "C_FindObjects: manager returned too many handles");
681         return CKR_DEVICE_ERROR;
682     }
683     unsafe {
684         *pulObjectCount = handles.len() as CK_ULONG;
685     }
686     for (index, handle) in handles.iter().enumerate() {
687         if index < ulMaxObjectCount as usize {
688             unsafe {
689                 *(phObject.add(index)) = *handle;
690             }
691         }
692     }
693     log_with_thread_id!(debug, "C_FindObjects: CKR_OK");
694     CKR_OK
697 /// This gets called after `C_FindObjectsInit` and `C_FindObjects` to finish a search. The module
698 /// tells the `ManagerProxy` to clear the search.
699 extern "C" fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV {
700     let mut module_state_guard = try_to_get_module_state_guard!();
701     let manager = module_state_guard_to_manager!(module_state_guard);
702     // It would be an error if there were no search for this session, but we can be permissive here.
703     match manager.clear_search(hSession) {
704         Ok(()) => {
705             log_with_thread_id!(debug, "C_FindObjectsFinal: CKR_OK");
706             CKR_OK
707         }
708         Err(e) => {
709             log_with_thread_id!(error, "C_FindObjectsFinal: clear_search failed: {}", e);
710             CKR_DEVICE_ERROR
711         }
712     }
715 extern "C" fn C_EncryptInit(
716     _hSession: CK_SESSION_HANDLE,
717     _pMechanism: CK_MECHANISM_PTR,
718     _hKey: CK_OBJECT_HANDLE,
719 ) -> CK_RV {
720     log_with_thread_id!(error, "C_EncryptInit: CKR_FUNCTION_NOT_SUPPORTED");
721     CKR_FUNCTION_NOT_SUPPORTED
724 extern "C" fn C_Encrypt(
725     _hSession: CK_SESSION_HANDLE,
726     _pData: CK_BYTE_PTR,
727     _ulDataLen: CK_ULONG,
728     _pEncryptedData: CK_BYTE_PTR,
729     _pulEncryptedDataLen: CK_ULONG_PTR,
730 ) -> CK_RV {
731     log_with_thread_id!(error, "C_Encrypt: CKR_FUNCTION_NOT_SUPPORTED");
732     CKR_FUNCTION_NOT_SUPPORTED
735 extern "C" fn C_EncryptUpdate(
736     _hSession: CK_SESSION_HANDLE,
737     _pPart: CK_BYTE_PTR,
738     _ulPartLen: CK_ULONG,
739     _pEncryptedPart: CK_BYTE_PTR,
740     _pulEncryptedPartLen: CK_ULONG_PTR,
741 ) -> CK_RV {
742     log_with_thread_id!(error, "C_EncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
743     CKR_FUNCTION_NOT_SUPPORTED
746 extern "C" fn C_EncryptFinal(
747     _hSession: CK_SESSION_HANDLE,
748     _pLastEncryptedPart: CK_BYTE_PTR,
749     _pulLastEncryptedPartLen: CK_ULONG_PTR,
750 ) -> CK_RV {
751     log_with_thread_id!(error, "C_EncryptFinal: CKR_FUNCTION_NOT_SUPPORTED");
752     CKR_FUNCTION_NOT_SUPPORTED
755 extern "C" fn C_DecryptInit(
756     _hSession: CK_SESSION_HANDLE,
757     _pMechanism: CK_MECHANISM_PTR,
758     _hKey: CK_OBJECT_HANDLE,
759 ) -> CK_RV {
760     log_with_thread_id!(error, "C_DecryptInit: CKR_FUNCTION_NOT_SUPPORTED");
761     CKR_FUNCTION_NOT_SUPPORTED
764 extern "C" fn C_Decrypt(
765     _hSession: CK_SESSION_HANDLE,
766     _pEncryptedData: CK_BYTE_PTR,
767     _ulEncryptedDataLen: CK_ULONG,
768     _pData: CK_BYTE_PTR,
769     _pulDataLen: CK_ULONG_PTR,
770 ) -> CK_RV {
771     log_with_thread_id!(error, "C_Decrypt: CKR_FUNCTION_NOT_SUPPORTED");
772     CKR_FUNCTION_NOT_SUPPORTED
775 extern "C" fn C_DecryptUpdate(
776     _hSession: CK_SESSION_HANDLE,
777     _pEncryptedPart: CK_BYTE_PTR,
778     _ulEncryptedPartLen: CK_ULONG,
779     _pPart: CK_BYTE_PTR,
780     _pulPartLen: CK_ULONG_PTR,
781 ) -> CK_RV {
782     log_with_thread_id!(error, "C_DecryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
783     CKR_FUNCTION_NOT_SUPPORTED
786 extern "C" fn C_DecryptFinal(
787     _hSession: CK_SESSION_HANDLE,
788     _pLastPart: CK_BYTE_PTR,
789     _pulLastPartLen: CK_ULONG_PTR,
790 ) -> CK_RV {
791     log_with_thread_id!(error, "C_DecryptFinal: CKR_FUNCTION_NOT_SUPPORTED");
792     CKR_FUNCTION_NOT_SUPPORTED
795 extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV {
796     log_with_thread_id!(error, "C_DigestInit: CKR_FUNCTION_NOT_SUPPORTED");
797     CKR_FUNCTION_NOT_SUPPORTED
800 extern "C" fn C_Digest(
801     _hSession: CK_SESSION_HANDLE,
802     _pData: CK_BYTE_PTR,
803     _ulDataLen: CK_ULONG,
804     _pDigest: CK_BYTE_PTR,
805     _pulDigestLen: CK_ULONG_PTR,
806 ) -> CK_RV {
807     log_with_thread_id!(error, "C_Digest: CKR_FUNCTION_NOT_SUPPORTED");
808     CKR_FUNCTION_NOT_SUPPORTED
811 extern "C" fn C_DigestUpdate(
812     _hSession: CK_SESSION_HANDLE,
813     _pPart: CK_BYTE_PTR,
814     _ulPartLen: CK_ULONG,
815 ) -> CK_RV {
816     log_with_thread_id!(error, "C_DigestUpdate: CKR_FUNCTION_NOT_SUPPORTED");
817     CKR_FUNCTION_NOT_SUPPORTED
820 extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV {
821     log_with_thread_id!(error, "C_DigestKey: CKR_FUNCTION_NOT_SUPPORTED");
822     CKR_FUNCTION_NOT_SUPPORTED
825 extern "C" fn C_DigestFinal(
826     _hSession: CK_SESSION_HANDLE,
827     _pDigest: CK_BYTE_PTR,
828     _pulDigestLen: CK_ULONG_PTR,
829 ) -> CK_RV {
830     log_with_thread_id!(error, "C_DigestFinal: CKR_FUNCTION_NOT_SUPPORTED");
831     CKR_FUNCTION_NOT_SUPPORTED
834 /// This gets called to set up a sign operation. The module essentially defers to the
835 /// `ManagerProxy`.
836 extern "C" fn C_SignInit(
837     hSession: CK_SESSION_HANDLE,
838     pMechanism: CK_MECHANISM_PTR,
839     hKey: CK_OBJECT_HANDLE,
840 ) -> CK_RV {
841     if pMechanism.is_null() {
842         log_with_thread_id!(error, "C_SignInit: CKR_ARGUMENTS_BAD");
843         return CKR_ARGUMENTS_BAD;
844     }
845     // Presumably we should validate the mechanism against hKey, but the specification doesn't
846     // actually seem to require this.
847     let mechanism = unsafe { *pMechanism };
848     log_with_thread_id!(debug, "C_SignInit: mechanism is {:?}", mechanism);
849     let mechanism_params = if mechanism.mechanism == CKM_RSA_PKCS_PSS {
850         if mechanism.ulParameterLen as usize != std::mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() {
851             log_with_thread_id!(
852                 error,
853                 "C_SignInit: bad ulParameterLen for CKM_RSA_PKCS_PSS: {}",
854                 unsafe_packed_field_access!(mechanism.ulParameterLen)
855             );
856             return CKR_ARGUMENTS_BAD;
857         }
858         Some(unsafe { *(mechanism.pParameter as *const CK_RSA_PKCS_PSS_PARAMS) })
859     } else {
860         None
861     };
862     let mut module_state_guard = try_to_get_module_state_guard!();
863     let manager = module_state_guard_to_manager!(module_state_guard);
864     match manager.start_sign(hSession, hKey, mechanism_params) {
865         Ok(()) => {}
866         Err(e) => {
867             log_with_thread_id!(error, "C_SignInit: CKR_GENERAL_ERROR: {}", e);
868             return CKR_GENERAL_ERROR;
869         }
870     };
871     log_with_thread_id!(debug, "C_SignInit: CKR_OK");
872     CKR_OK
875 /// NSS calls this after `C_SignInit` (there are more ways in the PKCS #11 specification to sign
876 /// data, but this is the only way supported by this module). The module essentially defers to the
877 /// `ManagerProxy` and copies out the resulting signature.
878 extern "C" fn C_Sign(
879     hSession: CK_SESSION_HANDLE,
880     pData: CK_BYTE_PTR,
881     ulDataLen: CK_ULONG,
882     pSignature: CK_BYTE_PTR,
883     pulSignatureLen: CK_ULONG_PTR,
884 ) -> CK_RV {
885     if pData.is_null() || pulSignatureLen.is_null() {
886         log_with_thread_id!(error, "C_Sign: CKR_ARGUMENTS_BAD");
887         return CKR_ARGUMENTS_BAD;
888     }
889     let data = unsafe { std::slice::from_raw_parts(pData, ulDataLen as usize) };
890     if pSignature.is_null() {
891         let mut module_state_guard = try_to_get_module_state_guard!();
892         let manager = module_state_guard_to_manager!(module_state_guard);
893         match manager.get_signature_length(hSession, data.to_vec()) {
894             Ok(signature_length) => unsafe {
895                 *pulSignatureLen = signature_length as CK_ULONG;
896             },
897             Err(e) => {
898                 log_with_thread_id!(error, "C_Sign: get_signature_length failed: {}", e);
899                 log_with_thread_id!(error, "C_Sign: try setting security.osclientcerts.assume_rsa_pss_support to false and restarting");
900                 return CKR_GENERAL_ERROR;
901             }
902         }
903     } else {
904         let mut module_state_guard = try_to_get_module_state_guard!();
905         let manager = module_state_guard_to_manager!(module_state_guard);
906         match manager.sign(hSession, data.to_vec()) {
907             Ok(signature) => {
908                 let signature_capacity = unsafe { *pulSignatureLen } as usize;
909                 if signature_capacity < signature.len() {
910                     log_with_thread_id!(error, "C_Sign: CKR_ARGUMENTS_BAD");
911                     return CKR_ARGUMENTS_BAD;
912                 }
913                 let ptr: *mut u8 = pSignature as *mut u8;
914                 unsafe {
915                     std::ptr::copy_nonoverlapping(signature.as_ptr(), ptr, signature.len());
916                     *pulSignatureLen = signature.len() as CK_ULONG;
917                 }
918             }
919             Err(e) => {
920                 log_with_thread_id!(error, "C_Sign: sign failed: {}", e);
921                 log_with_thread_id!(error, "C_Sign: try setting security.osclientcerts.assume_rsa_pss_support to false and restarting");
922                 return CKR_GENERAL_ERROR;
923             }
924         }
925     }
926     log_with_thread_id!(debug, "C_Sign: CKR_OK");
927     CKR_OK
930 extern "C" fn C_SignUpdate(
931     _hSession: CK_SESSION_HANDLE,
932     _pPart: CK_BYTE_PTR,
933     _ulPartLen: CK_ULONG,
934 ) -> CK_RV {
935     log_with_thread_id!(error, "C_SignUpdate: CKR_FUNCTION_NOT_SUPPORTED");
936     CKR_FUNCTION_NOT_SUPPORTED
939 extern "C" fn C_SignFinal(
940     _hSession: CK_SESSION_HANDLE,
941     _pSignature: CK_BYTE_PTR,
942     _pulSignatureLen: CK_ULONG_PTR,
943 ) -> CK_RV {
944     log_with_thread_id!(error, "C_SignFinal: CKR_FUNCTION_NOT_SUPPORTED");
945     CKR_FUNCTION_NOT_SUPPORTED
948 extern "C" fn C_SignRecoverInit(
949     _hSession: CK_SESSION_HANDLE,
950     _pMechanism: CK_MECHANISM_PTR,
951     _hKey: CK_OBJECT_HANDLE,
952 ) -> CK_RV {
953     log_with_thread_id!(error, "C_SignRecoverInit: CKR_FUNCTION_NOT_SUPPORTED");
954     CKR_FUNCTION_NOT_SUPPORTED
957 extern "C" fn C_SignRecover(
958     _hSession: CK_SESSION_HANDLE,
959     _pData: CK_BYTE_PTR,
960     _ulDataLen: CK_ULONG,
961     _pSignature: CK_BYTE_PTR,
962     _pulSignatureLen: CK_ULONG_PTR,
963 ) -> CK_RV {
964     log_with_thread_id!(error, "C_SignRecover: CKR_FUNCTION_NOT_SUPPORTED");
965     CKR_FUNCTION_NOT_SUPPORTED
968 extern "C" fn C_VerifyInit(
969     _hSession: CK_SESSION_HANDLE,
970     _pMechanism: CK_MECHANISM_PTR,
971     _hKey: CK_OBJECT_HANDLE,
972 ) -> CK_RV {
973     log_with_thread_id!(error, "C_VerifyInit: CKR_FUNCTION_NOT_SUPPORTED");
974     CKR_FUNCTION_NOT_SUPPORTED
977 extern "C" fn C_Verify(
978     _hSession: CK_SESSION_HANDLE,
979     _pData: CK_BYTE_PTR,
980     _ulDataLen: CK_ULONG,
981     _pSignature: CK_BYTE_PTR,
982     _ulSignatureLen: CK_ULONG,
983 ) -> CK_RV {
984     log_with_thread_id!(error, "C_Verify: CKR_FUNCTION_NOT_SUPPORTED");
985     CKR_FUNCTION_NOT_SUPPORTED
988 extern "C" fn C_VerifyUpdate(
989     _hSession: CK_SESSION_HANDLE,
990     _pPart: CK_BYTE_PTR,
991     _ulPartLen: CK_ULONG,
992 ) -> CK_RV {
993     log_with_thread_id!(error, "C_VerifyUpdate: CKR_FUNCTION_NOT_SUPPORTED");
994     CKR_FUNCTION_NOT_SUPPORTED
997 extern "C" fn C_VerifyFinal(
998     _hSession: CK_SESSION_HANDLE,
999     _pSignature: CK_BYTE_PTR,
1000     _ulSignatureLen: CK_ULONG,
1001 ) -> CK_RV {
1002     log_with_thread_id!(error, "C_VerifyFinal: CKR_FUNCTION_NOT_SUPPORTED");
1003     CKR_FUNCTION_NOT_SUPPORTED
1006 extern "C" fn C_VerifyRecoverInit(
1007     _hSession: CK_SESSION_HANDLE,
1008     _pMechanism: CK_MECHANISM_PTR,
1009     _hKey: CK_OBJECT_HANDLE,
1010 ) -> CK_RV {
1011     log_with_thread_id!(error, "C_VerifyRecoverInit: CKR_FUNCTION_NOT_SUPPORTED");
1012     CKR_FUNCTION_NOT_SUPPORTED
1015 extern "C" fn C_VerifyRecover(
1016     _hSession: CK_SESSION_HANDLE,
1017     _pSignature: CK_BYTE_PTR,
1018     _ulSignatureLen: CK_ULONG,
1019     _pData: CK_BYTE_PTR,
1020     _pulDataLen: CK_ULONG_PTR,
1021 ) -> CK_RV {
1022     log_with_thread_id!(error, "C_VerifyRecover: CKR_FUNCTION_NOT_SUPPORTED");
1023     CKR_FUNCTION_NOT_SUPPORTED
1026 extern "C" fn C_DigestEncryptUpdate(
1027     _hSession: CK_SESSION_HANDLE,
1028     _pPart: CK_BYTE_PTR,
1029     _ulPartLen: CK_ULONG,
1030     _pEncryptedPart: CK_BYTE_PTR,
1031     _pulEncryptedPartLen: CK_ULONG_PTR,
1032 ) -> CK_RV {
1033     log_with_thread_id!(error, "C_DigestEncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
1034     CKR_FUNCTION_NOT_SUPPORTED
1037 extern "C" fn C_DecryptDigestUpdate(
1038     _hSession: CK_SESSION_HANDLE,
1039     _pEncryptedPart: CK_BYTE_PTR,
1040     _ulEncryptedPartLen: CK_ULONG,
1041     _pPart: CK_BYTE_PTR,
1042     _pulPartLen: CK_ULONG_PTR,
1043 ) -> CK_RV {
1044     log_with_thread_id!(error, "C_DecryptDigestUpdate: CKR_FUNCTION_NOT_SUPPORTED");
1045     CKR_FUNCTION_NOT_SUPPORTED
1048 extern "C" fn C_SignEncryptUpdate(
1049     _hSession: CK_SESSION_HANDLE,
1050     _pPart: CK_BYTE_PTR,
1051     _ulPartLen: CK_ULONG,
1052     _pEncryptedPart: CK_BYTE_PTR,
1053     _pulEncryptedPartLen: CK_ULONG_PTR,
1054 ) -> CK_RV {
1055     log_with_thread_id!(error, "C_SignEncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
1056     CKR_FUNCTION_NOT_SUPPORTED
1059 extern "C" fn C_DecryptVerifyUpdate(
1060     _hSession: CK_SESSION_HANDLE,
1061     _pEncryptedPart: CK_BYTE_PTR,
1062     _ulEncryptedPartLen: CK_ULONG,
1063     _pPart: CK_BYTE_PTR,
1064     _pulPartLen: CK_ULONG_PTR,
1065 ) -> CK_RV {
1066     log_with_thread_id!(error, "C_DecryptVerifyUpdate: CKR_FUNCTION_NOT_SUPPORTED");
1067     CKR_FUNCTION_NOT_SUPPORTED
1070 extern "C" fn C_GenerateKey(
1071     _hSession: CK_SESSION_HANDLE,
1072     _pMechanism: CK_MECHANISM_PTR,
1073     _pTemplate: CK_ATTRIBUTE_PTR,
1074     _ulCount: CK_ULONG,
1075     _phKey: CK_OBJECT_HANDLE_PTR,
1076 ) -> CK_RV {
1077     log_with_thread_id!(error, "C_GenerateKey: CKR_FUNCTION_NOT_SUPPORTED");
1078     CKR_FUNCTION_NOT_SUPPORTED
1081 extern "C" fn C_GenerateKeyPair(
1082     _hSession: CK_SESSION_HANDLE,
1083     _pMechanism: CK_MECHANISM_PTR,
1084     _pPublicKeyTemplate: CK_ATTRIBUTE_PTR,
1085     _ulPublicKeyAttributeCount: CK_ULONG,
1086     _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR,
1087     _ulPrivateKeyAttributeCount: CK_ULONG,
1088     _phPublicKey: CK_OBJECT_HANDLE_PTR,
1089     _phPrivateKey: CK_OBJECT_HANDLE_PTR,
1090 ) -> CK_RV {
1091     log_with_thread_id!(error, "C_GenerateKeyPair: CKR_FUNCTION_NOT_SUPPORTED");
1092     CKR_FUNCTION_NOT_SUPPORTED
1095 extern "C" fn C_WrapKey(
1096     _hSession: CK_SESSION_HANDLE,
1097     _pMechanism: CK_MECHANISM_PTR,
1098     _hWrappingKey: CK_OBJECT_HANDLE,
1099     _hKey: CK_OBJECT_HANDLE,
1100     _pWrappedKey: CK_BYTE_PTR,
1101     _pulWrappedKeyLen: CK_ULONG_PTR,
1102 ) -> CK_RV {
1103     log_with_thread_id!(error, "C_WrapKey: CKR_FUNCTION_NOT_SUPPORTED");
1104     CKR_FUNCTION_NOT_SUPPORTED
1107 extern "C" fn C_UnwrapKey(
1108     _hSession: CK_SESSION_HANDLE,
1109     _pMechanism: CK_MECHANISM_PTR,
1110     _hUnwrappingKey: CK_OBJECT_HANDLE,
1111     _pWrappedKey: CK_BYTE_PTR,
1112     _ulWrappedKeyLen: CK_ULONG,
1113     _pTemplate: CK_ATTRIBUTE_PTR,
1114     _ulAttributeCount: CK_ULONG,
1115     _phKey: CK_OBJECT_HANDLE_PTR,
1116 ) -> CK_RV {
1117     log_with_thread_id!(error, "C_UnwrapKey: CKR_FUNCTION_NOT_SUPPORTED");
1118     CKR_FUNCTION_NOT_SUPPORTED
1121 extern "C" fn C_DeriveKey(
1122     _hSession: CK_SESSION_HANDLE,
1123     _pMechanism: CK_MECHANISM_PTR,
1124     _hBaseKey: CK_OBJECT_HANDLE,
1125     _pTemplate: CK_ATTRIBUTE_PTR,
1126     _ulAttributeCount: CK_ULONG,
1127     _phKey: CK_OBJECT_HANDLE_PTR,
1128 ) -> CK_RV {
1129     log_with_thread_id!(error, "C_DeriveKey: CKR_FUNCTION_NOT_SUPPORTED");
1130     CKR_FUNCTION_NOT_SUPPORTED
1133 extern "C" fn C_SeedRandom(
1134     _hSession: CK_SESSION_HANDLE,
1135     _pSeed: CK_BYTE_PTR,
1136     _ulSeedLen: CK_ULONG,
1137 ) -> CK_RV {
1138     log_with_thread_id!(error, "C_SeedRandom: CKR_FUNCTION_NOT_SUPPORTED");
1139     CKR_FUNCTION_NOT_SUPPORTED
1142 extern "C" fn C_GenerateRandom(
1143     _hSession: CK_SESSION_HANDLE,
1144     _RandomData: CK_BYTE_PTR,
1145     _ulRandomLen: CK_ULONG,
1146 ) -> CK_RV {
1147     log_with_thread_id!(error, "C_GenerateRandom: CKR_FUNCTION_NOT_SUPPORTED");
1148     CKR_FUNCTION_NOT_SUPPORTED
1151 extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV {
1152     log_with_thread_id!(error, "C_GetFunctionStatus: CKR_FUNCTION_NOT_SUPPORTED");
1153     CKR_FUNCTION_NOT_SUPPORTED
1156 extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV {
1157     log_with_thread_id!(error, "C_CancelFunction: CKR_FUNCTION_NOT_SUPPORTED");
1158     CKR_FUNCTION_NOT_SUPPORTED
1161 extern "C" fn C_WaitForSlotEvent(
1162     _flags: CK_FLAGS,
1163     _pSlot: CK_SLOT_ID_PTR,
1164     _pRserved: CK_VOID_PTR,
1165 ) -> CK_RV {
1166     log_with_thread_id!(error, "C_WaitForSlotEvent: CKR_FUNCTION_NOT_SUPPORTED");
1167     CKR_FUNCTION_NOT_SUPPORTED
1170 /// To be a valid PKCS #11 module, this list of functions must be supported. At least cryptoki 2.2
1171 /// must be supported for this module to work in NSS.
1172 static FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
1173     version: CK_VERSION { major: 2, minor: 2 },
1174     C_Initialize: Some(C_Initialize),
1175     C_Finalize: Some(C_Finalize),
1176     C_GetInfo: Some(C_GetInfo),
1177     C_GetFunctionList: None,
1178     C_GetSlotList: Some(C_GetSlotList),
1179     C_GetSlotInfo: Some(C_GetSlotInfo),
1180     C_GetTokenInfo: Some(C_GetTokenInfo),
1181     C_GetMechanismList: Some(C_GetMechanismList),
1182     C_GetMechanismInfo: Some(C_GetMechanismInfo),
1183     C_InitToken: Some(C_InitToken),
1184     C_InitPIN: Some(C_InitPIN),
1185     C_SetPIN: Some(C_SetPIN),
1186     C_OpenSession: Some(C_OpenSession),
1187     C_CloseSession: Some(C_CloseSession),
1188     C_CloseAllSessions: Some(C_CloseAllSessions),
1189     C_GetSessionInfo: Some(C_GetSessionInfo),
1190     C_GetOperationState: Some(C_GetOperationState),
1191     C_SetOperationState: Some(C_SetOperationState),
1192     C_Login: Some(C_Login),
1193     C_Logout: Some(C_Logout),
1194     C_CreateObject: Some(C_CreateObject),
1195     C_CopyObject: Some(C_CopyObject),
1196     C_DestroyObject: Some(C_DestroyObject),
1197     C_GetObjectSize: Some(C_GetObjectSize),
1198     C_GetAttributeValue: Some(C_GetAttributeValue),
1199     C_SetAttributeValue: Some(C_SetAttributeValue),
1200     C_FindObjectsInit: Some(C_FindObjectsInit),
1201     C_FindObjects: Some(C_FindObjects),
1202     C_FindObjectsFinal: Some(C_FindObjectsFinal),
1203     C_EncryptInit: Some(C_EncryptInit),
1204     C_Encrypt: Some(C_Encrypt),
1205     C_EncryptUpdate: Some(C_EncryptUpdate),
1206     C_EncryptFinal: Some(C_EncryptFinal),
1207     C_DecryptInit: Some(C_DecryptInit),
1208     C_Decrypt: Some(C_Decrypt),
1209     C_DecryptUpdate: Some(C_DecryptUpdate),
1210     C_DecryptFinal: Some(C_DecryptFinal),
1211     C_DigestInit: Some(C_DigestInit),
1212     C_Digest: Some(C_Digest),
1213     C_DigestUpdate: Some(C_DigestUpdate),
1214     C_DigestKey: Some(C_DigestKey),
1215     C_DigestFinal: Some(C_DigestFinal),
1216     C_SignInit: Some(C_SignInit),
1217     C_Sign: Some(C_Sign),
1218     C_SignUpdate: Some(C_SignUpdate),
1219     C_SignFinal: Some(C_SignFinal),
1220     C_SignRecoverInit: Some(C_SignRecoverInit),
1221     C_SignRecover: Some(C_SignRecover),
1222     C_VerifyInit: Some(C_VerifyInit),
1223     C_Verify: Some(C_Verify),
1224     C_VerifyUpdate: Some(C_VerifyUpdate),
1225     C_VerifyFinal: Some(C_VerifyFinal),
1226     C_VerifyRecoverInit: Some(C_VerifyRecoverInit),
1227     C_VerifyRecover: Some(C_VerifyRecover),
1228     C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate),
1229     C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate),
1230     C_SignEncryptUpdate: Some(C_SignEncryptUpdate),
1231     C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate),
1232     C_GenerateKey: Some(C_GenerateKey),
1233     C_GenerateKeyPair: Some(C_GenerateKeyPair),
1234     C_WrapKey: Some(C_WrapKey),
1235     C_UnwrapKey: Some(C_UnwrapKey),
1236     C_DeriveKey: Some(C_DeriveKey),
1237     C_SeedRandom: Some(C_SeedRandom),
1238     C_GenerateRandom: Some(C_GenerateRandom),
1239     C_GetFunctionStatus: Some(C_GetFunctionStatus),
1240     C_CancelFunction: Some(C_CancelFunction),
1241     C_WaitForSlotEvent: Some(C_WaitForSlotEvent),
1244 /// # Safety
1246 /// This is the only function this module exposes. NSS calls it to obtain the list of functions
1247 /// comprising this module.
1248 /// ppFunctionList must be a valid pointer.
1249 #[no_mangle]
1250 pub unsafe extern "C" fn C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV {
1251     if ppFunctionList.is_null() {
1252         return CKR_ARGUMENTS_BAD;
1253     }
1254     // CK_FUNCTION_LIST_PTR is a *mut CK_FUNCTION_LIST, but as per the
1255     // specification, the caller must treat it as *const CK_FUNCTION_LIST.
1256     *ppFunctionList = std::ptr::addr_of!(FUNCTION_LIST) as CK_FUNCTION_LIST_PTR;
1257     CKR_OK
1260 #[cfg_attr(
1261     any(target_os = "macos", target_os = "ios"),
1262     link(name = "Security", kind = "framework")
1264 extern "C" {}