Add compatibility wrappers for ISecureClock and ISharedSecret

Test: keystore2_km_compat_test
Change-Id: I0a5361e36298b6d240818dc83f4210f9ecb213af
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index 696f38e..3fd0580 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -62,7 +62,11 @@
 aidl_interface {
     name: "android.security.compat",
     srcs: [ "android/security/compat/*.aidl" ],
-    imports: [ "android.hardware.security.keymint" ],
+    imports: [
+        "android.hardware.security.keymint",
+        "android.hardware.security.secureclock",
+        "android.hardware.security.sharedsecret",
+    ],
     unstable: true,
     backend: {
         java: {
diff --git a/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl b/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl
index 6a72c75..4b6a93b 100644
--- a/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl
+++ b/keystore2/aidl/android/security/compat/IKeystoreCompatService.aidl
@@ -18,11 +18,30 @@
 
 import android.hardware.security.keymint.IKeyMintDevice;
 import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.secureclock.ISecureClock;
+import android.hardware.security.sharedsecret.ISharedSecret;
 
 /**
+ * The compatibility service allows Keystore 2.0 to connect to legacy wrapper implementations that
+ * it hosts itself without registering them as a service. Keystore 2.0 would not be allowed to
+ * register a HAL service, so instead it registers this service which it can then connect to.
  */
 interface IKeystoreCompatService {
     /**
+     * Return an implementation of IKeyMintDevice, that it implemented by Keystore 2.0 itself
+     * by means of Keymaster 4.1 or lower.
      */
     IKeyMintDevice getKeyMintDevice (SecurityLevel securityLevel);
+
+    /**
+     * Returns an implementation of ISecureClock, that is implemented by Keystore 2.0 itself
+     * by means of Keymaster 4.x.
+     */
+    ISecureClock getSecureClock ();
+
+    /**
+     * Returns an implementation of ISharedSecret, that is implemented by Keystore 2.0 itself
+     * by means of Keymaster 4.x.
+     */
+    ISharedSecret getSharedSecret (SecurityLevel securityLevel);
 }
diff --git a/keystore2/src/km_compat/Android.bp b/keystore2/src/km_compat/Android.bp
index 7ca6a63..a5da5a6 100644
--- a/keystore2/src/km_compat/Android.bp
+++ b/keystore2/src/km_compat/Android.bp
@@ -49,6 +49,8 @@
         "android.hardware.keymaster@4.0",
         "android.hardware.keymaster@4.1",
         "android.hardware.security.keymint-unstable-ndk_platform",
+        "android.hardware.security.secureclock-unstable-ndk_platform",
+        "android.hardware.security.sharedsecret-unstable-ndk_platform",
         "android.security.compat-ndk_platform",
         "android.system.keystore2-ndk_platform",
         "libbase",
@@ -66,6 +68,9 @@
     name: "libkm_compat_service",
     srcs: ["km_compat_service.cpp"],
     shared_libs: [
+        "android.hardware.security.keymint-unstable-ndk_platform",
+        "android.hardware.security.secureclock-unstable-ndk_platform",
+        "android.hardware.security.sharedsecret-unstable-ndk_platform",
         "android.security.compat-ndk_platform",
         "libbinder_ndk",
         "libcrypto",
@@ -93,6 +98,8 @@
         "android.hardware.keymaster@4.0",
         "android.hardware.keymaster@4.1",
         "android.hardware.security.keymint-unstable-ndk_platform",
+        "android.hardware.security.secureclock-unstable-ndk_platform",
+        "android.hardware.security.sharedsecret-unstable-ndk_platform",
         "android.security.compat-ndk_platform",
         "android.system.keystore2-ndk_platform",
         "libbase",
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index d6b7940..ac16666 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -41,6 +41,7 @@
 using ::android::hardware::keymaster::V4_0::TagType;
 using ::android::hidl::manager::V1_2::IServiceManager;
 using V4_0_HardwareAuthToken = ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using V4_0_HmacSharingParameters = ::android::hardware::keymaster::V4_0::HmacSharingParameters;
 using V4_0_KeyCharacteristics = ::android::hardware::keymaster::V4_0::KeyCharacteristics;
 using V4_0_KeyFormat = ::android::hardware::keymaster::V4_0::KeyFormat;
 using V4_0_KeyParameter = ::android::hardware::keymaster::V4_0::KeyParameter;
@@ -109,6 +110,22 @@
     return legacyVt;
 }
 
+static V4_0_HmacSharingParameters
+convertSharedSecretParameterToLegacy(const SharedSecretParameters& ssp) {
+    V4_0_HmacSharingParameters legacyHsp;
+    legacyHsp.seed = ssp.seed;
+    std::copy(ssp.nonce.begin(), ssp.nonce.end(), legacyHsp.nonce.data());
+    return legacyHsp;
+}
+
+static std::vector<V4_0_HmacSharingParameters>
+convertSharedSecretParametersToLegacy(const std::vector<SharedSecretParameters>& legacySsps) {
+    std::vector<V4_0_HmacSharingParameters> ssps(legacySsps.size());
+    std::transform(legacySsps.begin(), legacySsps.end(), ssps.begin(),
+                   convertSharedSecretParameterToLegacy);
+    return ssps;
+}
+
 void OperationSlots::setNumFreeSlots(uint8_t numFreeSlots) {
     std::lock_guard<std::mutex> lock(mNumFreeSlotsMutex);
     mNumFreeSlots = numFreeSlots;
@@ -427,6 +444,63 @@
     }
 }
 
+// SecureClock implementation
+
+ScopedAStatus SecureClock::generateTimeStamp(int64_t in_challenge, TimeStampToken* _aidl_return) {
+    V4_0_ErrorCode errorCode;
+    auto result = mDevice->verifyAuthorization(
+        in_challenge, {}, V4_0_HardwareAuthToken(),
+        [&](V4_0_ErrorCode error, const V4_0_VerificationToken& token) {
+            errorCode = error;
+            _aidl_return->challenge = token.challenge;
+            _aidl_return->timestamp.milliSeconds = token.timestamp;
+            _aidl_return->securityLevel =
+                static_cast<::aidl::android::hardware::security::keymint::SecurityLevel>(
+                    token.securityLevel);
+            _aidl_return->mac = token.mac;
+        });
+    if (!result.isOk()) {
+        return ScopedAStatus::fromServiceSpecificError(
+            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+    }
+    return convertErrorCode(errorCode);
+}
+
+// SharedSecret implementation
+
+ScopedAStatus SharedSecret::getSharedSecretParameters(SharedSecretParameters* _aidl_return) {
+    V4_0_ErrorCode errorCode;
+    auto result = mDevice->getHmacSharingParameters(
+        [&](V4_0_ErrorCode error, const V4_0_HmacSharingParameters& params) {
+            errorCode = error;
+            _aidl_return->seed = params.seed;
+            std::copy(params.nonce.data(), params.nonce.data() + params.nonce.elementCount(),
+                      std::back_inserter(_aidl_return->nonce));
+        });
+    if (!result.isOk()) {
+        return ScopedAStatus::fromServiceSpecificError(
+            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+    }
+    return convertErrorCode(errorCode);
+}
+
+ScopedAStatus
+SharedSecret::computeSharedSecret(const std::vector<SharedSecretParameters>& in_params,
+                                  std::vector<uint8_t>* _aidl_return) {
+    V4_0_ErrorCode errorCode;
+    auto legacyParams = convertSharedSecretParametersToLegacy(in_params);
+    auto result = mDevice->computeSharedHmac(
+        legacyParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& sharingCheck) {
+            errorCode = error;
+            *_aidl_return = sharingCheck;
+        });
+    if (!result.isOk()) {
+        return ScopedAStatus::fromServiceSpecificError(
+            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+    }
+    return convertErrorCode(errorCode);
+}
+
 // Certificate implementation
 
 template <KMV1::Tag tag, KMV1::TagType type>
@@ -830,7 +904,11 @@
     return result;
 }
 
-// KeyMintDevice implementation
+void KeyMintDevice::setNumFreeSlots(uint8_t numFreeSlots) {
+    mOperationSlots.setNumFreeSlots(numFreeSlots);
+}
+
+// Constructors and helpers.
 
 KeyMintDevice::KeyMintDevice(sp<Keymaster> device, KeyMintSecurityLevel securityLevel)
     : mDevice(device) {
@@ -841,8 +919,10 @@
     }
 }
 
-void KeyMintDevice::setNumFreeSlots(uint8_t numFreeSlots) {
-    mOperationSlots.setNumFreeSlots(numFreeSlots);
+sp<Keymaster> getDevice(KeyMintSecurityLevel securityLevel) {
+    auto secLevel = static_cast<SecurityLevel>(securityLevel);
+    auto devices = initializeKeymasters();
+    return devices[secLevel];
 }
 
 std::shared_ptr<KeyMintDevice>
@@ -862,6 +942,22 @@
     return device_ptr;
 }
 
+std::shared_ptr<SharedSecret> SharedSecret::createSharedSecret(KeyMintSecurityLevel securityLevel) {
+    auto device = getDevice(securityLevel);
+    if (!device) {
+        return {};
+    }
+    return ndk::SharedRefBase::make<SharedSecret>(std::move(device));
+}
+
+std::shared_ptr<SecureClock> SecureClock::createSecureClock(KeyMintSecurityLevel securityLevel) {
+    auto device = getDevice(securityLevel);
+    if (!device) {
+        return {};
+    }
+    return ndk::SharedRefBase::make<SecureClock>(std::move(device));
+}
+
 ScopedAStatus
 KeystoreCompatService::getKeyMintDevice(KeyMintSecurityLevel in_securityLevel,
                                         std::shared_ptr<IKeyMintDevice>* _aidl_return) {
@@ -875,3 +971,29 @@
     *_aidl_return = mDeviceCache[in_securityLevel];
     return ScopedAStatus::ok();
 }
+
+ScopedAStatus KeystoreCompatService::getSharedSecret(KeyMintSecurityLevel in_securityLevel,
+                                                     std::shared_ptr<ISharedSecret>* _aidl_return) {
+    if (!mSharedSecret) {
+        auto secret = SharedSecret::createSharedSecret(in_securityLevel);
+        if (!secret) {
+            return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
+        }
+        mSharedSecret = std::move(secret);
+    }
+    *_aidl_return = mSharedSecret;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus KeystoreCompatService::getSecureClock(std::shared_ptr<ISecureClock>* _aidl_return) {
+    if (!mSharedSecret) {
+        // The legacy verification service was always provided by the TEE variant.
+        auto clock = SecureClock::createSecureClock(KeyMintSecurityLevel::TRUSTED_ENVIRONMENT);
+        if (!clock) {
+            return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
+        }
+        mSecureClock = std::move(clock);
+    }
+    *_aidl_return = mSecureClock;
+    return ScopedAStatus::ok();
+}
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index 0634c26..64ad0ba 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -18,6 +18,8 @@
 
 #include <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
 #include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/BnSecureClock.h>
+#include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
 #include <aidl/android/security/compat/BnKeystoreCompatService.h>
 #include <keymasterV4_1/Keymaster4.h>
 #include <unordered_map>
@@ -40,6 +42,10 @@
 using KeyMintSecurityLevel = ::aidl::android::hardware::security::keymint::SecurityLevel;
 using V4_0_ErrorCode = ::android::hardware::keymaster::V4_0::ErrorCode;
 using ::aidl::android::hardware::security::keymint::IKeyMintDevice;
+using ::aidl::android::hardware::security::secureclock::ISecureClock;
+using ::aidl::android::hardware::security::secureclock::TimeStampToken;
+using ::aidl::android::hardware::security::sharedsecret::ISharedSecret;
+using ::aidl::android::hardware::security::sharedsecret::SharedSecretParameters;
 using ::aidl::android::security::compat::BnKeystoreCompatService;
 using ::android::hardware::keymaster::V4_1::support::Keymaster;
 using ::ndk::ScopedAStatus;
@@ -148,12 +154,41 @@
     ScopedAStatus abort();
 };
 
+class SharedSecret : public aidl::android::hardware::security::sharedsecret::BnSharedSecret {
+  private:
+    ::android::sp<Keymaster> mDevice;
+
+  public:
+    SharedSecret(::android::sp<Keymaster> device) : mDevice(device) {}
+    static std::shared_ptr<SharedSecret> createSharedSecret(KeyMintSecurityLevel securityLevel);
+
+    virtual ScopedAStatus getSharedSecretParameters(SharedSecretParameters* _aidl_return) override;
+    virtual ScopedAStatus computeSharedSecret(const std::vector<SharedSecretParameters>& in_params,
+                                              std::vector<uint8_t>* _aidl_return) override;
+};
+
+class SecureClock : public aidl::android::hardware::security::secureclock::BnSecureClock {
+  private:
+    ::android::sp<Keymaster> mDevice;
+
+  public:
+    SecureClock(::android::sp<Keymaster> device) : mDevice(device) {}
+    static std::shared_ptr<SecureClock> createSecureClock(KeyMintSecurityLevel securityLevel);
+
+    ScopedAStatus generateTimeStamp(int64_t in_challenge, TimeStampToken* _aidl_return) override;
+};
+
 class KeystoreCompatService : public BnKeystoreCompatService {
   private:
     std::unordered_map<KeyMintSecurityLevel, std::shared_ptr<IKeyMintDevice>> mDeviceCache;
+    std::shared_ptr<ISharedSecret> mSharedSecret;
+    std::shared_ptr<ISecureClock> mSecureClock;
 
   public:
     KeystoreCompatService() {}
     ScopedAStatus getKeyMintDevice(KeyMintSecurityLevel in_securityLevel,
                                    std::shared_ptr<IKeyMintDevice>* _aidl_return) override;
+    ScopedAStatus getSharedSecret(KeyMintSecurityLevel in_securityLevel,
+                                  std::shared_ptr<ISharedSecret>* _aidl_return) override;
+    ScopedAStatus getSecureClock(std::shared_ptr<ISecureClock>* _aidl_return) override;
 };
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 6d3aa96..aed0e7e 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -37,10 +37,12 @@
     use android_hardware_security_keymint::binder;
     use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
 
+    static COMPAT_NAME: &str = "android.security.compat";
+
     fn get_device() -> Box<dyn IKeyMintDevice> {
         add_keymint_device_service();
         let compat_service: Box<dyn IKeystoreCompatService> =
-            binder::get_interface("android.security.compat").unwrap();
+            binder::get_interface(COMPAT_NAME).unwrap();
         compat_service.getKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap()
     }
 
@@ -55,15 +57,6 @@
     }
 
     #[test]
-    fn test_verify_authorization() {
-        use android_hardware_security_keymint::aidl::android::hardware::security::keymint::HardwareAuthToken::HardwareAuthToken;
-        let legacy = get_device();
-        let result = legacy.verifyAuthorization(0, &HardwareAuthToken::default());
-        assert!(result.is_err());
-        assert_eq!(result.unwrap_err().service_specific_error(), ErrorCode::UNIMPLEMENTED.0,);
-    }
-
-    #[test]
     fn test_add_rng_entropy() {
         let legacy = get_device();
         let result = legacy.addRngEntropy(&[42; 16]);
@@ -306,4 +299,36 @@
         assert!(result.is_ok(), "{:?}", result);
         assert!(out_params.is_some());
     }
+
+    #[test]
+    fn test_secure_clock() {
+        add_keymint_device_service();
+        let compat_service: Box<dyn IKeystoreCompatService> =
+            binder::get_interface(COMPAT_NAME).unwrap();
+        let secure_clock = compat_service.getSecureClock().unwrap();
+
+        let challenge = 42;
+        let result = secure_clock.generateTimeStamp(challenge);
+        assert!(result.is_ok(), "{:?}", result);
+        let result = result.unwrap();
+        assert_eq!(result.challenge, challenge);
+        assert_eq!(result.mac.len(), 32);
+    }
+
+    #[test]
+    fn test_shared_secret() {
+        add_keymint_device_service();
+        let compat_service: Box<dyn IKeystoreCompatService> =
+            binder::get_interface(COMPAT_NAME).unwrap();
+        let shared_secret =
+            compat_service.getSharedSecret(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+        let result = shared_secret.getSharedSecretParameters();
+        assert!(result.is_ok(), "{:?}", result);
+        let params = result.unwrap();
+
+        let result = shared_secret.computeSharedSecret(&[params]);
+        assert!(result.is_ok(), "{:?}", result);
+        assert_ne!(result.unwrap().len(), 0);
+    }
 }