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