Rewrite key management & signing

Extend compos_helper to support signing, use it from CompOS.

Expose the public key from the VM. Rename compos_verify_key to
compos_verify and get it to verify the signature against the current
instance's public key.

Also move DICE access to compos_key_main. There's no use having it in
the library - neither the tests nor compos_verify can use it - and it
complicates the build rules.

There's a lot more that can be deleted, but I'll do that in a
follow-up; this is big enough already.

Bug: 218494522
Test: atest CompOsSigningHostTest CompOsDenialHostTest
Change-Id: I2d71f68a595d5ddadb2e7b16937fa6855f5db0ab
diff --git a/compos/compos_key_helper/Android.bp b/compos/compos_key_helper/Android.bp
index c53d88d..a932b40 100644
--- a/compos/compos_key_helper/Android.bp
+++ b/compos/compos_key_helper/Android.bp
@@ -8,7 +8,6 @@
 
     shared_libs: [
         "libbase",
-        "libbinder_ndk",
         "libcrypto",
     ],
 }
@@ -17,11 +16,7 @@
     name: "libcompos_key",
     defaults: ["compos_key_defaults"],
     srcs: ["compos_key.cpp"],
-
-    shared_libs: [
-        "android.hardware.security.dice-V1-ndk",
-        "android.security.dice-ndk",
-    ],
+    export_include_dirs: ["."],
 }
 
 cc_binary {
@@ -31,7 +26,9 @@
 
     static_libs: ["libcompos_key"],
     shared_libs: [
+        "android.hardware.security.dice-V1-ndk",
         "android.security.dice-ndk",
+        "libbinder_ndk",
     ],
 }
 
diff --git a/compos/compos_key_helper/compos_key.cpp b/compos/compos_key_helper/compos_key.cpp
index 84a736d..2e3252c 100644
--- a/compos/compos_key_helper/compos_key.cpp
+++ b/compos/compos_key_helper/compos_key.cpp
@@ -16,24 +16,20 @@
 
 #include "compos_key.h"
 
-#include <aidl/android/security/dice/IDiceNode.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_manager.h>
 #include <openssl/digest.h>
 #include <openssl/hkdf.h>
 #include <openssl/mem.h>
-#include <unistd.h>
 
-using aidl::android::hardware::security::dice::BccHandover;
-using aidl::android::hardware::security::dice::InputValues;
-using aidl::android::security::dice::IDiceNode;
 using android::base::ErrnoError;
 using android::base::Error;
 using android::base::Result;
+using compos_key::Ed25519KeyPair;
+using compos_key::Signature;
 
 // Used to ensure the key we derive is distinct from any other.
 constexpr const char* kSigningKeyInfo = "CompOS signing key";
 
+namespace compos_key {
 Result<Ed25519KeyPair> deriveKeyFromSecret(const uint8_t* secret, size_t secret_size) {
     // Ed25519 private keys are derived from a 32 byte seed:
     // https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5
@@ -64,22 +60,4 @@
             size_t data_size) {
     return ED25519_verify(data, data_size, signature.data(), public_key.data()) == 1;
 }
-
-Result<Ed25519KeyPair> deriveKeyFromDice() {
-    ndk::SpAIBinder binder{AServiceManager_getService("android.security.dice.IDiceNode")};
-    auto dice_node = IDiceNode::fromBinder(binder);
-    if (!dice_node) {
-        return Error() << "Unable to connect to IDiceNode";
-    }
-
-    const std::vector<InputValues> empty_input_values;
-    BccHandover bcc;
-    auto status = dice_node->derive(empty_input_values, &bcc);
-    if (!status.isOk()) {
-        return Error() << "Derive failed: " << status.getDescription();
-    }
-
-    // We use the sealing CDI because we want stability - the key needs to be the same
-    // for any instance of the "same" VM.
-    return deriveKeyFromSecret(bcc.cdiSeal.data(), bcc.cdiSeal.size());
-}
+} // namespace compos_key
diff --git a/compos/compos_key_helper/compos_key.h b/compos/compos_key_helper/compos_key.h
index 520f846..e9c6061 100644
--- a/compos/compos_key_helper/compos_key.h
+++ b/compos/compos_key_helper/compos_key.h
@@ -21,6 +21,7 @@
 
 #include <array>
 
+namespace compos_key {
 using PrivateKey = std::array<uint8_t, ED25519_PRIVATE_KEY_LEN>;
 using PublicKey = std::array<uint8_t, ED25519_PUBLIC_KEY_LEN>;
 using Signature = std::array<uint8_t, ED25519_SIGNATURE_LEN>;
@@ -33,10 +34,9 @@
 android::base::Result<Ed25519KeyPair> deriveKeyFromSecret(const uint8_t* secret,
                                                           size_t secret_size);
 
-android::base::Result<Ed25519KeyPair> deriveKeyFromDice();
-
 android::base::Result<Signature> sign(const PrivateKey& private_key, const uint8_t* data,
                                       size_t data_size);
 
 bool verify(const PublicKey& public_key, const Signature& signature, const uint8_t* data,
             size_t data_size);
+} // namespace compos_key
diff --git a/compos/compos_key_helper/compos_key_main.cpp b/compos/compos_key_helper/compos_key_main.cpp
index 70f7539..a0d0b18 100644
--- a/compos/compos_key_helper/compos_key_main.cpp
+++ b/compos/compos_key_helper/compos_key_main.cpp
@@ -14,39 +14,102 @@
  * limitations under the License.
  */
 
+#include <aidl/android/security/dice/IDiceNode.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
 #include <unistd.h>
 
-#include <iostream>
 #include <string_view>
 
 #include "compos_key.h"
 
-using android::base::ErrnoError;
+using aidl::android::hardware::security::dice::BccHandover;
+using aidl::android::hardware::security::dice::InputValues;
+using aidl::android::security::dice::IDiceNode;
+using android::base::Error;
+using android::base::ReadFdToString;
+using android::base::Result;
 using android::base::WriteFully;
 using namespace std::literals;
+using compos_key::Ed25519KeyPair;
+
+namespace {
+Result<Ed25519KeyPair> deriveKeyFromDice() {
+    ndk::SpAIBinder binder{AServiceManager_getService("android.security.dice.IDiceNode")};
+    auto dice_node = IDiceNode::fromBinder(binder);
+    if (!dice_node) {
+        return Error() << "Unable to connect to IDiceNode";
+    }
+
+    const std::vector<InputValues> empty_input_values;
+    BccHandover bcc;
+    auto status = dice_node->derive(empty_input_values, &bcc);
+    if (!status.isOk()) {
+        return Error() << "Derive failed: " << status.getDescription();
+    }
+
+    // We use the sealing CDI because we want stability - the key needs to be the same
+    // for any instance of the "same" VM.
+    return compos_key::deriveKeyFromSecret(bcc.cdiSeal.data(), bcc.cdiSeal.size());
+}
+
+int write_public_key() {
+    auto key_pair = deriveKeyFromDice();
+    if (!key_pair.ok()) {
+        LOG(ERROR) << key_pair.error();
+        return 1;
+    }
+    if (!WriteFully(STDOUT_FILENO, key_pair->public_key.data(), key_pair->public_key.size())) {
+        PLOG(ERROR) << "Write failed";
+        return 1;
+    }
+    return 0;
+}
+
+int sign_input() {
+    std::string to_sign;
+    if (!ReadFdToString(STDIN_FILENO, &to_sign)) {
+        PLOG(ERROR) << "Read failed";
+        return 1;
+    }
+
+    auto key_pair = deriveKeyFromDice();
+    if (!key_pair.ok()) {
+        LOG(ERROR) << key_pair.error();
+        return 1;
+    }
+
+    auto signature =
+            compos_key::sign(key_pair->private_key,
+                             reinterpret_cast<const uint8_t*>(to_sign.data()), to_sign.size());
+    if (!signature.ok()) {
+        LOG(ERROR) << signature.error();
+        return 1;
+    }
+
+    if (!WriteFully(STDOUT_FILENO, signature->data(), signature->size())) {
+        PLOG(ERROR) << "Write failed";
+        return 1;
+    }
+    return 0;
+}
+} // namespace
 
 int main(int argc, char** argv) {
     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
 
     if (argc == 2) {
         if (argv[1] == "public_key"sv) {
-            auto key_pair = deriveKeyFromDice();
-            if (!key_pair.ok()) {
-                LOG(ERROR) << key_pair.error();
-                return 1;
-            }
-            if (!WriteFully(STDOUT_FILENO, key_pair->public_key.data(),
-                            key_pair->public_key.size())) {
-                PLOG(ERROR) << "Write failed";
-                return 1;
-            }
-            return 0;
+            return write_public_key();
+        } else if (argv[1] == "sign"sv) {
+            return sign_input();
         }
     }
 
-    std::cerr << "Usage:\n"
-                 "compos_key_helper public_key   Write current public key to stdout\n";
+    LOG(INFO) << "Usage: compos_key_helper <command>. Available commands are:\n"
+                 "public_key   Write current public key to stdout\n"
+                 "sign         Consume stdin, sign it and write signature to stdout\n";
     return 1;
 }
diff --git a/compos/compos_key_helper/compos_key_test.cpp b/compos/compos_key_helper/compos_key_test.cpp
index e5c4768..e4c3e8a 100644
--- a/compos/compos_key_helper/compos_key_test.cpp
+++ b/compos/compos_key_helper/compos_key_test.cpp
@@ -20,6 +20,8 @@
 
 #include "gtest/gtest.h"
 
+using namespace compos_key;
+
 const std::vector<uint8_t> secret = {1, 2, 3};
 const std::vector<uint8_t> other_secret = {3, 2, 3};
 const std::vector<uint8_t> data = {42, 180, 65, 0};