blob: d086dd27629000d790e9c8bb6bc5fecf707e3e28 [file] [log] [blame]
Hasini Gunasinghe3410f792020-09-14 17:55:21 +00001// Copyright 2020, 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
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000015//! This is the Keystore 2.0 Enforcements module.
16// TODO: more description to follow.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000017use crate::ks_err;
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080018use crate::error::{map_binder_status, Error, ErrorCode};
19use crate::globals::{get_timestamp_service, ASYNC_TASK, DB, ENFORCEMENTS};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000020use crate::key_parameter::{KeyParameter, KeyParameterValue};
Paul Crowley7a658392021-03-18 17:08:20 -070021use crate::{authorization::Error as AuthzError, super_key::SuperEncryptionType};
Paul Crowley44c02da2021-04-08 17:04:43 +000022use crate::{
Eric Biggers19b3b0d2024-01-31 22:46:47 +000023 database::{AuthTokenEntry, BootTime},
Paul Crowley44c02da2021-04-08 17:04:43 +000024 globals::SUPER_KEY,
25};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000026use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000027 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080028 HardwareAuthenticatorType::HardwareAuthenticatorType,
29 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, Tag::Tag,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080030};
31use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Janis Danisevskis5f3a0572021-06-18 11:26:42 -070032 TimeStampToken::TimeStampToken,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000033};
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000034use android_security_authorization::aidl::android::security::authorization::ResponseCode::ResponseCode as AuthzResponseCode;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000035use android_system_keystore2::aidl::android::system::keystore2::{
Paul Crowley7a658392021-03-18 17:08:20 -070036 Domain::Domain, IKeystoreSecurityLevel::KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000037 OperationChallenge::OperationChallenge,
38};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000039use anyhow::{Context, Result};
Janis Danisevskisb1673db2021-02-08 18:11:57 -080040use std::{
41 collections::{HashMap, HashSet},
Paul Crowley7c57bf12021-02-02 16:26:57 -080042 sync::{
Paul Crowley7c57bf12021-02-02 16:26:57 -080043 mpsc::{channel, Receiver, Sender, TryRecvError},
44 Arc, Mutex, Weak,
45 },
46 time::SystemTime,
Janis Danisevskisb1673db2021-02-08 18:11:57 -080047};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000048
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080049#[derive(Debug)]
50enum AuthRequestState {
51 /// An outstanding per operation authorization request.
52 OpAuth,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080053 /// An outstanding request for a timestamp token.
Andrew Walbran7036c2b2023-07-21 17:25:45 +010054 TimeStamp(Mutex<Receiver<Result<TimeStampToken, Error>>>),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080055}
56
57#[derive(Debug)]
58struct AuthRequest {
59 state: AuthRequestState,
Eric Biggers9f7ebeb2024-06-20 14:59:32 +000060 /// This need to be set to Some to fulfill an AuthRequestState::OpAuth.
Janis Danisevskisbe1969e2021-04-20 15:16:24 -070061 hat: Mutex<Option<HardwareAuthToken>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080062}
63
64impl AuthRequest {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -070065 fn op_auth() -> Arc<Self> {
66 Arc::new(Self { state: AuthRequestState::OpAuth, hat: Mutex::new(None) })
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080067 }
68
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080069 fn timestamp(
70 hat: HardwareAuthToken,
71 receiver: Receiver<Result<TimeStampToken, Error>>,
Janis Danisevskisbe1969e2021-04-20 15:16:24 -070072 ) -> Arc<Self> {
Andrew Walbran7036c2b2023-07-21 17:25:45 +010073 Arc::new(Self {
74 state: AuthRequestState::TimeStamp(Mutex::new(receiver)),
75 hat: Mutex::new(Some(hat)),
76 })
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080077 }
78
Janis Danisevskisbe1969e2021-04-20 15:16:24 -070079 fn add_auth_token(&self, hat: HardwareAuthToken) {
80 *self.hat.lock().unwrap() = Some(hat)
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080081 }
82
Janis Danisevskisbe1969e2021-04-20 15:16:24 -070083 fn get_auth_tokens(&self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
84 let hat = self
85 .hat
86 .lock()
87 .unwrap()
88 .take()
89 .ok_or(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000090 .context(ks_err!("No operation auth token received."))?;
Janis Danisevskisbe1969e2021-04-20 15:16:24 -070091
92 let tst = match &self.state {
Eric Biggers9f7ebeb2024-06-20 14:59:32 +000093 AuthRequestState::TimeStamp(recv) => {
Andrew Walbran7036c2b2023-07-21 17:25:45 +010094 let result = recv
95 .lock()
96 .unwrap()
97 .recv()
98 .context("In get_auth_tokens: Sender disconnected.")?;
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000099 Some(result.context(ks_err!(
100 "Worker responded with error \
101 from generating timestamp token.",
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700102 ))?)
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800103 }
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700104 AuthRequestState::OpAuth => None,
105 };
106 Ok((hat, tst))
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800107 }
108}
109
110/// DeferredAuthState describes how auth tokens and timestamp tokens need to be provided when
111/// updating and finishing an operation.
112#[derive(Debug)]
113enum DeferredAuthState {
114 /// Used when an operation does not require further authorization.
115 NoAuthRequired,
116 /// Indicates that the operation requires an operation specific token. This means we have
117 /// to return an operation challenge to the client which should reward us with an
118 /// operation specific auth token. If it is not provided before the client calls update
119 /// or finish, the operation fails as not authorized.
120 OpAuthRequired,
121 /// Indicates that the operation requires a time stamp token. The auth token was already
122 /// loaded from the database, but it has to be accompanied by a time stamp token to inform
123 /// the target KM with a different clock about the time on the authenticators.
124 TimeStampRequired(HardwareAuthToken),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800125 /// In this state the auth info is waiting for the deferred authorizations to come in.
126 /// We block on timestamp tokens, because we can always make progress on these requests.
127 /// The per-op auth tokens might never come, which means we fail if the client calls
128 /// update or finish before we got a per-op auth token.
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700129 Waiting(Arc<AuthRequest>),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800130 /// In this state we have gotten all of the required tokens, we just cache them to
131 /// be used when the operation progresses.
132 Token(HardwareAuthToken, Option<TimeStampToken>),
133}
134
135/// Auth info hold all of the authorization related information of an operation. It is stored
136/// in and owned by the operation. It is constructed by authorize_create and stays with the
137/// operation until it completes.
138#[derive(Debug)]
139pub struct AuthInfo {
140 state: DeferredAuthState,
Qi Wub9433b52020-12-01 14:52:46 +0800141 /// An optional key id required to update the usage count if the key usage is limited.
142 key_usage_limited: Option<i64>,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800143 confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800144}
145
146struct TokenReceiverMap {
147 /// The map maps an outstanding challenge to a TokenReceiver. If an incoming Hardware Auth
148 /// Token (HAT) has the map key in its challenge field, it gets passed to the TokenReceiver
149 /// and the entry is removed from the map. In the case where no HAT is received before the
150 /// corresponding operation gets dropped, the entry goes stale. So every time the cleanup
151 /// counter (second field in the tuple) turns 0, the map is cleaned from stale entries.
152 /// The cleanup counter is decremented every time a new receiver is added.
153 /// and reset to TokenReceiverMap::CLEANUP_PERIOD + 1 after each cleanup.
154 map_and_cleanup_counter: Mutex<(HashMap<i64, TokenReceiver>, u8)>,
155}
156
157impl Default for TokenReceiverMap {
158 fn default() -> Self {
159 Self { map_and_cleanup_counter: Mutex::new((HashMap::new(), Self::CLEANUP_PERIOD + 1)) }
160 }
161}
162
163impl TokenReceiverMap {
164 /// There is a chance that receivers may become stale because their operation is dropped
165 /// without ever being authorized. So occasionally we iterate through the map and throw
166 /// out obsolete entries.
167 /// This is the number of calls to add_receiver between cleanups.
168 const CLEANUP_PERIOD: u8 = 25;
169
170 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700171 let recv = {
172 // Limit the scope of the mutex guard, so that it is not held while the auth token is
173 // added.
174 let mut map = self.map_and_cleanup_counter.lock().unwrap();
175 let (ref mut map, _) = *map;
176 map.remove_entry(&hat.challenge)
177 };
178
179 if let Some((_, recv)) = recv {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800180 recv.add_auth_token(hat);
181 }
182 }
183
184 pub fn add_receiver(&self, challenge: i64, recv: TokenReceiver) {
185 let mut map = self.map_and_cleanup_counter.lock().unwrap();
186 let (ref mut map, ref mut cleanup_counter) = *map;
187 map.insert(challenge, recv);
188
189 *cleanup_counter -= 1;
190 if *cleanup_counter == 0 {
191 map.retain(|_, v| !v.is_obsolete());
192 map.shrink_to_fit();
193 *cleanup_counter = Self::CLEANUP_PERIOD + 1;
194 }
195 }
196}
197
198#[derive(Debug)]
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700199struct TokenReceiver(Weak<AuthRequest>);
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800200
201impl TokenReceiver {
202 fn is_obsolete(&self) -> bool {
203 self.0.upgrade().is_none()
204 }
205
206 fn add_auth_token(&self, hat: HardwareAuthToken) {
207 if let Some(state_arc) = self.0.upgrade() {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700208 state_arc.add_auth_token(hat);
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800209 }
210 }
211}
212
213fn get_timestamp_token(challenge: i64) -> Result<TimeStampToken, Error> {
Janis Danisevskis5f3a0572021-06-18 11:26:42 -0700214 let dev = get_timestamp_service().expect(concat!(
215 "Secure Clock service must be present ",
216 "if TimeStampTokens are required."
217 ));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800218 map_binder_status(dev.generateTimeStamp(challenge))
219}
220
221fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
222 if let Err(e) = sender.send(get_timestamp_token(challenge)) {
223 log::info!(
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000224 concat!("Receiver hung up ", "before timestamp token could be delivered. {:?}"),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800225 e
226 );
227 }
228}
229
230impl AuthInfo {
231 /// This function gets called after an operation was successfully created.
232 /// It makes all the preparations required, so that the operation has all the authentication
233 /// related artifacts to advance on update and finish.
234 pub fn finalize_create_authorization(&mut self, challenge: i64) -> Option<OperationChallenge> {
235 match &self.state {
236 DeferredAuthState::OpAuthRequired => {
237 let auth_request = AuthRequest::op_auth();
238 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
239 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
240
241 self.state = DeferredAuthState::Waiting(auth_request);
242 Some(OperationChallenge { challenge })
243 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800244 DeferredAuthState::TimeStampRequired(hat) => {
245 let hat = (*hat).clone();
246 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
247 let auth_request = AuthRequest::timestamp(hat, receiver);
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800248 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800249 self.state = DeferredAuthState::Waiting(auth_request);
250 None
251 }
252 _ => None,
253 }
254 }
255
Qi Wub9433b52020-12-01 14:52:46 +0800256 /// This function is the authorization hook called before operation update.
257 /// It returns the auth tokens required by the operation to commence update.
258 pub fn before_update(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
259 self.get_auth_tokens()
260 }
261
262 /// This function is the authorization hook called before operation finish.
263 /// It returns the auth tokens required by the operation to commence finish.
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800264 /// The third token is a confirmation token.
265 pub fn before_finish(
266 &mut self,
267 ) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>, Option<Vec<u8>>)> {
268 let mut confirmation_token: Option<Vec<u8>> = None;
269 if let Some(ref confirmation_token_receiver) = self.confirmation_token_receiver {
270 let locked_receiver = confirmation_token_receiver.lock().unwrap();
271 if let Some(ref receiver) = *locked_receiver {
272 loop {
273 match receiver.try_recv() {
274 // As long as we get tokens we loop and discard all but the most
275 // recent one.
276 Ok(t) => confirmation_token = Some(t),
277 Err(TryRecvError::Empty) => break,
278 Err(TryRecvError::Disconnected) => {
279 log::error!(concat!(
280 "We got disconnected from the APC service, ",
281 "this should never happen."
282 ));
283 break;
284 }
285 }
286 }
287 }
288 }
289 self.get_auth_tokens().map(|(hat, tst)| (hat, tst, confirmation_token))
Qi Wub9433b52020-12-01 14:52:46 +0800290 }
291
292 /// This function is the authorization hook called after finish succeeded.
293 /// As of this writing it checks if the key was a limited use key. If so it updates the
294 /// use counter of the key in the database. When the use counter is depleted, the key gets
295 /// marked for deletion and the garbage collector is notified.
296 pub fn after_finish(&self) -> Result<()> {
297 if let Some(key_id) = self.key_usage_limited {
298 // On the last successful use, the key gets deleted. In this case we
299 // have to notify the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800300 DB.with(|db| {
301 db.borrow_mut()
302 .check_and_update_key_usage_count(key_id)
303 .context("Trying to update key usage count.")
304 })
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000305 .context(ks_err!())?;
Qi Wub9433b52020-12-01 14:52:46 +0800306 }
307 Ok(())
308 }
309
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800310 /// This function returns the auth tokens as needed by the ongoing operation or fails
311 /// with ErrorCode::KEY_USER_NOT_AUTHENTICATED. If this was called for the first time
312 /// after a deferred authorization was requested by finalize_create_authorization, this
313 /// function may block on the generation of a time stamp token. It then moves the
314 /// tokens into the DeferredAuthState::Token state for future use.
Qi Wub9433b52020-12-01 14:52:46 +0800315 fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800316 let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
Janis Danisevskisbe1969e2021-04-20 15:16:24 -0700317 Some(auth_request.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800318 } else {
319 None
320 };
321
322 if let Some((hat, tst)) = deferred_tokens {
323 self.state = DeferredAuthState::Token(hat, tst);
324 }
325
326 match &self.state {
327 DeferredAuthState::NoAuthRequired => Ok((None, None)),
328 DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000329 DeferredAuthState::OpAuthRequired | DeferredAuthState::TimeStampRequired(_) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000330 Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(ks_err!(
331 "No operation auth token requested??? \
332 This should not happen."
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800333 ))
334 }
335 // This should not be reachable, because it should have been handled above.
336 DeferredAuthState::Waiting(_) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000337 Err(Error::sys()).context(ks_err!("AuthInfo::get_auth_tokens: Cannot be reached.",))
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800338 }
339 }
340 }
341}
342
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000343/// Enforcements data structure
Paul Crowley7c57bf12021-02-02 16:26:57 -0800344#[derive(Default)]
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000345pub struct Enforcements {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800346 /// This hash set contains the user ids for whom the device is currently unlocked. If a user id
347 /// is not in the set, it implies that the device is locked for the user.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000348 device_unlocked_set: Mutex<HashSet<i32>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800349 /// This field maps outstanding auth challenges to their operations. When an auth token
350 /// with the right challenge is received it is passed to the map using
351 /// TokenReceiverMap::add_auth_token() which removes the entry from the map. If an entry goes
352 /// stale, because the operation gets dropped before an auth token is received, the map
353 /// is cleaned up in regular intervals.
354 op_auth_map: TokenReceiverMap,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800355 /// The enforcement module will try to get a confirmation token from this channel whenever
356 /// an operation that requires confirmation finishes.
357 confirmation_token_receiver: Arc<Mutex<Option<Receiver<Vec<u8>>>>>,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000358}
359
360impl Enforcements {
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800361 /// Install the confirmation token receiver. The enforcement module will try to get a
362 /// confirmation token from this channel whenever an operation that requires confirmation
363 /// finishes.
364 pub fn install_confirmation_token_receiver(
365 &self,
366 confirmation_token_receiver: Receiver<Vec<u8>>,
367 ) {
368 *self.confirmation_token_receiver.lock().unwrap() = Some(confirmation_token_receiver);
369 }
370
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000371 /// Checks if a create call is authorized, given key parameters and operation parameters.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800372 /// It returns an optional immediate auth token which can be presented to begin, and an
373 /// AuthInfo object which stays with the authorized operation and is used to obtain
374 /// auth tokens and timestamp tokens as required by the operation.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000375 /// With regard to auth tokens, the following steps are taken:
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800376 ///
377 /// If no key parameters are given (typically when the client is self managed
378 /// (see Domain.Blob)) nothing is enforced.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000379 /// If the key is time-bound, find a matching auth token from the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800380 /// If the above step is successful, and if requires_timestamp is given, the returned
381 /// AuthInfo will provide a Timestamp token as appropriate.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000382 pub fn authorize_create(
383 &self,
384 purpose: KeyPurpose,
Qi Wub9433b52020-12-01 14:52:46 +0800385 key_properties: Option<&(i64, Vec<KeyParameter>)>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800386 op_params: &[KmKeyParameter],
387 requires_timestamp: bool,
388 ) -> Result<(Option<HardwareAuthToken>, AuthInfo)> {
Qi Wub9433b52020-12-01 14:52:46 +0800389 let (key_id, key_params) = match key_properties {
390 Some((key_id, key_params)) => (*key_id, key_params),
391 None => {
392 return Ok((
393 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800394 AuthInfo {
395 state: DeferredAuthState::NoAuthRequired,
396 key_usage_limited: None,
397 confirmation_token_receiver: None,
398 },
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000399 ));
Qi Wub9433b52020-12-01 14:52:46 +0800400 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800401 };
402
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000403 match purpose {
404 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
405 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
406 // Rule out WRAP_KEY purpose
407 KeyPurpose::WRAP_KEY => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800408 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000409 .context(ks_err!("WRAP_KEY purpose is not allowed here.",));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000410 }
Bram Bonnéa6b83822021-01-20 11:10:05 +0100411 // Allow AGREE_KEY for EC keys only.
412 KeyPurpose::AGREE_KEY => {
413 for kp in key_params.iter() {
414 if kp.get_tag() == Tag::ALGORITHM
415 && *kp.key_parameter_value() != KeyParameterValue::Algorithm(Algorithm::EC)
416 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000417 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
418 .context(ks_err!("key agreement is only supported for EC keys.",));
Bram Bonnéa6b83822021-01-20 11:10:05 +0100419 }
420 }
421 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000422 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
423 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
424 // asymmetric keys.
425 for kp in key_params.iter() {
426 match *kp.key_parameter_value() {
427 KeyParameterValue::Algorithm(Algorithm::RSA)
428 | KeyParameterValue::Algorithm(Algorithm::EC) => {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000429 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(ks_err!(
430 "public operations on asymmetric keys are \
431 not supported."
432 ));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000433 }
434 _ => {}
435 }
436 }
437 }
438 _ => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800439 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000440 .context(ks_err!("authorize_create: specified purpose is not supported."));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000441 }
442 }
443 // The following variables are to record information from key parameters to be used in
444 // enforcements, when two or more such pieces of information are required for enforcements.
445 // There is only one additional variable than what legacy keystore has, but this helps
446 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
447 let mut key_purpose_authorized: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000448 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000449 let mut no_auth_required: bool = false;
450 let mut caller_nonce_allowed = false;
451 let mut user_id: i32 = -1;
452 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000453 let mut key_time_out: Option<i64> = None;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000454 let mut unlocked_device_required = false;
Qi Wub9433b52020-12-01 14:52:46 +0800455 let mut key_usage_limited: Option<i64> = None;
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800456 let mut confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>> = None;
Paul Crowley7c57bf12021-02-02 16:26:57 -0800457 let mut max_boot_level: Option<i32> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000458
459 // iterate through key parameters, recording information we need for authorization
460 // enforcements later, or enforcing authorizations in place, where applicable
461 for key_param in key_params.iter() {
462 match key_param.key_parameter_value() {
463 KeyParameterValue::NoAuthRequired => {
464 no_auth_required = true;
465 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000466 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000467 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000468 }
469 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000470 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000471 }
472 KeyParameterValue::KeyPurpose(p) => {
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800473 // The following check has the effect of key_params.contains(purpose)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000474 // Also, authorizing purpose can not be completed here, if there can be multiple
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800475 // key parameters for KeyPurpose.
476 key_purpose_authorized = key_purpose_authorized || *p == purpose;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000477 }
478 KeyParameterValue::CallerNonce => {
479 caller_nonce_allowed = true;
480 }
481 KeyParameterValue::ActiveDateTime(a) => {
482 if !Enforcements::is_given_time_passed(*a, true) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800483 return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000484 .context(ks_err!("key is not yet active."));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000485 }
486 }
487 KeyParameterValue::OriginationExpireDateTime(o) => {
488 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
489 && Enforcements::is_given_time_passed(*o, false)
490 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000491 return Err(Error::Km(Ec::KEY_EXPIRED)).context(ks_err!("key is expired."));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000492 }
493 }
494 KeyParameterValue::UsageExpireDateTime(u) => {
495 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
496 && Enforcements::is_given_time_passed(*u, false)
497 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000498 return Err(Error::Km(Ec::KEY_EXPIRED)).context(ks_err!("key is expired."));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000499 }
500 }
501 KeyParameterValue::UserSecureID(s) => {
502 user_secure_ids.push(*s);
503 }
504 KeyParameterValue::UserID(u) => {
505 user_id = *u;
506 }
507 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000508 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000509 }
Qi Wub9433b52020-12-01 14:52:46 +0800510 KeyParameterValue::UsageCountLimit(_) => {
511 // We don't examine the limit here because this is enforced on finish.
512 // Instead, we store the key_id so that finish can look up the key
513 // in the database again and check and update the counter.
514 key_usage_limited = Some(key_id);
515 }
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800516 KeyParameterValue::TrustedConfirmationRequired => {
517 confirmation_token_receiver = Some(self.confirmation_token_receiver.clone());
518 }
Paul Crowley7c57bf12021-02-02 16:26:57 -0800519 KeyParameterValue::MaxBootLevel(level) => {
520 max_boot_level = Some(*level);
521 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000522 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
523 // create operation if any non-allowed tags are present, is not done in
524 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800525 // a subset of non-allowed tags are present). Because sanitizing key parameters
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000526 // should have been done during generate/import key, by KeyMint.
527 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
528 }
529 }
530
531 // authorize the purpose
532 if !key_purpose_authorized {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800533 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000534 .context(ks_err!("the purpose is not authorized."));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000535 }
536
537 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
538 if !user_secure_ids.is_empty() && no_auth_required {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000539 return Err(Error::Km(Ec::INVALID_KEY_BLOB))
540 .context(ks_err!("key has both NO_AUTH_REQUIRED and USER_SECURE_ID tags."));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000541 }
542
543 // if either of auth_type or secure_id is present and the other is not present, return error
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000544 if (user_auth_type.is_some() && user_secure_ids.is_empty())
545 || (user_auth_type.is_none() && !user_secure_ids.is_empty())
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000546 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000547 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(ks_err!(
David Drysdalef8045562024-10-03 15:04:27 +0100548 "Auth required, but auth type {:?} + sids {:?} inconsistently specified",
549 user_auth_type,
550 user_secure_ids,
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000551 ));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000552 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800553
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000554 // validate caller nonce for origination purposes
555 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
556 && !caller_nonce_allowed
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800557 && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000558 {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000559 return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED))
560 .context(ks_err!("NONCE is present, although CALLER_NONCE is not present"));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000561 }
562
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000563 if unlocked_device_required {
564 // check the device locked status. If locked, operations on the key are not
565 // allowed.
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000566 if self.is_device_locked(user_id) {
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000567 return Err(Error::Km(Ec::DEVICE_LOCKED)).context(ks_err!("device is locked."));
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000568 }
569 }
570
Paul Crowley7c57bf12021-02-02 16:26:57 -0800571 if let Some(level) = max_boot_level {
Janis Danisevskis0fd25a62022-01-04 19:53:37 -0800572 if !SUPER_KEY.read().unwrap().level_accessible(level) {
Paul Crowley7c57bf12021-02-02 16:26:57 -0800573 return Err(Error::Km(Ec::BOOT_LEVEL_EXCEEDED))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000574 .context(ks_err!("boot level is too late."));
Paul Crowley7c57bf12021-02-02 16:26:57 -0800575 }
576 }
577
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000578 let (hat, state) = if user_secure_ids.is_empty() {
579 (None, DeferredAuthState::NoAuthRequired)
580 } else if let Some(key_time_out) = key_time_out {
581 let hat = Self::find_auth_token(|hat: &AuthTokenEntry| match user_auth_type {
582 Some(auth_type) => hat.satisfies(&user_secure_ids, auth_type),
583 None => false, // not reachable due to earlier check
584 })
585 .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
David Drysdalef8045562024-10-03 15:04:27 +0100586 .context(ks_err!(
587 "No suitable auth token for sids {:?} type {:?} received in last {}s found.",
588 user_secure_ids,
589 user_auth_type,
590 key_time_out
591 ))?;
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000592 let now = BootTime::now();
593 let token_age =
594 now.checked_sub(&hat.time_received()).ok_or_else(Error::sys).context(ks_err!(
David Drysdalef8045562024-10-03 15:04:27 +0100595 "Overflow while computing Auth token validity. Validity cannot be established."
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000596 ))?;
Eric Biggersb0478cf2023-10-27 03:55:29 +0000597
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000598 if token_age.seconds() > key_time_out {
David Drysdalef8045562024-10-03 15:04:27 +0100599 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(ks_err!(
600 concat!(
601 "matching auth token (challenge={}, userId={}, authId={}, ",
602 "authType={:#x}, timestamp={}ms) rcved={:?} ",
603 "for sids {:?} type {:?} is expired ({}s old > timeout={}s)"
604 ),
605 hat.auth_token().challenge,
606 hat.auth_token().userId,
607 hat.auth_token().authenticatorId,
608 hat.auth_token().authenticatorType.0,
609 hat.auth_token().timestamp.milliSeconds,
610 hat.time_received(),
611 user_secure_ids,
612 user_auth_type,
613 token_age.seconds(),
614 key_time_out
615 ));
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000616 }
617 let state = if requires_timestamp {
618 DeferredAuthState::TimeStampRequired(hat.auth_token().clone())
Eric Biggersb0478cf2023-10-27 03:55:29 +0000619 } else {
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000620 DeferredAuthState::NoAuthRequired
Eric Biggersb0478cf2023-10-27 03:55:29 +0000621 };
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000622 (Some(hat.take_auth_token()), state)
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800623 } else {
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000624 (None, DeferredAuthState::OpAuthRequired)
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800625 };
Eric Biggers9f7ebeb2024-06-20 14:59:32 +0000626 Ok((hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver }))
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800627 }
628
Eric Biggersb5613da2024-03-13 19:31:42 +0000629 fn find_auth_token<F>(p: F) -> Option<AuthTokenEntry>
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800630 where
631 F: Fn(&AuthTokenEntry) -> bool,
632 {
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700633 DB.with(|db| db.borrow().find_auth_token_entry(p))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000634 }
635
636 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
637 /// set) the given time (in milliseconds)
638 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
639 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
640
641 let time_since_epoch = match duration_since_epoch {
642 Ok(duration) => duration.as_millis(),
643 Err(_) => return false,
644 };
645
646 if is_given_time_inclusive {
647 time_since_epoch >= (given_time as u128)
648 } else {
649 time_since_epoch > (given_time as u128)
650 }
651 }
652
653 /// Check if the device is locked for the given user. If there's no entry yet for the user,
654 /// we assume that the device is locked
655 fn is_device_locked(&self, user_id: i32) -> bool {
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000656 let set = self.device_unlocked_set.lock().unwrap();
657 !set.contains(&user_id)
658 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000659
660 /// Sets the device locked status for the user. This method is called externally.
661 pub fn set_device_locked(&self, user_id: i32, device_locked_status: bool) {
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000662 let mut set = self.device_unlocked_set.lock().unwrap();
663 if device_locked_status {
664 set.remove(&user_id);
665 } else {
666 set.insert(user_id);
667 }
668 }
669
670 /// Add this auth token to the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800671 /// Then present the auth token to the op auth map. If an operation is waiting for this
672 /// auth token this fulfills the request and removes the receiver from the map.
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700673 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
674 DB.with(|db| db.borrow_mut().insert_auth_token(&hat));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800675 self.op_auth_map.add_auth_token(hat);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000676 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000677
678 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
679 /// This is to be called by create_operation, once it has received the operation challenge
680 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800681 /// by the DeferredAuthState.
682 fn register_op_auth_receiver(&self, challenge: i64, recv: TokenReceiver) {
683 self.op_auth_map.add_receiver(challenge, recv);
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000684 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000685
686 /// Given the set of key parameters and flags, check if super encryption is required.
Paul Crowley7a658392021-03-18 17:08:20 -0700687 pub fn super_encryption_required(
688 domain: &Domain,
689 key_parameters: &[KeyParameter],
690 flags: Option<i32>,
691 ) -> SuperEncryptionType {
Paul Crowley7a658392021-03-18 17:08:20 -0700692 if let Some(flags) = flags {
693 if (flags & KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING) != 0 {
694 return SuperEncryptionType::None;
695 }
696 }
Paul Crowley44c02da2021-04-08 17:04:43 +0000697 // Each answer has a priority, numerically largest priority wins.
698 struct Candidate {
699 priority: u32,
700 enc_type: SuperEncryptionType,
Paul Crowley7a658392021-03-18 17:08:20 -0700701 }
Paul Crowley44c02da2021-04-08 17:04:43 +0000702 let mut result = Candidate { priority: 0, enc_type: SuperEncryptionType::None };
703 for kp in key_parameters {
704 let t = match kp.key_parameter_value() {
705 KeyParameterValue::MaxBootLevel(level) => {
706 Candidate { priority: 3, enc_type: SuperEncryptionType::BootLevel(*level) }
707 }
708 KeyParameterValue::UnlockedDeviceRequired if *domain == Domain::APP => {
Eric Biggersb1f641d2023-10-18 01:54:18 +0000709 Candidate { priority: 2, enc_type: SuperEncryptionType::UnlockedDeviceRequired }
Paul Crowley44c02da2021-04-08 17:04:43 +0000710 }
711 KeyParameterValue::UserSecureID(_) if *domain == Domain::APP => {
Eric Biggers673d34a2023-10-18 01:54:18 +0000712 Candidate { priority: 1, enc_type: SuperEncryptionType::AfterFirstUnlock }
Paul Crowley44c02da2021-04-08 17:04:43 +0000713 }
714 _ => Candidate { priority: 0, enc_type: SuperEncryptionType::None },
715 };
716 if t.priority > result.priority {
717 result = t;
718 }
Ulyana Trafimovich229f2c02021-04-06 16:07:07 +0000719 }
Paul Crowley44c02da2021-04-08 17:04:43 +0000720 result.enc_type
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000721 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000722
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000723 /// Finds a matching auth token along with a timestamp token.
724 /// This method looks through auth-tokens cached by keystore which satisfy the given
725 /// authentication information (i.e. |secureUserId|).
726 /// The most recent matching auth token which has a |challenge| field which matches
727 /// the passed-in |challenge| parameter is returned.
728 /// In this case the |authTokenMaxAgeMillis| parameter is not used.
729 ///
730 /// Otherwise, the most recent matching auth token which is younger than |authTokenMaxAgeMillis|
731 /// is returned.
732 pub fn get_auth_tokens(
733 &self,
734 challenge: i64,
735 secure_user_id: i64,
736 auth_token_max_age_millis: i64,
737 ) -> Result<(HardwareAuthToken, TimeStampToken)> {
738 let auth_type = HardwareAuthenticatorType::ANY;
739 let sids: Vec<i64> = vec![secure_user_id];
740 // Filter the matching auth tokens by challenge
741 let result = Self::find_auth_token(|hat: &AuthTokenEntry| {
742 (challenge == hat.challenge()) && hat.satisfies(&sids, auth_type)
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700743 });
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000744
Eric Biggersb5613da2024-03-13 19:31:42 +0000745 let auth_token = if let Some(auth_token_entry) = result {
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000746 auth_token_entry.take_auth_token()
747 } else {
748 // Filter the matching auth tokens by age.
749 if auth_token_max_age_millis != 0 {
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000750 let now_in_millis = BootTime::now();
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000751 let result = Self::find_auth_token(|auth_token_entry: &AuthTokenEntry| {
752 let token_valid = now_in_millis
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000753 .checked_sub(&auth_token_entry.time_received())
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000754 .map_or(false, |token_age_in_millis| {
Hasini Gunasinghe66a24602021-05-12 19:03:12 +0000755 auth_token_max_age_millis > token_age_in_millis.milliseconds()
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000756 });
757 token_valid && auth_token_entry.satisfies(&sids, auth_type)
Matthew Maurerd7815ca2021-05-06 21:58:45 -0700758 });
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000759
Eric Biggersb5613da2024-03-13 19:31:42 +0000760 if let Some(auth_token_entry) = result {
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000761 auth_token_entry.take_auth_token()
762 } else {
763 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND))
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000764 .context(ks_err!("No auth token found."));
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000765 }
766 } else {
Hasini Gunasinghe1ce72932021-09-14 15:43:19 +0000767 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND)).context(
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000768 ks_err!(
769 "No auth token found for \
770 the given challenge and passed-in auth token max age is zero."
Hasini Gunasinghe1ce72932021-09-14 15:43:19 +0000771 ),
772 );
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000773 }
774 };
775 // Wait and obtain the timestamp token from secure clock service.
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +0000776 let tst =
777 get_timestamp_token(challenge).context(ks_err!("Error in getting timestamp token."))?;
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000778 Ok((auth_token, tst))
779 }
James Willcoxd215da82023-10-03 21:31:31 +0000780
781 /// Finds the most recent received time for an auth token that matches the given secure user id and authenticator
782 pub fn get_last_auth_time(
783 &self,
784 secure_user_id: i64,
785 auth_type: HardwareAuthenticatorType,
Eric Biggers19b3b0d2024-01-31 22:46:47 +0000786 ) -> Option<BootTime> {
James Willcoxd215da82023-10-03 21:31:31 +0000787 let sids: Vec<i64> = vec![secure_user_id];
788
789 let result =
790 Self::find_auth_token(|entry: &AuthTokenEntry| entry.satisfies(&sids, auth_type));
791
Eric Biggersb5613da2024-03-13 19:31:42 +0000792 result.map(|auth_token_entry| auth_token_entry.time_received())
James Willcoxd215da82023-10-03 21:31:31 +0000793 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000794}
795
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000796// TODO: Add tests to enforcement module (b/175578618).