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