blob: 7ff35fa432c312644a09d314e37c05d733023df2 [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
16//! and last-time-on-body for the main Keystore 2.0 database module.
17
18use super::{AuthTokenEntry, MonotonicRawTime};
19use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
20 HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
21};
22use lazy_static::lazy_static;
23use std::collections::HashSet;
24use std::sync::atomic::{AtomicI64, Ordering};
25use std::sync::Arc;
26use std::sync::RwLock;
27
28#[derive(PartialEq, PartialOrd, Ord, Eq, Hash)]
29struct AuthTokenId {
30 user_id: i64,
31 auth_id: i64,
32 authenticator_type: HardwareAuthenticatorType,
33}
34
35impl AuthTokenId {
36 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)]
48struct AuthTokenEntryWrap(AuthTokenEntry);
49
50impl std::hash::Hash for AuthTokenEntryWrap {
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
56impl PartialEq<AuthTokenEntryWrap> for AuthTokenEntryWrap {
57 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
63impl Eq for AuthTokenEntryWrap {}
64
65/// Per-boot state structure. Currently only used to track auth tokens and
66/// last-off-body.
67#[derive(Default)]
68pub 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
78lazy_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
84impl PerbootDB {
85 /// Construct a new perboot database. Currently just uses default values.
86 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.
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.
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
106 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
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.
114 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.
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}