blob: 4ff3950d123706030cb3916625121efc7b355110 [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.
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000017use crate::auth_token_handler::AuthTokenHandler;
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000018use crate::background_task_handler::Message;
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000019use crate::database::AuthTokenEntry;
20use crate::error::Error as KeystoreError;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +000021use crate::globals::DB;
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000022use crate::key_parameter::{KeyParameter, KeyParameterValue};
23use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000024 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
25 HardwareAuthenticatorType::HardwareAuthenticatorType, KeyPurpose::KeyPurpose,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080026 SecurityLevel::SecurityLevel, Tag::Tag,
27};
28use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
29 TimeStampToken::TimeStampToken, Timestamp::Timestamp,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000030};
31use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
32use anyhow::{Context, Result};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000033use std::collections::{HashMap, HashSet};
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000034use std::sync::mpsc::{channel, Sender};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000035use std::sync::Mutex;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000036use std::time::SystemTime;
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000037
38/// Enforcements data structure
39pub struct Enforcements {
40 // This hash set contains the user ids for whom the device is currently unlocked. If a user id
41 // is not in the set, it implies that the device is locked for the user.
42 device_unlocked_set: Mutex<HashSet<i32>>,
43 // This maps the operation challenge to an optional auth token, to maintain op-auth tokens
44 // in-memory, until they are picked up and given to the operation by authorise_update_finish().
45 op_auth_map: Mutex<HashMap<i64, Option<HardwareAuthToken>>>,
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000046 // sender end of the channel via which the enforcement module communicates with the
47 // background task handler (bth). This is of type Mutex in an Option because it is initialized
48 // after the global enforcement object is created.
49 sender_to_bth: Mutex<Option<Sender<Message>>>,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000050}
51
52impl Enforcements {
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000053 /// Creates an enforcement object with the two data structures it holds and the sender as None.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000054 pub fn new() -> Self {
55 Enforcements {
56 device_unlocked_set: Mutex::new(HashSet::new()),
57 op_auth_map: Mutex::new(HashMap::new()),
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000058 sender_to_bth: Mutex::new(None),
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000059 }
60 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000061
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +000062 /// Initialize the sender_to_bth field, using the given sender end of a channel.
63 pub fn set_sender_to_bth(&self, sender: Sender<Message>) {
64 // It is ok to unwrap here because there is no chance of poisoning this mutex.
65 let mut sender_guard = self.sender_to_bth.lock().unwrap();
66 *sender_guard = Some(sender);
67 }
68
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000069 /// Checks if update or finish calls are authorized. If the operation is based on per-op key,
70 /// try to receive the auth token from the op_auth_map. We assume that by the time update/finish
71 /// is called, the auth token has been delivered to keystore. Therefore, we do not wait for it
72 /// and if the auth token is not found in the map, an error is returned.
Hasini Gunasinghe888dd352020-11-17 23:08:39 +000073 /// This method is called only during the first call to update or if finish is called right
74 /// after create operation, because the operation caches the authorization decisions and tokens
75 /// from previous calls to enforcement module.
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000076 pub fn authorize_update_or_finish(
77 &self,
78 key_params: &[KeyParameter],
Hasini Gunasinghe888dd352020-11-17 23:08:39 +000079 op_challenge: Option<&OperationChallenge>,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000080 ) -> Result<AuthTokenHandler> {
81 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
82 let mut user_secure_ids = Vec::<i64>::new();
83 let mut is_timeout_key = false;
84
85 for key_param in key_params.iter() {
86 match key_param.key_parameter_value() {
87 KeyParameterValue::NoAuthRequired => {
88 // unlike in authorize_create, we do not check if both NoAuthRequired and user
89 // secure id are present, because that is already checked in authorize_create.
90 return Ok(AuthTokenHandler::NoAuthRequired);
91 }
92 KeyParameterValue::AuthTimeout(_) => {
93 is_timeout_key = true;
94 }
95 KeyParameterValue::HardwareAuthenticatorType(a) => {
96 user_auth_type = Some(*a);
97 }
98 KeyParameterValue::UserSecureID(u) => {
99 user_secure_ids.push(*u);
100 }
101 _ => {}
102 }
103 }
104
105 // If either of auth_type or secure_id is present and the other is not present,
106 // authorize_create would have already returned error.
107 // At this point, if UserSecureID is present and AuthTimeout is not present in
108 // key parameters, per-op auth is required.
109 // Obtain and validate the auth token.
110 if !is_timeout_key && !user_secure_ids.is_empty() {
111 let challenge =
112 op_challenge.ok_or(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
113 "In authorize_update_or_finish: Auth required, but operation challenge is not
114 present.",
115 )?;
116 let auth_type =
117 user_auth_type.ok_or(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
118 "In authorize_update_or_finish: Auth required, but authenticator type is not
119 present.",
120 )?;
121 // It is ok to unwrap here, because there is no way this lock can get poisoned and
122 // and there is no way to recover if it is poisoned.
123 let mut op_auth_map_guard = self.op_auth_map.lock().unwrap();
124 let auth_entry = op_auth_map_guard.remove(&(challenge.challenge));
125
126 match auth_entry {
127 Some(Some(auth_token)) => {
128 if AuthTokenEntry::satisfies_auth(&auth_token, &user_secure_ids, auth_type) {
129 return Ok(AuthTokenHandler::Token(auth_token, None));
130 } else {
131 return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
132 .context("In authorize_update_or_finish: Auth token does not match.");
133 }
134 }
135 _ => {
136 // there was no auth token
137 return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
138 "In authorize_update_or_finish: Auth required, but an auth token
139 is not found for the given operation challenge, in the op_auth_map.",
140 );
141 }
142 }
143 }
144
145 // If we don't find HardwareAuthenticatorType and UserSecureID, we assume that
146 // authentication is not required, because in legacy keys, authentication related
147 // key parameters may not present.
148 // TODO: METRICS: count how many times (if any) this code path is executed, in order
149 // to identify if any such keys are in use
150 Ok(AuthTokenHandler::NoAuthRequired)
151 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000152
153 /// Checks if a create call is authorized, given key parameters and operation parameters.
154 /// With regard to auth tokens, the following steps are taken:
155 /// If the key is time-bound, find a matching auth token from the database.
156 /// If the above step is successful, and if the security level is STRONGBOX, return a
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800157 /// TimestampRequired variant of the AuthTokenHandler with the found auth token to signal
158 /// the operation that it may need to obtain a timestamp token from TEE KeyMint.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000159 /// If the security level is not STRONGBOX, return a Token variant of the AuthTokenHandler with
160 /// the found auth token to signal the operation that no more authorization required.
161 /// If the key is per-op, return an OpAuthRequired variant of the AuthTokenHandler to signal
162 /// create_operation() that it needs to add the operation challenge to the op_auth_map, once it
163 /// is received from the keymint, and that operation needs to be authorized before update/finish
164 /// is called.
165 pub fn authorize_create(
166 &self,
167 purpose: KeyPurpose,
168 key_params: &[KeyParameter],
169 op_params: &[KeyParameter],
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000170 security_level: SecurityLevel,
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000171 ) -> Result<AuthTokenHandler> {
172 match purpose {
173 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
174 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
175 // Rule out WRAP_KEY purpose
176 KeyPurpose::WRAP_KEY => {
177 return Err(KeystoreError::Km(Ec::INCOMPATIBLE_PURPOSE))
178 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
179 }
180 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
181 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
182 // asymmetric keys.
183 for kp in key_params.iter() {
184 match *kp.key_parameter_value() {
185 KeyParameterValue::Algorithm(Algorithm::RSA)
186 | KeyParameterValue::Algorithm(Algorithm::EC) => {
187 return Err(KeystoreError::Km(Ec::UNSUPPORTED_PURPOSE)).context(
188 "In authorize_create: public operations on asymmetric keys are not
189 supported.",
190 );
191 }
192 _ => {}
193 }
194 }
195 }
196 _ => {
197 return Err(KeystoreError::Km(Ec::UNSUPPORTED_PURPOSE))
198 .context("In authorize_create: specified purpose is not supported.");
199 }
200 }
201 // The following variables are to record information from key parameters to be used in
202 // enforcements, when two or more such pieces of information are required for enforcements.
203 // There is only one additional variable than what legacy keystore has, but this helps
204 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
205 let mut key_purpose_authorized: bool = false;
206 let mut is_time_out_key: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000207 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000208 let mut no_auth_required: bool = false;
209 let mut caller_nonce_allowed = false;
210 let mut user_id: i32 = -1;
211 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000212 let mut key_time_out: Option<i64> = None;
213 let mut allow_while_on_body = false;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000214 let mut unlocked_device_required = false;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000215
216 // iterate through key parameters, recording information we need for authorization
217 // enforcements later, or enforcing authorizations in place, where applicable
218 for key_param in key_params.iter() {
219 match key_param.key_parameter_value() {
220 KeyParameterValue::NoAuthRequired => {
221 no_auth_required = true;
222 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000223 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000224 is_time_out_key = true;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000225 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000226 }
227 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000228 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000229 }
230 KeyParameterValue::KeyPurpose(p) => {
231 // Note: if there can be multiple KeyPurpose key parameters (TODO: confirm this),
232 // following check has the effect of key_params.contains(purpose)
233 // Also, authorizing purpose can not be completed here, if there can be multiple
234 // key parameters for KeyPurpose
235 if !key_purpose_authorized && *p == purpose {
236 key_purpose_authorized = true;
237 }
238 }
239 KeyParameterValue::CallerNonce => {
240 caller_nonce_allowed = true;
241 }
242 KeyParameterValue::ActiveDateTime(a) => {
243 if !Enforcements::is_given_time_passed(*a, true) {
244 return Err(KeystoreError::Km(Ec::KEY_NOT_YET_VALID))
245 .context("In authorize_create: key is not yet active.");
246 }
247 }
248 KeyParameterValue::OriginationExpireDateTime(o) => {
249 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
250 && Enforcements::is_given_time_passed(*o, false)
251 {
252 return Err(KeystoreError::Km(Ec::KEY_EXPIRED))
253 .context("In authorize_create: key is expired.");
254 }
255 }
256 KeyParameterValue::UsageExpireDateTime(u) => {
257 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
258 && Enforcements::is_given_time_passed(*u, false)
259 {
260 return Err(KeystoreError::Km(Ec::KEY_EXPIRED))
261 .context("In authorize_create: key is expired.");
262 }
263 }
264 KeyParameterValue::UserSecureID(s) => {
265 user_secure_ids.push(*s);
266 }
267 KeyParameterValue::UserID(u) => {
268 user_id = *u;
269 }
270 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000271 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000272 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000273 KeyParameterValue::AllowWhileOnBody => {
274 allow_while_on_body = true;
275 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000276 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
277 // create operation if any non-allowed tags are present, is not done in
278 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
279 // a subset of non-allowed tags are present). Because santizing key parameters
280 // should have been done during generate/import key, by KeyMint.
281 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
282 }
283 }
284
285 // authorize the purpose
286 if !key_purpose_authorized {
287 return Err(KeystoreError::Km(Ec::INCOMPATIBLE_PURPOSE))
288 .context("In authorize_create: the purpose is not authorized.");
289 }
290
291 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
292 if !user_secure_ids.is_empty() && no_auth_required {
293 return Err(KeystoreError::Km(Ec::INVALID_KEY_BLOB)).context(
294 "In authorize_create: key has both NO_AUTH_REQUIRED
295 and USER_SECURE_ID tags.",
296 );
297 }
298
299 // 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 +0000300 if (user_auth_type.is_some() && user_secure_ids.is_empty())
301 || (user_auth_type.is_none() && !user_secure_ids.is_empty())
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000302 {
303 return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
304 "In authorize_create: Auth required, but either auth type or secure ids
305 are not present.",
306 );
307 }
308 // validate caller nonce for origination purposes
309 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
310 && !caller_nonce_allowed
311 && op_params.iter().any(|kp| kp.get_tag() == Tag::NONCE)
312 {
313 return Err(KeystoreError::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
314 "In authorize_create, NONCE is present,
315 although CALLER_NONCE is not present",
316 );
317 }
318
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000319 if unlocked_device_required {
320 // check the device locked status. If locked, operations on the key are not
321 // allowed.
322 log::info!("Checking for lockd device of user {}.", user_id);
323 if self.is_device_locked(user_id) {
324 return Err(KeystoreError::Km(Ec::DEVICE_LOCKED))
325 .context("In authorize_create: device is locked.");
326 }
327 }
328
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000329 if !user_secure_ids.is_empty() {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000330 // key requiring authentication per operation
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000331 if !is_time_out_key {
332 return Ok(AuthTokenHandler::OpAuthRequired);
333 } else {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000334 // key requiring time-out based authentication
335 let auth_token = DB
336 .with::<_, Result<HardwareAuthToken>>(|db| {
337 let mut db = db.borrow_mut();
338 match (user_auth_type, key_time_out) {
339 (Some(auth_type), Some(key_time_out)) => {
340 let matching_entry = db
341 .find_timed_auth_token_entry(
342 &user_secure_ids,
343 auth_type,
344 key_time_out,
345 allow_while_on_body,
346 )
347 .context("Failed to find timed auth token.")?;
348 Ok(matching_entry.get_auth_token())
349 }
350 (_, _) => Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
351 .context("Authenticator type and/or key time out is not given."),
352 }
353 })
354 .context("In authorize_create.")?;
355
356 if security_level == SecurityLevel::STRONGBOX {
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800357 return Ok(AuthTokenHandler::TimestampRequired(auth_token));
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000358 } else {
359 return Ok(AuthTokenHandler::Token(auth_token, None));
360 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000361 }
362 }
363
364 // If we reach here, all authorization enforcements have passed and no auth token required.
365 Ok(AuthTokenHandler::NoAuthRequired)
366 }
367
368 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
369 /// set) the given time (in milliseconds)
370 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
371 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
372
373 let time_since_epoch = match duration_since_epoch {
374 Ok(duration) => duration.as_millis(),
375 Err(_) => return false,
376 };
377
378 if is_given_time_inclusive {
379 time_since_epoch >= (given_time as u128)
380 } else {
381 time_since_epoch > (given_time as u128)
382 }
383 }
384
385 /// Check if the device is locked for the given user. If there's no entry yet for the user,
386 /// we assume that the device is locked
387 fn is_device_locked(&self, user_id: i32) -> bool {
388 // unwrap here because there's no way this mutex guard can be poisoned and
389 // because there's no way to recover, even if it is poisoned.
390 let set = self.device_unlocked_set.lock().unwrap();
391 !set.contains(&user_id)
392 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000393
394 /// Sets the device locked status for the user. This method is called externally.
395 pub fn set_device_locked(&self, user_id: i32, device_locked_status: bool) {
396 // unwrap here because there's no way this mutex guard can be poisoned and
397 // because there's no way to recover, even if it is poisoned.
398 let mut set = self.device_unlocked_set.lock().unwrap();
399 if device_locked_status {
400 set.remove(&user_id);
401 } else {
402 set.insert(user_id);
403 }
404 }
405
406 /// Add this auth token to the database.
407 /// Then check if there is an entry in the op_auth_map, indexed by the challenge of this
408 /// auth token (which could have been inserted during create_operation of an operation on a
409 /// per-op-auth key). If so, add a copy of this auth token to the map indexed by the
410 /// challenge.
411 pub fn add_auth_token(&self, auth_token: HardwareAuthToken) -> Result<()> {
412 //it is ok to unwrap here, because there is no way this lock can get poisoned and
413 //and there is no way to recover if it is poisoned.
414 let mut op_auth_map_guard = self.op_auth_map.lock().unwrap();
415
416 if op_auth_map_guard.contains_key(&auth_token.challenge) {
417 let auth_token_copy = HardwareAuthToken {
418 challenge: auth_token.challenge,
419 userId: auth_token.userId,
420 authenticatorId: auth_token.authenticatorId,
421 authenticatorType: HardwareAuthenticatorType(auth_token.authenticatorType.0),
422 timestamp: Timestamp { milliSeconds: auth_token.timestamp.milliSeconds },
423 mac: auth_token.mac.clone(),
424 };
425 op_auth_map_guard.insert(auth_token.challenge, Some(auth_token_copy));
426 }
427
428 DB.with(|db| db.borrow_mut().insert_auth_token(&auth_token))
429 .context("In add_auth_token.")?;
430 Ok(())
431 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000432
433 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
434 /// This is to be called by create_operation, once it has received the operation challenge
435 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
436 /// by the AuthTokenHandler.
437 pub fn insert_to_op_auth_map(&self, op_challenge: i64) {
438 let mut op_auth_map_guard = self.op_auth_map.lock().unwrap();
439 op_auth_map_guard.insert(op_challenge, None);
440 }
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000441
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800442 /// Requests a timestamp token from the background task handler which will retrieve it from
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000443 /// Timestamp Service or TEE KeyMint.
444 /// Once the create_operation receives an operation challenge from KeyMint, if it has
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800445 /// previously received a TimestampRequired variant of AuthTokenHandler during
446 /// authorize_create_operation, it calls this method to obtain a TimeStampToken.
447 pub fn request_timestamp_token(
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000448 &self,
449 auth_token: HardwareAuthToken,
450 op_challenge: OperationChallenge,
451 ) -> Result<AuthTokenHandler> {
452 // create a channel for this particular operation
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800453 let (op_sender, op_receiver) = channel::<(HardwareAuthToken, TimeStampToken)>();
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000454 // it is ok to unwrap here because there is no way this mutex gets poisoned.
455 let sender_guard = self.sender_to_bth.lock().unwrap();
456 if let Some(sender) = &*sender_guard {
457 let sender_cloned = sender.clone();
458 drop(sender_guard);
459 sender_cloned
460 .send(Message::Inputs((auth_token, op_challenge, op_sender)))
461 .map_err(|_| KeystoreError::sys())
462 .context(
Janis Danisevskisc3a496b2021-01-05 10:37:22 -0800463 "In request_timestamp_token. Sending a request for a timestamp token
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000464 failed.",
465 )?;
466 }
467 Ok(AuthTokenHandler::Channel(op_receiver))
468 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000469}
470
471impl Default for Enforcements {
472 fn default() -> Self {
473 Self::new()
474 }
475}
476
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000477impl Drop for Enforcements {
478 fn drop(&mut self) {
479 let sender_guard = self.sender_to_bth.lock().unwrap();
480 if let Some(sender) = &*sender_guard {
481 let sender_cloned = sender.clone();
482 drop(sender_guard);
483 // TODO: Verify how best to handle the error in this case.
484 sender_cloned.send(Message::Shutdown).unwrap_or_else(|e| {
485 panic!(
486 "Failed to send shutdown message to background task handler because of {:?}.",
487 e
488 );
489 });
490 }
491 }
492}
493
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000494// TODO: Add tests to enforcement module (b/175578618).