Merge "Keystore 2.0: Provide confirmation token to operation."
diff --git a/keystore2/apc_compat/apc_compat.rs b/keystore2/apc_compat/apc_compat.rs
index 4391f5b..57f8710 100644
--- a/keystore2/apc_compat/apc_compat.rs
+++ b/keystore2/apc_compat/apc_compat.rs
@@ -141,6 +141,10 @@
     /// data_confirmed: Option<&[u8]> and
     /// confirmation_token: Option<&[u8]> hold the confirmed message and the confirmation token
     /// respectively. They must be `Some()` if `rc == APC_COMPAT_ERROR_OK` and `None` otherwise.
+    ///
+    /// `cb` does not get called if this function returns an error.
+    /// (Thus the allow(unused_must_use))
+    #[allow(unused_must_use)]
     pub fn prompt_user_confirmation<F>(
         &self,
         prompt_text: &str,
@@ -150,9 +154,9 @@
         cb: F,
     ) -> Result<(), u32>
     where
-        F: FnOnce(u32, Option<&[u8]>, Option<&[u8]>),
+        F: FnOnce(u32, Option<&[u8]>, Option<&[u8]>) + 'static,
     {
-        let cb_data_ptr = Box::into_raw(Box::new(Box::new(cb)));
+        let cb_data_ptr = Box::into_raw(Box::new(Box::new(cb) as Box<Callback>));
         let cb = ApcCompatCallback {
             data: cb_data_ptr as *mut std::ffi::c_void,
             result: Some(confirmation_result_callback),
diff --git a/keystore2/src/apc.rs b/keystore2/src/apc.rs
index 105e071..bdfec4e 100644
--- a/keystore2/src/apc.rs
+++ b/keystore2/src/apc.rs
@@ -12,16 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// TODO The confirmation token is yet unused.
-#![allow(unused_variables)]
-
 //! This module implements the Android Protected Confirmation (APC) service as defined
 //! in the android.security.apc AIDL spec.
 
 use std::{
     cmp::PartialEq,
     collections::HashMap,
-    sync::{Arc, Mutex},
+    sync::{mpsc::Sender, Arc, Mutex},
 };
 
 use crate::utils::{compat_2_response_code, ui_opts_2_compat};
@@ -182,10 +179,16 @@
     client_aborted: bool,
 }
 
-#[derive(Default)]
 struct ApcState {
     session: Option<ApcSessionState>,
     rate_limiting: HashMap<u32, RateInfo>,
+    confirmation_token_sender: Sender<Vec<u8>>,
+}
+
+impl ApcState {
+    fn new(confirmation_token_sender: Sender<Vec<u8>>) -> Self {
+        Self { session: None, rate_limiting: Default::default(), confirmation_token_sender }
+    }
 }
 
 /// Implementation of the APC service.
@@ -197,9 +200,11 @@
 
 impl ApcManager {
     /// Create a new instance of the Android Protected Confirmation service.
-    pub fn new_native_binder() -> Result<impl IProtectedConfirmation> {
+    pub fn new_native_binder(
+        confirmation_token_sender: Sender<Vec<u8>>,
+    ) -> Result<impl IProtectedConfirmation> {
         let result = BnProtectedConfirmation::new_binder(Self {
-            state: Arc::new(Mutex::new(Default::default())),
+            state: Arc::new(Mutex::new(ApcState::new(confirmation_token_sender))),
         });
         result.as_binder().set_requesting_sid(true);
         Ok(result)
@@ -222,21 +227,28 @@
         let rc = compat_2_response_code(rc);
 
         // Update rate limiting information.
-        match (rc, client_aborted) {
+        match (rc, client_aborted, confirmation_token) {
             // If the user confirmed the dialog.
-            (ResponseCode::OK, _) => {
+            (ResponseCode::OK, _, Some(confirmation_token)) => {
                 // Reset counter.
                 state.rate_limiting.remove(&uid);
-                // TODO at this point we need to send the confirmation token to where keystore can
-                // use it.
+                // Send confirmation token to the enforcement module.
+                if let Err(e) = state.confirmation_token_sender.send(confirmation_token.to_vec()) {
+                    log::error!("Got confirmation token, but receiver would not have it. {:?}", e);
+                }
             }
             // If cancelled by the user or if aborted by the client.
-            (ResponseCode::CANCELLED, _) | (ResponseCode::ABORTED, true) => {
+            (ResponseCode::CANCELLED, _, _) | (ResponseCode::ABORTED, true, _) => {
                 // Penalize.
                 let mut rate_info = state.rate_limiting.entry(uid).or_default();
                 rate_info.counter += 1;
                 rate_info.timestamp = start;
             }
+            (ResponseCode::OK, _, None) => {
+                log::error!(
+                    "Confirmation prompt was successful but no confirmation token was returned."
+                );
+            }
             // In any other case this try does not count at all.
             _ => {}
         }
@@ -299,7 +311,7 @@
             extra_data,
             locale,
             ui_opts,
-            |rc, data_confirmed, confirmation_token| {
+            move |rc, data_confirmed, confirmation_token| {
                 Self::result(state_clone, rc, data_confirmed, confirmation_token)
             },
         )
diff --git a/keystore2/src/enforcements.rs b/keystore2/src/enforcements.rs
index 3195ee0..bee0e4b 100644
--- a/keystore2/src/enforcements.rs
+++ b/keystore2/src/enforcements.rs
@@ -31,12 +31,15 @@
 };
 use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
 use anyhow::{Context, Result};
-use std::collections::{HashMap, HashSet};
 use std::sync::{
     mpsc::{channel, Receiver, Sender},
     Arc, Mutex, Weak,
 };
 use std::time::SystemTime;
+use std::{
+    collections::{HashMap, HashSet},
+    sync::mpsc::TryRecvError,
+};
 
 #[derive(Debug)]
 enum AuthRequestState {
@@ -133,6 +136,7 @@
     state: DeferredAuthState,
     /// An optional key id required to update the usage count if the key usage is limited.
     key_usage_limited: Option<i64>,
+    confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>>,
 }
 
 struct TokenReceiverMap {
@@ -264,8 +268,32 @@
 
     /// This function is the authorization hook called before operation finish.
     /// It returns the auth tokens required by the operation to commence finish.
-    pub fn before_finish(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
-        self.get_auth_tokens()
+    /// The third token is a confirmation token.
+    pub fn before_finish(
+        &mut self,
+    ) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>, Option<Vec<u8>>)> {
+        let mut confirmation_token: Option<Vec<u8>> = None;
+        if let Some(ref confirmation_token_receiver) = self.confirmation_token_receiver {
+            let locked_receiver = confirmation_token_receiver.lock().unwrap();
+            if let Some(ref receiver) = *locked_receiver {
+                loop {
+                    match receiver.try_recv() {
+                        // As long as we get tokens we loop and discard all but the most
+                        // recent one.
+                        Ok(t) => confirmation_token = Some(t),
+                        Err(TryRecvError::Empty) => break,
+                        Err(TryRecvError::Disconnected) => {
+                            log::error!(concat!(
+                                "We got disconnected from the APC service, ",
+                                "this should never happen."
+                            ));
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        self.get_auth_tokens().map(|(hat, tst)| (hat, tst, confirmation_token))
     }
 
     /// This function is the authorization hook called after finish succeeded.
@@ -337,6 +365,9 @@
     /// stale, because the operation gets dropped before an auth token is received, the map
     /// is cleaned up in regular intervals.
     op_auth_map: TokenReceiverMap,
+    /// The enforcement module will try to get a confirmation token from this channel whenever
+    /// an operation that requires confirmation finishes.
+    confirmation_token_receiver: Arc<Mutex<Option<Receiver<Vec<u8>>>>>,
 }
 
 impl Enforcements {
@@ -345,9 +376,20 @@
         Enforcements {
             device_unlocked_set: Mutex::new(HashSet::new()),
             op_auth_map: Default::default(),
+            confirmation_token_receiver: Default::default(),
         }
     }
 
+    /// Install the confirmation token receiver. The enforcement module will try to get a
+    /// confirmation token from this channel whenever an operation that requires confirmation
+    /// finishes.
+    pub fn install_confirmation_token_receiver(
+        &self,
+        confirmation_token_receiver: Receiver<Vec<u8>>,
+    ) {
+        *self.confirmation_token_receiver.lock().unwrap() = Some(confirmation_token_receiver);
+    }
+
     /// Checks if a create call is authorized, given key parameters and operation parameters.
     /// It returns an optional immediate auth token which can be presented to begin, and an
     /// AuthInfo object which stays with the authorized operation and is used to obtain
@@ -371,7 +413,11 @@
             None => {
                 return Ok((
                     None,
-                    AuthInfo { state: DeferredAuthState::NoAuthRequired, key_usage_limited: None },
+                    AuthInfo {
+                        state: DeferredAuthState::NoAuthRequired,
+                        key_usage_limited: None,
+                        confirmation_token_receiver: None,
+                    },
                 ))
             }
         };
@@ -431,6 +477,7 @@
         let mut allow_while_on_body = false;
         let mut unlocked_device_required = false;
         let mut key_usage_limited: Option<i64> = None;
+        let mut confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>> = None;
 
         // iterate through key parameters, recording information we need for authorization
         // enforcements later, or enforcing authorizations in place, where applicable
@@ -494,6 +541,9 @@
                     // in the database again and check and update the counter.
                     key_usage_limited = Some(key_id);
                 }
+                KeyParameterValue::TrustedConfirmationRequired => {
+                    confirmation_token_receiver = Some(self.confirmation_token_receiver.clone());
+                }
                 // 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
@@ -550,7 +600,11 @@
         if !unlocked_device_required && no_auth_required {
             return Ok((
                 None,
-                AuthInfo { state: DeferredAuthState::NoAuthRequired, key_usage_limited },
+                AuthInfo {
+                    state: DeferredAuthState::NoAuthRequired,
+                    key_usage_limited,
+                    confirmation_token_receiver,
+                },
             ));
         }
 
@@ -625,7 +679,9 @@
             (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
             (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
         })
-        .map(|(hat, state)| (hat, AuthInfo { state, key_usage_limited }))
+        .map(|(hat, state)| {
+            (hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver })
+        })
     }
 
     fn find_auth_token<F>(p: F) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index f8dba07..0fd515c 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -17,9 +17,10 @@
 use binder::Interface;
 use keystore2::apc::ApcManager;
 use keystore2::authorization::AuthorizationManager;
+use keystore2::globals::ENFORCEMENTS;
 use keystore2::service::KeystoreService;
 use log::{error, info};
-use std::{panic, path::Path};
+use std::{panic, path::Path, sync::mpsc::channel};
 
 static KS2_SERVICE_NAME: &str = "android.system.keystore2";
 static APC_SERVICE_NAME: &str = "android.security.apc";
@@ -57,6 +58,10 @@
         panic!("Must specify a working directory.");
     }
 
+    let (confirmation_token_sender, confirmation_token_receiver) = channel();
+
+    ENFORCEMENTS.install_confirmation_token_receiver(confirmation_token_receiver);
+
     info!("Starting thread pool now.");
     binder::ProcessState::start_thread_pool();
 
@@ -67,9 +72,10 @@
         panic!("Failed to register service {} because of {:?}.", KS2_SERVICE_NAME, e);
     });
 
-    let apc_service = ApcManager::new_native_binder().unwrap_or_else(|e| {
-        panic!("Failed to create service {} because of {:?}.", APC_SERVICE_NAME, e);
-    });
+    let apc_service =
+        ApcManager::new_native_binder(confirmation_token_sender).unwrap_or_else(|e| {
+            panic!("Failed to create service {} because of {:?}.", APC_SERVICE_NAME, e);
+        });
     binder::add_service(APC_SERVICE_NAME, apc_service.as_binder()).unwrap_or_else(|e| {
         panic!("Failed to register service {} because of {:?}.", APC_SERVICE_NAME, e);
     });
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 97bab77..18ea19f 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -429,18 +429,25 @@
         let km_op: Box<dyn IKeyMintOperation> =
             self.km_op.get_interface().context("In finish: Failed to get KeyMintOperation.")?;
 
-        let (hat, tst) = self
+        let (hat, tst, confirmation_token) = self
             .auth_info
             .lock()
             .unwrap()
             .before_finish()
             .context("In finish: Trying to get auth tokens.")?;
 
+        let in_params = confirmation_token.map(|token| KeyParameterArray {
+            params: vec![KmParam {
+                tag: Tag::CONFIRMATION_TOKEN,
+                value: KmParamValue::Blob(token),
+            }],
+        });
+
         let output = self
             .update_outcome(
                 &mut *outcome,
                 map_km_error(km_op.finish(
-                    None,
+                    in_params.as_ref(),
                     input,
                     signature,
                     hat.as_ref(),