1 // Copyright 2021, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! This module implements a per-boot, shared, in-memory storage of auth tokens 16 //! and last-time-on-body for the main Keystore 2.0 database module. 17 18 use super::{AuthTokenEntry, MonotonicRawTime}; 19 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ 20 HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType, 21 }; 22 use lazy_static::lazy_static; 23 use std::collections::HashSet; 24 use std::sync::atomic::{AtomicI64, Ordering}; 25 use std::sync::Arc; 26 use std::sync::RwLock; 27 28 #[derive(PartialEq, PartialOrd, Ord, Eq, Hash)] 29 struct AuthTokenId { 30 user_id: i64, 31 auth_id: i64, 32 authenticator_type: HardwareAuthenticatorType, 33 } 34 35 impl AuthTokenId { from_auth_token(tok: &HardwareAuthToken) -> Self36 fn from_auth_token(tok: &HardwareAuthToken) -> Self { 37 AuthTokenId { 38 user_id: tok.userId, 39 auth_id: tok.authenticatorId, 40 authenticator_type: tok.authenticatorType, 41 } 42 } 43 } 44 45 //Implements Eq/Hash to only operate on the AuthTokenId portion 46 //of the AuthTokenEntry. This allows a HashSet to DTRT. 47 #[derive(Clone)] 48 struct AuthTokenEntryWrap(AuthTokenEntry); 49 50 impl std::hash::Hash for AuthTokenEntryWrap { hash<H: std::hash::Hasher>(&self, state: &mut H)51 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 52 AuthTokenId::from_auth_token(&self.0.auth_token).hash(state) 53 } 54 } 55 56 impl PartialEq<AuthTokenEntryWrap> for AuthTokenEntryWrap { eq(&self, other: &AuthTokenEntryWrap) -> bool57 fn eq(&self, other: &AuthTokenEntryWrap) -> bool { 58 AuthTokenId::from_auth_token(&self.0.auth_token) 59 == AuthTokenId::from_auth_token(&other.0.auth_token) 60 } 61 } 62 63 impl Eq for AuthTokenEntryWrap {} 64 65 /// Per-boot state structure. Currently only used to track auth tokens and 66 /// last-off-body. 67 #[derive(Default)] 68 pub struct PerbootDB { 69 // We can use a .unwrap() discipline on this lock, because only panicking 70 // while holding a .write() lock will poison it. The only write usage is 71 // an insert call which inserts a pre-constructed pair. 72 auth_tokens: RwLock<HashSet<AuthTokenEntryWrap>>, 73 // Ordering::Relaxed is appropriate for accessing this atomic, since it 74 // does not currently need to be synchronized with anything else. 75 last_off_body: AtomicI64, 76 } 77 78 lazy_static! { 79 /// The global instance of the perboot DB. Located here rather than in globals 80 /// in order to restrict access to the database module. 81 pub static ref PERBOOT_DB: Arc<PerbootDB> = Arc::new(PerbootDB::new()); 82 } 83 84 impl PerbootDB { 85 /// Construct a new perboot database. Currently just uses default values. new() -> Self86 pub fn new() -> Self { 87 Default::default() 88 } 89 /// Add a new auth token + timestamp to the database, replacing any which 90 /// match all of user_id, auth_id, and auth_type. insert_auth_token_entry(&self, entry: AuthTokenEntry)91 pub fn insert_auth_token_entry(&self, entry: AuthTokenEntry) { 92 self.auth_tokens.write().unwrap().replace(AuthTokenEntryWrap(entry)); 93 } 94 /// Locate an auth token entry which matches the predicate with the most 95 /// recent update time. find_auth_token_entry<P: Fn(&AuthTokenEntry) -> bool>( &self, p: P, ) -> Option<AuthTokenEntry>96 pub fn find_auth_token_entry<P: Fn(&AuthTokenEntry) -> bool>( 97 &self, 98 p: P, 99 ) -> Option<AuthTokenEntry> { 100 let reader = self.auth_tokens.read().unwrap(); 101 let mut matches: Vec<_> = reader.iter().filter(|x| p(&x.0)).collect(); 102 matches.sort_by_key(|x| x.0.time_received); 103 matches.last().map(|x| x.0.clone()) 104 } 105 /// Get the last time the device was off the user's body get_last_off_body(&self) -> MonotonicRawTime106 pub fn get_last_off_body(&self) -> MonotonicRawTime { 107 MonotonicRawTime(self.last_off_body.load(Ordering::Relaxed)) 108 } 109 /// Set the last time the device was off the user's body set_last_off_body(&self, last_off_body: MonotonicRawTime)110 pub fn set_last_off_body(&self, last_off_body: MonotonicRawTime) { 111 self.last_off_body.store(last_off_body.0, Ordering::Relaxed) 112 } 113 /// Return how many auth tokens are currently tracked. auth_tokens_len(&self) -> usize114 pub fn auth_tokens_len(&self) -> usize { 115 self.auth_tokens.read().unwrap().len() 116 } 117 #[cfg(test)] 118 /// For testing, return all auth tokens currently tracked. get_all_auth_token_entries(&self) -> Vec<AuthTokenEntry>119 pub fn get_all_auth_token_entries(&self) -> Vec<AuthTokenEntry> { 120 self.auth_tokens.read().unwrap().iter().cloned().map(|x| x.0).collect() 121 } 122 } 123