Implement authorize_create and authorize_operation.

This CL implements authorize_create and authorize_operation.
There are two TODOs in authorize_create, which will be addressed in the
upcoming CLs in the stack.

Bug: 159461976
Test: Unit tests
Change-Id: Id43abd0286ea3adce597bfe059abf4ef00568f34
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index dfd89b5..1c64833 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -22,13 +22,15 @@
 use crate::error::Error as KeystoreError;
 use crate::key_parameter::{KeyParameter, KeyParameterValue};
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-    ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
-    HardwareAuthenticatorType::HardwareAuthenticatorType,
+    Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
+    HardwareAuthenticatorType::HardwareAuthenticatorType, KeyPurpose::KeyPurpose,
+    SecurityLevel::SecurityLevel, Tag::Tag,
 };
 use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
 use anyhow::{Context, Result};
 use std::collections::{HashMap, HashSet};
 use std::sync::Mutex;
+use std::time::SystemTime;
 
 /// Enforcements data structure
 pub struct Enforcements {
@@ -129,6 +131,212 @@
         // to identify if any such keys are in use
         Ok(AuthTokenHandler::NoAuthRequired)
     }
+
+    /// Checks if a create call is authorized, given key parameters and operation parameters.
+    /// With regard to auth tokens, the following steps are taken:
+    /// If the key is time-bound, find a matching auth token from the database.
+    /// If the above step is successful, and if the security level is STRONGBOX, return a
+    /// VerificationRequired variant of the AuthTokenHandler with the found auth token to signal
+    /// the operation that it may need to obtain a verification token from TEE KeyMint.
+    /// If the security level is not STRONGBOX, return a Token variant of the AuthTokenHandler with
+    /// the found auth token to signal the operation that no more authorization required.
+    /// If the key is per-op, return an OpAuthRequired variant of the AuthTokenHandler to signal
+    /// create_operation() that it needs to add the operation challenge to the op_auth_map, once it
+    /// is received from the keymint, and that operation needs to be authorized before update/finish
+    /// is called.
+    pub fn authorize_create(
+        &self,
+        purpose: KeyPurpose,
+        key_params: &[KeyParameter],
+        op_params: &[KeyParameter],
+        // security_level will be used in the next CL
+        _security_level: SecurityLevel,
+    ) -> Result<AuthTokenHandler> {
+        match purpose {
+            // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
+            KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
+            // Rule out WRAP_KEY purpose
+            KeyPurpose::WRAP_KEY => {
+                return Err(KeystoreError::Km(Ec::INCOMPATIBLE_PURPOSE))
+                    .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
+            }
+            KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
+                // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
+                // asymmetric keys.
+                for kp in key_params.iter() {
+                    match *kp.key_parameter_value() {
+                        KeyParameterValue::Algorithm(Algorithm::RSA)
+                        | KeyParameterValue::Algorithm(Algorithm::EC) => {
+                            return Err(KeystoreError::Km(Ec::UNSUPPORTED_PURPOSE)).context(
+                                "In authorize_create: public operations on asymmetric keys are not
+                                 supported.",
+                            );
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            _ => {
+                return Err(KeystoreError::Km(Ec::UNSUPPORTED_PURPOSE))
+                    .context("In authorize_create: specified purpose is not supported.");
+            }
+        }
+        // The following variables are to record information from key parameters to be used in
+        // enforcements, when two or more such pieces of information are required for enforcements.
+        // There is only one additional variable than what legacy keystore has, but this helps
+        // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
+        let mut key_purpose_authorized: bool = false;
+        let mut is_time_out_key: bool = false;
+        let mut auth_type: Option<HardwareAuthenticatorType> = None;
+        let mut no_auth_required: bool = false;
+        let mut caller_nonce_allowed = false;
+        let mut user_id: i32 = -1;
+        let mut user_secure_ids = Vec::<i64>::new();
+
+        // iterate through key parameters, recording information we need for authorization
+        // enforcements later, or enforcing authorizations in place, where applicable
+        for key_param in key_params.iter() {
+            match key_param.key_parameter_value() {
+                KeyParameterValue::NoAuthRequired => {
+                    no_auth_required = true;
+                }
+                KeyParameterValue::AuthTimeout(_) => {
+                    is_time_out_key = true;
+                }
+                KeyParameterValue::HardwareAuthenticatorType(a) => {
+                    auth_type = Some(*a);
+                }
+                KeyParameterValue::KeyPurpose(p) => {
+                    // Note: if there can be multiple KeyPurpose key parameters (TODO: confirm this),
+                    // following check has the effect of key_params.contains(purpose)
+                    // Also, authorizing purpose can not be completed here, if there can be multiple
+                    // key parameters for KeyPurpose
+                    if !key_purpose_authorized && *p == purpose {
+                        key_purpose_authorized = true;
+                    }
+                }
+                KeyParameterValue::CallerNonce => {
+                    caller_nonce_allowed = true;
+                }
+                KeyParameterValue::ActiveDateTime(a) => {
+                    if !Enforcements::is_given_time_passed(*a, true) {
+                        return Err(KeystoreError::Km(Ec::KEY_NOT_YET_VALID))
+                            .context("In authorize_create: key is not yet active.");
+                    }
+                }
+                KeyParameterValue::OriginationExpireDateTime(o) => {
+                    if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
+                        && Enforcements::is_given_time_passed(*o, false)
+                    {
+                        return Err(KeystoreError::Km(Ec::KEY_EXPIRED))
+                            .context("In authorize_create: key is expired.");
+                    }
+                }
+                KeyParameterValue::UsageExpireDateTime(u) => {
+                    if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
+                        && Enforcements::is_given_time_passed(*u, false)
+                    {
+                        return Err(KeystoreError::Km(Ec::KEY_EXPIRED))
+                            .context("In authorize_create: key is expired.");
+                    }
+                }
+                KeyParameterValue::UserSecureID(s) => {
+                    user_secure_ids.push(*s);
+                }
+                KeyParameterValue::UserID(u) => {
+                    user_id = *u;
+                }
+                KeyParameterValue::UnlockedDeviceRequired => {
+                    // check the device locked status. If locked, operations on the key are not
+                    // allowed.
+                    if self.is_device_locked(user_id) {
+                        return Err(KeystoreError::Km(Ec::DEVICE_LOCKED))
+                            .context("In authorize_create: device is locked.");
+                    }
+                }
+                // NOTE: as per offline discussion, sanitizing key parameters and rejecting
+                // create operation if any non-allowed tags are present, is not done in
+                // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
+                // a subset of non-allowed tags are present). Because santizing key parameters
+                // should have been done during generate/import key, by KeyMint.
+                _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
+            }
+        }
+
+        // authorize the purpose
+        if !key_purpose_authorized {
+            return Err(KeystoreError::Km(Ec::INCOMPATIBLE_PURPOSE))
+                .context("In authorize_create: the purpose is not authorized.");
+        }
+
+        // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
+        if !user_secure_ids.is_empty() && no_auth_required {
+            return Err(KeystoreError::Km(Ec::INVALID_KEY_BLOB)).context(
+                "In authorize_create: key has both NO_AUTH_REQUIRED
+                and USER_SECURE_ID tags.",
+            );
+        }
+
+        // if either of auth_type or secure_id is present and the other is not present, return error
+        if (auth_type.is_some() && user_secure_ids.is_empty())
+            || (auth_type.is_none() && !user_secure_ids.is_empty())
+        {
+            return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
+                "In authorize_create: Auth required, but either auth type or secure ids
+                are not present.",
+            );
+        }
+        // validate caller nonce for origination purposes
+        if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
+            && !caller_nonce_allowed
+            && op_params.iter().any(|kp| kp.get_tag() == Tag::NONCE)
+        {
+            return Err(KeystoreError::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
+                "In authorize_create, NONCE is present,
+                    although CALLER_NONCE is not present",
+            );
+        }
+
+        if !user_secure_ids.is_empty() {
+            // per op auth token
+            if !is_time_out_key {
+                return Ok(AuthTokenHandler::OpAuthRequired);
+            } else {
+                //time out token
+                // TODO: retrieve it from the database
+                // - in an upcoming CL
+            }
+        }
+
+        // If we reach here, all authorization enforcements have passed and no auth token required.
+        Ok(AuthTokenHandler::NoAuthRequired)
+    }
+
+    /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
+    /// set) the given time (in milliseconds)
+    fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
+        let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
+
+        let time_since_epoch = match duration_since_epoch {
+            Ok(duration) => duration.as_millis(),
+            Err(_) => return false,
+        };
+
+        if is_given_time_inclusive {
+            time_since_epoch >= (given_time as u128)
+        } else {
+            time_since_epoch > (given_time as u128)
+        }
+    }
+
+    /// Check if the device is locked for the given user. If there's no entry yet for the user,
+    /// we assume that the device is locked
+    fn is_device_locked(&self, user_id: i32) -> bool {
+        // unwrap here because there's no way this mutex guard can be poisoned and
+        // because there's no way to recover, even if it is poisoned.
+        let set = self.device_unlocked_set.lock().unwrap();
+        !set.contains(&user_id)
+    }
 }
 
 impl Default for Enforcements {