Merge "Keystore 2.0 certificate utils: Set time by string." into sc-dev
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 89114a6..9ce2b46 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -216,9 +216,12 @@
         }
     };
 
-    let keymint = if let Some(service_name) = service_name {
-        map_binder_status_code(binder::get_interface(&service_name))
-            .context("In connect_keymint: Trying to connect to genuine KeyMint service.")
+    let (keymint, hal_version) = if let Some(service_name) = service_name {
+        (
+            map_binder_status_code(binder::get_interface(&service_name))
+                .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?,
+            Some(100i32), // The HAL version code for KeyMint V1 is 100.
+        )
     } else {
         // This is a no-op if it was called before.
         keystore2_km_compat::add_keymint_device_service();
@@ -226,21 +229,35 @@
         let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
             map_binder_status_code(binder::get_interface("android.security.compat"))
                 .context("In connect_keymint: Trying to connect to compat service.")?;
-        map_binder_status(keystore_compat_service.getKeyMintDevice(*security_level))
-            .map_err(|e| match e {
-                Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
-                    Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
-                }
-                e => e,
-            })
-            .context("In connect_keymint: Trying to get Legacy wrapper.")
-    }?;
+        (
+            map_binder_status(keystore_compat_service.getKeyMintDevice(*security_level))
+                .map_err(|e| match e {
+                    Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
+                        Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
+                    }
+                    e => e,
+                })
+                .context("In connect_keymint: Trying to get Legacy wrapper.")?,
+            None,
+        )
+    };
 
     let wp = wd::watch_millis("In connect_keymint: calling getHardwareInfo()", 500);
-    let hw_info = map_km_error(keymint.getHardwareInfo())
+    let mut hw_info = map_km_error(keymint.getHardwareInfo())
         .context("In connect_keymint: Failed to get hardware info.")?;
     drop(wp);
 
+    // The legacy wrapper sets hw_info.versionNumber to the underlying HAL version like so:
+    // 10 * <major> + <minor>, e.g., KM 3.0 = 30. So 30, 40, and 41 are the only viable values.
+    // For KeyMint the versionNumber is implementation defined and thus completely meaningless
+    // to Keystore 2.0. So at this point the versionNumber field is set to the HAL version, so
+    // that higher levels have a meaningful guide as to which feature set to expect from the
+    // implementation. As of this writing the only meaningful version number is 100 for KeyMint V1,
+    // and future AIDL versions should follow the pattern <AIDL version> * 100.
+    if let Some(hal_version) = hal_version {
+        hw_info.versionNumber = hal_version;
+    }
+
     Ok((Asp::new(keymint.as_binder()), hw_info))
 }
 
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 19576aa..f6f8bfe 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -1395,8 +1395,7 @@
         if (!device) {
             return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
         }
-        bool inserted = false;
-        std::tie(i, inserted) = mDeviceCache.insert({in_securityLevel, std::move(device)});
+        i = mDeviceCache.insert(i, {in_securityLevel, std::move(device)});
     }
     *_aidl_return = i->second;
     return ScopedAStatus::ok();
@@ -1404,14 +1403,15 @@
 
 ScopedAStatus KeystoreCompatService::getSharedSecret(KeyMintSecurityLevel in_securityLevel,
                                                      std::shared_ptr<ISharedSecret>* _aidl_return) {
-    if (!mSharedSecret) {
+    auto i = mSharedSecretCache.find(in_securityLevel);
+    if (i == mSharedSecretCache.end()) {
         auto secret = SharedSecret::createSharedSecret(in_securityLevel);
         if (!secret) {
             return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
         }
-        mSharedSecret = std::move(secret);
+        i = mSharedSecretCache.insert(i, {in_securityLevel, std::move(secret)});
     }
-    *_aidl_return = mSharedSecret;
+    *_aidl_return = i->second;
     return ScopedAStatus::ok();
 }
 
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index 09c9157..2d892da 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -197,7 +197,7 @@
 class KeystoreCompatService : public BnKeystoreCompatService {
   private:
     std::unordered_map<KeyMintSecurityLevel, std::shared_ptr<IKeyMintDevice>> mDeviceCache;
-    std::shared_ptr<ISharedSecret> mSharedSecret;
+    std::unordered_map<KeyMintSecurityLevel, std::shared_ptr<ISharedSecret>> mSharedSecretCache;
     std::shared_ptr<ISecureClock> mSecureClock;
 
   public:
diff --git a/keystore2/src/shared_secret_negotiation.rs b/keystore2/src/shared_secret_negotiation.rs
index fb55f33..64bc2c3 100644
--- a/keystore2/src/shared_secret_negotiation.rs
+++ b/keystore2/src/shared_secret_negotiation.rs
@@ -24,6 +24,7 @@
 use anyhow::{Context, Result};
 use keystore2_vintf::{get_aidl_instances, get_hidl_instances};
 use std::fmt::{self, Display, Formatter};
+use std::time::Duration;
 
 /// This function initiates the shared secret negotiation. It starts a thread and then returns
 /// immediately. The thread consults the vintf manifest to enumerate expected negotiation
@@ -109,7 +110,11 @@
 
 /// Lists participants.
 fn list_participants() -> Result<Vec<SharedSecretParticipant>> {
-    Ok([(4, 0), (4, 1)]
+    // 4.1 implementation always also register as 4.0. So only the highest version of each
+    // "default" and "strongbox" makes the cut.
+    let mut legacy_default_found: bool = false;
+    let mut legacy_strongbox_found: bool = false;
+    Ok([(4, 1), (4, 0)]
         .iter()
         .map(|(ma, mi)| {
             get_hidl_instances(KEYMASTER_PACKAGE_NAME, *ma, *mi, KEYMASTER_INTERFACE_NAME)
@@ -119,7 +124,24 @@
                     instances
                         .into_iter()
                         .filter_map(|name| {
-                            filter_map_legacy_km_instances(name.to_string(), (*ma, *mi))
+                            filter_map_legacy_km_instances(name.to_string(), (*ma, *mi)).and_then(
+                                |sp| {
+                                    if let SharedSecretParticipant::Hidl {
+                                        is_strongbox: true,
+                                        ..
+                                    } = &sp
+                                    {
+                                        if !legacy_strongbox_found {
+                                            legacy_strongbox_found = true;
+                                            return Some(sp);
+                                        }
+                                    } else if !legacy_default_found {
+                                        legacy_default_found = true;
+                                        return Some(sp);
+                                    }
+                                    None
+                                },
+                            )
                         })
                         .collect::<Vec<SharedSecretParticipant>>()
                 })
@@ -215,7 +237,7 @@
         if participants.is_empty() {
             break;
         }
-        std::thread::sleep(std::time::Duration::from_millis(1000));
+        std::thread::sleep(Duration::from_millis(1000));
     }
     connected_participants
 }
@@ -237,7 +259,7 @@
             Err(e) => {
                 log::warn!("{:?}", e);
                 log::warn!("Retrying in one second.");
-                std::thread::sleep(std::time::Duration::from_millis(1000));
+                std::thread::sleep(Duration::from_millis(1000));
             }
             Ok(params) => break params,
         }
@@ -246,20 +268,28 @@
     params.sort_unstable();
 
     // Phase 2: Send the sorted sharing parameters to all participants.
-    participants
-        .into_iter()
-        .try_fold(None, |acc, (s, p)| {
-            match (acc, map_binder_status(s.computeSharedSecret(&params))) {
-                (None, Ok(new_sum)) => Ok(Some(new_sum)),
-                (Some(old_sum), Ok(new_sum)) => {
-                    if old_sum == new_sum {
-                        Ok(Some(old_sum))
-                    } else {
-                        Err(SharedSecretError::Checksum(p))
-                    }
+    let negotiation_result = participants.into_iter().try_fold(None, |acc, (s, p)| {
+        match (acc, map_binder_status(s.computeSharedSecret(&params))) {
+            (None, Ok(new_sum)) => Ok(Some(new_sum)),
+            (Some(old_sum), Ok(new_sum)) => {
+                if old_sum == new_sum {
+                    Ok(Some(old_sum))
+                } else {
+                    Err(SharedSecretError::Checksum(p))
                 }
-                (_, Err(e)) => Err(SharedSecretError::Computation { e, p }),
             }
-        })
-        .expect("Fatal: Shared secret computation failed.");
+            (_, Err(e)) => Err(SharedSecretError::Computation { e, p }),
+        }
+    });
+
+    if let Err(e) = negotiation_result {
+        log::error!("In negotiate_shared_secret: {:?}.", e);
+        if let SharedSecretError::Checksum(_) = e {
+            log::error!(concat!(
+                "This means that this device is NOT PROVISIONED CORRECTLY.\n",
+                "User authorization and other security functions will not work\n",
+                "as expected. Please contact your OEM for instructions.",
+            ));
+        }
+    }
 }