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 use pkcs11::types::*;
7 use std::collections::{BTreeMap, BTreeSet};
8 
9 #[cfg(target_os = "macos")]
10 use crate::backend_macos as backend;
11 #[cfg(target_os = "windows")]
12 use crate::backend_windows as backend;
13 use crate::util::*;
14 use backend::*;
15 
16 use std::sync::mpsc::{channel, Receiver, Sender};
17 use std::thread;
18 use std::thread::JoinHandle;
19 use std::time::{Duration, Instant};
20 
21 /// Helper enum to differentiate between sessions on the modern slot and sessions on the legacy
22 /// slot. The former is for EC keys and RSA keys that can be used with RSA-PSS whereas the latter is
23 /// for RSA keys that cannot be used with RSA-PSS.
24 #[derive(Clone, Copy, PartialEq)]
25 pub enum SlotType {
26     Modern,
27     Legacy,
28 }
29 
30 /// Helper type for sending `ManagerArguments` to the real `Manager`.
31 type ManagerArgumentsSender = Sender<ManagerArguments>;
32 /// Helper type for receiving `ManagerReturnValue`s from the real `Manager`.
33 type ManagerReturnValueReceiver = Receiver<ManagerReturnValue>;
34 
35 /// Helper enum that encapsulates arguments to send from the `ManagerProxy` to the real `Manager`.
36 /// `ManagerArguments::Stop` is a special variant that stops the background thread and drops the
37 /// `Manager`.
38 enum ManagerArguments {
39     OpenSession(SlotType),
40     CloseSession(CK_SESSION_HANDLE),
41     CloseAllSessions(SlotType),
42     StartSearch(CK_SESSION_HANDLE, Vec<(CK_ATTRIBUTE_TYPE, Vec<u8>)>),
43     Search(CK_SESSION_HANDLE, usize),
44     ClearSearch(CK_SESSION_HANDLE),
45     GetAttributes(CK_OBJECT_HANDLE, Vec<CK_ATTRIBUTE_TYPE>),
46     StartSign(
47         CK_SESSION_HANDLE,
48         CK_OBJECT_HANDLE,
49         Option<CK_RSA_PKCS_PSS_PARAMS>,
50     ),
51     GetSignatureLength(CK_SESSION_HANDLE, Vec<u8>),
52     Sign(CK_SESSION_HANDLE, Vec<u8>),
53     Stop,
54 }
55 
56 /// Helper enum that encapsulates return values from the real `Manager` that are sent back to the
57 /// `ManagerProxy`. `ManagerReturnValue::Stop` is a special variant that indicates that the
58 /// `Manager` will stop.
59 enum ManagerReturnValue {
60     OpenSession(Result<CK_SESSION_HANDLE, ()>),
61     CloseSession(Result<(), ()>),
62     CloseAllSessions(Result<(), ()>),
63     StartSearch(Result<(), ()>),
64     Search(Result<Vec<CK_OBJECT_HANDLE>, ()>),
65     ClearSearch(Result<(), ()>),
66     GetAttributes(Result<Vec<Option<Vec<u8>>>, ()>),
67     StartSign(Result<(), ()>),
68     GetSignatureLength(Result<usize, ()>),
69     Sign(Result<Vec<u8>, ()>),
70     Stop(Result<(), ()>),
71 }
72 
73 /// Helper macro to implement the body of each public `ManagerProxy` function. Takes a
74 /// `ManagerProxy` instance (should always be `self`), a `ManagerArguments` representing the
75 /// `Manager` function to call and the arguments to use, and the qualified type of the expected
76 /// `ManagerReturnValue` that will be received from the `Manager` when it is done.
77 macro_rules! manager_proxy_fn_impl {
78     ($manager:ident, $argument_enum:expr, $return_type:path) => {
79         match $manager.proxy_call($argument_enum) {
80             Ok($return_type(result)) => result,
81             Ok(_) => {
82                 error!("unexpected return value from manager");
83                 Err(())
84             }
85             Err(()) => Err(()),
86         }
87     };
88 }
89 
90 /// `ManagerProxy` synchronously proxies calls from any thread to the `Manager` that runs on a
91 /// single thread. This is necessary because the underlying OS APIs in use are not guaranteed to be
92 /// thread-safe (e.g. they may use thread-local storage). Using it should be identical to using the
93 /// real `Manager`.
94 pub struct ManagerProxy {
95     sender: ManagerArgumentsSender,
96     receiver: ManagerReturnValueReceiver,
97     thread_handle: Option<JoinHandle<()>>,
98 }
99 
100 impl ManagerProxy {
new() -> Result<ManagerProxy, ()>101     pub fn new() -> Result<ManagerProxy, ()> {
102         let (proxy_sender, manager_receiver) = channel();
103         let (manager_sender, proxy_receiver) = channel();
104         let thread_handle = thread::Builder::new()
105             .name("osclientcert".into())
106             .spawn(move || {
107                 let mut real_manager = Manager::new();
108                 loop {
109                     let arguments = match manager_receiver.recv() {
110                         Ok(arguments) => arguments,
111                         Err(e) => {
112                             error!("error recv()ing arguments from ManagerProxy: {}", e);
113                             break;
114                         }
115                     };
116                     let results = match arguments {
117                         ManagerArguments::OpenSession(slot_type) => {
118                             ManagerReturnValue::OpenSession(real_manager.open_session(slot_type))
119                         }
120                         ManagerArguments::CloseSession(session_handle) => {
121                             ManagerReturnValue::CloseSession(
122                                 real_manager.close_session(session_handle),
123                             )
124                         }
125                         ManagerArguments::CloseAllSessions(slot_type) => {
126                             ManagerReturnValue::CloseAllSessions(
127                                 real_manager.close_all_sessions(slot_type),
128                             )
129                         }
130                         ManagerArguments::StartSearch(session, attrs) => {
131                             ManagerReturnValue::StartSearch(
132                                 real_manager.start_search(session, &attrs),
133                             )
134                         }
135                         ManagerArguments::Search(session, max_objects) => {
136                             ManagerReturnValue::Search(real_manager.search(session, max_objects))
137                         }
138                         ManagerArguments::ClearSearch(session) => {
139                             ManagerReturnValue::ClearSearch(real_manager.clear_search(session))
140                         }
141                         ManagerArguments::GetAttributes(object_handle, attr_types) => {
142                             ManagerReturnValue::GetAttributes(
143                                 real_manager.get_attributes(object_handle, attr_types),
144                             )
145                         }
146                         ManagerArguments::StartSign(session, key_handle, params) => {
147                             ManagerReturnValue::StartSign(
148                                 real_manager.start_sign(session, key_handle, params),
149                             )
150                         }
151                         ManagerArguments::GetSignatureLength(session, data) => {
152                             ManagerReturnValue::GetSignatureLength(
153                                 real_manager.get_signature_length(session, &data),
154                             )
155                         }
156                         ManagerArguments::Sign(session, data) => {
157                             ManagerReturnValue::Sign(real_manager.sign(session, &data))
158                         }
159                         ManagerArguments::Stop => {
160                             debug!("ManagerArguments::Stop received - stopping Manager thread.");
161                             ManagerReturnValue::Stop(Ok(()))
162                         }
163                     };
164                     let stop_after_send = match &results {
165                         &ManagerReturnValue::Stop(_) => true,
166                         _ => false,
167                     };
168                     match manager_sender.send(results) {
169                         Ok(()) => {}
170                         Err(e) => {
171                             error!("error send()ing results from Manager: {}", e);
172                             break;
173                         }
174                     }
175                     if stop_after_send {
176                         break;
177                     }
178                 }
179             });
180         match thread_handle {
181             Ok(thread_handle) => Ok(ManagerProxy {
182                 sender: proxy_sender,
183                 receiver: proxy_receiver,
184                 thread_handle: Some(thread_handle),
185             }),
186             Err(e) => {
187                 error!("error creating manager proxy: {}", e);
188                 Err(())
189             }
190         }
191     }
192 
proxy_call(&self, args: ManagerArguments) -> Result<ManagerReturnValue, ()>193     fn proxy_call(&self, args: ManagerArguments) -> Result<ManagerReturnValue, ()> {
194         match self.sender.send(args) {
195             Ok(()) => {}
196             Err(e) => {
197                 error!("error send()ing arguments to Manager: {}", e);
198                 return Err(());
199             }
200         };
201         let result = match self.receiver.recv() {
202             Ok(result) => result,
203             Err(e) => {
204                 error!("error recv()ing result from Manager: {}", e);
205                 return Err(());
206             }
207         };
208         Ok(result)
209     }
210 
open_session(&mut self, slot_type: SlotType) -> Result<CK_SESSION_HANDLE, ()>211     pub fn open_session(&mut self, slot_type: SlotType) -> Result<CK_SESSION_HANDLE, ()> {
212         manager_proxy_fn_impl!(
213             self,
214             ManagerArguments::OpenSession(slot_type),
215             ManagerReturnValue::OpenSession
216         )
217     }
218 
close_session(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()>219     pub fn close_session(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()> {
220         manager_proxy_fn_impl!(
221             self,
222             ManagerArguments::CloseSession(session),
223             ManagerReturnValue::CloseSession
224         )
225     }
226 
close_all_sessions(&mut self, slot_type: SlotType) -> Result<(), ()>227     pub fn close_all_sessions(&mut self, slot_type: SlotType) -> Result<(), ()> {
228         manager_proxy_fn_impl!(
229             self,
230             ManagerArguments::CloseAllSessions(slot_type),
231             ManagerReturnValue::CloseAllSessions
232         )
233     }
234 
start_search( &mut self, session: CK_SESSION_HANDLE, attrs: Vec<(CK_ATTRIBUTE_TYPE, Vec<u8>)>, ) -> Result<(), ()>235     pub fn start_search(
236         &mut self,
237         session: CK_SESSION_HANDLE,
238         attrs: Vec<(CK_ATTRIBUTE_TYPE, Vec<u8>)>,
239     ) -> Result<(), ()> {
240         manager_proxy_fn_impl!(
241             self,
242             ManagerArguments::StartSearch(session, attrs),
243             ManagerReturnValue::StartSearch
244         )
245     }
246 
search( &mut self, session: CK_SESSION_HANDLE, max_objects: usize, ) -> Result<Vec<CK_OBJECT_HANDLE>, ()>247     pub fn search(
248         &mut self,
249         session: CK_SESSION_HANDLE,
250         max_objects: usize,
251     ) -> Result<Vec<CK_OBJECT_HANDLE>, ()> {
252         manager_proxy_fn_impl!(
253             self,
254             ManagerArguments::Search(session, max_objects),
255             ManagerReturnValue::Search
256         )
257     }
258 
clear_search(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()>259     pub fn clear_search(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()> {
260         manager_proxy_fn_impl!(
261             self,
262             ManagerArguments::ClearSearch(session),
263             ManagerReturnValue::ClearSearch
264         )
265     }
266 
get_attributes( &self, object_handle: CK_OBJECT_HANDLE, attr_types: Vec<CK_ATTRIBUTE_TYPE>, ) -> Result<Vec<Option<Vec<u8>>>, ()>267     pub fn get_attributes(
268         &self,
269         object_handle: CK_OBJECT_HANDLE,
270         attr_types: Vec<CK_ATTRIBUTE_TYPE>,
271     ) -> Result<Vec<Option<Vec<u8>>>, ()> {
272         manager_proxy_fn_impl!(
273             self,
274             ManagerArguments::GetAttributes(object_handle, attr_types,),
275             ManagerReturnValue::GetAttributes
276         )
277     }
278 
start_sign( &mut self, session: CK_SESSION_HANDLE, key_handle: CK_OBJECT_HANDLE, params: Option<CK_RSA_PKCS_PSS_PARAMS>, ) -> Result<(), ()>279     pub fn start_sign(
280         &mut self,
281         session: CK_SESSION_HANDLE,
282         key_handle: CK_OBJECT_HANDLE,
283         params: Option<CK_RSA_PKCS_PSS_PARAMS>,
284     ) -> Result<(), ()> {
285         manager_proxy_fn_impl!(
286             self,
287             ManagerArguments::StartSign(session, key_handle, params),
288             ManagerReturnValue::StartSign
289         )
290     }
291 
get_signature_length( &self, session: CK_SESSION_HANDLE, data: Vec<u8>, ) -> Result<usize, ()>292     pub fn get_signature_length(
293         &self,
294         session: CK_SESSION_HANDLE,
295         data: Vec<u8>,
296     ) -> Result<usize, ()> {
297         manager_proxy_fn_impl!(
298             self,
299             ManagerArguments::GetSignatureLength(session, data),
300             ManagerReturnValue::GetSignatureLength
301         )
302     }
303 
sign(&mut self, session: CK_SESSION_HANDLE, data: Vec<u8>) -> Result<Vec<u8>, ()>304     pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: Vec<u8>) -> Result<Vec<u8>, ()> {
305         manager_proxy_fn_impl!(
306             self,
307             ManagerArguments::Sign(session, data),
308             ManagerReturnValue::Sign
309         )
310     }
311 
stop(&mut self) -> Result<(), ()>312     pub fn stop(&mut self) -> Result<(), ()> {
313         manager_proxy_fn_impl!(self, ManagerArguments::Stop, ManagerReturnValue::Stop)?;
314         let thread_handle = match self.thread_handle.take() {
315             Some(thread_handle) => thread_handle,
316             None => {
317                 error!("stop should only be called once");
318                 return Err(());
319             }
320         };
321         match thread_handle.join() {
322             Ok(()) => {}
323             Err(e) => {
324                 error!("manager thread panicked: {:?}", e);
325                 return Err(());
326             }
327         };
328         Ok(())
329     }
330 }
331 
332 // Determines if the attributes of a given search correspond to NSS looking for all certificates or
333 // private keys. Returns true if so, and false otherwise.
334 // These searches are of the form:
335 //   { { type: CKA_TOKEN, value: [1] },
336 //     { type: CKA_CLASS, value: [CKO_CERTIFICATE or CKO_PRIVATE_KEY, as serialized bytes] } }
337 // (although not necessarily in that order - see nssToken_TraverseCertificates and
338 // nssToken_FindPrivateKeys)
search_is_for_all_certificates_or_keys( attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)], ) -> Result<bool, ()>339 fn search_is_for_all_certificates_or_keys(
340     attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)],
341 ) -> Result<bool, ()> {
342     if attrs.len() != 2 {
343         return Ok(false);
344     }
345     let token_bytes = vec![1 as u8];
346     let mut found_token = false;
347     let cko_certificate_bytes = serialize_uint(CKO_CERTIFICATE)?;
348     let cko_private_key_bytes = serialize_uint(CKO_PRIVATE_KEY)?;
349     let mut found_certificate_or_private_key = false;
350     for (attr_type, attr_value) in attrs.iter() {
351         if attr_type == &CKA_TOKEN && attr_value == &token_bytes {
352             found_token = true;
353         }
354         if attr_type == &CKA_CLASS
355             && (attr_value == &cko_certificate_bytes || attr_value == &cko_private_key_bytes)
356         {
357             found_certificate_or_private_key = true;
358         }
359     }
360     Ok(found_token && found_certificate_or_private_key)
361 }
362 
363 /// The `Manager` keeps track of the state of this module with respect to the PKCS #11
364 /// specification. This includes what sessions are open, which search and sign operations are
365 /// ongoing, and what objects are known and by what handle.
366 struct Manager {
367     /// A map of session to session type (modern or legacy). Sessions can be created (opened) and
368     /// later closed.
369     sessions: BTreeMap<CK_SESSION_HANDLE, SlotType>,
370     /// A map of searches to PKCS #11 object handles that match those searches.
371     searches: BTreeMap<CK_SESSION_HANDLE, Vec<CK_OBJECT_HANDLE>>,
372     /// A map of sign operations to a pair of the object handle and optionally some params being
373     /// used by each one.
374     signs: BTreeMap<CK_SESSION_HANDLE, (CK_OBJECT_HANDLE, Option<CK_RSA_PKCS_PSS_PARAMS>)>,
375     /// A map of object handles to the underlying objects.
376     objects: BTreeMap<CK_OBJECT_HANDLE, Object>,
377     /// A set of certificate identifiers (not the same as handles).
378     cert_ids: BTreeSet<Vec<u8>>,
379     /// A set of key identifiers (not the same as handles). For each id in this set, there should be
380     /// a corresponding identical id in the `cert_ids` set, and vice-versa.
381     key_ids: BTreeSet<Vec<u8>>,
382     /// The next session handle to hand out.
383     next_session: CK_SESSION_HANDLE,
384     /// The next object handle to hand out.
385     next_handle: CK_OBJECT_HANDLE,
386     /// The last time the implementation looked for new objects in the backend.
387     /// The implementation does this search no more than once every 3 seconds.
388     last_scan_time: Option<Instant>,
389 }
390 
391 impl Manager {
new() -> Manager392     pub fn new() -> Manager {
393         Manager {
394             sessions: BTreeMap::new(),
395             searches: BTreeMap::new(),
396             signs: BTreeMap::new(),
397             objects: BTreeMap::new(),
398             cert_ids: BTreeSet::new(),
399             key_ids: BTreeSet::new(),
400             next_session: 1,
401             next_handle: 1,
402             last_scan_time: None,
403         }
404     }
405 
406     /// When a new search session is opened (provided at least 3 seconds have elapsed since the
407     /// last session was opened), this searches for certificates and keys to expose. We
408     /// de-duplicate previously-found certificates and keys by keeping track of their IDs.
maybe_find_new_objects(&mut self)409     fn maybe_find_new_objects(&mut self) {
410         let now = Instant::now();
411         match self.last_scan_time {
412             Some(last_scan_time) => {
413                 if now.duration_since(last_scan_time) < Duration::new(3, 0) {
414                     return;
415                 }
416             }
417             None => {}
418         }
419         self.last_scan_time = Some(now);
420         let objects = list_objects();
421         debug!("found {} objects", objects.len());
422         for object in objects {
423             match &object {
424                 Object::Cert(cert) => {
425                     if self.cert_ids.contains(cert.id()) {
426                         continue;
427                     }
428                     self.cert_ids.insert(cert.id().to_vec());
429                     let handle = self.get_next_handle();
430                     self.objects.insert(handle, object);
431                 }
432                 Object::Key(key) => {
433                     if self.key_ids.contains(key.id()) {
434                         continue;
435                     }
436                     self.key_ids.insert(key.id().to_vec());
437                     let handle = self.get_next_handle();
438                     self.objects.insert(handle, object);
439                 }
440             }
441         }
442     }
443 
open_session(&mut self, slot_type: SlotType) -> Result<CK_SESSION_HANDLE, ()>444     pub fn open_session(&mut self, slot_type: SlotType) -> Result<CK_SESSION_HANDLE, ()> {
445         let next_session = self.next_session;
446         self.next_session += 1;
447         self.sessions.insert(next_session, slot_type);
448         Ok(next_session)
449     }
450 
close_session(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()>451     pub fn close_session(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()> {
452         self.sessions.remove(&session).ok_or(()).map(|_| ())
453     }
454 
close_all_sessions(&mut self, slot_type: SlotType) -> Result<(), ()>455     pub fn close_all_sessions(&mut self, slot_type: SlotType) -> Result<(), ()> {
456         let mut to_remove = Vec::new();
457         for (session, open_slot_type) in self.sessions.iter() {
458             if slot_type == *open_slot_type {
459                 to_remove.push(*session);
460             }
461         }
462         for session in to_remove {
463             if self.sessions.remove(&session).is_none() {
464                 return Err(());
465             }
466         }
467         Ok(())
468     }
469 
get_next_handle(&mut self) -> CK_OBJECT_HANDLE470     fn get_next_handle(&mut self) -> CK_OBJECT_HANDLE {
471         let next_handle = self.next_handle;
472         self.next_handle += 1;
473         next_handle
474     }
475 
476     /// PKCS #11 specifies that search operations happen in three phases: setup, get any matches
477     /// (this part may be repeated if the caller uses a small buffer), and end. This implementation
478     /// does all of the work up front and gathers all matching objects during setup and retains them
479     /// until they are retrieved and consumed via `search`.
start_search( &mut self, session: CK_SESSION_HANDLE, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)], ) -> Result<(), ()>480     pub fn start_search(
481         &mut self,
482         session: CK_SESSION_HANDLE,
483         attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)],
484     ) -> Result<(), ()> {
485         let slot_type = match self.sessions.get(&session) {
486             Some(slot_type) => *slot_type,
487             None => return Err(()),
488         };
489         // If the search is for an attribute we don't support, no objects will match. This check
490         // saves us having to look through all of our objects.
491         for (attr, _) in attrs {
492             if !SUPPORTED_ATTRIBUTES.contains(attr) {
493                 self.searches.insert(session, Vec::new());
494                 return Ok(());
495             }
496         }
497         // When NSS wants to find all certificates or all private keys, it will perform a search
498         // with a particular set of attributes. This implementation uses these searches as an
499         // indication for the backend to re-scan for new objects from tokens that may have been
500         // inserted or certificates that may have been imported into the OS. Since these searches
501         // are relatively rare, this minimizes the impact of doing these re-scans.
502         if search_is_for_all_certificates_or_keys(attrs)? {
503             self.maybe_find_new_objects();
504         }
505         let mut handles = Vec::new();
506         for (handle, object) in &self.objects {
507             if object.matches(slot_type, attrs) {
508                 handles.push(*handle);
509             }
510         }
511         self.searches.insert(session, handles);
512         Ok(())
513     }
514 
515     /// Given a session and a maximum number of object handles to return, attempts to retrieve up to
516     /// that many objects from the corresponding search. Updates the search so those objects are not
517     /// returned repeatedly. `max_objects` must be non-zero.
search( &mut self, session: CK_SESSION_HANDLE, max_objects: usize, ) -> Result<Vec<CK_OBJECT_HANDLE>, ()>518     pub fn search(
519         &mut self,
520         session: CK_SESSION_HANDLE,
521         max_objects: usize,
522     ) -> Result<Vec<CK_OBJECT_HANDLE>, ()> {
523         if max_objects == 0 {
524             return Err(());
525         }
526         match self.searches.get_mut(&session) {
527             Some(search) => {
528                 let split_at = if max_objects >= search.len() {
529                     0
530                 } else {
531                     search.len() - max_objects
532                 };
533                 let to_return = search.split_off(split_at);
534                 if to_return.len() > max_objects {
535                     error!(
536                         "search trying to return too many handles: {} > {}",
537                         to_return.len(),
538                         max_objects
539                     );
540                     return Err(());
541                 }
542                 Ok(to_return)
543             }
544             None => Err(()),
545         }
546     }
547 
clear_search(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()>548     pub fn clear_search(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()> {
549         self.searches.remove(&session);
550         Ok(())
551     }
552 
get_attributes( &self, object_handle: CK_OBJECT_HANDLE, attr_types: Vec<CK_ATTRIBUTE_TYPE>, ) -> Result<Vec<Option<Vec<u8>>>, ()>553     pub fn get_attributes(
554         &self,
555         object_handle: CK_OBJECT_HANDLE,
556         attr_types: Vec<CK_ATTRIBUTE_TYPE>,
557     ) -> Result<Vec<Option<Vec<u8>>>, ()> {
558         let object = match self.objects.get(&object_handle) {
559             Some(object) => object,
560             None => return Err(()),
561         };
562         let mut results = Vec::with_capacity(attr_types.len());
563         for attr_type in attr_types {
564             let result = match object.get_attribute(attr_type) {
565                 Some(value) => Some(value.to_owned()),
566                 None => None,
567             };
568             results.push(result);
569         }
570         Ok(results)
571     }
572 
573     /// The way NSS uses PKCS #11 to sign data happens in two phases: setup and sign. This
574     /// implementation makes a note of which key is to be used (if it exists) during setup. When the
575     /// caller finishes with the sign operation, this implementation retrieves the key handle and
576     /// performs the signature.
start_sign( &mut self, session: CK_SESSION_HANDLE, key_handle: CK_OBJECT_HANDLE, params: Option<CK_RSA_PKCS_PSS_PARAMS>, ) -> Result<(), ()>577     pub fn start_sign(
578         &mut self,
579         session: CK_SESSION_HANDLE,
580         key_handle: CK_OBJECT_HANDLE,
581         params: Option<CK_RSA_PKCS_PSS_PARAMS>,
582     ) -> Result<(), ()> {
583         if self.signs.contains_key(&session) {
584             return Err(());
585         }
586         match self.objects.get(&key_handle) {
587             Some(Object::Key(_)) => {}
588             _ => return Err(()),
589         };
590         self.signs.insert(session, (key_handle, params));
591         Ok(())
592     }
593 
get_signature_length( &mut self, session: CK_SESSION_HANDLE, data: &[u8], ) -> Result<usize, ()>594     pub fn get_signature_length(
595         &mut self,
596         session: CK_SESSION_HANDLE,
597         data: &[u8],
598     ) -> Result<usize, ()> {
599         let (key_handle, params) = match self.signs.get(&session) {
600             Some((key_handle, params)) => (key_handle, params),
601             None => return Err(()),
602         };
603         let key = match self.objects.get_mut(&key_handle) {
604             Some(Object::Key(key)) => key,
605             _ => return Err(()),
606         };
607         key.get_signature_length(data, params)
608     }
609 
sign(&mut self, session: CK_SESSION_HANDLE, data: &[u8]) -> Result<Vec<u8>, ()>610     pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: &[u8]) -> Result<Vec<u8>, ()> {
611         // Performing the signature (via C_Sign, which is the only way we support) finishes the sign
612         // operation, so it needs to be removed here.
613         let (key_handle, params) = match self.signs.remove(&session) {
614             Some((key_handle, params)) => (key_handle, params),
615             None => return Err(()),
616         };
617         let key = match self.objects.get_mut(&key_handle) {
618             Some(Object::Key(key)) => key,
619             _ => return Err(()),
620         };
621         key.sign(data, &params)
622     }
623 }
624