Specialize the KM context to use encrypted key blobs
These key blobs are intended to be exported outside the VM, without need
for further encryption. This will allows a limited form of persistence
for VMs between boots of the same code.
The authorization set is left in plain text which reveals some metadata
about the key but does not compromise its security.
Bug: 190578423
Test: atest MicrodroidHostTestCases
Change-Id: I47a0f80e2137e189634b77c0b4aafb32d002be50
diff --git a/microdroid/keymint/Android.bp b/microdroid/keymint/Android.bp
index 5a87145..6d651b9 100644
--- a/microdroid/keymint/Android.bp
+++ b/microdroid/keymint/Android.bp
@@ -25,6 +25,7 @@
"libkeymint",
"liblog",
"libpuresoftkeymasterdevice",
+ "libsoft_attestation_cert",
"libutils",
],
local_include_dirs: [
@@ -32,6 +33,7 @@
],
srcs: [
"MicrodroidKeyMintDevice.cpp",
+ "MicrodroidKeymasterContext.cpp",
"service.cpp",
],
}
diff --git a/microdroid/keymint/MicrodroidKeyMintDevice.cpp b/microdroid/keymint/MicrodroidKeyMintDevice.cpp
index aa3447e..c2f01f2 100644
--- a/microdroid/keymint/MicrodroidKeyMintDevice.cpp
+++ b/microdroid/keymint/MicrodroidKeyMintDevice.cpp
@@ -17,14 +17,16 @@
#define LOG_TAG "android.hardware.security.keymint-impl"
#include "MicrodroidKeyMintDevice.h"
+#include <AndroidKeyMintOperation.h>
+#include <KeyMintUtils.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <android-base/logging.h>
#include <keymaster/android_keymaster.h>
#include <keymaster/contexts/pure_soft_keymaster_context.h>
#include <keymaster/keymaster_configuration.h>
-#include "AndroidKeyMintOperation.h"
-#include "KeyMintUtils.h"
+#include "MicrodroidKeyMintDevice.h"
+#include "MicrodroidKeymasterContext.h"
namespace aidl::android::hardware::security::keymint {
@@ -195,11 +197,10 @@
constexpr size_t kOperationTableSize = 16;
-MicrodroidKeyMintDevice::MicrodroidKeyMintDevice()
+MicrodroidKeyMintDevice::MicrodroidKeyMintDevice(::keymaster::KeymasterKeyBlob& rootKey)
: impl_(new ::keymaster::AndroidKeymaster(
[&]() -> auto {
- auto context = new PureSoftKeymasterContext(KmVersion::KEYMINT_1,
- KM_SECURITY_LEVEL_SOFTWARE);
+ auto context = new MicrodroidKeymasterContext(KmVersion::KEYMINT_1, rootKey);
context->SetSystemVersion(::keymaster::GetOsVersion(),
::keymaster::GetOsPatchlevel());
return context;
diff --git a/microdroid/keymint/MicrodroidKeymasterContext.cpp b/microdroid/keymint/MicrodroidKeymasterContext.cpp
new file mode 100644
index 0000000..b5440f3
--- /dev/null
+++ b/microdroid/keymint/MicrodroidKeymasterContext.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MicrodroidKeymasterContext.h"
+
+#include <android-base/logging.h>
+#include <keymaster/key.h>
+#include <keymaster/key_blob_utils/auth_encrypted_key_blob.h>
+#include <keymaster/key_blob_utils/software_keyblobs.h>
+
+using namespace ::keymaster;
+
+// This value is used for the ROOT_OF_TRUST tag which is only used in
+// attestation records which aren't supported in this implementation so a
+// constant doesn't cause any hard. MicroDroid SoftWare root-of-trust.
+static uint8_t SWROT[] = {'M', 'D', 'S', 'W'};
+static const KeymasterBlob microdroidSoftwareRootOfTrust(SWROT);
+
+keymaster_error_t MicrodroidKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description,
+ keymaster_key_origin_t origin,
+ const KeymasterKeyBlob& key_material,
+ KeymasterKeyBlob* blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const {
+ keymaster_error_t error;
+
+ if (key_description.GetTagValue(TAG_ROLLBACK_RESISTANCE)) {
+ return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE;
+ }
+
+ error = SetKeyBlobAuthorizations(key_description, origin, os_version_, os_patchlevel_,
+ hw_enforced, sw_enforced);
+ if (error != KM_ERROR_OK) return error;
+
+ AuthorizationSet hidden;
+ error = BuildHiddenAuthorizations(key_description, &hidden, microdroidSoftwareRootOfTrust);
+ if (error != KM_ERROR_OK) return error;
+
+ CHECK(hw_enforced->empty());
+
+ // Note that the authorizations included in the blob are not encrypted. This
+ // doesn't pose a problem for the current applications but may be a
+ // candidate for hardening.
+ auto encrypted_key = EncryptKey(key_material, AES_GCM_WITH_SW_ENFORCED, *hw_enforced,
+ *sw_enforced, hidden, root_key_, random_, &error);
+ if (error != KM_ERROR_OK) return error;
+
+ *blob = SerializeAuthEncryptedBlob(encrypted_key, *hw_enforced, *sw_enforced, &error);
+ return error;
+}
+
+keymaster_error_t MicrodroidKeymasterContext::ParseKeyBlob(
+ const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+ UniquePtr<Key>* key) const {
+ keymaster_error_t error;
+
+ AuthorizationSet hidden;
+ error = BuildHiddenAuthorizations(additional_params, &hidden, microdroidSoftwareRootOfTrust);
+ if (error != KM_ERROR_OK) return error;
+
+ auto deserialized_key = DeserializeAuthEncryptedBlob(blob, &error);
+ if (error != KM_ERROR_OK) return error;
+
+ keymaster_algorithm_t algorithm;
+ if (!deserialized_key.sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) {
+ return KM_ERROR_INVALID_ARGUMENT;
+ }
+
+ auto key_material = DecryptKey(deserialized_key, hidden, root_key_, &error);
+ if (error != KM_ERROR_OK) return error;
+
+ auto factory = GetKeyFactory(algorithm);
+ return factory->LoadKey(move(key_material), additional_params,
+ move(deserialized_key.hw_enforced), move(deserialized_key.sw_enforced),
+ key);
+}
+
+static bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set) {
+ int index = set->find(tag);
+ if (index == -1) {
+ keymaster_key_param_t param;
+ param.tag = tag;
+ param.integer = value;
+ set->push_back(param);
+ return true;
+ }
+
+ if (set->params[index].integer > value) return false;
+
+ if (set->params[index].integer != value) {
+ set->params[index].integer = value;
+ }
+ return true;
+}
+
+keymaster_error_t MicrodroidKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+ const AuthorizationSet& upgrade_params,
+ KeymasterKeyBlob* upgraded_key) const {
+ UniquePtr<Key> key;
+ keymaster_error_t error = ParseKeyBlob(key_to_upgrade, upgrade_params, &key);
+ if (error != KM_ERROR_OK) return error;
+
+ if (os_version_ == 0) {
+ // We need to allow "upgrading" OS version to zero, to support upgrading from proper
+ // numbered releases to unnumbered development and preview releases.
+
+ int key_os_version_pos = key->sw_enforced().find(TAG_OS_VERSION);
+ if (key_os_version_pos != -1) {
+ uint32_t key_os_version = key->sw_enforced()[key_os_version_pos].integer;
+ if (key_os_version != 0) {
+ key->sw_enforced()[key_os_version_pos].integer = os_version_;
+ }
+ }
+ }
+
+ if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version_, &key->sw_enforced()) ||
+ !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel_, &key->sw_enforced()))
+ // One of the version fields would have been a downgrade. Not allowed.
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ AuthorizationSet hidden;
+ error = BuildHiddenAuthorizations(upgrade_params, &hidden, microdroidSoftwareRootOfTrust);
+ if (error != KM_ERROR_OK) return error;
+
+ auto encrypted_key =
+ EncryptKey(key->key_material(), AES_GCM_WITH_SW_ENFORCED, key->hw_enforced(),
+ key->sw_enforced(), hidden, root_key_, random_, &error);
+ if (error != KM_ERROR_OK) return error;
+
+ *upgraded_key = SerializeAuthEncryptedBlob(encrypted_key, key->hw_enforced(),
+ key->sw_enforced(), &error);
+ return error;
+}
diff --git a/microdroid/keymint/include/MicrodroidKeyMintDevice.h b/microdroid/keymint/include/MicrodroidKeyMintDevice.h
index db2c806..dec7baa 100644
--- a/microdroid/keymint/include/MicrodroidKeyMintDevice.h
+++ b/microdroid/keymint/include/MicrodroidKeyMintDevice.h
@@ -19,6 +19,7 @@
#include <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <keymaster/android_keymaster_utils.h>
namespace keymaster {
class AndroidKeymaster;
@@ -34,7 +35,7 @@
class MicrodroidKeyMintDevice : public BnKeyMintDevice {
public:
- MicrodroidKeyMintDevice();
+ explicit MicrodroidKeyMintDevice(::keymaster::KeymasterKeyBlob& rootKey);
virtual ~MicrodroidKeyMintDevice();
ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
diff --git a/microdroid/keymint/include/MicrodroidKeymasterContext.h b/microdroid/keymint/include/MicrodroidKeymasterContext.h
new file mode 100644
index 0000000..636d240
--- /dev/null
+++ b/microdroid/keymint/include/MicrodroidKeymasterContext.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/km_openssl/software_random_source.h>
+
+class MicrodroidKeymasterContext : public ::keymaster::PureSoftKeymasterContext {
+public:
+ explicit MicrodroidKeymasterContext(::keymaster::KmVersion version,
+ ::keymaster::KeymasterKeyBlob& root_key)
+ : PureSoftKeymasterContext(version, KM_SECURITY_LEVEL_SOFTWARE), root_key_(root_key) {}
+
+ keymaster_error_t CreateKeyBlob(const ::keymaster::AuthorizationSet& auths,
+ keymaster_key_origin_t origin,
+ const ::keymaster::KeymasterKeyBlob& key_material,
+ ::keymaster::KeymasterKeyBlob* blob,
+ ::keymaster::AuthorizationSet* hw_enforced,
+ ::keymaster::AuthorizationSet* sw_enforced) const override;
+
+ keymaster_error_t ParseKeyBlob(const ::keymaster::KeymasterKeyBlob& blob,
+ const ::keymaster::AuthorizationSet& additional_params,
+ ::keymaster::UniquePtr<::keymaster::Key>* key) const override;
+
+ keymaster_error_t UpgradeKeyBlob(const ::keymaster::KeymasterKeyBlob& key_to_upgrade,
+ const ::keymaster::AuthorizationSet& upgrade_params,
+ ::keymaster::KeymasterKeyBlob* upgraded_key) const override;
+
+private:
+ ::keymaster::SoftwareRandomSource random_;
+ ::keymaster::KeymasterKeyBlob root_key_;
+};
diff --git a/microdroid/keymint/service.cpp b/microdroid/keymint/service.cpp
index 8e20f44..5fc0bd2 100644
--- a/microdroid/keymint/service.cpp
+++ b/microdroid/keymint/service.cpp
@@ -102,7 +102,7 @@
// Add Keymint Service
std::shared_ptr<MicrodroidKeyMintDevice> keyMint =
- ndk::SharedRefBase::make<MicrodroidKeyMintDevice>();
+ ndk::SharedRefBase::make<MicrodroidKeyMintDevice>(*rootKey);
auto instanceName = std::string(MicrodroidKeyMintDevice::descriptor) + "/default";
LOG(INFO) << "adding keymint service instance: " << instanceName;
binder_status_t status =