Merge changes I47a0f80e,I675cc9d6,Ic49c4515

* changes:
  Specialize the KM context to use encrypted key blobs
  Pass a VM secret to KeyMint from microdroid_manager
  Strip out unused parts of keymint
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 62d6942..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 {
 
@@ -41,26 +43,11 @@
 
 namespace {
 
-vector<KeyCharacteristics> convertKeyCharacteristics(SecurityLevel keyMintSecurityLevel,
-                                                     const AuthorizationSet& requestParams,
+vector<KeyCharacteristics> convertKeyCharacteristics(const AuthorizationSet& requestParams,
                                                      const AuthorizationSet& sw_enforced,
                                                      const AuthorizationSet& hw_enforced,
                                                      bool include_keystore_enforced = true) {
-    KeyCharacteristics keyMintEnforced{keyMintSecurityLevel, {}};
-
-    if (keyMintSecurityLevel != SecurityLevel::SOFTWARE) {
-        // We're pretending to be TRUSTED_ENVIRONMENT or STRONGBOX.
-        keyMintEnforced.authorizations = kmParamSet2Aidl(hw_enforced);
-        if (include_keystore_enforced) {
-            // Put all the software authorizations in the keystore list.
-            KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE,
-                                                kmParamSet2Aidl(sw_enforced)};
-            return {std::move(keyMintEnforced), std::move(keystoreEnforced)};
-        } else {
-            return {std::move(keyMintEnforced)};
-        }
-    }
-
+    KeyCharacteristics keyMintEnforced{SecurityLevel::SOFTWARE, {}};
     KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE, {}};
     CHECK(hw_enforced.empty()) << "Hardware-enforced list is non-empty for pure SW KeyMint";
 
@@ -210,26 +197,22 @@
 
 constexpr size_t kOperationTableSize = 16;
 
-MicrodroidKeyMintDevice::MicrodroidKeyMintDevice(SecurityLevel securityLevel)
+MicrodroidKeyMintDevice::MicrodroidKeyMintDevice(::keymaster::KeymasterKeyBlob& rootKey)
       : impl_(new ::keymaster::AndroidKeymaster(
                 [&]() -> auto {
-                    auto context =
-                            new PureSoftKeymasterContext(KmVersion::KEYMINT_1,
-                                                         static_cast<keymaster_security_level_t>(
-                                                                 securityLevel));
+                    auto context = new MicrodroidKeymasterContext(KmVersion::KEYMINT_1, rootKey);
                     context->SetSystemVersion(::keymaster::GetOsVersion(),
                                               ::keymaster::GetOsPatchlevel());
                     return context;
                 }(),
-                kOperationTableSize)),
-        securityLevel_(securityLevel) {}
+                kOperationTableSize)) {}
 
 MicrodroidKeyMintDevice::~MicrodroidKeyMintDevice() {}
 
 ScopedAStatus MicrodroidKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
     info->versionNumber = 1;
-    info->securityLevel = securityLevel_;
-    info->keyMintName = "FakeKeyMintDevice";
+    info->securityLevel = SecurityLevel::SOFTWARE;
+    info->keyMintName = "MicrodroidKeyMintDevice";
     info->keyMintAuthorName = "Google";
     info->timestampTokenRequired = false;
     return ScopedAStatus::ok();
@@ -280,7 +263,7 @@
 
     creationResult->keyBlob = kmBlob2vector(response.key_blob);
     creationResult->keyCharacteristics =
-            convertKeyCharacteristics(securityLevel_, request.key_description, response.unenforced,
+            convertKeyCharacteristics(request.key_description, response.unenforced,
                                       response.enforced);
     creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
     return ScopedAStatus::ok();
@@ -312,7 +295,7 @@
 
     creationResult->keyBlob = kmBlob2vector(response.key_blob);
     creationResult->keyCharacteristics =
-            convertKeyCharacteristics(securityLevel_, request.key_description, response.unenforced,
+            convertKeyCharacteristics(request.key_description, response.unenforced,
                                       response.enforced);
     creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
 
@@ -320,12 +303,9 @@
 }
 
 ScopedAStatus MicrodroidKeyMintDevice::importWrappedKey(
-        const vector<uint8_t>& wrappedKeyData,        //
-        const vector<uint8_t>& wrappingKeyBlob,       //
-        const vector<uint8_t>& maskingKey,            //
-        const vector<KeyParameter>& unwrappingParams, //
-        int64_t passwordSid, int64_t biometricSid,    //
-        KeyCreationResult* creationResult) {
+        const vector<uint8_t>& wrappedKeyData, const vector<uint8_t>& wrappingKeyBlob,
+        const vector<uint8_t>& maskingKey, const vector<KeyParameter>& unwrappingParams,
+        int64_t passwordSid, int64_t biometricSid, KeyCreationResult* creationResult) {
     ImportWrappedKeyRequest request(impl_->message_version());
     request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
     request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
@@ -343,8 +323,8 @@
 
     creationResult->keyBlob = kmBlob2vector(response.key_blob);
     creationResult->keyCharacteristics =
-            convertKeyCharacteristics(securityLevel_, request.additional_params,
-                                      response.unenforced, response.enforced);
+            convertKeyCharacteristics(request.additional_params, response.unenforced,
+                                      response.enforced);
     creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
 
     return ScopedAStatus::ok();
@@ -368,23 +348,14 @@
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus MicrodroidKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
-    DeleteKeyRequest request(impl_->message_version());
-    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
-
-    DeleteKeyResponse response(impl_->message_version());
-    impl_->DeleteKey(request, &response);
-
-    return kmError2ScopedAStatus(response.error);
+ScopedAStatus MicrodroidKeyMintDevice::deleteKey(const vector<uint8_t>&) {
+    // There's nothing to be done to delete software key blobs.
+    return kmError2ScopedAStatus(KM_ERROR_OK);
 }
 
 ScopedAStatus MicrodroidKeyMintDevice::deleteAllKeys() {
     // There's nothing to be done to delete software key blobs.
-    DeleteAllKeysRequest request(impl_->message_version());
-    DeleteAllKeysResponse response(impl_->message_version());
-    impl_->DeleteAllKeys(request, &response);
-
-    return kmError2ScopedAStatus(response.error);
+    return kmError2ScopedAStatus(KM_ERROR_OK);
 }
 
 ScopedAStatus MicrodroidKeyMintDevice::destroyAttestationIds() {
@@ -420,21 +391,13 @@
 }
 
 ScopedAStatus MicrodroidKeyMintDevice::deviceLocked(
-        bool passwordOnly, const std::optional<secureclock::TimeStampToken>& timestampToken) {
-    DeviceLockedRequest request(impl_->message_version());
-    request.passwordOnly = passwordOnly;
-    if (timestampToken.has_value()) {
-        request.token.challenge = timestampToken->challenge;
-        request.token.mac = {timestampToken->mac.data(), timestampToken->mac.size()};
-        request.token.timestamp = timestampToken->timestamp.milliSeconds;
-    }
-    DeviceLockedResponse response = impl_->DeviceLocked(request);
-    return kmError2ScopedAStatus(response.error);
+        bool, const std::optional<secureclock::TimeStampToken>&) {
+    // Microdroid doesn't yet have a concept of a locked device.
+    return kmError2ScopedAStatus(KM_ERROR_OK);
 }
 
 ScopedAStatus MicrodroidKeyMintDevice::earlyBootEnded() {
-    EarlyBootEndedResponse response = impl_->EarlyBootEnded();
-    return kmError2ScopedAStatus(response.error);
+    return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
 }
 
 ScopedAStatus MicrodroidKeyMintDevice::convertStorageKeyToEphemeral(
@@ -458,15 +421,11 @@
     }
 
     AuthorizationSet emptySet;
-    *keyCharacteristics = convertKeyCharacteristics(securityLevel_, emptySet, response.unenforced,
-                                                    response.enforced,
-                                                    /* include_keystore_enforced = */ false);
+    *keyCharacteristics =
+            convertKeyCharacteristics(emptySet, response.unenforced, response.enforced,
+                                      /* include_keystore_enforced = */ false);
 
     return ScopedAStatus::ok();
 }
 
-IKeyMintDevice* CreateKeyMintDevice(SecurityLevel securityLevel) {
-    return ::new MicrodroidKeyMintDevice(securityLevel);
-}
-
 } // namespace aidl::android::hardware::security::keymint
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 34d09bf..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:
-    explicit MicrodroidKeyMintDevice(SecurityLevel securityLevel);
+    explicit MicrodroidKeyMintDevice(::keymaster::KeymasterKeyBlob& rootKey);
     virtual ~MicrodroidKeyMintDevice();
 
     ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
@@ -85,9 +86,6 @@
 
 protected:
     std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
-    SecurityLevel securityLevel_;
 };
 
-IKeyMintDevice* CreateKeyMintDevice(SecurityLevel securityLevel);
-
 } // namespace aidl::android::hardware::security::keymint
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 2cdad0f..5fc0bd2 100644
--- a/microdroid/keymint/service.cpp
+++ b/microdroid/keymint/service.cpp
@@ -18,23 +18,91 @@
 
 #include <AndroidKeyMintDevice.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/result.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/mem.h>
 #include <keymaster/soft_keymaster_logger.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/is_boringssl.h>
+#include <openssl/sha.h>
 
 #include "MicrodroidKeyMintDevice.h"
 
 using aidl::android::hardware::security::keymint::MicrodroidKeyMintDevice;
 using aidl::android::hardware::security::keymint::SecurityLevel;
 
+using android::base::Error;
+using android::base::GetProperty;
+using android::base::Result;
+
+using keymaster::KeymasterBlob;
+using keymaster::KeymasterKeyBlob;
+using keymaster::memset_s;
+
+namespace {
+
+template <typename T, class... Args>
+std::shared_ptr<T> addService(Args&&... args) {
+    std::shared_ptr<T> ser = ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
+    auto instanceName = std::string(T::descriptor) + "/default";
+    LOG(INFO) << "adding keymint service instance: " << instanceName;
+    binder_status_t status =
+            AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
+    CHECK(status == STATUS_OK);
+    return ser;
+}
+
+Result<KeymasterKeyBlob> getRootKey() {
+    const std::string prop = "ro.vmsecret.keymint";
+    const std::chrono::seconds timeout(15);
+    while (!android::base::WaitForPropertyCreation(prop, timeout)) {
+        LOG(WARNING) << "waited " << timeout.count() << "seconds for " << prop
+                     << ", still waiting...";
+    }
+
+    // In a small effort to avoid spreading the secret around too widely in
+    // memory, move the secert into a buffer that will wipe itself and clear
+    // the original string.
+    std::string secretProp = GetProperty(prop, "");
+    KeymasterBlob secret(reinterpret_cast<const uint8_t*>(secretProp.data()), secretProp.size());
+    memset_s(secretProp.data(), 0, secretProp.size());
+    if (secret.size() < 64u) return Error() << "secret is too small";
+
+    // Derive the root key from the secret to avoid getting locked into using
+    // the secret directly.
+    KeymasterKeyBlob rootKey(SHA512_DIGEST_LENGTH);
+    const uint8_t kRootKeyIkm[] = "keymint_root_key";
+    const uint8_t* kNoSalt = nullptr;
+    const size_t kNoSaltLen = 0;
+    if (!HKDF(rootKey.writable_data(), rootKey.size(), EVP_sha512(), (uint8_t*)secret.begin(),
+              secret.size(), kNoSalt, kNoSaltLen, kRootKeyIkm, sizeof(kRootKeyIkm))) {
+        return Error() << "Failed to derive a key";
+    }
+    if (rootKey.size() < 64u) return Error() << "root key is too small";
+
+    LOG(INFO) << "root key obtained";
+    return rootKey;
+}
+
+} // namespace
+
 int main() {
+    auto rootKey = getRootKey();
+    if (!rootKey.ok()) {
+        LOG(FATAL) << "Failed to get root key: " << rootKey.error();
+    }
+
     // Zero threads seems like a useless pool, but below we'll join this thread
     // to it, increasing the pool size to 1.
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
     // Add Keymint Service
     std::shared_ptr<MicrodroidKeyMintDevice> keyMint =
-            ndk::SharedRefBase::make<MicrodroidKeyMintDevice>(SecurityLevel::SOFTWARE);
+            ndk::SharedRefBase::make<MicrodroidKeyMintDevice>(*rootKey);
     auto instanceName = std::string(MicrodroidKeyMintDevice::descriptor) + "/default";
     LOG(INFO) << "adding keymint service instance: " << instanceName;
     binder_status_t status =
diff --git a/microdroid/sepolicy/system/private/domain.te b/microdroid/sepolicy/system/private/domain.te
index 54423ec..da811ed 100644
--- a/microdroid/sepolicy/system/private/domain.te
+++ b/microdroid/sepolicy/system/private/domain.te
@@ -218,7 +218,7 @@
 
 # workaround for supressing property accesses.
 # TODO: remove these
-set_prop(domain, property_type)
+set_prop(domain, property_type -vmsecret_keymint_prop)
 # auditallow { domain -init } property_type:property_service set;
 # auditallow { domain -init } property_type:file rw_file_perms;
 
diff --git a/microdroid/sepolicy/system/private/microdroid_manager.te b/microdroid/sepolicy/system/private/microdroid_manager.te
index 781a5e1..074024f 100644
--- a/microdroid/sepolicy/system/private/microdroid_manager.te
+++ b/microdroid/sepolicy/system/private/microdroid_manager.te
@@ -23,6 +23,9 @@
 # Let microdroid_manager kernel-log.
 allow microdroid_manager kmsg_device:chr_file w_file_perms;
 
+# Let microdroid_manager initialize the derived VM secrets.
+set_prop(microdroid_manager, vmsecret_keymint_prop);
+
 # Let microdroid_manager read a config file from /mnt/apk (fusefs)
 # TODO(b/188400186) remove the below two rules
 userdebug_or_eng(`
diff --git a/microdroid/sepolicy/system/private/property.te b/microdroid/sepolicy/system/private/property.te
new file mode 100644
index 0000000..d3d413e
--- /dev/null
+++ b/microdroid/sepolicy/system/private/property.te
@@ -0,0 +1,16 @@
+###
+### Neverallow rules
+###
+
+neverallow {
+  domain
+  -init
+  -microdroid_manager
+} vmsecret_keymint_prop:property_service set;
+
+neverallow {
+  domain
+  -init
+  -microdroid_manager
+  -hal_keymint_server
+} vmsecret_keymint_prop:file no_rw_file_perms;
diff --git a/microdroid/sepolicy/system/private/property_contexts b/microdroid/sepolicy/system/private/property_contexts
index deeb840..c8be9d9 100644
--- a/microdroid/sepolicy/system/private/property_contexts
+++ b/microdroid/sepolicy/system/private/property_contexts
@@ -50,6 +50,8 @@
 
 ro.build.fingerprint u:object_r:fingerprint_prop:s0 exact string
 
+ro.vmsecret.keymint u:object_r:vmsecret_keymint_prop:s0 exact string
+
 hwservicemanager.ready u:object_r:hwservicemanager_prop:s0 exact bool
 
 apexd.status u:object_r:apexd_prop:s0 exact enum starting activated ready
diff --git a/microdroid/sepolicy/system/public/property.te b/microdroid/sepolicy/system/public/property.te
index 2f3255b..f5dc758 100644
--- a/microdroid/sepolicy/system/public/property.te
+++ b/microdroid/sepolicy/system/public/property.te
@@ -30,6 +30,7 @@
 type shell_prop, property_type;
 type usb_control_prop, property_type;
 type vendor_default_prop, property_type;
+type vmsecret_keymint_prop, property_type;
 
 allow property_type tmpfs:filesystem associate;
 
diff --git a/microdroid/sepolicy/vendor/hal_keymint_default.te b/microdroid/sepolicy/vendor/hal_keymint_default.te
index 9ddd787..359ca60 100644
--- a/microdroid/sepolicy/vendor/hal_keymint_default.te
+++ b/microdroid/sepolicy/vendor/hal_keymint_default.te
@@ -9,3 +9,5 @@
 
 allow logd hal_keymint_default:dir search;
 allow logd hal_keymint_default:file { getattr open read };
+
+get_prop(hal_keymint_default, vmsecret_keymint_prop);
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index 15c439b..902b5da 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -12,6 +12,7 @@
         "libanyhow",
         "libkernlog",
         "libkeystore2_system_property-rust",
+        "liblibc",
         "liblog_rust",
         "libmicrodroid_metadata",
         "libmicrodroid_payload_config",
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index d88ba1a..1506142 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -19,7 +19,7 @@
 
 use anyhow::{anyhow, bail, Result};
 use keystore2_system_property::PropertyWatcher;
-use log::{error, info};
+use log::{error, info, warn};
 use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
 use std::fs::{self, File};
 use std::os::unix::io::{FromRawFd, IntoRawFd};
@@ -39,6 +39,11 @@
     if !metadata.payload_config_path.is_empty() {
         let config = load_config(Path::new(&metadata.payload_config_path))?;
 
+        let fake_secret = "This is a placeholder for a value that is derived from the images that are loaded in the VM.";
+        if let Err(err) = keystore2_system_property::write("ro.vmsecret.keymint", fake_secret) {
+            warn!("failed to set ro.vmsecret.keymint: {}", err);
+        }
+
         // TODO(jooyung): wait until sys.boot_completed?
         if let Some(main_task) = &config.task {
             exec_task(main_task).map_err(|e| {