xref: /aosp_15_r20/system/security/keystore2/src/database/perboot.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
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