Integrate authorizations with the operations.

Bug: 171503362, 171503128
Test: TBD
Change-Id: If12104eec4f9f32a9af4f4da8e620543ce26548d
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 1d0608e..c5b5da0 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -17,19 +17,23 @@
 //! This crate implements the IKeystoreSecurityLevel interface.
 
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
-    Algorithm::Algorithm, HardwareAuthenticatorType::HardwareAuthenticatorType,
-    IKeyMintDevice::IKeyMintDevice, KeyCreationResult::KeyCreationResult, KeyFormat::KeyFormat,
-    KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel,
-    Tag::Tag,
+    Algorithm::Algorithm, HardwareAuthToken::HardwareAuthToken,
+    HardwareAuthenticatorType::HardwareAuthenticatorType, IKeyMintDevice::IKeyMintDevice,
+    KeyCreationResult::KeyCreationResult, KeyFormat::KeyFormat, KeyParameter::KeyParameter,
+    KeyParameterValue::KeyParameterValue, SecurityLevel::SecurityLevel, Tag::Tag,
+    VerificationToken::VerificationToken,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
     AuthenticatorSpec::AuthenticatorSpec, CreateOperationResponse::CreateOperationResponse,
     Domain::Domain, IKeystoreOperation::IKeystoreOperation,
     IKeystoreSecurityLevel::BnKeystoreSecurityLevel,
     IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
-    KeyMetadata::KeyMetadata, KeyParameters::KeyParameters,
+    KeyMetadata::KeyMetadata, KeyParameters::KeyParameters, OperationChallenge::OperationChallenge,
 };
 
+use crate::auth_token_handler::AuthTokenHandler;
+use crate::globals::ENFORCEMENTS;
+use crate::key_parameter::KeyParameter as KsKeyParam;
 use crate::utils::{check_key_permission, Asp};
 use crate::{database::KeyIdGuard, globals::DB};
 use crate::{
@@ -47,6 +51,7 @@
 };
 use anyhow::{Context, Result};
 use binder::{IBinder, Interface, ThreadState};
+use std::sync::mpsc::channel;
 
 /// Implementation of the IKeystoreSecurityLevel Interface.
 pub struct KeystoreSecurityLevel {
@@ -159,7 +164,7 @@
         // so that we can use it by reference like the blob provided by the key descriptor.
         // Otherwise, we would have to clone the blob from the key descriptor.
         let scoping_blob: Vec<u8>;
-        let (km_blob, key_id_guard) = match key.domain {
+        let (km_blob, key_id_guard, key_parameters) = match key.domain {
             Domain::BLOB => {
                 check_key_permission(KeyPerm::use_(), key, &None)
                     .context("In create_operation: checking use permission for Domain::BLOB.")?;
@@ -174,6 +179,7 @@
                         }
                     },
                     None,
+                    None,
                 )
             }
             _ => {
@@ -197,14 +203,10 @@
                         ))
                     }
                 };
-                (&scoping_blob, Some(key_id_guard))
+                (&scoping_blob, Some(key_id_guard), Some(key_entry.into_key_parameters()))
             }
         };
 
-        // TODO Authorize begin operation.
-        // Check if we need an authorization token.
-        // Lookup authorization token and request VerificationToken if required.
-
         let purpose = operation_parameters.iter().find(|p| p.tag == Tag::PURPOSE).map_or(
             Err(Error::Km(ErrorCode::INVALID_ARGUMENT))
                 .context("In create_operation: No operation purpose specified."),
@@ -215,6 +217,35 @@
             },
         )?;
 
+        let mut auth_token_for_km: &HardwareAuthToken = &Default::default();
+        let mut auth_token_handler = AuthTokenHandler::NoAuthRequired;
+
+        // keystore performs authorizations only if the key parameters are loaded above
+        if let Some(ref key_params) = key_parameters {
+            // Note: although currently only one operation parameter is checked in authorizing the
+            // operation, the whole operation_parameter vector is converted into the internal
+            // representation of key parameter because we might need to sanitize operation
+            // parameters (b/175792701)
+            let mut op_params: Vec<KsKeyParam> = Vec::new();
+            for op_param in operation_parameters.iter() {
+                op_params.push(KsKeyParam::new(op_param.into(), self.security_level));
+            }
+            // authorize the operation, and receive an AuthTokenHandler, if authorized, else
+            // propagate the error
+            auth_token_handler = ENFORCEMENTS
+                .authorize_create(
+                    purpose,
+                    key_params.as_slice(),
+                    op_params.as_slice(),
+                    self.security_level,
+                )
+                .context("In create_operation.")?;
+            // if an auth token was found, pass it to keymint
+            if let Some(auth_token) = auth_token_handler.get_auth_token() {
+                auth_token_for_km = auth_token;
+            }
+        }
+
         let km_dev: Box<dyn IKeyMintDevice> = self
             .keymint
             .get_interface()
@@ -231,7 +262,7 @@
                         purpose,
                         blob,
                         &operation_parameters,
-                        &Default::default(),
+                        auth_token_for_km,
                     )) {
                         Err(Error::Km(ErrorCode::TOO_MANY_OPERATIONS)) => {
                             self.operation_db.prune(caller_uid)?;
@@ -243,8 +274,32 @@
             )
             .context("In create_operation: Failed to begin operation.")?;
 
+        let mut operation_challenge: Option<OperationChallenge> = None;
+
+        // take actions based on the authorization decision (if any) received via auth token handler
+        match auth_token_handler {
+            AuthTokenHandler::OpAuthRequired => {
+                operation_challenge =
+                    Some(OperationChallenge { challenge: begin_result.challenge });
+                ENFORCEMENTS.insert_to_op_auth_map(begin_result.challenge);
+            }
+            AuthTokenHandler::VerificationRequired(auth_token) => {
+                let (_sender, receiver) = channel::<(HardwareAuthToken, VerificationToken)>();
+                //TODO: call the worker thread and hand over the sender, auth token and challenge
+                auth_token_handler = AuthTokenHandler::Channel(receiver);
+            }
+            _ => {}
+        }
+
         let operation = match begin_result.operation {
-            Some(km_op) => self.operation_db.create_operation(km_op, caller_uid),
+            Some(km_op) => {
+                let mut op_challenge_copy: Option<OperationChallenge> = None;
+                if let Some(ref op_challenge) = operation_challenge {
+                    op_challenge_copy = Some(OperationChallenge{challenge: op_challenge.challenge});
+                }
+                self.operation_db.create_operation(km_op, caller_uid,
+                 auth_token_handler, key_parameters, op_challenge_copy)
+            },
             None => return Err(Error::sys()).context("In create_operation: Begin operation returned successfully, but did not return a valid operation."),
         };
 
@@ -258,7 +313,7 @@
         // We return None for now because we don't support auth bound keys yet.
         Ok(CreateOperationResponse {
             iOperation: Some(op_binder),
-            operationChallenge: None,
+            operationChallenge: operation_challenge,
             parameters: match begin_result.params.len() {
                 0 => None,
                 _ => Some(KeyParameters { keyParameter: begin_result.params }),