Bug 1940967 - Vendor glean_parser v16.2.0 r=TravisLong,mach-reviewers,ahal
[gecko.git] / security / manager / ssl / ipcclientcerts / src / lib.rs
blob6317956ae57fd5c2048b68bda86905b7a809aa53
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 extern crate pkcs11_bindings;
10 #[macro_use]
11 extern crate rsclientcerts;
12 extern crate sha2;
14 use pkcs11_bindings::*;
15 use rsclientcerts::manager::{Manager, SlotType};
16 use std::ffi::{c_void, CStr};
17 use std::sync::Mutex;
19 mod backend;
21 use backend::Backend;
23 type FindObjectsCallback = Option<
24     unsafe extern "C" fn(
25         typ: u8,
26         data_len: usize,
27         data: *const u8,
28         extra_len: usize,
29         extra: *const u8,
30         slot_type: u32,
31         ctx: *mut c_void,
32     ),
35 type FindObjectsFunction = extern "C" fn(callback: FindObjectsCallback, ctx: *mut c_void);
37 type SignCallback =
38     Option<unsafe extern "C" fn(data_len: usize, data: *const u8, ctx: *mut c_void)>;
40 type SignFunction = extern "C" fn(
41     cert_len: usize,
42     cert: *const u8,
43     data_len: usize,
44     data: *const u8,
45     params_len: usize,
46     params: *const u8,
47     callback: SignCallback,
48     ctx: *mut c_void,
51 /// The singleton `Manager` that handles state with respect to PKCS #11. Only one thread
52 /// may use it at a time, but there is no restriction on which threads may use it.
53 static MANAGER: Mutex<Option<Manager<Backend>>> = Mutex::new(None);
55 // Obtaining a handle on the manager is a two-step process. First the mutex must be locked, which
56 // (if successful), results in a mutex guard object. We must then get a mutable refence to the
57 // underlying manager (if set - otherwise we return an error). This can't happen all in one macro
58 // without dropping a reference that needs to live long enough for this to be safe. In
59 // practice, this looks like:
60 //   let mut manager_guard = try_to_get_manager_guard!();
61 //   let manager = manager_guard_to_manager!(manager_guard);
62 macro_rules! try_to_get_manager_guard {
63     () => {
64         match MANAGER.lock() {
65             Ok(maybe_manager) => maybe_manager,
66             Err(_) => return CKR_DEVICE_ERROR,
67         }
68     };
71 macro_rules! manager_guard_to_manager {
72     ($manager_guard:ident) => {
73         match $manager_guard.as_mut() {
74             Some(manager) => manager,
75             None => return CKR_DEVICE_ERROR,
76         }
77     };
80 /// This gets called to initialize the module. For this implementation, this consists of
81 /// instantiating the `Manager`.
82 extern "C" fn C_Initialize(pInitArgs: CK_VOID_PTR) -> CK_RV {
83     // pInitArgs.pReserved will be a c-string containing the base-16
84     // stringification of the addresses of the functions to call to communicate
85     // with the main process.
86     if pInitArgs.is_null() {
87         return CKR_DEVICE_ERROR;
88     }
89     let serialized_addresses_ptr = unsafe { (*(pInitArgs as CK_C_INITIALIZE_ARGS_PTR)).pReserved };
90     if serialized_addresses_ptr.is_null() {
91         return CKR_DEVICE_ERROR;
92     }
93     let serialized_addresses_cstr =
94         unsafe { CStr::from_ptr(serialized_addresses_ptr as *mut std::os::raw::c_char) };
95     let serialized_addresses = match serialized_addresses_cstr.to_str() {
96         Ok(serialized_addresses) => serialized_addresses,
97         Err(_) => return CKR_DEVICE_ERROR,
98     };
99     let function_addresses: Vec<usize> = serialized_addresses
100         .split(',')
101         .filter_map(|serialized_address| usize::from_str_radix(serialized_address, 16).ok())
102         .collect();
103     if function_addresses.len() != 2 {
104         return CKR_DEVICE_ERROR;
105     }
106     let find_objects: FindObjectsFunction = unsafe { std::mem::transmute(function_addresses[0]) };
107     let sign: SignFunction = unsafe { std::mem::transmute(function_addresses[1]) };
108     let mut manager_guard = try_to_get_manager_guard!();
109     let _unexpected_previous_manager =
110         manager_guard.replace(Manager::new(Backend::new(find_objects, sign)));
111     CKR_OK
114 extern "C" fn C_Finalize(_pReserved: CK_VOID_PTR) -> CK_RV {
115     // Drop the manager. When C_Finalize is called, there should be only one
116     // reference to this module (which is going away), so there shouldn't be
117     // any concurrency issues.
118     let mut manager_guard = try_to_get_manager_guard!();
119     match manager_guard.take() {
120         Some(_) => CKR_OK,
121         None => CKR_CRYPTOKI_NOT_INITIALIZED,
122     }
125 // The specification mandates that these strings be padded with spaces to the appropriate length.
126 // Since the length of fixed-size arrays in rust is part of the type, the compiler enforces that
127 // these byte strings are of the correct length.
128 const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Corporation             ";
129 const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"IPC Client Cert Module          ";
131 /// This gets called to gather some information about the module. In particular, this implementation
132 /// supports (portions of) cryptoki (PKCS #11) version 2.2.
133 extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV {
134     if pInfo.is_null() {
135         return CKR_ARGUMENTS_BAD;
136     }
137     let mut info = CK_INFO::default();
138     info.cryptokiVersion.major = 2;
139     info.cryptokiVersion.minor = 2;
140     info.manufacturerID = *MANUFACTURER_ID_BYTES;
141     info.libraryDescription = *LIBRARY_DESCRIPTION_BYTES;
142     unsafe {
143         *pInfo = info;
144     }
145     CKR_OK
148 /// This module has two slots.
149 const SLOT_COUNT: CK_ULONG = 2;
150 /// The slot with ID 1 supports modern mechanisms like RSA-PSS.
151 const SLOT_ID_MODERN: CK_SLOT_ID = 1;
152 /// The slot with ID 2 only supports legacy mechanisms.
153 const SLOT_ID_LEGACY: CK_SLOT_ID = 2;
155 /// This gets called twice: once with a null `pSlotList` to get the number of slots (returned via
156 /// `pulCount`) and a second time to get the ID for each slot.
157 extern "C" fn C_GetSlotList(
158     _tokenPresent: CK_BBOOL,
159     pSlotList: CK_SLOT_ID_PTR,
160     pulCount: CK_ULONG_PTR,
161 ) -> CK_RV {
162     if pulCount.is_null() {
163         return CKR_ARGUMENTS_BAD;
164     }
165     if !pSlotList.is_null() {
166         if unsafe { *pulCount } < SLOT_COUNT {
167             return CKR_BUFFER_TOO_SMALL;
168         }
169         unsafe {
170             *pSlotList = SLOT_ID_MODERN;
171             *pSlotList.offset(1) = SLOT_ID_LEGACY;
172         }
173     };
174     unsafe {
175         *pulCount = SLOT_COUNT;
176     }
177     CKR_OK
180 const SLOT_DESCRIPTION_MODERN_BYTES: &[u8; 64] =
181     b"IPC Client Cert Slot (Modern)                                   ";
182 const SLOT_DESCRIPTION_LEGACY_BYTES: &[u8; 64] =
183     b"IPC Client Cert Slot (Legacy)                                   ";
185 /// This gets called to obtain information about slots. In this implementation, the tokens are
186 /// always present in the slots.
187 extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV {
188     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() {
189         return CKR_ARGUMENTS_BAD;
190     }
191     let description = if slotID == SLOT_ID_MODERN {
192         SLOT_DESCRIPTION_MODERN_BYTES
193     } else {
194         SLOT_DESCRIPTION_LEGACY_BYTES
195     };
196     let slot_info = CK_SLOT_INFO {
197         slotDescription: *description,
198         manufacturerID: *MANUFACTURER_ID_BYTES,
199         flags: CKF_TOKEN_PRESENT,
200         hardwareVersion: CK_VERSION::default(),
201         firmwareVersion: CK_VERSION::default(),
202     };
203     unsafe {
204         *pInfo = slot_info;
205     }
206     CKR_OK
209 const TOKEN_LABEL_MODERN_BYTES: &[u8; 32] = b"IPC Client Cert Token (Modern)  ";
210 const TOKEN_LABEL_LEGACY_BYTES: &[u8; 32] = b"IPC Client Cert Token (Legacy)  ";
211 const TOKEN_MODEL_BYTES: &[u8; 16] = b"ipcclientcerts  ";
212 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
214 /// This gets called to obtain some information about tokens. This implementation has two slots,
215 /// so it has two tokens. This information is primarily for display purposes.
216 extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV {
217     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() {
218         return CKR_ARGUMENTS_BAD;
219     }
220     let mut token_info = CK_TOKEN_INFO::default();
221     let label = if slotID == SLOT_ID_MODERN {
222         TOKEN_LABEL_MODERN_BYTES
223     } else {
224         TOKEN_LABEL_LEGACY_BYTES
225     };
226     token_info.label = *label;
227     token_info.manufacturerID = *MANUFACTURER_ID_BYTES;
228     token_info.model = *TOKEN_MODEL_BYTES;
229     token_info.serialNumber = *TOKEN_SERIAL_NUMBER_BYTES;
230     unsafe {
231         *pInfo = token_info;
232     }
233     CKR_OK
236 /// This gets called to determine what mechanisms a slot supports. The modern slot supports ECDSA,
237 /// RSA PKCS, and RSA PSS. The legacy slot only supports RSA PKCS.
238 extern "C" fn C_GetMechanismList(
239     slotID: CK_SLOT_ID,
240     pMechanismList: CK_MECHANISM_TYPE_PTR,
241     pulCount: CK_ULONG_PTR,
242 ) -> CK_RV {
243     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pulCount.is_null() {
244         return CKR_ARGUMENTS_BAD;
245     }
246     let mechanisms = if slotID == SLOT_ID_MODERN {
247         vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
248     } else {
249         vec![CKM_RSA_PKCS]
250     };
251     if !pMechanismList.is_null() {
252         if unsafe { *pulCount as usize } < mechanisms.len() {
253             return CKR_ARGUMENTS_BAD;
254         }
255         for i in 0..mechanisms.len() {
256             unsafe {
257                 *pMechanismList.offset(i as isize) = mechanisms[i];
258             }
259         }
260     }
261     unsafe {
262         *pulCount = mechanisms.len() as CK_ULONG;
263     }
264     CKR_OK
267 extern "C" fn C_GetMechanismInfo(
268     _slotID: CK_SLOT_ID,
269     _type: CK_MECHANISM_TYPE,
270     _pInfo: CK_MECHANISM_INFO_PTR,
271 ) -> CK_RV {
272     CKR_FUNCTION_NOT_SUPPORTED
275 extern "C" fn C_InitToken(
276     _slotID: CK_SLOT_ID,
277     _pPin: CK_UTF8CHAR_PTR,
278     _ulPinLen: CK_ULONG,
279     _pLabel: CK_UTF8CHAR_PTR,
280 ) -> CK_RV {
281     CKR_FUNCTION_NOT_SUPPORTED
284 extern "C" fn C_InitPIN(
285     _hSession: CK_SESSION_HANDLE,
286     _pPin: CK_UTF8CHAR_PTR,
287     _ulPinLen: CK_ULONG,
288 ) -> CK_RV {
289     CKR_FUNCTION_NOT_SUPPORTED
292 extern "C" fn C_SetPIN(
293     _hSession: CK_SESSION_HANDLE,
294     _pOldPin: CK_UTF8CHAR_PTR,
295     _ulOldLen: CK_ULONG,
296     _pNewPin: CK_UTF8CHAR_PTR,
297     _ulNewLen: CK_ULONG,
298 ) -> CK_RV {
299     CKR_FUNCTION_NOT_SUPPORTED
302 /// This gets called to create a new session. This module defers to the `ManagerProxy` to implement
303 /// this.
304 extern "C" fn C_OpenSession(
305     slotID: CK_SLOT_ID,
306     _flags: CK_FLAGS,
307     _pApplication: CK_VOID_PTR,
308     _Notify: CK_NOTIFY,
309     phSession: CK_SESSION_HANDLE_PTR,
310 ) -> CK_RV {
311     if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || phSession.is_null() {
312         return CKR_ARGUMENTS_BAD;
313     }
314     let mut manager_guard = try_to_get_manager_guard!();
315     let manager = manager_guard_to_manager!(manager_guard);
316     let slot_type = if slotID == SLOT_ID_MODERN {
317         SlotType::Modern
318     } else {
319         SlotType::Legacy
320     };
321     let session_handle = match manager.open_session(slot_type) {
322         Ok(session_handle) => session_handle,
323         Err(_) => return CKR_DEVICE_ERROR,
324     };
325     unsafe {
326         *phSession = session_handle;
327     }
328     CKR_OK
331 /// This gets called to close a session. This is handled by the `ManagerProxy`.
332 extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV {
333     let mut manager_guard = try_to_get_manager_guard!();
334     let manager = manager_guard_to_manager!(manager_guard);
335     if manager.close_session(hSession).is_err() {
336         return CKR_SESSION_HANDLE_INVALID;
337     }
338     CKR_OK
341 /// This gets called to close all open sessions at once. This is handled by the `ManagerProxy`.
342 extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV {
343     if slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY {
344         return CKR_ARGUMENTS_BAD;
345     }
346     let mut manager_guard = try_to_get_manager_guard!();
347     let manager = manager_guard_to_manager!(manager_guard);
348     let slot_type = if slotID == SLOT_ID_MODERN {
349         SlotType::Modern
350     } else {
351         SlotType::Legacy
352     };
353     match manager.close_all_sessions(slot_type) {
354         Ok(()) => CKR_OK,
355         Err(_) => CKR_DEVICE_ERROR,
356     }
359 extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV {
360     CKR_FUNCTION_NOT_SUPPORTED
363 extern "C" fn C_GetOperationState(
364     _hSession: CK_SESSION_HANDLE,
365     _pOperationState: CK_BYTE_PTR,
366     _pulOperationStateLen: CK_ULONG_PTR,
367 ) -> CK_RV {
368     CKR_FUNCTION_NOT_SUPPORTED
371 extern "C" fn C_SetOperationState(
372     _hSession: CK_SESSION_HANDLE,
373     _pOperationState: CK_BYTE_PTR,
374     _ulOperationStateLen: CK_ULONG,
375     _hEncryptionKey: CK_OBJECT_HANDLE,
376     _hAuthenticationKey: CK_OBJECT_HANDLE,
377 ) -> CK_RV {
378     CKR_FUNCTION_NOT_SUPPORTED
381 extern "C" fn C_Login(
382     _hSession: CK_SESSION_HANDLE,
383     _userType: CK_USER_TYPE,
384     _pPin: CK_UTF8CHAR_PTR,
385     _ulPinLen: CK_ULONG,
386 ) -> CK_RV {
387     CKR_FUNCTION_NOT_SUPPORTED
390 /// This gets called to log out and drop any authenticated resources. Because this module does not
391 /// hold on to authenticated resources, this module "implements" this by doing nothing and
392 /// returning a success result.
393 extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV {
394     CKR_OK
397 extern "C" fn C_CreateObject(
398     _hSession: CK_SESSION_HANDLE,
399     _pTemplate: CK_ATTRIBUTE_PTR,
400     _ulCount: CK_ULONG,
401     _phObject: CK_OBJECT_HANDLE_PTR,
402 ) -> CK_RV {
403     CKR_FUNCTION_NOT_SUPPORTED
406 extern "C" fn C_CopyObject(
407     _hSession: CK_SESSION_HANDLE,
408     _hObject: CK_OBJECT_HANDLE,
409     _pTemplate: CK_ATTRIBUTE_PTR,
410     _ulCount: CK_ULONG,
411     _phNewObject: CK_OBJECT_HANDLE_PTR,
412 ) -> CK_RV {
413     CKR_FUNCTION_NOT_SUPPORTED
416 extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV {
417     CKR_FUNCTION_NOT_SUPPORTED
420 extern "C" fn C_GetObjectSize(
421     _hSession: CK_SESSION_HANDLE,
422     _hObject: CK_OBJECT_HANDLE,
423     _pulSize: CK_ULONG_PTR,
424 ) -> CK_RV {
425     CKR_FUNCTION_NOT_SUPPORTED
428 /// This gets called to obtain the values of a number of attributes of an object identified by the
429 /// given handle. This module implements this by requesting that the `ManagerProxy` find the object
430 /// and attempt to get the value of each attribute. If a specified attribute is not defined on the
431 /// object, the length of that attribute is set to -1 to indicate that it is not available.
432 /// This gets called twice: once to obtain the lengths of the attributes and again to get the
433 /// values.
434 extern "C" fn C_GetAttributeValue(
435     _hSession: CK_SESSION_HANDLE,
436     hObject: CK_OBJECT_HANDLE,
437     pTemplate: CK_ATTRIBUTE_PTR,
438     ulCount: CK_ULONG,
439 ) -> CK_RV {
440     if pTemplate.is_null() {
441         return CKR_ARGUMENTS_BAD;
442     }
443     let mut attr_types = Vec::with_capacity(ulCount as usize);
444     for i in 0..ulCount {
445         let attr = unsafe { &*pTemplate.offset(i as isize) };
446         attr_types.push(attr.type_);
447     }
448     let mut manager_guard = try_to_get_manager_guard!();
449     let manager = manager_guard_to_manager!(manager_guard);
450     let values = match manager.get_attributes(hObject, attr_types) {
451         Ok(values) => values,
452         Err(_) => return CKR_ARGUMENTS_BAD,
453     };
454     if values.len() != ulCount as usize {
455         return CKR_DEVICE_ERROR;
456     }
457     for i in 0..ulCount as usize {
458         let attr = unsafe { &mut *pTemplate.offset(i as isize) };
459         // NB: the safety of this array access depends on the length check above
460         if let Some(attr_value) = &values[i] {
461             if attr.pValue.is_null() {
462                 attr.ulValueLen = attr_value.len() as CK_ULONG;
463             } else {
464                 let ptr: *mut u8 = attr.pValue as *mut u8;
465                 if attr_value.len() != attr.ulValueLen as usize {
466                     return CKR_ARGUMENTS_BAD;
467                 }
468                 unsafe {
469                     std::ptr::copy_nonoverlapping(attr_value.as_ptr(), ptr, attr_value.len());
470                 }
471             }
472         } else {
473             attr.ulValueLen = (0 - 1) as CK_ULONG;
474         }
475     }
476     CKR_OK
479 extern "C" fn C_SetAttributeValue(
480     _hSession: CK_SESSION_HANDLE,
481     _hObject: CK_OBJECT_HANDLE,
482     _pTemplate: CK_ATTRIBUTE_PTR,
483     _ulCount: CK_ULONG,
484 ) -> CK_RV {
485     CKR_FUNCTION_NOT_SUPPORTED
488 const RELEVANT_ATTRIBUTES: &[CK_ATTRIBUTE_TYPE] = &[
489     CKA_CLASS,
490     CKA_EC_PARAMS,
491     CKA_ID,
492     CKA_ISSUER,
493     CKA_KEY_TYPE,
494     CKA_LABEL,
495     CKA_MODULUS,
496     CKA_PRIVATE,
497     CKA_SERIAL_NUMBER,
498     CKA_SUBJECT,
499     CKA_TOKEN,
500     CKA_VALUE,
503 /// This gets called to initialize a search for objects matching a given list of attributes. This
504 /// module implements this by gathering the attributes and passing them to the `ManagerProxy` to
505 /// start the search.
506 extern "C" fn C_FindObjectsInit(
507     hSession: CK_SESSION_HANDLE,
508     pTemplate: CK_ATTRIBUTE_PTR,
509     ulCount: CK_ULONG,
510 ) -> CK_RV {
511     if pTemplate.is_null() {
512         return CKR_ARGUMENTS_BAD;
513     }
514     let mut attrs = Vec::new();
515     for i in 0..ulCount {
516         let attr = unsafe { &*pTemplate.offset(i as isize) };
517         // Copy out the attribute type to avoid making a reference to an unaligned field.
518         let attr_type = attr.type_;
519         if !RELEVANT_ATTRIBUTES.contains(&attr_type) {
520             return CKR_ATTRIBUTE_TYPE_INVALID;
521         }
522         let slice = unsafe {
523             std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize)
524         };
525         attrs.push((attr_type, slice.to_owned()));
526     }
527     let mut manager_guard = try_to_get_manager_guard!();
528     let manager = manager_guard_to_manager!(manager_guard);
529     match manager.start_search(hSession, attrs) {
530         Ok(()) => {}
531         Err(_) => return CKR_ARGUMENTS_BAD,
532     }
533     CKR_OK
536 /// This gets called after `C_FindObjectsInit` to get the results of a search. This module
537 /// implements this by looking up the search in the `ManagerProxy` and copying out the matching
538 /// object handles.
539 extern "C" fn C_FindObjects(
540     hSession: CK_SESSION_HANDLE,
541     phObject: CK_OBJECT_HANDLE_PTR,
542     ulMaxObjectCount: CK_ULONG,
543     pulObjectCount: CK_ULONG_PTR,
544 ) -> CK_RV {
545     if phObject.is_null() || pulObjectCount.is_null() || ulMaxObjectCount == 0 {
546         return CKR_ARGUMENTS_BAD;
547     }
548     let mut manager_guard = try_to_get_manager_guard!();
549     let manager = manager_guard_to_manager!(manager_guard);
550     let handles = match manager.search(hSession, ulMaxObjectCount as usize) {
551         Ok(handles) => handles,
552         Err(_) => return CKR_ARGUMENTS_BAD,
553     };
554     if handles.len() > ulMaxObjectCount as usize {
555         return CKR_DEVICE_ERROR;
556     }
557     unsafe {
558         *pulObjectCount = handles.len() as CK_ULONG;
559     }
560     for (index, handle) in handles.iter().enumerate() {
561         if index < ulMaxObjectCount as usize {
562             unsafe {
563                 *(phObject.add(index)) = *handle;
564             }
565         }
566     }
567     CKR_OK
570 /// This gets called after `C_FindObjectsInit` and `C_FindObjects` to finish a search. The module
571 /// tells the `ManagerProxy` to clear the search.
572 extern "C" fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV {
573     let mut manager_guard = try_to_get_manager_guard!();
574     let manager = manager_guard_to_manager!(manager_guard);
575     // It would be an error if there were no search for this session, but we can be permissive here.
576     match manager.clear_search(hSession) {
577         Ok(()) => CKR_OK,
578         Err(_) => CKR_DEVICE_ERROR,
579     }
582 extern "C" fn C_EncryptInit(
583     _hSession: CK_SESSION_HANDLE,
584     _pMechanism: CK_MECHANISM_PTR,
585     _hKey: CK_OBJECT_HANDLE,
586 ) -> CK_RV {
587     CKR_FUNCTION_NOT_SUPPORTED
590 extern "C" fn C_Encrypt(
591     _hSession: CK_SESSION_HANDLE,
592     _pData: CK_BYTE_PTR,
593     _ulDataLen: CK_ULONG,
594     _pEncryptedData: CK_BYTE_PTR,
595     _pulEncryptedDataLen: CK_ULONG_PTR,
596 ) -> CK_RV {
597     CKR_FUNCTION_NOT_SUPPORTED
600 extern "C" fn C_EncryptUpdate(
601     _hSession: CK_SESSION_HANDLE,
602     _pPart: CK_BYTE_PTR,
603     _ulPartLen: CK_ULONG,
604     _pEncryptedPart: CK_BYTE_PTR,
605     _pulEncryptedPartLen: CK_ULONG_PTR,
606 ) -> CK_RV {
607     CKR_FUNCTION_NOT_SUPPORTED
610 extern "C" fn C_EncryptFinal(
611     _hSession: CK_SESSION_HANDLE,
612     _pLastEncryptedPart: CK_BYTE_PTR,
613     _pulLastEncryptedPartLen: CK_ULONG_PTR,
614 ) -> CK_RV {
615     CKR_FUNCTION_NOT_SUPPORTED
618 extern "C" fn C_DecryptInit(
619     _hSession: CK_SESSION_HANDLE,
620     _pMechanism: CK_MECHANISM_PTR,
621     _hKey: CK_OBJECT_HANDLE,
622 ) -> CK_RV {
623     CKR_FUNCTION_NOT_SUPPORTED
626 extern "C" fn C_Decrypt(
627     _hSession: CK_SESSION_HANDLE,
628     _pEncryptedData: CK_BYTE_PTR,
629     _ulEncryptedDataLen: CK_ULONG,
630     _pData: CK_BYTE_PTR,
631     _pulDataLen: CK_ULONG_PTR,
632 ) -> CK_RV {
633     CKR_FUNCTION_NOT_SUPPORTED
636 extern "C" fn C_DecryptUpdate(
637     _hSession: CK_SESSION_HANDLE,
638     _pEncryptedPart: CK_BYTE_PTR,
639     _ulEncryptedPartLen: CK_ULONG,
640     _pPart: CK_BYTE_PTR,
641     _pulPartLen: CK_ULONG_PTR,
642 ) -> CK_RV {
643     CKR_FUNCTION_NOT_SUPPORTED
646 extern "C" fn C_DecryptFinal(
647     _hSession: CK_SESSION_HANDLE,
648     _pLastPart: CK_BYTE_PTR,
649     _pulLastPartLen: CK_ULONG_PTR,
650 ) -> CK_RV {
651     CKR_FUNCTION_NOT_SUPPORTED
654 extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV {
655     CKR_FUNCTION_NOT_SUPPORTED
658 extern "C" fn C_Digest(
659     _hSession: CK_SESSION_HANDLE,
660     _pData: CK_BYTE_PTR,
661     _ulDataLen: CK_ULONG,
662     _pDigest: CK_BYTE_PTR,
663     _pulDigestLen: CK_ULONG_PTR,
664 ) -> CK_RV {
665     CKR_FUNCTION_NOT_SUPPORTED
668 extern "C" fn C_DigestUpdate(
669     _hSession: CK_SESSION_HANDLE,
670     _pPart: CK_BYTE_PTR,
671     _ulPartLen: CK_ULONG,
672 ) -> CK_RV {
673     CKR_FUNCTION_NOT_SUPPORTED
676 extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV {
677     CKR_FUNCTION_NOT_SUPPORTED
680 extern "C" fn C_DigestFinal(
681     _hSession: CK_SESSION_HANDLE,
682     _pDigest: CK_BYTE_PTR,
683     _pulDigestLen: CK_ULONG_PTR,
684 ) -> CK_RV {
685     CKR_FUNCTION_NOT_SUPPORTED
688 /// This gets called to set up a sign operation. The module essentially defers to the
689 /// `ManagerProxy`.
690 extern "C" fn C_SignInit(
691     hSession: CK_SESSION_HANDLE,
692     pMechanism: CK_MECHANISM_PTR,
693     hKey: CK_OBJECT_HANDLE,
694 ) -> CK_RV {
695     if pMechanism.is_null() {
696         return CKR_ARGUMENTS_BAD;
697     }
698     // Presumably we should validate the mechanism against hKey, but the specification doesn't
699     // actually seem to require this.
700     let mechanism = unsafe { *pMechanism };
701     let mechanism_params = if mechanism.mechanism == CKM_RSA_PKCS_PSS {
702         if mechanism.ulParameterLen as usize != std::mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>() {
703             return CKR_ARGUMENTS_BAD;
704         }
705         Some(unsafe { *(mechanism.pParameter as *const CK_RSA_PKCS_PSS_PARAMS) })
706     } else {
707         None
708     };
709     let mut manager_guard = try_to_get_manager_guard!();
710     let manager = manager_guard_to_manager!(manager_guard);
711     match manager.start_sign(hSession, hKey, mechanism_params) {
712         Ok(()) => {}
713         Err(_) => return CKR_GENERAL_ERROR,
714     };
715     CKR_OK
718 /// NSS calls this after `C_SignInit` (there are more ways in the PKCS #11 specification to sign
719 /// data, but this is the only way supported by this module). The module essentially defers to the
720 /// `ManagerProxy` and copies out the resulting signature.
721 extern "C" fn C_Sign(
722     hSession: CK_SESSION_HANDLE,
723     pData: CK_BYTE_PTR,
724     ulDataLen: CK_ULONG,
725     pSignature: CK_BYTE_PTR,
726     pulSignatureLen: CK_ULONG_PTR,
727 ) -> CK_RV {
728     if pData.is_null() || pulSignatureLen.is_null() {
729         return CKR_ARGUMENTS_BAD;
730     }
731     let data = unsafe { std::slice::from_raw_parts(pData, ulDataLen as usize) };
732     if pSignature.is_null() {
733         let mut manager_guard = try_to_get_manager_guard!();
734         let manager = manager_guard_to_manager!(manager_guard);
735         match manager.get_signature_length(hSession, data.to_vec()) {
736             Ok(signature_length) => unsafe {
737                 *pulSignatureLen = signature_length as CK_ULONG;
738             },
739             Err(_) => return CKR_GENERAL_ERROR,
740         }
741     } else {
742         let mut manager_guard = try_to_get_manager_guard!();
743         let manager = manager_guard_to_manager!(manager_guard);
744         match manager.sign(hSession, data.to_vec()) {
745             Ok(signature) => {
746                 let signature_capacity = unsafe { *pulSignatureLen } as usize;
747                 if signature_capacity < signature.len() {
748                     return CKR_ARGUMENTS_BAD;
749                 }
750                 let ptr: *mut u8 = pSignature as *mut u8;
751                 unsafe {
752                     std::ptr::copy_nonoverlapping(signature.as_ptr(), ptr, signature.len());
753                     *pulSignatureLen = signature.len() as CK_ULONG;
754                 }
755             }
756             Err(_) => return CKR_GENERAL_ERROR,
757         }
758     }
759     CKR_OK
762 extern "C" fn C_SignUpdate(
763     _hSession: CK_SESSION_HANDLE,
764     _pPart: CK_BYTE_PTR,
765     _ulPartLen: CK_ULONG,
766 ) -> CK_RV {
767     CKR_FUNCTION_NOT_SUPPORTED
770 extern "C" fn C_SignFinal(
771     _hSession: CK_SESSION_HANDLE,
772     _pSignature: CK_BYTE_PTR,
773     _pulSignatureLen: CK_ULONG_PTR,
774 ) -> CK_RV {
775     CKR_FUNCTION_NOT_SUPPORTED
778 extern "C" fn C_SignRecoverInit(
779     _hSession: CK_SESSION_HANDLE,
780     _pMechanism: CK_MECHANISM_PTR,
781     _hKey: CK_OBJECT_HANDLE,
782 ) -> CK_RV {
783     CKR_FUNCTION_NOT_SUPPORTED
786 extern "C" fn C_SignRecover(
787     _hSession: CK_SESSION_HANDLE,
788     _pData: CK_BYTE_PTR,
789     _ulDataLen: CK_ULONG,
790     _pSignature: CK_BYTE_PTR,
791     _pulSignatureLen: CK_ULONG_PTR,
792 ) -> CK_RV {
793     CKR_FUNCTION_NOT_SUPPORTED
796 extern "C" fn C_VerifyInit(
797     _hSession: CK_SESSION_HANDLE,
798     _pMechanism: CK_MECHANISM_PTR,
799     _hKey: CK_OBJECT_HANDLE,
800 ) -> CK_RV {
801     CKR_FUNCTION_NOT_SUPPORTED
804 extern "C" fn C_Verify(
805     _hSession: CK_SESSION_HANDLE,
806     _pData: CK_BYTE_PTR,
807     _ulDataLen: CK_ULONG,
808     _pSignature: CK_BYTE_PTR,
809     _ulSignatureLen: CK_ULONG,
810 ) -> CK_RV {
811     CKR_FUNCTION_NOT_SUPPORTED
814 extern "C" fn C_VerifyUpdate(
815     _hSession: CK_SESSION_HANDLE,
816     _pPart: CK_BYTE_PTR,
817     _ulPartLen: CK_ULONG,
818 ) -> CK_RV {
819     CKR_FUNCTION_NOT_SUPPORTED
822 extern "C" fn C_VerifyFinal(
823     _hSession: CK_SESSION_HANDLE,
824     _pSignature: CK_BYTE_PTR,
825     _ulSignatureLen: CK_ULONG,
826 ) -> CK_RV {
827     CKR_FUNCTION_NOT_SUPPORTED
830 extern "C" fn C_VerifyRecoverInit(
831     _hSession: CK_SESSION_HANDLE,
832     _pMechanism: CK_MECHANISM_PTR,
833     _hKey: CK_OBJECT_HANDLE,
834 ) -> CK_RV {
835     CKR_FUNCTION_NOT_SUPPORTED
838 extern "C" fn C_VerifyRecover(
839     _hSession: CK_SESSION_HANDLE,
840     _pSignature: CK_BYTE_PTR,
841     _ulSignatureLen: CK_ULONG,
842     _pData: CK_BYTE_PTR,
843     _pulDataLen: CK_ULONG_PTR,
844 ) -> CK_RV {
845     CKR_FUNCTION_NOT_SUPPORTED
848 extern "C" fn C_DigestEncryptUpdate(
849     _hSession: CK_SESSION_HANDLE,
850     _pPart: CK_BYTE_PTR,
851     _ulPartLen: CK_ULONG,
852     _pEncryptedPart: CK_BYTE_PTR,
853     _pulEncryptedPartLen: CK_ULONG_PTR,
854 ) -> CK_RV {
855     CKR_FUNCTION_NOT_SUPPORTED
858 extern "C" fn C_DecryptDigestUpdate(
859     _hSession: CK_SESSION_HANDLE,
860     _pEncryptedPart: CK_BYTE_PTR,
861     _ulEncryptedPartLen: CK_ULONG,
862     _pPart: CK_BYTE_PTR,
863     _pulPartLen: CK_ULONG_PTR,
864 ) -> CK_RV {
865     CKR_FUNCTION_NOT_SUPPORTED
868 extern "C" fn C_SignEncryptUpdate(
869     _hSession: CK_SESSION_HANDLE,
870     _pPart: CK_BYTE_PTR,
871     _ulPartLen: CK_ULONG,
872     _pEncryptedPart: CK_BYTE_PTR,
873     _pulEncryptedPartLen: CK_ULONG_PTR,
874 ) -> CK_RV {
875     CKR_FUNCTION_NOT_SUPPORTED
878 extern "C" fn C_DecryptVerifyUpdate(
879     _hSession: CK_SESSION_HANDLE,
880     _pEncryptedPart: CK_BYTE_PTR,
881     _ulEncryptedPartLen: CK_ULONG,
882     _pPart: CK_BYTE_PTR,
883     _pulPartLen: CK_ULONG_PTR,
884 ) -> CK_RV {
885     CKR_FUNCTION_NOT_SUPPORTED
888 extern "C" fn C_GenerateKey(
889     _hSession: CK_SESSION_HANDLE,
890     _pMechanism: CK_MECHANISM_PTR,
891     _pTemplate: CK_ATTRIBUTE_PTR,
892     _ulCount: CK_ULONG,
893     _phKey: CK_OBJECT_HANDLE_PTR,
894 ) -> CK_RV {
895     CKR_FUNCTION_NOT_SUPPORTED
898 extern "C" fn C_GenerateKeyPair(
899     _hSession: CK_SESSION_HANDLE,
900     _pMechanism: CK_MECHANISM_PTR,
901     _pPublicKeyTemplate: CK_ATTRIBUTE_PTR,
902     _ulPublicKeyAttributeCount: CK_ULONG,
903     _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR,
904     _ulPrivateKeyAttributeCount: CK_ULONG,
905     _phPublicKey: CK_OBJECT_HANDLE_PTR,
906     _phPrivateKey: CK_OBJECT_HANDLE_PTR,
907 ) -> CK_RV {
908     CKR_FUNCTION_NOT_SUPPORTED
911 extern "C" fn C_WrapKey(
912     _hSession: CK_SESSION_HANDLE,
913     _pMechanism: CK_MECHANISM_PTR,
914     _hWrappingKey: CK_OBJECT_HANDLE,
915     _hKey: CK_OBJECT_HANDLE,
916     _pWrappedKey: CK_BYTE_PTR,
917     _pulWrappedKeyLen: CK_ULONG_PTR,
918 ) -> CK_RV {
919     CKR_FUNCTION_NOT_SUPPORTED
922 extern "C" fn C_UnwrapKey(
923     _hSession: CK_SESSION_HANDLE,
924     _pMechanism: CK_MECHANISM_PTR,
925     _hUnwrappingKey: CK_OBJECT_HANDLE,
926     _pWrappedKey: CK_BYTE_PTR,
927     _ulWrappedKeyLen: CK_ULONG,
928     _pTemplate: CK_ATTRIBUTE_PTR,
929     _ulAttributeCount: CK_ULONG,
930     _phKey: CK_OBJECT_HANDLE_PTR,
931 ) -> CK_RV {
932     CKR_FUNCTION_NOT_SUPPORTED
935 extern "C" fn C_DeriveKey(
936     _hSession: CK_SESSION_HANDLE,
937     _pMechanism: CK_MECHANISM_PTR,
938     _hBaseKey: CK_OBJECT_HANDLE,
939     _pTemplate: CK_ATTRIBUTE_PTR,
940     _ulAttributeCount: CK_ULONG,
941     _phKey: CK_OBJECT_HANDLE_PTR,
942 ) -> CK_RV {
943     CKR_FUNCTION_NOT_SUPPORTED
946 extern "C" fn C_SeedRandom(
947     _hSession: CK_SESSION_HANDLE,
948     _pSeed: CK_BYTE_PTR,
949     _ulSeedLen: CK_ULONG,
950 ) -> CK_RV {
951     CKR_FUNCTION_NOT_SUPPORTED
954 extern "C" fn C_GenerateRandom(
955     _hSession: CK_SESSION_HANDLE,
956     _RandomData: CK_BYTE_PTR,
957     _ulRandomLen: CK_ULONG,
958 ) -> CK_RV {
959     CKR_FUNCTION_NOT_SUPPORTED
962 extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV {
963     CKR_FUNCTION_NOT_SUPPORTED
966 extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV {
967     CKR_FUNCTION_NOT_SUPPORTED
970 extern "C" fn C_WaitForSlotEvent(
971     _flags: CK_FLAGS,
972     _pSlot: CK_SLOT_ID_PTR,
973     _pRserved: CK_VOID_PTR,
974 ) -> CK_RV {
975     CKR_FUNCTION_NOT_SUPPORTED
978 /// To be a valid PKCS #11 module, this list of functions must be supported. At least cryptoki 2.2
979 /// must be supported for this module to work in NSS.
980 static FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
981     version: CK_VERSION { major: 2, minor: 2 },
982     C_Initialize: Some(C_Initialize),
983     C_Finalize: Some(C_Finalize),
984     C_GetInfo: Some(C_GetInfo),
985     C_GetFunctionList: None,
986     C_GetSlotList: Some(C_GetSlotList),
987     C_GetSlotInfo: Some(C_GetSlotInfo),
988     C_GetTokenInfo: Some(C_GetTokenInfo),
989     C_GetMechanismList: Some(C_GetMechanismList),
990     C_GetMechanismInfo: Some(C_GetMechanismInfo),
991     C_InitToken: Some(C_InitToken),
992     C_InitPIN: Some(C_InitPIN),
993     C_SetPIN: Some(C_SetPIN),
994     C_OpenSession: Some(C_OpenSession),
995     C_CloseSession: Some(C_CloseSession),
996     C_CloseAllSessions: Some(C_CloseAllSessions),
997     C_GetSessionInfo: Some(C_GetSessionInfo),
998     C_GetOperationState: Some(C_GetOperationState),
999     C_SetOperationState: Some(C_SetOperationState),
1000     C_Login: Some(C_Login),
1001     C_Logout: Some(C_Logout),
1002     C_CreateObject: Some(C_CreateObject),
1003     C_CopyObject: Some(C_CopyObject),
1004     C_DestroyObject: Some(C_DestroyObject),
1005     C_GetObjectSize: Some(C_GetObjectSize),
1006     C_GetAttributeValue: Some(C_GetAttributeValue),
1007     C_SetAttributeValue: Some(C_SetAttributeValue),
1008     C_FindObjectsInit: Some(C_FindObjectsInit),
1009     C_FindObjects: Some(C_FindObjects),
1010     C_FindObjectsFinal: Some(C_FindObjectsFinal),
1011     C_EncryptInit: Some(C_EncryptInit),
1012     C_Encrypt: Some(C_Encrypt),
1013     C_EncryptUpdate: Some(C_EncryptUpdate),
1014     C_EncryptFinal: Some(C_EncryptFinal),
1015     C_DecryptInit: Some(C_DecryptInit),
1016     C_Decrypt: Some(C_Decrypt),
1017     C_DecryptUpdate: Some(C_DecryptUpdate),
1018     C_DecryptFinal: Some(C_DecryptFinal),
1019     C_DigestInit: Some(C_DigestInit),
1020     C_Digest: Some(C_Digest),
1021     C_DigestUpdate: Some(C_DigestUpdate),
1022     C_DigestKey: Some(C_DigestKey),
1023     C_DigestFinal: Some(C_DigestFinal),
1024     C_SignInit: Some(C_SignInit),
1025     C_Sign: Some(C_Sign),
1026     C_SignUpdate: Some(C_SignUpdate),
1027     C_SignFinal: Some(C_SignFinal),
1028     C_SignRecoverInit: Some(C_SignRecoverInit),
1029     C_SignRecover: Some(C_SignRecover),
1030     C_VerifyInit: Some(C_VerifyInit),
1031     C_Verify: Some(C_Verify),
1032     C_VerifyUpdate: Some(C_VerifyUpdate),
1033     C_VerifyFinal: Some(C_VerifyFinal),
1034     C_VerifyRecoverInit: Some(C_VerifyRecoverInit),
1035     C_VerifyRecover: Some(C_VerifyRecover),
1036     C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate),
1037     C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate),
1038     C_SignEncryptUpdate: Some(C_SignEncryptUpdate),
1039     C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate),
1040     C_GenerateKey: Some(C_GenerateKey),
1041     C_GenerateKeyPair: Some(C_GenerateKeyPair),
1042     C_WrapKey: Some(C_WrapKey),
1043     C_UnwrapKey: Some(C_UnwrapKey),
1044     C_DeriveKey: Some(C_DeriveKey),
1045     C_SeedRandom: Some(C_SeedRandom),
1046     C_GenerateRandom: Some(C_GenerateRandom),
1047     C_GetFunctionStatus: Some(C_GetFunctionStatus),
1048     C_CancelFunction: Some(C_CancelFunction),
1049     C_WaitForSlotEvent: Some(C_WaitForSlotEvent),
1052 /// This is the only function this module exposes. The C stub calls it when NSS
1053 /// calls its exposed C_GetFunctionList function to obtain the list of functions
1054 /// comprising this module.
1055 #[no_mangle]
1056 pub extern "C" fn IPCCC_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV {
1057     if ppFunctionList.is_null() {
1058         return CKR_ARGUMENTS_BAD;
1059     }
1060     unsafe {
1061         // CK_FUNCTION_LIST_PTR is a *mut CK_FUNCTION_LIST, but as per the
1062         // specification, the caller must treat it as *const CK_FUNCTION_LIST.
1063         *ppFunctionList = std::ptr::addr_of!(FUNCTION_LIST) as CK_FUNCTION_LIST_PTR;
1064     }
1065     CKR_OK
1068 #[cfg_attr(
1069     any(target_os = "macos", target_os = "ios"),
1070     link(name = "Security", kind = "framework")
1072 extern "C" {}