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, ¶ms) 555 } 556 } 557