xref: /aosp_15_r20/system/security/keystore2/src/database/perboot.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
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 //! for the main Keystore 2.0 database module.
17 
18 use super::AuthTokenEntry;
19 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
20     HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
21 };
22 use std::collections::HashSet;
23 use std::sync::Arc;
24 use std::sync::LazyLock;
25 use std::sync::RwLock;
26 
27 #[derive(PartialEq, PartialOrd, Ord, Eq, Hash)]
28 struct AuthTokenId {
29     user_id: i64,
30     auth_id: i64,
31     authenticator_type: HardwareAuthenticatorType,
32 }
33 
34 impl AuthTokenId {
from_auth_token(tok: &HardwareAuthToken) -> Self35     fn from_auth_token(tok: &HardwareAuthToken) -> Self {
36         AuthTokenId {
37             user_id: tok.userId,
38             auth_id: tok.authenticatorId,
39             authenticator_type: tok.authenticatorType,
40         }
41     }
42 }
43 
44 //Implements Eq/Hash to only operate on the AuthTokenId portion
45 //of the AuthTokenEntry. This allows a HashSet to DTRT.
46 #[derive(Clone)]
47 struct AuthTokenEntryWrap(AuthTokenEntry);
48 
49 impl std::hash::Hash for AuthTokenEntryWrap {
hash<H: std::hash::Hasher>(&self, state: &mut H)50     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
51         AuthTokenId::from_auth_token(&self.0.auth_token).hash(state)
52     }
53 }
54 
55 impl PartialEq<AuthTokenEntryWrap> for AuthTokenEntryWrap {
eq(&self, other: &AuthTokenEntryWrap) -> bool56     fn eq(&self, other: &AuthTokenEntryWrap) -> bool {
57         AuthTokenId::from_auth_token(&self.0.auth_token)
58             == AuthTokenId::from_auth_token(&other.0.auth_token)
59     }
60 }
61 
62 impl Eq for AuthTokenEntryWrap {}
63 
64 /// Per-boot state structure. Currently only used to track auth tokens.
65 #[derive(Default)]
66 pub struct PerbootDB {
67     // We can use a .unwrap() discipline on this lock, because only panicking
68     // while holding a .write() lock will poison it. The only write usage is
69     // an insert call which inserts a pre-constructed pair.
70     auth_tokens: RwLock<HashSet<AuthTokenEntryWrap>>,
71 }
72 
73 /// The global instance of the perboot DB. Located here rather than in globals
74 /// in order to restrict access to the database module.
75 pub static PERBOOT_DB: LazyLock<Arc<PerbootDB>> = LazyLock::new(|| Arc::new(PerbootDB::new()));
76 
77 impl PerbootDB {
78     /// Construct a new perboot database. Currently just uses default values.
new() -> Self79     pub fn new() -> Self {
80         Default::default()
81     }
82     /// Add a new auth token + timestamp to the database, replacing any which
83     /// match all of user_id, auth_id, and auth_type.
insert_auth_token_entry(&self, entry: AuthTokenEntry)84     pub fn insert_auth_token_entry(&self, entry: AuthTokenEntry) {
85         self.auth_tokens.write().unwrap().replace(AuthTokenEntryWrap(entry));
86     }
87     /// Locate an auth token entry which matches the predicate with the most
88     /// recent update time.
find_auth_token_entry<P: Fn(&AuthTokenEntry) -> bool>( &self, p: P, ) -> Option<AuthTokenEntry>89     pub fn find_auth_token_entry<P: Fn(&AuthTokenEntry) -> bool>(
90         &self,
91         p: P,
92     ) -> Option<AuthTokenEntry> {
93         let reader = self.auth_tokens.read().unwrap();
94         let mut matches: Vec<_> = reader.iter().filter(|x| p(&x.0)).collect();
95         matches.sort_by_key(|x| x.0.time_received);
96         matches.last().map(|x| x.0.clone())
97     }
98     /// Return how many auth tokens are currently tracked.
auth_tokens_len(&self) -> usize99     pub fn auth_tokens_len(&self) -> usize {
100         self.auth_tokens.read().unwrap().len()
101     }
102     #[cfg(test)]
103     /// For testing, return all auth tokens currently tracked.
get_all_auth_token_entries(&self) -> Vec<AuthTokenEntry>104     pub fn get_all_auth_token_entries(&self) -> Vec<AuthTokenEntry> {
105         self.auth_tokens.read().unwrap().iter().cloned().map(|x| x.0).collect()
106     }
107 }
108