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/. */
5 
6 #![allow(non_snake_case)]
7 
8 extern crate byteorder;
9 #[cfg(target_os = "macos")]
10 #[macro_use]
11 extern crate core_foundation;
12 extern crate env_logger;
13 #[macro_use]
14 extern crate lazy_static;
15 #[cfg(target_os = "macos")]
16 extern crate libloading;
17 #[macro_use]
18 extern crate log;
19 extern crate pkcs11;
20 #[cfg(target_os = "macos")]
21 #[macro_use]
22 extern crate rental;
23 extern crate sha2;
24 #[cfg(target_os = "windows")]
25 extern crate winapi;
26 
27 use pkcs11::types::*;
28 use std::sync::Mutex;
29 use std::thread;
30 
31 mod manager;
32 #[macro_use]
33 mod util;
34 #[cfg(target_os = "macos")]
35 mod backend_macos;
36 #[cfg(target_os = "windows")]
37 mod backend_windows;
38 
39 use manager::{ManagerProxy, SlotType};
40 
41 lazy_static! {
42     /// The singleton `ManagerProxy` that handles state with respect to PKCS #11. Only one thread
43     /// may use it at a time, but there is no restriction on which threads may use it. However, as
44     /// OS APIs being used are not necessarily thread-safe (e.g. they may be using
45     /// thread-local-storage), the `ManagerProxy` forwards calls from any thread to a single thread
46     /// where the real `Manager` does the actual work.
47     static ref MANAGER_PROXY: Mutex<Option<ManagerProxy>> = Mutex::new(None);
48 }
49 
50 // Obtaining a handle on the manager proxy is a two-step process. First the mutex must be locked,
51 // which (if successful), results in a mutex guard object. We must then get a mutable refence to the
52 // underlying manager proxy (if set - otherwise we return an error). This can't happen all in one
53 // macro without dropping a reference that needs to live long enough for this to be safe. In
54 // practice, this looks like:
55 //   let mut manager_guard = try_to_get_manager_guard!();
56 //   let manager = manager_guard_to_manager!(manager_guard);
57 macro_rules! try_to_get_manager_guard {
58     () => {
59         match MANAGER_PROXY.lock() {
60             Ok(maybe_manager_proxy) => maybe_manager_proxy,
61             Err(poison_error) => {
62                 log_with_thread_id!(
63                     error,
64                     "previous thread panicked acquiring manager lock: {}",
65                     poison_error
66                 );
67                 return CKR_DEVICE_ERROR;
68             }
69         }
70     };
71 }
72 
73 macro_rules! manager_guard_to_manager {
74     ($manager_guard:ident) => {
75         match $manager_guard.as_mut() {
76             Some(manager_proxy) => manager_proxy,
77             None => {
78                 log_with_thread_id!(error, "manager expected to be set, but it is not");
79                 return CKR_DEVICE_ERROR;
80             }
81         }
82     };
83 }
84 
85 // Helper macro to prefix log messages with the current thread ID.
86 macro_rules! log_with_thread_id {
87     ($log_level:ident, $($message:expr),*) => {
88         let message = format!($($message),*);
89         $log_level!("{:?} {}", thread::current().id(), message);
90     };
91 }
92 
93 /// This gets called to initialize the module. For this implementation, this consists of
94 /// instantiating the `ManagerProxy`.
C_Initialize(_pInitArgs: CK_C_INITIALIZE_ARGS_PTR) -> CK_RV95 extern "C" fn C_Initialize(_pInitArgs: CK_C_INITIALIZE_ARGS_PTR) -> CK_RV {
96     // This will fail if this has already been called, but this isn't a problem because either way,
97     // logging has been initialized.
98     let _ = env_logger::try_init();
99     let mut manager_guard = try_to_get_manager_guard!();
100     let manager_proxy = match ManagerProxy::new() {
101         Ok(p) => p,
102         Err(()) => return CKR_DEVICE_ERROR,
103     };
104     match manager_guard.replace(manager_proxy) {
105         Some(_unexpected_previous_manager) => {
106             #[cfg(target_os = "macos")]
107             {
108                 log_with_thread_id!(info, "C_Initialize: manager previously set (this is expected on macOS - replacing it)");
109             }
110             #[cfg(target_os = "windows")]
111             {
112                 log_with_thread_id!(warn, "C_Initialize: manager unexpectedly previously set (bravely continuing by replacing it)");
113             }
114         }
115         None => {}
116     }
117     log_with_thread_id!(debug, "C_Initialize: CKR_OK");
118     CKR_OK
119 }
120 
C_Finalize(_pReserved: CK_VOID_PTR) -> CK_RV121 extern "C" fn C_Finalize(_pReserved: CK_VOID_PTR) -> CK_RV {
122     let mut manager_guard = try_to_get_manager_guard!();
123     let manager = manager_guard_to_manager!(manager_guard);
124     match manager.stop() {
125         Ok(()) => {
126             log_with_thread_id!(debug, "C_Finalize: CKR_OK");
127             CKR_OK
128         }
129         Err(()) => {
130             log_with_thread_id!(error, "C_Finalize: CKR_DEVICE_ERROR");
131             CKR_DEVICE_ERROR
132         }
133     }
134 }
135 
136 // The specification mandates that these strings be padded with spaces to the appropriate length.
137 // Since the length of fixed-size arrays in rust is part of the type, the compiler enforces that
138 // these byte strings are of the correct length.
139 const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Corporation             ";
140 const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"OS Client Cert Module           ";
141 
142 /// This gets called to gather some information about the module. In particular, this implementation
143 /// supports (portions of) cryptoki (PKCS #11) version 2.2.
C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV144 extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV {
145     if pInfo.is_null() {
146         log_with_thread_id!(error, "C_GetInfo: CKR_ARGUMENTS_BAD");
147         return CKR_ARGUMENTS_BAD;
148     }
149     log_with_thread_id!(debug, "C_GetInfo: CKR_OK");
150     let mut info = CK_INFO::default();
151     info.cryptokiVersion.major = 2;
152     info.cryptokiVersion.minor = 2;
153     info.manufacturerID = *MANUFACTURER_ID_BYTES;
154     info.libraryDescription = *LIBRARY_DESCRIPTION_BYTES;
155     unsafe {
156         *pInfo = info;
157     }
158     CKR_OK
159 }
160 
161 /// This module has two slots.
162 const SLOT_COUNT: CK_ULONG = 2;
163 /// The slot with ID 1 supports modern mechanisms like RSA-PSS.
164 const SLOT_ID_MODERN: CK_SLOT_ID = 1;
165 /// The slot with ID 2 only supports legacy mechanisms.
166 const SLOT_ID_LEGACY: CK_SLOT_ID = 2;
167 
168 /// This gets called twice: once with a null `pSlotList` to get the number of slots (returned via
169 /// `pulCount`) and a second time to get the ID for each slot.
C_GetSlotList( _tokenPresent: CK_BBOOL, pSlotList: CK_SLOT_ID_PTR, pulCount: CK_ULONG_PTR, ) -> CK_RV170 extern "C" fn C_GetSlotList(
171     _tokenPresent: CK_BBOOL,
172     pSlotList: CK_SLOT_ID_PTR,
173     pulCount: CK_ULONG_PTR,
174 ) -> CK_RV {
175     if pulCount.is_null() {
176         log_with_thread_id!(error, "C_GetSlotList: CKR_ARGUMENTS_BAD");
177         return CKR_ARGUMENTS_BAD;
178     }
179     if !pSlotList.is_null() {
180         if unsafe { *pulCount } < SLOT_COUNT {
181             log_with_thread_id!(error, "C_GetSlotList: CKR_BUFFER_TOO_SMALL");
182             return CKR_BUFFER_TOO_SMALL;
183         }
184         unsafe {
185             *pSlotList = SLOT_ID_MODERN;
186             *pSlotList.offset(1) = SLOT_ID_LEGACY;
187         }
188     };
189     unsafe {
190         *pulCount = SLOT_COUNT;
191     }
192     log_with_thread_id!(debug, "C_GetSlotList: CKR_OK");
193     CKR_OK
194 }
195 
196 const SLOT_DESCRIPTION_MODERN_BYTES: &[u8; 64] =
197     b"OS Client Cert Slot (Modern)                                    ";
198 const SLOT_DESCRIPTION_LEGACY_BYTES: &[u8; 64] =
199     b"OS Client Cert Slot (Legacy)                                    ";
200 
201 /// This gets called to obtain information about slots. In this implementation, the tokens are
202 /// always present in the slots.
C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV203 extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV {
204     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() {
205         log_with_thread_id!(error, "C_GetSlotInfo: CKR_ARGUMENTS_BAD");
206         return CKR_ARGUMENTS_BAD;
207     }
208     let description = if slotID == SLOT_ID_MODERN {
209         SLOT_DESCRIPTION_MODERN_BYTES
210     } else {
211         SLOT_DESCRIPTION_LEGACY_BYTES
212     };
213     let slot_info = CK_SLOT_INFO {
214         slotDescription: *description,
215         manufacturerID: *MANUFACTURER_ID_BYTES,
216         flags: CKF_TOKEN_PRESENT,
217         hardwareVersion: CK_VERSION::default(),
218         firmwareVersion: CK_VERSION::default(),
219     };
220     unsafe {
221         *pInfo = slot_info;
222     }
223     log_with_thread_id!(debug, "C_GetSlotInfo: CKR_OK");
224     CKR_OK
225 }
226 
227 const TOKEN_LABEL_MODERN_BYTES: &[u8; 32] = b"OS Client Cert Token (Modern)   ";
228 const TOKEN_LABEL_LEGACY_BYTES: &[u8; 32] = b"OS Client Cert Token (Legacy)   ";
229 const TOKEN_MODEL_BYTES: &[u8; 16] = b"osclientcerts   ";
230 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
231 
232 /// This gets called to obtain some information about tokens. This implementation has two slots,
233 /// so it has two tokens. This information is primarily for display purposes.
C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV234 extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV {
235     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() {
236         log_with_thread_id!(error, "C_GetTokenInfo: CKR_ARGUMENTS_BAD");
237         return CKR_ARGUMENTS_BAD;
238     }
239     let mut token_info = CK_TOKEN_INFO::default();
240     let label = if slotID == SLOT_ID_MODERN {
241         TOKEN_LABEL_MODERN_BYTES
242     } else {
243         TOKEN_LABEL_LEGACY_BYTES
244     };
245     token_info.label = *label;
246     token_info.manufacturerID = *MANUFACTURER_ID_BYTES;
247     token_info.model = *TOKEN_MODEL_BYTES;
248     token_info.serialNumber = *TOKEN_SERIAL_NUMBER_BYTES;
249     unsafe {
250         *pInfo = token_info;
251     }
252     log_with_thread_id!(debug, "C_GetTokenInfo: CKR_OK");
253     CKR_OK
254 }
255 
256 /// This gets called to determine what mechanisms a slot supports. The modern slot supports ECDSA,
257 /// RSA PKCS, and RSA PSS. The legacy slot only supports RSA PKCS.
C_GetMechanismList( slotID: CK_SLOT_ID, pMechanismList: CK_MECHANISM_TYPE_PTR, pulCount: CK_ULONG_PTR, ) -> CK_RV258 extern "C" fn C_GetMechanismList(
259     slotID: CK_SLOT_ID,
260     pMechanismList: CK_MECHANISM_TYPE_PTR,
261     pulCount: CK_ULONG_PTR,
262 ) -> CK_RV {
263     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pulCount.is_null() {
264         log_with_thread_id!(error, "C_GetMechanismList: CKR_ARGUMENTS_BAD");
265         return CKR_ARGUMENTS_BAD;
266     }
267     let mechanisms = if slotID == SLOT_ID_MODERN {
268         vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
269     } else {
270         vec![CKM_RSA_PKCS]
271     };
272     if !pMechanismList.is_null() {
273         if unsafe { *pulCount as usize } < mechanisms.len() {
274             log_with_thread_id!(error, "C_GetMechanismList: CKR_ARGUMENTS_BAD");
275             return CKR_ARGUMENTS_BAD;
276         }
277         for i in 0..mechanisms.len() {
278             unsafe {
279                 *pMechanismList.offset(i as isize) = mechanisms[i];
280             }
281         }
282     }
283     unsafe {
284         *pulCount = mechanisms.len() as CK_ULONG;
285     }
286     log_with_thread_id!(debug, "C_GetMechanismList: CKR_OK");
287     CKR_OK
288 }
289 
C_GetMechanismInfo( _slotID: CK_SLOT_ID, _type: CK_MECHANISM_TYPE, _pInfo: CK_MECHANISM_INFO_PTR, ) -> CK_RV290 extern "C" fn C_GetMechanismInfo(
291     _slotID: CK_SLOT_ID,
292     _type: CK_MECHANISM_TYPE,
293     _pInfo: CK_MECHANISM_INFO_PTR,
294 ) -> CK_RV {
295     log_with_thread_id!(error, "C_GetMechanismInfo: CKR_FUNCTION_NOT_SUPPORTED");
296     CKR_FUNCTION_NOT_SUPPORTED
297 }
298 
C_InitToken( _slotID: CK_SLOT_ID, _pPin: CK_UTF8CHAR_PTR, _ulPinLen: CK_ULONG, _pLabel: CK_UTF8CHAR_PTR, ) -> CK_RV299 extern "C" fn C_InitToken(
300     _slotID: CK_SLOT_ID,
301     _pPin: CK_UTF8CHAR_PTR,
302     _ulPinLen: CK_ULONG,
303     _pLabel: CK_UTF8CHAR_PTR,
304 ) -> CK_RV {
305     log_with_thread_id!(error, "C_InitToken: CKR_FUNCTION_NOT_SUPPORTED");
306     CKR_FUNCTION_NOT_SUPPORTED
307 }
308 
C_InitPIN( _hSession: CK_SESSION_HANDLE, _pPin: CK_UTF8CHAR_PTR, _ulPinLen: CK_ULONG, ) -> CK_RV309 extern "C" fn C_InitPIN(
310     _hSession: CK_SESSION_HANDLE,
311     _pPin: CK_UTF8CHAR_PTR,
312     _ulPinLen: CK_ULONG,
313 ) -> CK_RV {
314     log_with_thread_id!(error, "C_InitPIN: CKR_FUNCTION_NOT_SUPPORTED");
315     CKR_FUNCTION_NOT_SUPPORTED
316 }
317 
C_SetPIN( _hSession: CK_SESSION_HANDLE, _pOldPin: CK_UTF8CHAR_PTR, _ulOldLen: CK_ULONG, _pNewPin: CK_UTF8CHAR_PTR, _ulNewLen: CK_ULONG, ) -> CK_RV318 extern "C" fn C_SetPIN(
319     _hSession: CK_SESSION_HANDLE,
320     _pOldPin: CK_UTF8CHAR_PTR,
321     _ulOldLen: CK_ULONG,
322     _pNewPin: CK_UTF8CHAR_PTR,
323     _ulNewLen: CK_ULONG,
324 ) -> CK_RV {
325     log_with_thread_id!(error, "C_SetPIN: CKR_FUNCTION_NOT_SUPPORTED");
326     CKR_FUNCTION_NOT_SUPPORTED
327 }
328 
329 /// This gets called to create a new session. This module defers to the `ManagerProxy` to implement
330 /// this.
C_OpenSession( slotID: CK_SLOT_ID, _flags: CK_FLAGS, _pApplication: CK_VOID_PTR, _Notify: CK_NOTIFY, phSession: CK_SESSION_HANDLE_PTR, ) -> CK_RV331 extern "C" fn C_OpenSession(
332     slotID: CK_SLOT_ID,
333     _flags: CK_FLAGS,
334     _pApplication: CK_VOID_PTR,
335     _Notify: CK_NOTIFY,
336     phSession: CK_SESSION_HANDLE_PTR,
337 ) -> CK_RV {
338     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || phSession.is_null() {
339         log_with_thread_id!(error, "C_OpenSession: CKR_ARGUMENTS_BAD");
340         return CKR_ARGUMENTS_BAD;
341     }
342     let mut manager_guard = try_to_get_manager_guard!();
343     let manager = manager_guard_to_manager!(manager_guard);
344     let slot_type = if slotID == SLOT_ID_MODERN {
345         SlotType::Modern
346     } else {
347         SlotType::Legacy
348     };
349     let session_handle = match manager.open_session(slot_type) {
350         Ok(session_handle) => session_handle,
351         Err(()) => {
352             log_with_thread_id!(error, "C_OpenSession: open_session failed");
353             return CKR_DEVICE_ERROR;
354         }
355     };
356     unsafe {
357         *phSession = session_handle;
358     }
359     log_with_thread_id!(debug, "C_OpenSession: CKR_OK");
360     CKR_OK
361 }
362 
363 /// This gets called to close a session. This is handled by the `ManagerProxy`.
C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV364 extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV {
365     let mut manager_guard = try_to_get_manager_guard!();
366     let manager = manager_guard_to_manager!(manager_guard);
367     if manager.close_session(hSession).is_err() {
368         log_with_thread_id!(error, "C_CloseSession: CKR_SESSION_HANDLE_INVALID");
369         return CKR_SESSION_HANDLE_INVALID;
370     }
371     log_with_thread_id!(debug, "C_CloseSession: CKR_OK");
372     CKR_OK
373 }
374 
375 /// This gets called to close all open sessions at once. This is handled by the `ManagerProxy`.
C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV376 extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV {
377     if slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY {
378         log_with_thread_id!(error, "C_CloseAllSessions: CKR_ARGUMENTS_BAD");
379         return CKR_ARGUMENTS_BAD;
380     }
381     let mut manager_guard = try_to_get_manager_guard!();
382     let manager = manager_guard_to_manager!(manager_guard);
383     let slot_type = if slotID == SLOT_ID_MODERN {
384         SlotType::Modern
385     } else {
386         SlotType::Legacy
387     };
388     match manager.close_all_sessions(slot_type) {
389         Ok(()) => {
390             log_with_thread_id!(debug, "C_CloseAllSessions: CKR_OK");
391             CKR_OK
392         }
393         Err(()) => {
394             log_with_thread_id!(error, "C_CloseAllSessions: close_all_sessions failed");
395             CKR_DEVICE_ERROR
396         }
397     }
398 }
399 
C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV400 extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV {
401     log_with_thread_id!(error, "C_GetSessionInfo: CKR_FUNCTION_NOT_SUPPORTED");
402     CKR_FUNCTION_NOT_SUPPORTED
403 }
404 
C_GetOperationState( _hSession: CK_SESSION_HANDLE, _pOperationState: CK_BYTE_PTR, _pulOperationStateLen: CK_ULONG_PTR, ) -> CK_RV405 extern "C" fn C_GetOperationState(
406     _hSession: CK_SESSION_HANDLE,
407     _pOperationState: CK_BYTE_PTR,
408     _pulOperationStateLen: CK_ULONG_PTR,
409 ) -> CK_RV {
410     log_with_thread_id!(error, "C_GetOperationState: CKR_FUNCTION_NOT_SUPPORTED");
411     CKR_FUNCTION_NOT_SUPPORTED
412 }
413 
C_SetOperationState( _hSession: CK_SESSION_HANDLE, _pOperationState: CK_BYTE_PTR, _ulOperationStateLen: CK_ULONG, _hEncryptionKey: CK_OBJECT_HANDLE, _hAuthenticationKey: CK_OBJECT_HANDLE, ) -> CK_RV414 extern "C" fn C_SetOperationState(
415     _hSession: CK_SESSION_HANDLE,
416     _pOperationState: CK_BYTE_PTR,
417     _ulOperationStateLen: CK_ULONG,
418     _hEncryptionKey: CK_OBJECT_HANDLE,
419     _hAuthenticationKey: CK_OBJECT_HANDLE,
420 ) -> CK_RV {
421     log_with_thread_id!(error, "C_SetOperationState: CKR_FUNCTION_NOT_SUPPORTED");
422     CKR_FUNCTION_NOT_SUPPORTED
423 }
424 
C_Login( _hSession: CK_SESSION_HANDLE, _userType: CK_USER_TYPE, _pPin: CK_UTF8CHAR_PTR, _ulPinLen: CK_ULONG, ) -> CK_RV425 extern "C" fn C_Login(
426     _hSession: CK_SESSION_HANDLE,
427     _userType: CK_USER_TYPE,
428     _pPin: CK_UTF8CHAR_PTR,
429     _ulPinLen: CK_ULONG,
430 ) -> CK_RV {
431     log_with_thread_id!(error, "C_Login: CKR_FUNCTION_NOT_SUPPORTED");
432     CKR_FUNCTION_NOT_SUPPORTED
433 }
434 
435 /// This gets called to log out and drop any authenticated resources. Because this module does not
436 /// hold on to authenticated resources, this module "implements" this by doing nothing and
437 /// returning a success result.
C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV438 extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV {
439     log_with_thread_id!(debug, "C_Logout: CKR_OK");
440     CKR_OK
441 }
442 
C_CreateObject( _hSession: CK_SESSION_HANDLE, _pTemplate: CK_ATTRIBUTE_PTR, _ulCount: CK_ULONG, _phObject: CK_OBJECT_HANDLE_PTR, ) -> CK_RV443 extern "C" fn C_CreateObject(
444     _hSession: CK_SESSION_HANDLE,
445     _pTemplate: CK_ATTRIBUTE_PTR,
446     _ulCount: CK_ULONG,
447     _phObject: CK_OBJECT_HANDLE_PTR,
448 ) -> CK_RV {
449     log_with_thread_id!(error, "C_CreateObject: CKR_FUNCTION_NOT_SUPPORTED");
450     CKR_FUNCTION_NOT_SUPPORTED
451 }
452 
C_CopyObject( _hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE, _pTemplate: CK_ATTRIBUTE_PTR, _ulCount: CK_ULONG, _phNewObject: CK_OBJECT_HANDLE_PTR, ) -> CK_RV453 extern "C" fn C_CopyObject(
454     _hSession: CK_SESSION_HANDLE,
455     _hObject: CK_OBJECT_HANDLE,
456     _pTemplate: CK_ATTRIBUTE_PTR,
457     _ulCount: CK_ULONG,
458     _phNewObject: CK_OBJECT_HANDLE_PTR,
459 ) -> CK_RV {
460     log_with_thread_id!(error, "C_CopyObject: CKR_FUNCTION_NOT_SUPPORTED");
461     CKR_FUNCTION_NOT_SUPPORTED
462 }
463 
C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV464 extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV {
465     log_with_thread_id!(error, "C_DestroyObject: CKR_FUNCTION_NOT_SUPPORTED");
466     CKR_FUNCTION_NOT_SUPPORTED
467 }
468 
C_GetObjectSize( _hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE, _pulSize: CK_ULONG_PTR, ) -> CK_RV469 extern "C" fn C_GetObjectSize(
470     _hSession: CK_SESSION_HANDLE,
471     _hObject: CK_OBJECT_HANDLE,
472     _pulSize: CK_ULONG_PTR,
473 ) -> CK_RV {
474     log_with_thread_id!(error, "C_GetObjectSize: CKR_FUNCTION_NOT_SUPPORTED");
475     CKR_FUNCTION_NOT_SUPPORTED
476 }
477 
478 /// This gets called to obtain the values of a number of attributes of an object identified by the
479 /// given handle. This module implements this by requesting that the `ManagerProxy` find the object
480 /// and attempt to get the value of each attribute. If a specified attribute is not defined on the
481 /// object, the length of that attribute is set to -1 to indicate that it is not available.
482 /// This gets called twice: once to obtain the lengths of the attributes and again to get the
483 /// values.
C_GetAttributeValue( _hSession: CK_SESSION_HANDLE, hObject: CK_OBJECT_HANDLE, pTemplate: CK_ATTRIBUTE_PTR, ulCount: CK_ULONG, ) -> CK_RV484 extern "C" fn C_GetAttributeValue(
485     _hSession: CK_SESSION_HANDLE,
486     hObject: CK_OBJECT_HANDLE,
487     pTemplate: CK_ATTRIBUTE_PTR,
488     ulCount: CK_ULONG,
489 ) -> CK_RV {
490     if pTemplate.is_null() {
491         log_with_thread_id!(error, "C_GetAttributeValue: CKR_ARGUMENTS_BAD");
492         return CKR_ARGUMENTS_BAD;
493     }
494     let mut attr_types = Vec::with_capacity(ulCount as usize);
495     for i in 0..ulCount {
496         let attr = unsafe { &*pTemplate.offset(i as isize) };
497         attr_types.push(attr.attrType);
498     }
499     let mut manager_guard = try_to_get_manager_guard!();
500     let manager = manager_guard_to_manager!(manager_guard);
501     let values = match manager.get_attributes(hObject, attr_types) {
502         Ok(values) => values,
503         Err(()) => {
504             log_with_thread_id!(error, "C_GetAttributeValue: CKR_ARGUMENTS_BAD");
505             return CKR_ARGUMENTS_BAD;
506         }
507     };
508     if values.len() != ulCount as usize {
509         log_with_thread_id!(
510             error,
511             "C_GetAttributeValue: manager.get_attributes didn't return the right number of values"
512         );
513         return CKR_DEVICE_ERROR;
514     }
515     for i in 0..ulCount as usize {
516         let mut attr = unsafe { &mut *pTemplate.offset(i as isize) };
517         // NB: the safety of this array access depends on the length check above
518         if let Some(attr_value) = &values[i] {
519             if attr.pValue.is_null() {
520                 attr.ulValueLen = attr_value.len() as CK_ULONG;
521             } else {
522                 let ptr: *mut u8 = attr.pValue as *mut u8;
523                 if attr_value.len() != attr.ulValueLen as usize {
524                     log_with_thread_id!(error, "C_GetAttributeValue: incorrect attr size");
525                     return CKR_ARGUMENTS_BAD;
526                 }
527                 unsafe {
528                     std::ptr::copy_nonoverlapping(attr_value.as_ptr(), ptr, attr_value.len());
529                 }
530             }
531         } else {
532             attr.ulValueLen = (0 - 1) as CK_ULONG;
533         }
534     }
535     log_with_thread_id!(debug, "C_GetAttributeValue: CKR_OK");
536     CKR_OK
537 }
538 
C_SetAttributeValue( _hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE, _pTemplate: CK_ATTRIBUTE_PTR, _ulCount: CK_ULONG, ) -> CK_RV539 extern "C" fn C_SetAttributeValue(
540     _hSession: CK_SESSION_HANDLE,
541     _hObject: CK_OBJECT_HANDLE,
542     _pTemplate: CK_ATTRIBUTE_PTR,
543     _ulCount: CK_ULONG,
544 ) -> CK_RV {
545     log_with_thread_id!(error, "C_SetAttributeValue: CKR_FUNCTION_NOT_SUPPORTED");
546     CKR_FUNCTION_NOT_SUPPORTED
547 }
548 
trace_attr(prefix: &str, attr: &CK_ATTRIBUTE)549 fn trace_attr(prefix: &str, attr: &CK_ATTRIBUTE) {
550     let typ = match unsafe_packed_field_access!(attr.attrType) {
551         CKA_CLASS => "CKA_CLASS".to_string(),
552         CKA_TOKEN => "CKA_TOKEN".to_string(),
553         CKA_LABEL => "CKA_LABEL".to_string(),
554         CKA_ID => "CKA_ID".to_string(),
555         CKA_VALUE => "CKA_VALUE".to_string(),
556         CKA_ISSUER => "CKA_ISSUER".to_string(),
557         CKA_SERIAL_NUMBER => "CKA_SERIAL_NUMBER".to_string(),
558         CKA_SUBJECT => "CKA_SUBJECT".to_string(),
559         CKA_PRIVATE => "CKA_PRIVATE".to_string(),
560         CKA_KEY_TYPE => "CKA_KEY_TYPE".to_string(),
561         CKA_MODULUS => "CKA_MODULUS".to_string(),
562         CKA_EC_PARAMS => "CKA_EC_PARAMS".to_string(),
563         _ => format!("0x{:x}", unsafe_packed_field_access!(attr.attrType)),
564     };
565     let value =
566         unsafe { std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize) };
567     log_with_thread_id!(
568         trace,
569         "{}CK_ATTRIBUTE {{ attrType: {}, pValue: {:?}, ulValueLen: {} }}",
570         prefix,
571         typ,
572         value,
573         unsafe_packed_field_access!(attr.ulValueLen)
574     );
575 }
576 
577 /// This gets called to initialize a search for objects matching a given list of attributes. This
578 /// module implements this by gathering the attributes and passing them to the `ManagerProxy` to
579 /// start the search.
C_FindObjectsInit( hSession: CK_SESSION_HANDLE, pTemplate: CK_ATTRIBUTE_PTR, ulCount: CK_ULONG, ) -> CK_RV580 extern "C" fn C_FindObjectsInit(
581     hSession: CK_SESSION_HANDLE,
582     pTemplate: CK_ATTRIBUTE_PTR,
583     ulCount: CK_ULONG,
584 ) -> CK_RV {
585     if pTemplate.is_null() {
586         log_with_thread_id!(error, "C_FindObjectsInit: CKR_ARGUMENTS_BAD");
587         return CKR_ARGUMENTS_BAD;
588     }
589     let mut attrs = Vec::new();
590     log_with_thread_id!(trace, "C_FindObjectsInit:");
591     for i in 0..ulCount {
592         let attr = unsafe { &*pTemplate.offset(i as isize) };
593         trace_attr("  ", &attr);
594         let slice = unsafe {
595             std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize)
596         };
597         attrs.push((attr.attrType, slice.to_owned()));
598     }
599     let mut manager_guard = try_to_get_manager_guard!();
600     let manager = manager_guard_to_manager!(manager_guard);
601     match manager.start_search(hSession, attrs) {
602         Ok(()) => {}
603         Err(()) => {
604             log_with_thread_id!(error, "C_FindObjectsInit: CKR_ARGUMENTS_BAD");
605             return CKR_ARGUMENTS_BAD;
606         }
607     }
608     log_with_thread_id!(debug, "C_FindObjectsInit: CKR_OK");
609     CKR_OK
610 }
611 
612 /// This gets called after `C_FindObjectsInit` to get the results of a search. This module
613 /// implements this by looking up the search in the `ManagerProxy` and copying out the matching
614 /// object handles.
C_FindObjects( hSession: CK_SESSION_HANDLE, phObject: CK_OBJECT_HANDLE_PTR, ulMaxObjectCount: CK_ULONG, pulObjectCount: CK_ULONG_PTR, ) -> CK_RV615 extern "C" fn C_FindObjects(
616     hSession: CK_SESSION_HANDLE,
617     phObject: CK_OBJECT_HANDLE_PTR,
618     ulMaxObjectCount: CK_ULONG,
619     pulObjectCount: CK_ULONG_PTR,
620 ) -> CK_RV {
621     if phObject.is_null() || pulObjectCount.is_null() || ulMaxObjectCount == 0 {
622         log_with_thread_id!(error, "C_FindObjects: CKR_ARGUMENTS_BAD");
623         return CKR_ARGUMENTS_BAD;
624     }
625     let mut manager_guard = try_to_get_manager_guard!();
626     let manager = manager_guard_to_manager!(manager_guard);
627     let handles = match manager.search(hSession, ulMaxObjectCount as usize) {
628         Ok(handles) => handles,
629         Err(()) => {
630             log_with_thread_id!(error, "C_FindObjects: CKR_ARGUMENTS_BAD");
631             return CKR_ARGUMENTS_BAD;
632         }
633     };
634     log_with_thread_id!(debug, "C_FindObjects: found handles {:?}", handles);
635     if handles.len() > ulMaxObjectCount as usize {
636         log_with_thread_id!(error, "C_FindObjects: manager returned too many handles");
637         return CKR_DEVICE_ERROR;
638     }
639     unsafe {
640         *pulObjectCount = handles.len() as CK_ULONG;
641     }
642     for (index, handle) in handles.iter().enumerate() {
643         if index < ulMaxObjectCount as usize {
644             unsafe {
645                 *(phObject.add(index)) = *handle;
646             }
647         }
648     }
649     log_with_thread_id!(debug, "C_FindObjects: CKR_OK");
650     CKR_OK
651 }
652 
653 /// This gets called after `C_FindObjectsInit` and `C_FindObjects` to finish a search. The module
654 /// tells the `ManagerProxy` to clear the search.
C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV655 extern "C" fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV {
656     let mut manager_guard = try_to_get_manager_guard!();
657     let manager = manager_guard_to_manager!(manager_guard);
658     // It would be an error if there were no search for this session, but we can be permissive here.
659     match manager.clear_search(hSession) {
660         Ok(()) => {
661             log_with_thread_id!(debug, "C_FindObjectsFinal: CKR_OK");
662             CKR_OK
663         }
664         Err(()) => {
665             log_with_thread_id!(error, "C_FindObjectsFinal: clear_search failed");
666             CKR_DEVICE_ERROR
667         }
668     }
669 }
670 
C_EncryptInit( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hKey: CK_OBJECT_HANDLE, ) -> CK_RV671 extern "C" fn C_EncryptInit(
672     _hSession: CK_SESSION_HANDLE,
673     _pMechanism: CK_MECHANISM_PTR,
674     _hKey: CK_OBJECT_HANDLE,
675 ) -> CK_RV {
676     log_with_thread_id!(error, "C_EncryptInit: CKR_FUNCTION_NOT_SUPPORTED");
677     CKR_FUNCTION_NOT_SUPPORTED
678 }
679 
C_Encrypt( _hSession: CK_SESSION_HANDLE, _pData: CK_BYTE_PTR, _ulDataLen: CK_ULONG, _pEncryptedData: CK_BYTE_PTR, _pulEncryptedDataLen: CK_ULONG_PTR, ) -> CK_RV680 extern "C" fn C_Encrypt(
681     _hSession: CK_SESSION_HANDLE,
682     _pData: CK_BYTE_PTR,
683     _ulDataLen: CK_ULONG,
684     _pEncryptedData: CK_BYTE_PTR,
685     _pulEncryptedDataLen: CK_ULONG_PTR,
686 ) -> CK_RV {
687     log_with_thread_id!(error, "C_Encrypt: CKR_FUNCTION_NOT_SUPPORTED");
688     CKR_FUNCTION_NOT_SUPPORTED
689 }
690 
C_EncryptUpdate( _hSession: CK_SESSION_HANDLE, _pPart: CK_BYTE_PTR, _ulPartLen: CK_ULONG, _pEncryptedPart: CK_BYTE_PTR, _pulEncryptedPartLen: CK_ULONG_PTR, ) -> CK_RV691 extern "C" fn C_EncryptUpdate(
692     _hSession: CK_SESSION_HANDLE,
693     _pPart: CK_BYTE_PTR,
694     _ulPartLen: CK_ULONG,
695     _pEncryptedPart: CK_BYTE_PTR,
696     _pulEncryptedPartLen: CK_ULONG_PTR,
697 ) -> CK_RV {
698     log_with_thread_id!(error, "C_EncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
699     CKR_FUNCTION_NOT_SUPPORTED
700 }
701 
C_EncryptFinal( _hSession: CK_SESSION_HANDLE, _pLastEncryptedPart: CK_BYTE_PTR, _pulLastEncryptedPartLen: CK_ULONG_PTR, ) -> CK_RV702 extern "C" fn C_EncryptFinal(
703     _hSession: CK_SESSION_HANDLE,
704     _pLastEncryptedPart: CK_BYTE_PTR,
705     _pulLastEncryptedPartLen: CK_ULONG_PTR,
706 ) -> CK_RV {
707     log_with_thread_id!(error, "C_EncryptFinal: CKR_FUNCTION_NOT_SUPPORTED");
708     CKR_FUNCTION_NOT_SUPPORTED
709 }
710 
C_DecryptInit( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hKey: CK_OBJECT_HANDLE, ) -> CK_RV711 extern "C" fn C_DecryptInit(
712     _hSession: CK_SESSION_HANDLE,
713     _pMechanism: CK_MECHANISM_PTR,
714     _hKey: CK_OBJECT_HANDLE,
715 ) -> CK_RV {
716     log_with_thread_id!(error, "C_DecryptInit: CKR_FUNCTION_NOT_SUPPORTED");
717     CKR_FUNCTION_NOT_SUPPORTED
718 }
719 
C_Decrypt( _hSession: CK_SESSION_HANDLE, _pEncryptedData: CK_BYTE_PTR, _ulEncryptedDataLen: CK_ULONG, _pData: CK_BYTE_PTR, _pulDataLen: CK_ULONG_PTR, ) -> CK_RV720 extern "C" fn C_Decrypt(
721     _hSession: CK_SESSION_HANDLE,
722     _pEncryptedData: CK_BYTE_PTR,
723     _ulEncryptedDataLen: CK_ULONG,
724     _pData: CK_BYTE_PTR,
725     _pulDataLen: CK_ULONG_PTR,
726 ) -> CK_RV {
727     log_with_thread_id!(error, "C_Decrypt: CKR_FUNCTION_NOT_SUPPORTED");
728     CKR_FUNCTION_NOT_SUPPORTED
729 }
730 
C_DecryptUpdate( _hSession: CK_SESSION_HANDLE, _pEncryptedPart: CK_BYTE_PTR, _ulEncryptedPartLen: CK_ULONG, _pPart: CK_BYTE_PTR, _pulPartLen: CK_ULONG_PTR, ) -> CK_RV731 extern "C" fn C_DecryptUpdate(
732     _hSession: CK_SESSION_HANDLE,
733     _pEncryptedPart: CK_BYTE_PTR,
734     _ulEncryptedPartLen: CK_ULONG,
735     _pPart: CK_BYTE_PTR,
736     _pulPartLen: CK_ULONG_PTR,
737 ) -> CK_RV {
738     log_with_thread_id!(error, "C_DecryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
739     CKR_FUNCTION_NOT_SUPPORTED
740 }
741 
C_DecryptFinal( _hSession: CK_SESSION_HANDLE, _pLastPart: CK_BYTE_PTR, _pulLastPartLen: CK_ULONG_PTR, ) -> CK_RV742 extern "C" fn C_DecryptFinal(
743     _hSession: CK_SESSION_HANDLE,
744     _pLastPart: CK_BYTE_PTR,
745     _pulLastPartLen: CK_ULONG_PTR,
746 ) -> CK_RV {
747     log_with_thread_id!(error, "C_DecryptFinal: CKR_FUNCTION_NOT_SUPPORTED");
748     CKR_FUNCTION_NOT_SUPPORTED
749 }
750 
C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV751 extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV {
752     log_with_thread_id!(error, "C_DigestInit: CKR_FUNCTION_NOT_SUPPORTED");
753     CKR_FUNCTION_NOT_SUPPORTED
754 }
755 
C_Digest( _hSession: CK_SESSION_HANDLE, _pData: CK_BYTE_PTR, _ulDataLen: CK_ULONG, _pDigest: CK_BYTE_PTR, _pulDigestLen: CK_ULONG_PTR, ) -> CK_RV756 extern "C" fn C_Digest(
757     _hSession: CK_SESSION_HANDLE,
758     _pData: CK_BYTE_PTR,
759     _ulDataLen: CK_ULONG,
760     _pDigest: CK_BYTE_PTR,
761     _pulDigestLen: CK_ULONG_PTR,
762 ) -> CK_RV {
763     log_with_thread_id!(error, "C_Digest: CKR_FUNCTION_NOT_SUPPORTED");
764     CKR_FUNCTION_NOT_SUPPORTED
765 }
766 
C_DigestUpdate( _hSession: CK_SESSION_HANDLE, _pPart: CK_BYTE_PTR, _ulPartLen: CK_ULONG, ) -> CK_RV767 extern "C" fn C_DigestUpdate(
768     _hSession: CK_SESSION_HANDLE,
769     _pPart: CK_BYTE_PTR,
770     _ulPartLen: CK_ULONG,
771 ) -> CK_RV {
772     log_with_thread_id!(error, "C_DigestUpdate: CKR_FUNCTION_NOT_SUPPORTED");
773     CKR_FUNCTION_NOT_SUPPORTED
774 }
775 
C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV776 extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV {
777     log_with_thread_id!(error, "C_DigestKey: CKR_FUNCTION_NOT_SUPPORTED");
778     CKR_FUNCTION_NOT_SUPPORTED
779 }
780 
C_DigestFinal( _hSession: CK_SESSION_HANDLE, _pDigest: CK_BYTE_PTR, _pulDigestLen: CK_ULONG_PTR, ) -> CK_RV781 extern "C" fn C_DigestFinal(
782     _hSession: CK_SESSION_HANDLE,
783     _pDigest: CK_BYTE_PTR,
784     _pulDigestLen: CK_ULONG_PTR,
785 ) -> CK_RV {
786     log_with_thread_id!(error, "C_DigestFinal: CKR_FUNCTION_NOT_SUPPORTED");
787     CKR_FUNCTION_NOT_SUPPORTED
788 }
789 
790 /// This gets called to set up a sign operation. The module essentially defers to the
791 /// `ManagerProxy`.
C_SignInit( hSession: CK_SESSION_HANDLE, pMechanism: CK_MECHANISM_PTR, hKey: CK_OBJECT_HANDLE, ) -> CK_RV792 extern "C" fn C_SignInit(
793     hSession: CK_SESSION_HANDLE,
794     pMechanism: CK_MECHANISM_PTR,
795     hKey: CK_OBJECT_HANDLE,
796 ) -> CK_RV {
797     if pMechanism.is_null() {
798         log_with_thread_id!(error, "C_SignInit: CKR_ARGUMENTS_BAD");
799         return CKR_ARGUMENTS_BAD;
800     }
801     // Presumably we should validate the mechanism against hKey, but the specification doesn't
802     // actually seem to require this.
803     let mechanism = unsafe { *pMechanism };
804     log_with_thread_id!(debug, "C_SignInit: mechanism is {:?}", mechanism);
805     let mechanism_params = if mechanism.mechanism == CKM_RSA_PKCS_PSS {
806         if mechanism.ulParameterLen as usize != std::mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() {
807             log_with_thread_id!(
808                 error,
809                 "C_SignInit: bad ulParameterLen for CKM_RSA_PKCS_PSS: {}",
810                 unsafe_packed_field_access!(mechanism.ulParameterLen)
811             );
812             return CKR_ARGUMENTS_BAD;
813         }
814         Some(unsafe { *(mechanism.pParameter as *const CK_RSA_PKCS_PSS_PARAMS) })
815     } else {
816         None
817     };
818     let mut manager_guard = try_to_get_manager_guard!();
819     let manager = manager_guard_to_manager!(manager_guard);
820     match manager.start_sign(hSession, hKey, mechanism_params) {
821         Ok(()) => {}
822         Err(()) => {
823             log_with_thread_id!(error, "C_SignInit: CKR_GENERAL_ERROR");
824             return CKR_GENERAL_ERROR;
825         }
826     };
827     log_with_thread_id!(debug, "C_SignInit: CKR_OK");
828     CKR_OK
829 }
830 
831 /// NSS calls this after `C_SignInit` (there are more ways in the PKCS #11 specification to sign
832 /// data, but this is the only way supported by this module). The module essentially defers to the
833 /// `ManagerProxy` and copies out the resulting signature.
C_Sign( hSession: CK_SESSION_HANDLE, pData: CK_BYTE_PTR, ulDataLen: CK_ULONG, pSignature: CK_BYTE_PTR, pulSignatureLen: CK_ULONG_PTR, ) -> CK_RV834 extern "C" fn C_Sign(
835     hSession: CK_SESSION_HANDLE,
836     pData: CK_BYTE_PTR,
837     ulDataLen: CK_ULONG,
838     pSignature: CK_BYTE_PTR,
839     pulSignatureLen: CK_ULONG_PTR,
840 ) -> CK_RV {
841     if pData.is_null() || pulSignatureLen.is_null() {
842         log_with_thread_id!(error, "C_Sign: CKR_ARGUMENTS_BAD");
843         return CKR_ARGUMENTS_BAD;
844     }
845     let data = unsafe { std::slice::from_raw_parts(pData, ulDataLen as usize) };
846     if pSignature.is_null() {
847         let mut manager_guard = try_to_get_manager_guard!();
848         let manager = manager_guard_to_manager!(manager_guard);
849         match manager.get_signature_length(hSession, data.to_vec()) {
850             Ok(signature_length) => unsafe {
851                 *pulSignatureLen = signature_length as CK_ULONG;
852             },
853             Err(()) => {
854                 log_with_thread_id!(error, "C_Sign: get_signature_length failed");
855                 return CKR_GENERAL_ERROR;
856             }
857         }
858     } else {
859         let mut manager_guard = try_to_get_manager_guard!();
860         let manager = manager_guard_to_manager!(manager_guard);
861         match manager.sign(hSession, data.to_vec()) {
862             Ok(signature) => {
863                 let signature_capacity = unsafe { *pulSignatureLen } as usize;
864                 if signature_capacity < signature.len() {
865                     log_with_thread_id!(error, "C_Sign: CKR_ARGUMENTS_BAD");
866                     return CKR_ARGUMENTS_BAD;
867                 }
868                 let ptr: *mut u8 = pSignature as *mut u8;
869                 unsafe {
870                     std::ptr::copy_nonoverlapping(signature.as_ptr(), ptr, signature.len());
871                     *pulSignatureLen = signature.len() as CK_ULONG;
872                 }
873             }
874             Err(()) => {
875                 log_with_thread_id!(error, "C_Sign: sign failed");
876                 return CKR_GENERAL_ERROR;
877             }
878         }
879     }
880     log_with_thread_id!(debug, "C_Sign: CKR_OK");
881     CKR_OK
882 }
883 
C_SignUpdate( _hSession: CK_SESSION_HANDLE, _pPart: CK_BYTE_PTR, _ulPartLen: CK_ULONG, ) -> CK_RV884 extern "C" fn C_SignUpdate(
885     _hSession: CK_SESSION_HANDLE,
886     _pPart: CK_BYTE_PTR,
887     _ulPartLen: CK_ULONG,
888 ) -> CK_RV {
889     log_with_thread_id!(error, "C_SignUpdate: CKR_FUNCTION_NOT_SUPPORTED");
890     CKR_FUNCTION_NOT_SUPPORTED
891 }
892 
C_SignFinal( _hSession: CK_SESSION_HANDLE, _pSignature: CK_BYTE_PTR, _pulSignatureLen: CK_ULONG_PTR, ) -> CK_RV893 extern "C" fn C_SignFinal(
894     _hSession: CK_SESSION_HANDLE,
895     _pSignature: CK_BYTE_PTR,
896     _pulSignatureLen: CK_ULONG_PTR,
897 ) -> CK_RV {
898     log_with_thread_id!(error, "C_SignFinal: CKR_FUNCTION_NOT_SUPPORTED");
899     CKR_FUNCTION_NOT_SUPPORTED
900 }
901 
C_SignRecoverInit( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hKey: CK_OBJECT_HANDLE, ) -> CK_RV902 extern "C" fn C_SignRecoverInit(
903     _hSession: CK_SESSION_HANDLE,
904     _pMechanism: CK_MECHANISM_PTR,
905     _hKey: CK_OBJECT_HANDLE,
906 ) -> CK_RV {
907     log_with_thread_id!(error, "C_SignRecoverInit: CKR_FUNCTION_NOT_SUPPORTED");
908     CKR_FUNCTION_NOT_SUPPORTED
909 }
910 
C_SignRecover( _hSession: CK_SESSION_HANDLE, _pData: CK_BYTE_PTR, _ulDataLen: CK_ULONG, _pSignature: CK_BYTE_PTR, _pulSignatureLen: CK_ULONG_PTR, ) -> CK_RV911 extern "C" fn C_SignRecover(
912     _hSession: CK_SESSION_HANDLE,
913     _pData: CK_BYTE_PTR,
914     _ulDataLen: CK_ULONG,
915     _pSignature: CK_BYTE_PTR,
916     _pulSignatureLen: CK_ULONG_PTR,
917 ) -> CK_RV {
918     log_with_thread_id!(error, "C_SignRecover: CKR_FUNCTION_NOT_SUPPORTED");
919     CKR_FUNCTION_NOT_SUPPORTED
920 }
921 
C_VerifyInit( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hKey: CK_OBJECT_HANDLE, ) -> CK_RV922 extern "C" fn C_VerifyInit(
923     _hSession: CK_SESSION_HANDLE,
924     _pMechanism: CK_MECHANISM_PTR,
925     _hKey: CK_OBJECT_HANDLE,
926 ) -> CK_RV {
927     log_with_thread_id!(error, "C_VerifyInit: CKR_FUNCTION_NOT_SUPPORTED");
928     CKR_FUNCTION_NOT_SUPPORTED
929 }
930 
C_Verify( _hSession: CK_SESSION_HANDLE, _pData: CK_BYTE_PTR, _ulDataLen: CK_ULONG, _pSignature: CK_BYTE_PTR, _ulSignatureLen: CK_ULONG, ) -> CK_RV931 extern "C" fn C_Verify(
932     _hSession: CK_SESSION_HANDLE,
933     _pData: CK_BYTE_PTR,
934     _ulDataLen: CK_ULONG,
935     _pSignature: CK_BYTE_PTR,
936     _ulSignatureLen: CK_ULONG,
937 ) -> CK_RV {
938     log_with_thread_id!(error, "C_Verify: CKR_FUNCTION_NOT_SUPPORTED");
939     CKR_FUNCTION_NOT_SUPPORTED
940 }
941 
C_VerifyUpdate( _hSession: CK_SESSION_HANDLE, _pPart: CK_BYTE_PTR, _ulPartLen: CK_ULONG, ) -> CK_RV942 extern "C" fn C_VerifyUpdate(
943     _hSession: CK_SESSION_HANDLE,
944     _pPart: CK_BYTE_PTR,
945     _ulPartLen: CK_ULONG,
946 ) -> CK_RV {
947     log_with_thread_id!(error, "C_VerifyUpdate: CKR_FUNCTION_NOT_SUPPORTED");
948     CKR_FUNCTION_NOT_SUPPORTED
949 }
950 
C_VerifyFinal( _hSession: CK_SESSION_HANDLE, _pSignature: CK_BYTE_PTR, _ulSignatureLen: CK_ULONG, ) -> CK_RV951 extern "C" fn C_VerifyFinal(
952     _hSession: CK_SESSION_HANDLE,
953     _pSignature: CK_BYTE_PTR,
954     _ulSignatureLen: CK_ULONG,
955 ) -> CK_RV {
956     log_with_thread_id!(error, "C_VerifyFinal: CKR_FUNCTION_NOT_SUPPORTED");
957     CKR_FUNCTION_NOT_SUPPORTED
958 }
959 
C_VerifyRecoverInit( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hKey: CK_OBJECT_HANDLE, ) -> CK_RV960 extern "C" fn C_VerifyRecoverInit(
961     _hSession: CK_SESSION_HANDLE,
962     _pMechanism: CK_MECHANISM_PTR,
963     _hKey: CK_OBJECT_HANDLE,
964 ) -> CK_RV {
965     log_with_thread_id!(error, "C_VerifyRecoverInit: CKR_FUNCTION_NOT_SUPPORTED");
966     CKR_FUNCTION_NOT_SUPPORTED
967 }
968 
C_VerifyRecover( _hSession: CK_SESSION_HANDLE, _pSignature: CK_BYTE_PTR, _ulSignatureLen: CK_ULONG, _pData: CK_BYTE_PTR, _pulDataLen: CK_ULONG_PTR, ) -> CK_RV969 extern "C" fn C_VerifyRecover(
970     _hSession: CK_SESSION_HANDLE,
971     _pSignature: CK_BYTE_PTR,
972     _ulSignatureLen: CK_ULONG,
973     _pData: CK_BYTE_PTR,
974     _pulDataLen: CK_ULONG_PTR,
975 ) -> CK_RV {
976     log_with_thread_id!(error, "C_VerifyRecover: CKR_FUNCTION_NOT_SUPPORTED");
977     CKR_FUNCTION_NOT_SUPPORTED
978 }
979 
C_DigestEncryptUpdate( _hSession: CK_SESSION_HANDLE, _pPart: CK_BYTE_PTR, _ulPartLen: CK_ULONG, _pEncryptedPart: CK_BYTE_PTR, _pulEncryptedPartLen: CK_ULONG_PTR, ) -> CK_RV980 extern "C" fn C_DigestEncryptUpdate(
981     _hSession: CK_SESSION_HANDLE,
982     _pPart: CK_BYTE_PTR,
983     _ulPartLen: CK_ULONG,
984     _pEncryptedPart: CK_BYTE_PTR,
985     _pulEncryptedPartLen: CK_ULONG_PTR,
986 ) -> CK_RV {
987     log_with_thread_id!(error, "C_DigestEncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
988     CKR_FUNCTION_NOT_SUPPORTED
989 }
990 
C_DecryptDigestUpdate( _hSession: CK_SESSION_HANDLE, _pEncryptedPart: CK_BYTE_PTR, _ulEncryptedPartLen: CK_ULONG, _pPart: CK_BYTE_PTR, _pulPartLen: CK_ULONG_PTR, ) -> CK_RV991 extern "C" fn C_DecryptDigestUpdate(
992     _hSession: CK_SESSION_HANDLE,
993     _pEncryptedPart: CK_BYTE_PTR,
994     _ulEncryptedPartLen: CK_ULONG,
995     _pPart: CK_BYTE_PTR,
996     _pulPartLen: CK_ULONG_PTR,
997 ) -> CK_RV {
998     log_with_thread_id!(error, "C_DecryptDigestUpdate: CKR_FUNCTION_NOT_SUPPORTED");
999     CKR_FUNCTION_NOT_SUPPORTED
1000 }
1001 
C_SignEncryptUpdate( _hSession: CK_SESSION_HANDLE, _pPart: CK_BYTE_PTR, _ulPartLen: CK_ULONG, _pEncryptedPart: CK_BYTE_PTR, _pulEncryptedPartLen: CK_ULONG_PTR, ) -> CK_RV1002 extern "C" fn C_SignEncryptUpdate(
1003     _hSession: CK_SESSION_HANDLE,
1004     _pPart: CK_BYTE_PTR,
1005     _ulPartLen: CK_ULONG,
1006     _pEncryptedPart: CK_BYTE_PTR,
1007     _pulEncryptedPartLen: CK_ULONG_PTR,
1008 ) -> CK_RV {
1009     log_with_thread_id!(error, "C_SignEncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
1010     CKR_FUNCTION_NOT_SUPPORTED
1011 }
1012 
C_DecryptVerifyUpdate( _hSession: CK_SESSION_HANDLE, _pEncryptedPart: CK_BYTE_PTR, _ulEncryptedPartLen: CK_ULONG, _pPart: CK_BYTE_PTR, _pulPartLen: CK_ULONG_PTR, ) -> CK_RV1013 extern "C" fn C_DecryptVerifyUpdate(
1014     _hSession: CK_SESSION_HANDLE,
1015     _pEncryptedPart: CK_BYTE_PTR,
1016     _ulEncryptedPartLen: CK_ULONG,
1017     _pPart: CK_BYTE_PTR,
1018     _pulPartLen: CK_ULONG_PTR,
1019 ) -> CK_RV {
1020     log_with_thread_id!(error, "C_DecryptVerifyUpdate: CKR_FUNCTION_NOT_SUPPORTED");
1021     CKR_FUNCTION_NOT_SUPPORTED
1022 }
1023 
C_GenerateKey( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _pTemplate: CK_ATTRIBUTE_PTR, _ulCount: CK_ULONG, _phKey: CK_OBJECT_HANDLE_PTR, ) -> CK_RV1024 extern "C" fn C_GenerateKey(
1025     _hSession: CK_SESSION_HANDLE,
1026     _pMechanism: CK_MECHANISM_PTR,
1027     _pTemplate: CK_ATTRIBUTE_PTR,
1028     _ulCount: CK_ULONG,
1029     _phKey: CK_OBJECT_HANDLE_PTR,
1030 ) -> CK_RV {
1031     log_with_thread_id!(error, "C_GenerateKey: CKR_FUNCTION_NOT_SUPPORTED");
1032     CKR_FUNCTION_NOT_SUPPORTED
1033 }
1034 
C_GenerateKeyPair( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _pPublicKeyTemplate: CK_ATTRIBUTE_PTR, _ulPublicKeyAttributeCount: CK_ULONG, _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR, _ulPrivateKeyAttributeCount: CK_ULONG, _phPublicKey: CK_OBJECT_HANDLE_PTR, _phPrivateKey: CK_OBJECT_HANDLE_PTR, ) -> CK_RV1035 extern "C" fn C_GenerateKeyPair(
1036     _hSession: CK_SESSION_HANDLE,
1037     _pMechanism: CK_MECHANISM_PTR,
1038     _pPublicKeyTemplate: CK_ATTRIBUTE_PTR,
1039     _ulPublicKeyAttributeCount: CK_ULONG,
1040     _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR,
1041     _ulPrivateKeyAttributeCount: CK_ULONG,
1042     _phPublicKey: CK_OBJECT_HANDLE_PTR,
1043     _phPrivateKey: CK_OBJECT_HANDLE_PTR,
1044 ) -> CK_RV {
1045     log_with_thread_id!(error, "C_GenerateKeyPair: CKR_FUNCTION_NOT_SUPPORTED");
1046     CKR_FUNCTION_NOT_SUPPORTED
1047 }
1048 
C_WrapKey( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hWrappingKey: CK_OBJECT_HANDLE, _hKey: CK_OBJECT_HANDLE, _pWrappedKey: CK_BYTE_PTR, _pulWrappedKeyLen: CK_ULONG_PTR, ) -> CK_RV1049 extern "C" fn C_WrapKey(
1050     _hSession: CK_SESSION_HANDLE,
1051     _pMechanism: CK_MECHANISM_PTR,
1052     _hWrappingKey: CK_OBJECT_HANDLE,
1053     _hKey: CK_OBJECT_HANDLE,
1054     _pWrappedKey: CK_BYTE_PTR,
1055     _pulWrappedKeyLen: CK_ULONG_PTR,
1056 ) -> CK_RV {
1057     log_with_thread_id!(error, "C_WrapKey: CKR_FUNCTION_NOT_SUPPORTED");
1058     CKR_FUNCTION_NOT_SUPPORTED
1059 }
1060 
C_UnwrapKey( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hUnwrappingKey: CK_OBJECT_HANDLE, _pWrappedKey: CK_BYTE_PTR, _ulWrappedKeyLen: CK_ULONG, _pTemplate: CK_ATTRIBUTE_PTR, _ulAttributeCount: CK_ULONG, _phKey: CK_OBJECT_HANDLE_PTR, ) -> CK_RV1061 extern "C" fn C_UnwrapKey(
1062     _hSession: CK_SESSION_HANDLE,
1063     _pMechanism: CK_MECHANISM_PTR,
1064     _hUnwrappingKey: CK_OBJECT_HANDLE,
1065     _pWrappedKey: CK_BYTE_PTR,
1066     _ulWrappedKeyLen: CK_ULONG,
1067     _pTemplate: CK_ATTRIBUTE_PTR,
1068     _ulAttributeCount: CK_ULONG,
1069     _phKey: CK_OBJECT_HANDLE_PTR,
1070 ) -> CK_RV {
1071     log_with_thread_id!(error, "C_UnwrapKey: CKR_FUNCTION_NOT_SUPPORTED");
1072     CKR_FUNCTION_NOT_SUPPORTED
1073 }
1074 
C_DeriveKey( _hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR, _hBaseKey: CK_OBJECT_HANDLE, _pTemplate: CK_ATTRIBUTE_PTR, _ulAttributeCount: CK_ULONG, _phKey: CK_OBJECT_HANDLE_PTR, ) -> CK_RV1075 extern "C" fn C_DeriveKey(
1076     _hSession: CK_SESSION_HANDLE,
1077     _pMechanism: CK_MECHANISM_PTR,
1078     _hBaseKey: CK_OBJECT_HANDLE,
1079     _pTemplate: CK_ATTRIBUTE_PTR,
1080     _ulAttributeCount: CK_ULONG,
1081     _phKey: CK_OBJECT_HANDLE_PTR,
1082 ) -> CK_RV {
1083     log_with_thread_id!(error, "C_DeriveKey: CKR_FUNCTION_NOT_SUPPORTED");
1084     CKR_FUNCTION_NOT_SUPPORTED
1085 }
1086 
C_SeedRandom( _hSession: CK_SESSION_HANDLE, _pSeed: CK_BYTE_PTR, _ulSeedLen: CK_ULONG, ) -> CK_RV1087 extern "C" fn C_SeedRandom(
1088     _hSession: CK_SESSION_HANDLE,
1089     _pSeed: CK_BYTE_PTR,
1090     _ulSeedLen: CK_ULONG,
1091 ) -> CK_RV {
1092     log_with_thread_id!(error, "C_SeedRandom: CKR_FUNCTION_NOT_SUPPORTED");
1093     CKR_FUNCTION_NOT_SUPPORTED
1094 }
1095 
C_GenerateRandom( _hSession: CK_SESSION_HANDLE, _RandomData: CK_BYTE_PTR, _ulRandomLen: CK_ULONG, ) -> CK_RV1096 extern "C" fn C_GenerateRandom(
1097     _hSession: CK_SESSION_HANDLE,
1098     _RandomData: CK_BYTE_PTR,
1099     _ulRandomLen: CK_ULONG,
1100 ) -> CK_RV {
1101     log_with_thread_id!(error, "C_GenerateRandom: CKR_FUNCTION_NOT_SUPPORTED");
1102     CKR_FUNCTION_NOT_SUPPORTED
1103 }
1104 
C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV1105 extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV {
1106     log_with_thread_id!(error, "C_GetFunctionStatus: CKR_FUNCTION_NOT_SUPPORTED");
1107     CKR_FUNCTION_NOT_SUPPORTED
1108 }
1109 
C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV1110 extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV {
1111     log_with_thread_id!(error, "C_CancelFunction: CKR_FUNCTION_NOT_SUPPORTED");
1112     CKR_FUNCTION_NOT_SUPPORTED
1113 }
1114 
C_WaitForSlotEvent( _flags: CK_FLAGS, _pSlot: CK_SLOT_ID_PTR, _pRserved: CK_VOID_PTR, ) -> CK_RV1115 extern "C" fn C_WaitForSlotEvent(
1116     _flags: CK_FLAGS,
1117     _pSlot: CK_SLOT_ID_PTR,
1118     _pRserved: CK_VOID_PTR,
1119 ) -> CK_RV {
1120     log_with_thread_id!(error, "C_WaitForSlotEvent: CKR_FUNCTION_NOT_SUPPORTED");
1121     CKR_FUNCTION_NOT_SUPPORTED
1122 }
1123 
1124 /// To be a valid PKCS #11 module, this list of functions must be supported. At least cryptoki 2.2
1125 /// must be supported for this module to work in NSS.
1126 static mut FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
1127     version: CK_VERSION { major: 2, minor: 2 },
1128     C_Initialize: Some(C_Initialize),
1129     C_Finalize: Some(C_Finalize),
1130     C_GetInfo: Some(C_GetInfo),
1131     C_GetFunctionList: None,
1132     C_GetSlotList: Some(C_GetSlotList),
1133     C_GetSlotInfo: Some(C_GetSlotInfo),
1134     C_GetTokenInfo: Some(C_GetTokenInfo),
1135     C_GetMechanismList: Some(C_GetMechanismList),
1136     C_GetMechanismInfo: Some(C_GetMechanismInfo),
1137     C_InitToken: Some(C_InitToken),
1138     C_InitPIN: Some(C_InitPIN),
1139     C_SetPIN: Some(C_SetPIN),
1140     C_OpenSession: Some(C_OpenSession),
1141     C_CloseSession: Some(C_CloseSession),
1142     C_CloseAllSessions: Some(C_CloseAllSessions),
1143     C_GetSessionInfo: Some(C_GetSessionInfo),
1144     C_GetOperationState: Some(C_GetOperationState),
1145     C_SetOperationState: Some(C_SetOperationState),
1146     C_Login: Some(C_Login),
1147     C_Logout: Some(C_Logout),
1148     C_CreateObject: Some(C_CreateObject),
1149     C_CopyObject: Some(C_CopyObject),
1150     C_DestroyObject: Some(C_DestroyObject),
1151     C_GetObjectSize: Some(C_GetObjectSize),
1152     C_GetAttributeValue: Some(C_GetAttributeValue),
1153     C_SetAttributeValue: Some(C_SetAttributeValue),
1154     C_FindObjectsInit: Some(C_FindObjectsInit),
1155     C_FindObjects: Some(C_FindObjects),
1156     C_FindObjectsFinal: Some(C_FindObjectsFinal),
1157     C_EncryptInit: Some(C_EncryptInit),
1158     C_Encrypt: Some(C_Encrypt),
1159     C_EncryptUpdate: Some(C_EncryptUpdate),
1160     C_EncryptFinal: Some(C_EncryptFinal),
1161     C_DecryptInit: Some(C_DecryptInit),
1162     C_Decrypt: Some(C_Decrypt),
1163     C_DecryptUpdate: Some(C_DecryptUpdate),
1164     C_DecryptFinal: Some(C_DecryptFinal),
1165     C_DigestInit: Some(C_DigestInit),
1166     C_Digest: Some(C_Digest),
1167     C_DigestUpdate: Some(C_DigestUpdate),
1168     C_DigestKey: Some(C_DigestKey),
1169     C_DigestFinal: Some(C_DigestFinal),
1170     C_SignInit: Some(C_SignInit),
1171     C_Sign: Some(C_Sign),
1172     C_SignUpdate: Some(C_SignUpdate),
1173     C_SignFinal: Some(C_SignFinal),
1174     C_SignRecoverInit: Some(C_SignRecoverInit),
1175     C_SignRecover: Some(C_SignRecover),
1176     C_VerifyInit: Some(C_VerifyInit),
1177     C_Verify: Some(C_Verify),
1178     C_VerifyUpdate: Some(C_VerifyUpdate),
1179     C_VerifyFinal: Some(C_VerifyFinal),
1180     C_VerifyRecoverInit: Some(C_VerifyRecoverInit),
1181     C_VerifyRecover: Some(C_VerifyRecover),
1182     C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate),
1183     C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate),
1184     C_SignEncryptUpdate: Some(C_SignEncryptUpdate),
1185     C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate),
1186     C_GenerateKey: Some(C_GenerateKey),
1187     C_GenerateKeyPair: Some(C_GenerateKeyPair),
1188     C_WrapKey: Some(C_WrapKey),
1189     C_UnwrapKey: Some(C_UnwrapKey),
1190     C_DeriveKey: Some(C_DeriveKey),
1191     C_SeedRandom: Some(C_SeedRandom),
1192     C_GenerateRandom: Some(C_GenerateRandom),
1193     C_GetFunctionStatus: Some(C_GetFunctionStatus),
1194     C_CancelFunction: Some(C_CancelFunction),
1195     C_WaitForSlotEvent: Some(C_WaitForSlotEvent),
1196 };
1197 
1198 /// This is the only function this module exposes. NSS calls it to obtain the list of functions
1199 /// comprising this module.
1200 #[no_mangle]
C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV1201 pub extern "C" fn C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV {
1202     if ppFunctionList.is_null() {
1203         return CKR_ARGUMENTS_BAD;
1204     }
1205     unsafe {
1206         *ppFunctionList = &mut FUNCTION_LIST;
1207     }
1208     CKR_OK
1209 }
1210 
1211 #[cfg_attr(target_os = "macos", link(name = "Security", kind = "framework"))]
1212 extern "C" {}
1213