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);
+ }
}