Pass a VM secret to KeyMint from microdroid_manager

This secret will be used to protect the keyblobs so that only a VM that
gets the same secret will be able to use those blobs. It is held in a
system property so that it won't be lost should KeyMint happen to
restart and has SELinux rules to ensure only microdroid_manager can set
the value and only KeyMint can read the value.

Bug: 190578423
Test: atest MicrodroidHostTestCases
Change-Id: I675cc9d6e9942090a761b83a6b9456b5c9909747
diff --git a/microdroid/keymint/service.cpp b/microdroid/keymint/service.cpp
index 325e852..8e20f44 100644
--- a/microdroid/keymint/service.cpp
+++ b/microdroid/keymint/service.cpp
@@ -18,16 +18,84 @@
 
 #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);