Keystore 2.0: Revisit Enforcements.
This patch revisits the Keystore 2.0 enforcements module to support
KM4.1 hardware enforced device locked keys.
* Consolidate the background handler into async_task.
* The auth token handler became AuthInfo and was moved into
enforcements.rs.
* The auth token validity check moved from database.rs to
enforcements.rs.
Bug: 171503362
Test: Keystore CTS tests
Change-Id: If37d38183901b356242079af812c7a0e1e79abf3
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 8e4f800..30e6d55 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -125,23 +125,16 @@
//! or it transitions to its end-of-life, which means we may get a free slot.
//! Either way, we have to revaluate the pruning scores.
-use crate::auth_token_handler::AuthTokenHandler;
+use crate::enforcements::AuthInfo;
use crate::error::{map_km_error, map_or_log_err, Error, ErrorCode, ResponseCode};
-use crate::globals::ENFORCEMENTS;
-use crate::key_parameter::KeyParameter;
use crate::utils::Asp;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- ByteArray::ByteArray, HardwareAuthToken::HardwareAuthToken,
- IKeyMintOperation::IKeyMintOperation, KeyParameter::KeyParameter as KmParam,
- KeyParameterArray::KeyParameterArray, KeyParameterValue::KeyParameterValue as KmParamValue,
- Tag::Tag,
-};
-use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
- TimeStampToken::TimeStampToken,
+ ByteArray::ByteArray, IKeyMintOperation::IKeyMintOperation,
+ KeyParameter::KeyParameter as KmParam, KeyParameterArray::KeyParameterArray,
+ KeyParameterValue::KeyParameterValue as KmParamValue, Tag::Tag,
};
use android_system_keystore2::aidl::android::system::keystore2::{
IKeystoreOperation::BnKeystoreOperation, IKeystoreOperation::IKeystoreOperation,
- OperationChallenge::OperationChallenge,
};
use anyhow::{anyhow, Context, Result};
use binder::{IBinder, Interface};
@@ -175,11 +168,7 @@
last_usage: Mutex<Instant>,
outcome: Mutex<Outcome>,
owner: u32, // Uid of the operation's owner.
- auth_token_handler: Mutex<AuthTokenHandler>,
- // optional because in create_operation, there is a case in which we might not load
- // key parameters
- key_params: Option<Vec<KeyParameter>>,
- op_challenge: Option<OperationChallenge>,
+ auth_info: Mutex<AuthInfo>,
}
struct PruningInfo {
@@ -197,9 +186,7 @@
index: usize,
km_op: Box<dyn IKeyMintOperation>,
owner: u32,
- auth_token_handler: AuthTokenHandler,
- key_params: Option<Vec<KeyParameter>>,
- op_challenge: Option<OperationChallenge>,
+ auth_info: AuthInfo,
) -> Self {
Self {
index,
@@ -207,9 +194,7 @@
last_usage: Mutex::new(Instant::now()),
outcome: Mutex::new(Outcome::Unknown),
owner,
- auth_token_handler: Mutex::new(auth_token_handler),
- key_params,
- op_challenge,
+ auth_info: Mutex::new(auth_info),
}
}
@@ -352,15 +337,20 @@
let km_op: Box<dyn IKeyMintOperation> =
self.km_op.get_interface().context("In update: Failed to get KeyMintOperation.")?;
+ let (hat, tst) = self
+ .auth_info
+ .lock()
+ .unwrap()
+ .get_auth_tokens()
+ .context("In update_aad: Trying to get auth tokens.")?;
+
self.update_outcome(
&mut *outcome,
map_km_error(km_op.update(
Some(¶ms),
None,
- // TODO Get auth token from enforcement module if required.
- None,
- // TODO Get timestamp token from enforcement module if required.
- None,
+ hat.as_ref(),
+ tst.as_ref(),
&mut out_params,
&mut output,
)),
@@ -370,43 +360,6 @@
Ok(())
}
- /// Based on the authorization information stored in the operation during create_operation(),
- /// and any previous calls to update(), this function returns appropriate auth token and
- /// timestamp token to be passed to keymint.
- /// Note that the call to the global enforcement object happens only during the first call to
- /// update or if finish() is called right after create_opertation.
- fn handle_authorization<'a>(
- auth_token_handler: &'a mut AuthTokenHandler,
- key_params: Option<&Vec<KeyParameter>>,
- op_challenge: Option<&OperationChallenge>,
- ) -> Result<(Option<&'a HardwareAuthToken>, Option<&'a TimeStampToken>)> {
- // keystore performs authorization only if key parameters have been loaded during
- // create_operation()
- if let Some(key_parameters) = key_params {
- match *auth_token_handler {
- // this variant is found only in a first call to update or if finish is called
- // right after create_operation.
- AuthTokenHandler::OpAuthRequired => {
- *auth_token_handler = ENFORCEMENTS
- .authorize_update_or_finish(key_parameters.as_slice(), op_challenge)
- .context("In handle_authorization.")?;
- Ok((auth_token_handler.get_auth_token(), None))
- }
- // this variant is found only in a first call to update or if finish is called
- // right after create_operation.
- AuthTokenHandler::Channel(_)|
- // this variant is found in every subsequent call to update/finish,
- // unless the authorization is not required for the key
- AuthTokenHandler::Token(_, _) => {
- auth_token_handler.retrieve_auth_and_timestamp_tokens()
- }
- _ => Ok((None, None))
- }
- } else {
- Ok((None, None))
- }
- }
-
/// Implementation of `IKeystoreOperation::update`.
/// Refer to the AIDL spec at system/hardware/interfaces/keystore2 for details.
fn update(&self, input: &[u8]) -> Result<Option<Vec<u8>>> {
@@ -420,21 +373,20 @@
let km_op: Box<dyn IKeyMintOperation> =
self.km_op.get_interface().context("In update: Failed to get KeyMintOperation.")?;
- let mut auth_handler = self.auth_token_handler.lock().unwrap();
- let (auth_token_for_km, timestamp_token_for_km) = Self::handle_authorization(
- &mut auth_handler,
- self.key_params.as_ref(),
- self.op_challenge.as_ref(),
- )
- .context("In update.")?;
+ let (hat, tst) = self
+ .auth_info
+ .lock()
+ .unwrap()
+ .get_auth_tokens()
+ .context("In update: Trying to get auth tokens.")?;
self.update_outcome(
&mut *outcome,
map_km_error(km_op.update(
None,
Some(input),
- auth_token_for_km,
- timestamp_token_for_km,
+ hat.as_ref(),
+ tst.as_ref(),
&mut out_params,
&mut output,
)),
@@ -467,13 +419,12 @@
let km_op: Box<dyn IKeyMintOperation> =
self.km_op.get_interface().context("In finish: Failed to get KeyMintOperation.")?;
- let mut auth_handler = self.auth_token_handler.lock().unwrap();
- let (auth_token_for_km, timestamp_token_for_km) = Self::handle_authorization(
- &mut auth_handler,
- self.key_params.as_ref(),
- self.op_challenge.as_ref(),
- )
- .context("In finish.")?;
+ let (hat, tst) = self
+ .auth_info
+ .lock()
+ .unwrap()
+ .get_auth_tokens()
+ .context("In finish: Trying to get auth tokens.")?;
let output = self
.update_outcome(
@@ -482,8 +433,8 @@
None,
input,
signature,
- auth_token_for_km,
- timestamp_token_for_km,
+ hat.as_ref(),
+ tst.as_ref(),
&mut out_params,
)),
)
@@ -546,9 +497,7 @@
&self,
km_op: Box<dyn IKeyMintOperation>,
owner: u32,
- auth_token_handler: AuthTokenHandler,
- key_params: Option<Vec<KeyParameter>>,
- op_challenge: Option<OperationChallenge>,
+ auth_info: AuthInfo,
) -> Arc<Operation> {
// We use unwrap because we don't allow code that can panic while locked.
let mut operations = self.operations.lock().expect("In create_operation.");
@@ -561,26 +510,12 @@
s.upgrade().is_none()
}) {
Some(free_slot) => {
- let new_op = Arc::new(Operation::new(
- index - 1,
- km_op,
- owner,
- auth_token_handler,
- key_params,
- op_challenge,
- ));
+ let new_op = Arc::new(Operation::new(index - 1, km_op, owner, auth_info));
*free_slot = Arc::downgrade(&new_op);
new_op
}
None => {
- let new_op = Arc::new(Operation::new(
- operations.len(),
- km_op,
- owner,
- auth_token_handler,
- key_params,
- op_challenge,
- ));
+ let new_op = Arc::new(Operation::new(operations.len(), km_op, owner, auth_info));
operations.push(Arc::downgrade(&new_op));
new_op
}