Replace FakeCompOs with real CompOs

Change the implementation of verifyCompOsKey to execute the
compos_verify_key binary to verify the pending and/or current
instance.

Then delete FakeCompOs since there is no remaiing usage of it.

Note that this CL also removes the "if (false)" that has been guarding
this code. Instead it is active if we have a userdebug or eng build,
kvm is enabled, and the CompOs APEX is present. Currently this will be
very few devices; even on those nothing significant will happen unless
valid CompOs key files and artifacts are present which can only occur
via test tools for now.

The flag is retained to give an easy kill switch.

Bug: 193603140
Test: In progress
Change-Id: Id9de0852fafc54a825a04b1bee2637a7965214e6
diff --git a/ondevice-signing/Android.bp b/ondevice-signing/Android.bp
index 5219240..efa0389 100644
--- a/ondevice-signing/Android.bp
+++ b/ondevice-signing/Android.bp
@@ -84,7 +84,6 @@
   srcs: [
     "odsign_main.cpp",
     "CertUtils.cpp",
-    "FakeCompOs.cpp",
     "KeystoreKey.cpp",
     "KeystoreHmacKey.cpp",
     "VerityUtils.cpp",
diff --git a/ondevice-signing/FakeCompOs.cpp b/ondevice-signing/FakeCompOs.cpp
deleted file mode 100644
index 596d6e2..0000000
--- a/ondevice-signing/FakeCompOs.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 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 "FakeCompOs.h"
-
-#include "CertUtils.h"
-#include "KeyConstants.h"
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/result.h>
-#include <android-base/scopeguard.h>
-
-#include <binder/IServiceManager.h>
-
-#include <openssl/nid.h>
-#include <openssl/rand.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-using android::String16;
-
-using android::hardware::security::keymint::Algorithm;
-using android::hardware::security::keymint::Digest;
-using android::hardware::security::keymint::KeyParameter;
-using android::hardware::security::keymint::KeyParameterValue;
-using android::hardware::security::keymint::KeyPurpose;
-using android::hardware::security::keymint::PaddingMode;
-using android::hardware::security::keymint::SecurityLevel;
-using android::hardware::security::keymint::Tag;
-
-using android::system::keystore2::CreateOperationResponse;
-using android::system::keystore2::Domain;
-
-using android::base::Error;
-using android::base::Result;
-
-using android::binder::Status;
-
-// TODO: Allocate a namespace for CompOS
-const int64_t kCompOsNamespace = 101;
-
-Result<std::unique_ptr<FakeCompOs>>
-FakeCompOs::startInstance(const std::string& /*instanceImagePath*/) {
-    std::unique_ptr<FakeCompOs> compOs(new FakeCompOs);
-    auto init = compOs->initialize();
-    if (init.ok()) {
-        return compOs;
-    } else {
-        return init.error();
-    }
-}
-
-FakeCompOs::FakeCompOs() {}
-
-Result<void> FakeCompOs::initialize() {
-    auto sm = android::defaultServiceManager();
-    if (!sm) {
-        return Error() << "No ServiceManager";
-    }
-    auto rawService = sm->getService(String16("android.system.keystore2.IKeystoreService/default"));
-    if (!rawService) {
-        return Error() << "No Keystore service";
-    }
-    mService = interface_cast<android::system::keystore2::IKeystoreService>(rawService);
-    if (!mService) {
-        return Error() << "Bad Keystore service";
-    }
-
-    // TODO: We probably want SecurityLevel::SOFTWARE here, in the VM, but Keystore doesn't do it
-    auto status = mService->getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT, &mSecurityLevel);
-    if (!status.isOk()) {
-        return Error() << status;
-    }
-
-    return {};
-}
-
-Result<FakeCompOs::ByteVector> FakeCompOs::signData(const ByteVector& keyBlob,
-                                                    const ByteVector& data) const {
-    KeyDescriptor descriptor;
-    descriptor.domain = Domain::BLOB;
-    descriptor.nspace = kCompOsNamespace;
-    descriptor.blob = keyBlob;
-
-    std::vector<KeyParameter> parameters;
-
-    {
-        KeyParameter algo;
-        algo.tag = Tag::ALGORITHM;
-        algo.value = KeyParameterValue::make<KeyParameterValue::algorithm>(Algorithm::RSA);
-        parameters.push_back(algo);
-
-        KeyParameter digest;
-        digest.tag = Tag::DIGEST;
-        digest.value = KeyParameterValue::make<KeyParameterValue::digest>(Digest::SHA_2_256);
-        parameters.push_back(digest);
-
-        KeyParameter padding;
-        padding.tag = Tag::PADDING;
-        padding.value = KeyParameterValue::make<KeyParameterValue::paddingMode>(
-            PaddingMode::RSA_PKCS1_1_5_SIGN);
-        parameters.push_back(padding);
-
-        KeyParameter purpose;
-        purpose.tag = Tag::PURPOSE;
-        purpose.value = KeyParameterValue::make<KeyParameterValue::keyPurpose>(KeyPurpose::SIGN);
-        parameters.push_back(purpose);
-    }
-
-    Status status;
-
-    CreateOperationResponse response;
-    status = mSecurityLevel->createOperation(descriptor, parameters, /*forced=*/false, &response);
-    if (!status.isOk()) {
-        return Error() << "Failed to create operation: " << status;
-    }
-
-    auto operation = response.iOperation;
-    auto abort_guard = android::base::make_scope_guard([&] { operation->abort(); });
-
-    if (response.operationChallenge.has_value()) {
-        return Error() << "Key requires user authorization";
-    }
-
-    std::optional<ByteVector> signature;
-    status = operation->finish(data, {}, &signature);
-    if (!status.isOk()) {
-        return Error() << "Failed to sign data: " << status;
-    }
-
-    abort_guard.Disable();
-
-    if (!signature.has_value()) {
-        return Error() << "No signature received from keystore.";
-    }
-
-    return signature.value();
-}
-
-Result<void> FakeCompOs::loadAndVerifyKey(const ByteVector& keyBlob,
-                                          const ByteVector& publicKey) const {
-    // To verify the key is valid, we use it to sign some data, and then verify the signature using
-    // the supplied public key.
-
-    ByteVector data(32);
-    if (RAND_bytes(data.data(), data.size()) != 1) {
-        return Error() << "No random bytes";
-    }
-
-    auto signature = signData(keyBlob, data);
-    if (!signature.ok()) {
-        return signature.error();
-    }
-
-    std::string signatureString(reinterpret_cast<char*>(signature.value().data()),
-                                signature.value().size());
-    std::string dataString(reinterpret_cast<char*>(data.data()), data.size());
-    return verifyRsaPublicKeySignature(dataString, signatureString, publicKey);
-}
diff --git a/ondevice-signing/FakeCompOs.h b/ondevice-signing/FakeCompOs.h
deleted file mode 100644
index 6c7a445..0000000
--- a/ondevice-signing/FakeCompOs.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <android-base/result.h>
-
-#include <utils/StrongPointer.h>
-
-#include <android/system/keystore2/IKeystoreService.h>
-
-class FakeCompOs {
-    using IKeystoreService = ::android::system::keystore2::IKeystoreService;
-    using IKeystoreSecurityLevel = ::android::system::keystore2::IKeystoreSecurityLevel;
-    using KeyDescriptor = ::android::system::keystore2::KeyDescriptor;
-    using KeyMetadata = ::android::system::keystore2::KeyMetadata;
-
-  public:
-    using ByteVector = std::vector<uint8_t>;
-
-    static android::base::Result<std::unique_ptr<FakeCompOs>>
-    startInstance(const std::string& instanceImagePath);
-
-    android::base::Result<void> loadAndVerifyKey(const ByteVector& keyBlob,
-                                                 const ByteVector& publicKey) const;
-
-  private:
-    FakeCompOs();
-
-    android::base::Result<void> initialize();
-
-    android::base::Result<ByteVector> signData(const ByteVector& keyBlob,
-                                               const ByteVector& data) const;
-
-    KeyDescriptor mDescriptor;
-    android::sp<IKeystoreService> mService;
-    android::sp<IKeystoreSecurityLevel> mSecurityLevel;
-};
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index bba39b8..4a7baad 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -32,7 +32,6 @@
 #include <odrefresh/odrefresh.h>
 
 #include "CertUtils.h"
-#include "FakeCompOs.h"
 #include "KeystoreKey.h"
 #include "VerityUtils.h"
 
@@ -40,6 +39,7 @@
 
 using android::base::ErrnoError;
 using android::base::Error;
+using android::base::GetProperty;
 using android::base::Result;
 using android::base::SetProperty;
 
@@ -52,24 +52,20 @@
 const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
 
 constexpr const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
-
+constexpr const char* kCompOsVerifyPath = "/apex/com.android.compos/bin/compos_verify_key";
 constexpr const char* kFsVerityProcPath = "/proc/sys/fs/verity";
+constexpr const char* kKvmDevicePath = "/dev/kvm";
 
 constexpr bool kForceCompilation = false;
-constexpr bool kUseCompOs = false;  // STOPSHIP if true
+constexpr bool kUseCompOs = true;
 
-constexpr const char* kCompOsApexPath = "/apex/com.android.compos";
 const std::string kCompOsCert = "/data/misc/odsign/compos_key.cert";
-const std::string kCompOsPublicKey = "/data/misc/apexdata/com.android.compos/compos_key.pubkey";
-const std::string kCompOsKeyBlob = "/data/misc/apexdata/com.android.compos/compos_key.blob";
-const std::string kCompOsInstance = "/data/misc/apexdata/com.android.compos/compos_instance.img";
 
+const std::string kCompOsCurrentPublicKey =
+    "/data/misc/apexdata/com.android.compos/current/key.pubkey";
 const std::string kCompOsPendingPublicKey =
-    "/data/misc/apexdata/com.android.compos/compos_pending_key.pubkey";
-const std::string kCompOsPendingKeyBlob =
-    "/data/misc/apexdata/com.android.compos/compos_pending_key.blob";
-const std::string kCompOsPendingInstance =
-    "/data/misc/apexdata/com.android.compos/compos_pending_instance.img";
+    "/data/misc/apexdata/com.android.compos/pending/key.pubkey";
+
 const std::string kCompOsPendingArtifactsDir = "/data/misc/apexdata/com.android.art/compos-pending";
 
 constexpr const char* kOdsignVerificationDoneProp = "odsign.verification.done";
@@ -81,6 +77,8 @@
 
 constexpr const char* kStopServiceProp = "ctl.stop";
 
+enum class CompOsInstance { kCurrent, kPending };
+
 static std::vector<uint8_t> readBytesFromFile(const std::string& path) {
     std::string str;
     android::base::ReadFileToString(path, &str);
@@ -140,7 +138,12 @@
 }
 
 bool compOsPresent() {
-    return access(kCompOsApexPath, F_OK) == 0;
+    return access(kCompOsVerifyPath, X_OK) == 0 && access(kKvmDevicePath, F_OK) == 0;
+}
+
+bool isDebugBuild() {
+    std::string build_type = GetProperty("ro.build.type", "");
+    return build_type == "userdebug" || build_type == "eng";
 }
 
 Result<void> verifyExistingRootCert(const SigningKey& key) {
@@ -203,62 +206,36 @@
     return existingCertInfo.value().subjectRsaPublicKey;
 }
 
-// Attempt to start a CompOS VM from the given instance image and then get it to
-// verify the public key & key blob.  Returns the RsaPublicKey bytes if
-// successful, an empty vector if any of the files are not present, or an error
-// otherwise.
-Result<std::vector<uint8_t>> loadAndVerifyCompOsKey(const std::string& instanceFile,
-                                                    const std::string& publicKeyFile,
-                                                    const std::string& keyBlobFile) {
-    if (access(instanceFile.c_str(), F_OK) != 0 || access(publicKeyFile.c_str(), F_OK) != 0 ||
-        access(keyBlobFile.c_str(), F_OK) != 0) {
-        return {};
+// Attempt to start a CompOS VM for the specified instance to get it to
+// verify ita public key & key blob.
+bool startCompOsAndVerifyKey(CompOsInstance instance) {
+    bool isCurrent = instance == CompOsInstance::kCurrent;
+    const std::string& keyPath = isCurrent ? kCompOsCurrentPublicKey : kCompOsPendingPublicKey;
+    if (access(keyPath.c_str(), R_OK) != 0) {
+        return false;
     }
 
-    auto compOsStatus = FakeCompOs::startInstance(instanceFile);
-    if (!compOsStatus.ok()) {
-        return Error() << "Failed to start CompOs instance " << instanceFile << ": "
-                       << compOsStatus.error();
-    }
-    auto& compOs = compOsStatus.value();
-
-    auto publicKey = readBytesFromFile(publicKeyFile);
-    auto keyBlob = readBytesFromFile(keyBlobFile);
-    auto response = compOs->loadAndVerifyKey(keyBlob, publicKey);
-    if (!response.ok()) {
-        return response.error();
+    const char* const argv[] = {kCompOsVerifyPath, "--instance", isCurrent ? "current" : "pending"};
+    int result =
+        logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
+    if (result == 0) {
+        return true;
     }
 
-    return publicKey;
+    LOG(ERROR) << kCompOsVerifyPath << " returned " << result;
+    return false;
 }
 
 Result<std::vector<uint8_t>> verifyCompOsKey(const SigningKey& signingKey) {
-    std::vector<uint8_t> publicKey;
+    bool verified = false;
 
     // If a pending key has been generated we don't know if it is the correct
     // one for the pending CompOS VM, so we need to start it and ask it.
-    auto pendingPublicKey = loadAndVerifyCompOsKey(kCompOsPendingInstance, kCompOsPendingPublicKey,
-                                                   kCompOsPendingKeyBlob);
-    if (pendingPublicKey.ok()) {
-        if (!pendingPublicKey->empty()) {
-            LOG(INFO) << "Verified pending CompOs key";
-
-            if (rename(kCompOsPendingInstance, kCompOsInstance) &&
-                rename(kCompOsPendingPublicKey, kCompOsPublicKey) &&
-                rename(kCompOsPendingKeyBlob, kCompOsKeyBlob)) {
-                publicKey = std::move(*pendingPublicKey);
-            }
-        }
-    } else {
-        LOG(WARNING) << "Failed to verify pending CompOs key: " << pendingPublicKey.error();
-        // And fall through to dealing with any current key.
+    if (startCompOsAndVerifyKey(CompOsInstance::kPending)) {
+        verified = true;
     }
-    // Whether good or bad, we've finished with these files.
-    unlink(kCompOsPendingInstance.c_str());
-    unlink(kCompOsPendingKeyBlob.c_str());
-    unlink(kCompOsPendingPublicKey.c_str());
 
-    if (publicKey.empty()) {
+    if (!verified) {
         // Alternatively if we signed a cert for the key on a previous boot, then we
         // can use that straight away.
         auto existing_key =
@@ -270,30 +247,25 @@
         }
     }
 
-    // Otherwise, if there is an existing key that we haven't signed yet, then we can sign it
-    // now if CompOS confirms it's OK.
-    if (publicKey.empty()) {
-        auto currentPublicKey =
-            loadAndVerifyCompOsKey(kCompOsInstance, kCompOsPublicKey, kCompOsKeyBlob);
-        if (currentPublicKey.ok()) {
-            if (!currentPublicKey->empty()) {
-                LOG(INFO) << "Verified existing CompOs key";
-                publicKey = std::move(*currentPublicKey);
-            }
-        } else {
-            LOG(WARNING) << "Failed to verify existing CompOs key: " << currentPublicKey.error();
-            // Delete so we won't try again on next boot.
-            unlink(kCompOsInstance.c_str());
-            unlink(kCompOsKeyBlob.c_str());
-            unlink(kCompOsPublicKey.c_str());
-        }
+    // Otherwise, if there is an existing key that we haven't signed yet, then we can sign
+    // it now if CompOS confirms it's OK.
+    if (!verified && startCompOsAndVerifyKey(CompOsInstance::kCurrent)) {
+        verified = true;
     }
 
-    if (publicKey.empty()) {
+    if (!verified) {
         return Error() << "No valid CompOs key present.";
     }
 
-    // One way or another we now have a valid key pair. Persist a certificate so
+    // If the pending key was verified it will have been promoted to current, so
+    // at this stage if there is a key it will be the current one.
+    auto publicKey = readBytesFromFile(kCompOsCurrentPublicKey);
+    if (publicKey.empty()) {
+        // This shouldn`t really happen.
+        return Error() << "Failed to read CompOs key.";
+    }
+
+    // One way or another we now have a valid public key. Persist a certificate so
     // we can simplify the checks on subsequent boots.
 
     auto signFunction = [&](const std::string& to_be_signed) {
@@ -305,6 +277,8 @@
         return Error() << "Failed to create CompOs cert: " << certStatus.error();
     }
 
+    LOG(INFO) << "Verified key, wrote new CompOs cert";
+
     return publicKey;
 }
 
@@ -546,7 +520,8 @@
 
 int main(int /* argc */, char** /* argv */) {
     auto errorScopeGuard = []() {
-        // In case we hit any error, remove the artifacts and tell Zygote not to use anything
+        // In case we hit any error, remove the artifacts and tell Zygote not to use
+        // anything
         removeDirectory(kArtArtifactsDir);
         removeDirectory(kCompOsPendingArtifactsDir);
         // Tell init we don't need to use our key anymore
@@ -576,7 +551,7 @@
         LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
     }
 
-    bool supportsCompOs = kUseCompOs && supportsFsVerity && compOsPresent();
+    bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent() && isDebugBuild();
 
     if (supportsFsVerity) {
         auto existing_cert = verifyExistingRootCert(*key);
@@ -604,7 +579,7 @@
     art::odrefresh::ExitCode odrefresh_status = art::odrefresh::ExitCode::kCompilationRequired;
     bool digests_verified = false;
 
-    if (supportsCompOs) {
+    if (useCompOs) {
         auto compos_key = addCompOsCertToFsVerityKeyring(*key);
         if (!compos_key.ok()) {
             LOG(WARNING) << compos_key.error();