Implement a back-level KeyMint compatibility wrapper

 - Implement a general back-level KeyMint wrapper, which forwards
   requests to either a back-level real device, or an up-level
   software device. Keyblobs from the latter are given a marker
   prefix and an authentication suffix.
 - Add an FFI wrapper function to allow calculation of HMAC-SHA256,
   so this can be used to give an authenticated suffix to wrapped
   keyblobs.
 - Abstract out the decision process for whether emulation is required
   to a EmulationDetector trait, and provide implementations for
   KeyMint V1 and for a km_compat-wrapped Keymaster.
 - Impose the KeyMint V1 wrapper whenever the real device is detected to
   be a V1 implementation.
 - Add support to the IKeystoreCompatService for returning a device for
   SecurityLevel::SOFTWARE. This device will always be the most recent
   KeyMint version.
 - Clarify what level of IKeyMint implementation gets returned from
   the IKeystoreCompatService for the other security levels.
 - Add an inner function to the km_compat code to allow unit tests
   to still work.

Co-authored-by: Janis Danisevskis <jdanis@google.com>
Bug: 194358913
Test: CtsKeystoreTestCases on oriole/bramble/cuttlefish
Change-Id: I297e8ad1cf00fd15cd5358b2760cd2ca88f53abb
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 7028aae..e8f3ff9 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -27,6 +27,7 @@
     database::Uuid,
     error::{map_binder_status, map_binder_status_code, Error, ErrorCode},
 };
+use crate::km_compat::{KeyMintV1, BacklevelKeyMintWrapper};
 use crate::{enforcements::Enforcements, error::map_km_error};
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     IKeyMintDevice::IKeyMintDevice, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
@@ -197,14 +198,15 @@
 
 static KEYMINT_SERVICE_NAME: &str = "android.hardware.security.keymint.IKeyMintDevice";
 
-/// Make a new connection to a KeyMint device of the given security level.
-/// If no native KeyMint device can be found this function also brings
-/// up the compatibility service and attempts to connect to the legacy wrapper.
-fn connect_keymint(
+/// Determine the service name for a KeyMint device of the given security level
+/// which implements at least the specified version of the `IKeyMintDevice`
+/// interface.
+fn keymint_service_name_by_version(
     security_level: &SecurityLevel,
-) -> Result<(Strong<dyn IKeyMintDevice>, KeyMintHardwareInfo)> {
+    version: i32,
+) -> Result<Option<(i32, String)>> {
     let keymint_instances =
-        get_aidl_instances("android.hardware.security.keymint", 1, "IKeyMintDevice");
+        get_aidl_instances("android.hardware.security.keymint", version as usize, "IKeyMintDevice");
 
     let service_name = match *security_level {
         SecurityLevel::TRUSTED_ENVIRONMENT => {
@@ -222,12 +224,36 @@
             }
         }
         _ => {
-            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
-                .context("In connect_keymint.")
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(format!(
+                "In keymint_service_name_by_version: Trying to find keymint V{} for security level: {:?}",
+                version, security_level
+            ));
         }
     };
 
-    let (keymint, hal_version) = if let Some(service_name) = service_name {
+    Ok(service_name.map(|service_name| (version, service_name)))
+}
+
+/// Make a new connection to a KeyMint device of the given security level.
+/// If no native KeyMint device can be found this function also brings
+/// up the compatibility service and attempts to connect to the legacy wrapper.
+fn connect_keymint(
+    security_level: &SecurityLevel,
+) -> Result<(Strong<dyn IKeyMintDevice>, KeyMintHardwareInfo)> {
+    // Count down from the current interface version back to one in order to
+    // also find out the interface version -- an implementation of V2 will show
+    // up in the list of V1-capable devices, but not vice-versa.
+    let service_name = keymint_service_name_by_version(security_level, 2)
+        .and_then(|sl| {
+            if sl.is_none() {
+                keymint_service_name_by_version(security_level, 1)
+            } else {
+                Ok(sl)
+            }
+        })
+        .context("In connect_keymint.")?;
+
+    let (keymint, hal_version) = if let Some((version, service_name)) = service_name {
         let km: Strong<dyn IKeyMintDevice> =
             map_binder_status_code(binder::get_interface(&service_name))
                 .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?;
@@ -235,11 +261,7 @@
         // - V1 is 100
         // - V2 is 200
         // etc.
-        let hal_version = km
-            .getInterfaceVersion()
-            .map(|v| v * 100i32)
-            .context("In connect_keymint: Trying to determine KeyMint AIDL version")?;
-        (km, Some(hal_version))
+        (km, Some(version * 100))
     } else {
         // This is a no-op if it was called before.
         keystore2_km_compat::add_keymint_device_service();
@@ -260,6 +282,48 @@
         )
     };
 
+    // If the KeyMint device is back-level, use a wrapper that intercepts and
+    // emulates things that are not supported by the hardware.
+    let keymint = match hal_version {
+        Some(200) => {
+            // Current KeyMint version: use as-is.
+            log::info!(
+                "KeyMint device is current version ({:?}) for security level: {:?}",
+                hal_version,
+                security_level
+            );
+            keymint
+        }
+        Some(100) => {
+            // KeyMint v1: perform software emulation.
+            log::info!(
+                "Add emulation wrapper around {:?} device for security level: {:?}",
+                hal_version,
+                security_level
+            );
+            BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint)
+                .context("In connect_keymint: Trying to create V1 compatibility wrapper.")?
+        }
+        None => {
+            // Compatibility wrapper around a KeyMaster device: this roughly
+            // behaves like KeyMint V1 (e.g. it includes AGREE_KEY support,
+            // albeit in software.)
+            log::info!(
+                "Add emulation wrapper around Keymaster device for security level: {:?}",
+                security_level
+            );
+            BacklevelKeyMintWrapper::wrap(KeyMintV1::new(*security_level), keymint).context(
+                "In connect_keymint: Trying to create km_compat V1 compatibility wrapper .",
+            )?
+        }
+        _ => {
+            return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)).context(format!(
+                "In connect_keymint: unexpected hal_version {:?} for security level: {:?}",
+                hal_version, security_level
+            ))
+        }
+    };
+
     let wp = wd::watch_millis("In connect_keymint: calling getHardwareInfo()", 500);
     let mut hw_info = map_km_error(keymint.getHardwareInfo())
         .context("In connect_keymint: Failed to get hardware info.")?;