blob: a1890a6621c57b3b20458249547779e797ad29b1 [file] [log] [blame]
Matthew Maurerd7815ca2021-05-06 21:58:45 -07001// 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
Eric Biggersb5613da2024-03-13 19:31:42 +000016//! for the main Keystore 2.0 database module.
Matthew Maurerd7815ca2021-05-06 21:58:45 -070017
Eric Biggersb5613da2024-03-13 19:31:42 +000018use super::AuthTokenEntry;
Matthew Maurerd7815ca2021-05-06 21:58:45 -070019use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
20 HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
21};
Matthew Maurerd7815ca2021-05-06 21:58:45 -070022use std::collections::HashSet;
Matthew Maurerd7815ca2021-05-06 21:58:45 -070023use std::sync::Arc;
Andrew Walbrana4bc1a92024-09-03 13:08:17 +010024use std::sync::LazyLock;
Matthew Maurerd7815ca2021-05-06 21:58:45 -070025use std::sync::RwLock;
26
27#[derive(PartialEq, PartialOrd, Ord, Eq, Hash)]
28struct AuthTokenId {
29 user_id: i64,
30 auth_id: i64,
31 authenticator_type: HardwareAuthenticatorType,
32}
33
34impl AuthTokenId {
35 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)]
47struct AuthTokenEntryWrap(AuthTokenEntry);
48
49impl std::hash::Hash for AuthTokenEntryWrap {
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
55impl PartialEq<AuthTokenEntryWrap> for AuthTokenEntryWrap {
56 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
62impl Eq for AuthTokenEntryWrap {}
63
Eric Biggersb5613da2024-03-13 19:31:42 +000064/// Per-boot state structure. Currently only used to track auth tokens.
Matthew Maurerd7815ca2021-05-06 21:58:45 -070065#[derive(Default)]
66pub 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>>,
Matthew Maurerd7815ca2021-05-06 21:58:45 -070071}
72
Andrew Walbrana4bc1a92024-09-03 13:08:17 +010073/// The global instance of the perboot DB. Located here rather than in globals
74/// in order to restrict access to the database module.
75pub static PERBOOT_DB: LazyLock<Arc<PerbootDB>> = LazyLock::new(|| Arc::new(PerbootDB::new()));
Matthew Maurerd7815ca2021-05-06 21:58:45 -070076
77impl PerbootDB {
78 /// Construct a new perboot database. Currently just uses default values.
79 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.
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.
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 }
Matthew Maurerd7815ca2021-05-06 21:58:45 -070098 /// Return how many auth tokens are currently tracked.
99 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.
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}