Keystore 2.0: Initialize all KeyMint instances.

Test: Strongbox CTS tests on Devices sporting Strongbox.
Bug: 173546020
Change-Id: Ief1983571c8a16979ed1e0ed7e4f636ab269ce8d
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index b4cf913..7227f62 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -38,7 +38,7 @@
 use keystore2_selinux as selinux;
 
 use android_system_keystore2::binder::{
-    ExceptionCode, Result as BinderResult, Status as BinderStatus,
+    ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
 };
 
 /// This is the main Keystore error type. It wraps the Keystore `ResponseCode` generated
@@ -54,6 +54,9 @@
     /// Wraps a Binder exception code other than a service specific exception.
     #[error("Binder exception code {0:?}, {1:?}")]
     Binder(ExceptionCode, i32),
+    /// Wraps a Binder status code.
+    #[error("Binder transaction error {0:?}")]
+    BinderTransaction(StatusCode),
 }
 
 impl Error {
@@ -98,6 +101,28 @@
     })
 }
 
+/// This function is similar to map_km_error only that we don't expect
+/// any KeyMint error codes, we simply preserve the exception code and optional
+/// service specific exception.
+pub fn map_binder_status<T>(r: BinderResult<T>) -> Result<T, Error> {
+    r.map_err(|s| match s.exception_code() {
+        ExceptionCode::SERVICE_SPECIFIC => {
+            let se = s.service_specific_error();
+            Error::Binder(ExceptionCode::SERVICE_SPECIFIC, se)
+        }
+        ExceptionCode::TRANSACTION_FAILED => {
+            let e = s.transaction_error();
+            Error::BinderTransaction(e)
+        }
+        e_code => Error::Binder(e_code, 0),
+    })
+}
+
+/// This function maps a status code onto a Keystore Error.
+pub fn map_binder_status_code<T>(r: Result<T, StatusCode>) -> Result<T, Error> {
+    r.map_err(Error::BinderTransaction)
+}
+
 /// This function should be used by Keystore service calls to translate error conditions
 /// into service specific exceptions.
 ///
@@ -142,7 +167,9 @@
                 // If an Error::Binder reaches this stage we report a system error.
                 // The exception code and possible service specific error will be
                 // printed in the error log above.
-                Some(Error::Binder(_, _)) => ResponseCode::SYSTEM_ERROR.0,
+                Some(Error::Binder(_, _)) | Some(Error::BinderTransaction(_)) => {
+                    ResponseCode::SYSTEM_ERROR.0
+                }
                 None => match root_cause.downcast_ref::<selinux::Error>() {
                     Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
                     _ => ResponseCode::SYSTEM_ERROR.0,
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index eff3196..d6c2ba4 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -16,10 +16,20 @@
 //! database connections and connections to services that Keystore needs
 //! to talk to.
 
-use crate::database::KeystoreDB;
 use crate::super_key::SuperKeyManager;
+use crate::utils::Asp;
+use crate::{
+    database::KeystoreDB,
+    error::{map_binder_status_code, Error, ErrorCode},
+};
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
+};
+use anyhow::{Context, Result};
 use lazy_static::lazy_static;
 use std::cell::RefCell;
+use std::collections::HashMap;
+use std::sync::Mutex;
 
 thread_local! {
     /// Database connections are not thread safe, but connecting to the
@@ -40,4 +50,42 @@
 lazy_static! {
     /// Runtime database of unwrapped super keys.
     pub static ref SUPER_KEY: SuperKeyManager = Default::default();
+    /// Map of KeyMint devices.
+    static ref KEY_MINT_DEVICES: Mutex<HashMap<SecurityLevel, Asp>> = Default::default();
+}
+
+static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
+
+/// Make a new connection to a KeyMint device of the given security level.
+fn connect_keymint(security_level: SecurityLevel) -> Result<Asp> {
+    let service_name = match security_level {
+        SecurityLevel::TRUSTED_ENVIRONMENT => format!("{}/default", KEYMINT_SERVICE_NAME),
+        SecurityLevel::STRONGBOX => format!("{}/strongbox", KEYMINT_SERVICE_NAME),
+        _ => {
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
+                .context("In connect_keymint.")
+        }
+    };
+
+    let keymint: Box<dyn IKeyMintDevice> =
+        map_binder_status_code(binder::get_interface(&service_name))
+            .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?;
+
+    Ok(Asp::new(keymint.as_binder()))
+}
+
+/// Get a keymint device for the given security level either from our cache or
+/// by making a new connection.
+pub fn get_keymint_device(security_level: SecurityLevel) -> Result<Asp> {
+    let mut devices_map = KEY_MINT_DEVICES.lock().unwrap();
+    if let Some(dev) = devices_map.get(&security_level) {
+        Ok(dev.clone())
+    } else {
+        let dev = connect_keymint(security_level).map_err(|e| {
+            anyhow::anyhow!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
+                .context(format!("In get_keymint_device: {:?}", e))
+        })?;
+        devices_map.insert(security_level, dev.clone());
+        Ok(dev)
+    }
 }
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index a89f309..29bb9b2 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -45,7 +45,7 @@
     error::{self, map_km_error, map_or_log_err, Error, ErrorCode},
     utils::key_characteristics_to_internal,
 };
-use anyhow::{anyhow, Context, Result};
+use anyhow::{Context, Result};
 use binder::{IBinder, Interface, ThreadState};
 
 /// Implementation of the IKeystoreSecurityLevel Interface.
@@ -55,8 +55,6 @@
     operation_db: OperationDb,
 }
 
-static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
-
 // Blob of 32 zeroes used as empty masking key.
 static ZERO_BLOB_32: &[u8] = &[0; 32];
 
@@ -68,18 +66,10 @@
     pub fn new_native_binder(
         security_level: SecurityLevel,
     ) -> Result<impl IKeystoreSecurityLevel + Send> {
-        let service_name = format!("{}/default", KEYMINT_SERVICE_NAME);
-        let keymint: Box<dyn IKeyMintDevice> =
-            binder::get_interface(&service_name).map_err(|e| {
-                anyhow!(format!(
-                    "Could not get KeyMint instance: {} failed with error code {:?}",
-                    service_name, e
-                ))
-            })?;
-
         let result = BnKeystoreSecurityLevel::new_binder(Self {
             security_level,
-            keymint: Asp::new(keymint.as_binder()),
+            keymint: crate::globals::get_keymint_device(security_level)
+                .context("In KeystoreSecurityLevel::new_native_binder.")?,
             operation_db: OperationDb::new(),
         });
         result.as_binder().set_requesting_sid(true);
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index d475b7e..d185025 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -44,35 +44,55 @@
 
 /// Implementation of the IKeystoreService.
 pub struct KeystoreService {
-    sec_level: Asp,
+    sec_level_tee: Asp,
+    sec_level_strongbox: Option<Asp>,
 }
 
 impl KeystoreService {
     /// Create a new instance of the Keystore 2.0 service.
     pub fn new_native_binder() -> Result<impl IKeystoreService> {
+        let tee = KeystoreSecurityLevel::new_native_binder(SecurityLevel::TRUSTED_ENVIRONMENT)
+            .map(|tee| Asp::new(tee.as_binder()))
+            .context(concat!(
+                "In KeystoreService::new_native_binder: ",
+                "Trying to construct mendatory security level TEE."
+            ))?;
+        // Strongbox is optional, so we ignore errors and turn the result into an Option.
+        let strongbox =
+            KeystoreSecurityLevel::new_native_binder(SecurityLevel::TRUSTED_ENVIRONMENT)
+                .map(|tee| Asp::new(tee.as_binder()))
+                .ok();
+
         let result = BnKeystoreService::new_binder(Self {
-            sec_level: Asp::new({
-                let sec_level =
-                    KeystoreSecurityLevel::new_native_binder(SecurityLevel::TRUSTED_ENVIRONMENT)
-                        .context("While trying to create IKeystoreSecurityLevel")?;
-                sec_level.as_binder()
-            }),
+            sec_level_tee: tee,
+            sec_level_strongbox: strongbox,
         });
         result.as_binder().set_requesting_sid(true);
         Ok(result)
     }
 
+    fn get_security_level_internal(
+        &self,
+        security_level: SecurityLevel,
+    ) -> Result<Option<Box<dyn IKeystoreSecurityLevel>>> {
+        Ok(match (security_level, &self.sec_level_strongbox) {
+            (SecurityLevel::TRUSTED_ENVIRONMENT, _) => Some(self.sec_level_tee.get_interface().context(
+                "In get_security_level_internal: Failed to get IKeystoreSecurityLevel (TEE).",
+            )?),
+            (SecurityLevel::STRONGBOX, Some(strongbox)) => Some(strongbox.get_interface().context(
+                "In get_security_level_internal: Failed to get IKeystoreSecurityLevel (Strongbox).",
+            )?),
+            _ => None,
+        })
+    }
+
     fn get_security_level(
         &self,
         security_level: SecurityLevel,
     ) -> Result<Box<dyn IKeystoreSecurityLevel>> {
-        match security_level {
-            SecurityLevel::TRUSTED_ENVIRONMENT => self
-                .sec_level
-                .get_interface()
-                .context("In get_security_level: Failed to get IKeystoreSecurityLevel."),
-            _ => Err(anyhow!(error::Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))),
-        }
+        self.get_security_level_internal(security_level)
+            .context("In get_security_level.")?
+            .ok_or_else(|| anyhow!(error::Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)))
     }
 
     fn get_key_entry(&self, key: &KeyDescriptor) -> Result<KeyEntryResponse> {
@@ -88,13 +108,18 @@
             })
             .context("In get_key_entry, while trying to load key info.")?;
 
-        let i_sec_level = match key_entry.sec_level() {
-            SecurityLevel::TRUSTED_ENVIRONMENT => self
-                .sec_level
-                .get_interface()
-                .context("In get_key_entry: Failed to get IKeystoreSecurityLevel.")?,
-            _ => return Err(anyhow!(error::Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))),
-        };
+        let i_sec_level = self
+            .get_security_level_internal(key_entry.sec_level())
+            .context("In get_key_entry.")?
+            .ok_or_else(|| {
+                anyhow!(error::Error::sys()).context(format!(
+                    concat!(
+                        "Found key with security level {:?} ",
+                        "but no KeyMint instance of that security level."
+                    ),
+                    key_entry.sec_level()
+                ))
+            })?;
 
         Ok(KeyEntryResponse {
             iSecurityLevel: Some(i_sec_level),
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index eab9b4d..86a86dd 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -117,6 +117,13 @@
     }
 }
 
+impl Clone for Asp {
+    fn clone(&self) -> Self {
+        let lock = self.0.lock().unwrap();
+        Self(Mutex::new((*lock).clone()))
+    }
+}
+
 /// Converts a set of key characteristics as returned from KeyMint into the internal
 /// representation of the keystore service.
 /// The parameter `hw_security_level` indicates which security level shall be used for