Support pending CompOS keys.

When CompOS generates new artifacts it may also need to generate a new
keypair. Modify odsign to account for this. It needs to start up
CompOS to find out if the pending key is now the correct one; if so it
replaces the existing key, otherwise we keep the current key (if there
is one).

The pending keys are stored in /data/misc/apexdata/com.android.compos
since they are created & written by CompOS.

Fixed another RsaPublicKey bug.

Bug: 190166662
Test: Manual: No keys at all, no pending key, valid pending key, invalid pending key.
Change-Id: I17871b1e59380d037d71e8065f4cad699374ecaf
diff --git a/ondevice-signing/FakeCompOs.cpp b/ondevice-signing/FakeCompOs.cpp
index e2273a3..cd54e28 100644
--- a/ondevice-signing/FakeCompOs.cpp
+++ b/ondevice-signing/FakeCompOs.cpp
@@ -231,5 +231,5 @@
     std::string signatureString(reinterpret_cast<char*>(signature.value().data()),
                                 signature.value().size());
     std::string dataString(reinterpret_cast<char*>(data.data()), data.size());
-    return verifySignature(dataString, signatureString, publicKey);
+    return verifyRsaPublicKeySignature(dataString, signatureString, publicKey);
 }
diff --git a/ondevice-signing/FakeCompOs.h b/ondevice-signing/FakeCompOs.h
index 7d76938..eb1a8dd 100644
--- a/ondevice-signing/FakeCompOs.h
+++ b/ondevice-signing/FakeCompOs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index d11107f..ff7a105 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -62,7 +62,11 @@
 const std::string kCompOsCert = "/data/misc/odsign/compos_key.cert";
 const std::string kCompOsPublicKey = "/data/misc/odsign/compos_key.pubkey";
 const std::string kCompOsKeyBlob = "/data/misc/odsign/compos_key.blob";
-const std::string kCompOsPendingDir = "/data/misc/apexdata/com.android.art/compos-pending";
+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 kCompOsPendingArtifactsDir = "/data/misc/apexdata/com.android.art/compos-pending";
 
 static const char* kOdsignVerificationDoneProp = "odsign.verification.done";
 static const char* kOdsignKeyDoneProp = "odsign.key.done";
@@ -189,34 +193,80 @@
 }
 
 Result<std::vector<uint8_t>> verifyOrGenerateCompOsKey(const SigningKey& signingKey) {
-    auto compOsStatus = FakeCompOs::newInstance();
-    if (!compOsStatus.ok()) {
-        return Error() << "Failed to start CompOs: " << compOsStatus.error();
-    }
-
-    FakeCompOs* compOs = compOsStatus.value().get();
-
+    std::unique_ptr<FakeCompOs> compOs;
     std::vector<uint8_t> keyBlob;
     std::vector<uint8_t> publicKey;
-    bool haveKey = false;
+    bool new_key = true;
 
-    if (access(kCompOsPublicKey.c_str(), F_OK) == 0 && access(kCompOsKeyBlob.c_str(), F_OK) == 0) {
-        // We have a purported key, but not a valid signature for it.
-        // If compOs can verify it, we can sign it now.
-        keyBlob = readBytesFromFile(kCompOsKeyBlob);
-        publicKey = readBytesFromFile(kCompOsPublicKey);
+    // If a pending key has been generated we don't know if it is the correct
+    // one for the current CompOS VM, so we need to start it and ask it.
+    if (access(kCompOsPendingPublicKey.c_str(), F_OK) == 0 &&
+        access(kCompOsPendingKeyBlob.c_str(), F_OK) == 0) {
+        auto compOsStatus = FakeCompOs::newInstance();
+        if (!compOsStatus.ok()) {
+            return Error() << "Failed to start CompOs: " << compOsStatus.error();
+        }
+        compOs = std::move(compOsStatus.value());
 
-        auto response = compOs->loadAndVerifyKey(keyBlob, publicKey);
+        auto pendingKeyBlob = readBytesFromFile(kCompOsPendingKeyBlob);
+        auto pendingPublicKey = readBytesFromFile(kCompOsPendingPublicKey);
+
+        auto response = compOs->loadAndVerifyKey(pendingKeyBlob, pendingPublicKey);
         if (response.ok()) {
-            LOG(INFO) << "Verified existing CompOs key";
-            haveKey = true;
+            LOG(INFO) << "Verified pending CompOs key";
+            keyBlob = std::move(pendingKeyBlob);
+            publicKey = std::move(pendingPublicKey);
         } else {
-            LOG(WARNING) << "Failed to verify existing CompOs key: " << response.error();
+            LOG(WARNING) << "Failed to verify pending CompOs key: " << response.error();
+            // And fall through to looking at the current key.
+        }
+        // Whether they're good or bad, we've finished with these files.
+        unlink(kCompOsPendingKeyBlob.c_str());
+        unlink(kCompOsPendingPublicKey.c_str());
+    }
+
+    if (publicKey.empty()) {
+        // Alternatively if we signed a cert for the key on a previous boot, then we
+        // can use that straight away.
+        auto existing_key =
+            extractRsaPublicKeyFromLeafCert(signingKey, kCompOsCert, kCompOsSubject.commonName);
+        if (existing_key.ok()) {
+            LOG(INFO) << "Found and verified existing CompOs public key certificate: "
+                      << kCompOsCert;
+            return existing_key.value();
         }
     }
 
-    if (!haveKey) {
-        // If we don't have a key, or it doesn't verify, then we need a new one.
+    if (compOs == nullptr) {
+        auto compOsStatus = FakeCompOs::newInstance();
+        if (!compOsStatus.ok()) {
+            return Error() << "Failed to start CompOs: " << compOsStatus.error();
+        }
+        compOs = std::move(compOsStatus.value());
+    }
+
+    // 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()) {
+        if (access(kCompOsPublicKey.c_str(), F_OK) == 0 &&
+            access(kCompOsKeyBlob.c_str(), F_OK) == 0) {
+            auto currentKeyBlob = readBytesFromFile(kCompOsKeyBlob);
+            auto currentPublicKey = readBytesFromFile(kCompOsPublicKey);
+
+            auto response = compOs->loadAndVerifyKey(currentKeyBlob, currentPublicKey);
+            if (response.ok()) {
+                LOG(INFO) << "Verified existing CompOs key";
+                keyBlob = std::move(currentKeyBlob);
+                publicKey = std::move(currentPublicKey);
+                new_key = false;
+            } else {
+                LOG(WARNING) << "Failed to verify existing CompOs key: " << response.error();
+            }
+        }
+    }
+
+    // If all else has failed we need to ask CompOS to generate a new key.
+    if (publicKey.empty()) {
         auto keyData = compOs->generateKey();
         if (!keyData.ok()) {
             return Error() << "Failed to generate key: " << keyData.error();
@@ -226,9 +276,19 @@
             return Error() << "Failed to extract CompOs public key" << publicKeyStatus.error();
         }
 
+        LOG(INFO) << "Generated new CompOs key";
+
         keyBlob = std::move(keyData.value().blob);
         publicKey = std::move(publicKeyStatus.value());
+    }
 
+    // We've finished with CompOs now, let it exit.
+    compOs.reset();
+
+    // One way or another we now have a valid key pair. Persist the data for
+    // CompOS, and a cert so we can simplify the checks on subsequent boots.
+
+    if (new_key) {
         writeBytesToFile(keyBlob, kCompOsKeyBlob);
         writeBytesToFile(publicKey, kCompOsPublicKey);
     }
@@ -401,22 +461,9 @@
 }
 
 Result<std::vector<uint8_t>> addCompOsCertToFsVerityKeyring(const SigningKey& signingKey) {
-    std::vector<uint8_t> compos_key;
-    auto existing_key =
-        extractRsaPublicKeyFromLeafCert(signingKey, kCompOsCert, kCompOsSubject.commonName);
-    if (existing_key.ok()) {
-        LOG(INFO) << "Found and verified existing CompOs public key certificate: " << kCompOsCert;
-        compos_key = std::move(existing_key.value());
-    } else {
-        LOG(WARNING) << existing_key.error();
-
-        auto new_key = verifyOrGenerateCompOsKey(signingKey);
-        if (!new_key.ok()) {
-            return new_key.error();
-        } else {
-            LOG(INFO) << "Generated new CompOs public key certificate";
-            compos_key = std::move(new_key.value());
-        }
+    auto publicKey = verifyOrGenerateCompOsKey(signingKey);
+    if (!publicKey.ok()) {
+        return publicKey.error();
     }
 
     auto cert_add_result = addCertToFsVerityKeyring(kCompOsCert, "fsv_compos");
@@ -427,13 +474,13 @@
                        << cert_add_result.error();
     }
 
-    return compos_key;
+    return publicKey;
 }
 
 art::odrefresh::ExitCode checkCompOsPendingArtifacts(const std::vector<uint8_t>& compos_key,
                                                      const SigningKey& signingKey,
                                                      bool* digests_verified) {
-    if (!directoryHasContent(kCompOsPendingDir)) {
+    if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
         return art::odrefresh::ExitCode::kCompilationRequired;
     }
 
@@ -444,7 +491,7 @@
     if (odrefresh_status != art::odrefresh::ExitCode::kCompilationRequired) {
         if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
             LOG(INFO) << "Current artifacts are OK, deleting pending artifacts";
-            removeDirectory(kCompOsPendingDir);
+            removeDirectory(kCompOsPendingArtifactsDir);
         }
         return odrefresh_status;
     }
@@ -453,11 +500,11 @@
     LOG(INFO) << "Current artifacts are out of date, switching to pending artifacts";
     removeDirectory(kArtArtifactsDir);
     std::error_code ec;
-    std::filesystem::rename(kCompOsPendingDir, kArtArtifactsDir, ec);
+    std::filesystem::rename(kCompOsPendingArtifactsDir, kArtArtifactsDir, ec);
     if (ec) {
-        LOG(ERROR) << "Can't rename " << kCompOsPendingDir << " to " << kArtArtifactsDir << ": "
-                   << ec.message();
-        removeDirectory(kCompOsPendingDir);
+        LOG(ERROR) << "Can't rename " << kCompOsPendingArtifactsDir << " to " << kArtArtifactsDir
+                   << ": " << ec.message();
+        removeDirectory(kCompOsPendingArtifactsDir);
         return art::odrefresh::ExitCode::kCompilationRequired;
     }
     // TODO: Make sure that we check here that the contents of the artifacts
@@ -501,7 +548,7 @@
     auto errorScopeGuard = []() {
         // In case we hit any error, remove the artifacts and tell Zygote not to use anything
         removeDirectory(kArtArtifactsDir);
-        removeDirectory(kCompOsPendingDir);
+        removeDirectory(kCompOsPendingArtifactsDir);
         // Tell init we don't need to use our key anymore
         SetProperty(kOdsignKeyDoneProp, "1");
         // Tell init we're done with verification, and that it was an error