Switch from compos_verify_key to compos_verify
We no longer need to validate the public/private key files. Instead we
delegate signature checking to compos_verify.
(I've left the stub of the key checking in for, partly because
completely removing it will be a big change in its own right, and
partly to avoid merge conflicts.)
Bug: 218494522
Test: atest CompOsSigningHostTest CompOsDenialHostTest
Change-Id: I84e62c0f092e663fde78ac68766f922f58568e57
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 5c541ae..dadcf08 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -57,6 +57,7 @@
constexpr bool kForceCompilation = false;
constexpr bool kUseCompOs = true;
+constexpr const char* kNewCompOsVerifyPath = "/apex/com.android.compos/bin/compos_verify";
const std::string kCompOsCert = "/data/misc/odsign/compos_key.cert";
const std::string kCompOsCurrentPublicKey =
@@ -85,12 +86,6 @@
namespace {
-std::vector<uint8_t> readBytesFromFile(const std::string& path) {
- std::string str;
- android::base::ReadFileToString(path, &str);
- return std::vector<uint8_t>(str.begin(), str.end());
-}
-
bool rename(const std::string& from, const std::string& to) {
std::error_code ec;
std::filesystem::rename(from, to, ec);
@@ -145,7 +140,7 @@
bool compOsPresent() {
// We must have the CompOS APEX
- return access(kCompOsVerifyPath, X_OK) == 0;
+ return access(kNewCompOsVerifyPath, X_OK) == 0;
}
Result<void> verifyExistingRootCert(const SigningKey& key) {
@@ -182,108 +177,6 @@
return createSelfSignedCertificate(*publicKey, keySignFunction, outPath);
}
-Result<std::vector<uint8_t>> extractRsaPublicKeyFromLeafCert(const SigningKey& key,
- const std::string& certPath,
- const std::string& expectedCn) {
- if (access(certPath.c_str(), F_OK) < 0) {
- return ErrnoError() << "Certificate not found: " << certPath;
- }
- auto trustedPublicKey = key.getPublicKey();
- if (!trustedPublicKey.ok()) {
- return Error() << "Failed to retrieve signing public key: " << trustedPublicKey.error();
- }
-
- auto existingCertInfo = verifyAndExtractCertInfoFromX509(certPath, trustedPublicKey.value());
- if (!existingCertInfo.ok()) {
- return Error() << "Failed to verify certificate at " << certPath << ": "
- << existingCertInfo.error();
- }
-
- auto& actualCn = existingCertInfo.value().subjectCn;
- if (actualCn != expectedCn) {
- return Error() << "CN of existing certificate at " << certPath << " is " << actualCn
- << ", should be " << expectedCn;
- }
-
- return existingCertInfo.value().subjectRsaPublicKey;
-}
-
-// 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;
- }
-
- 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;
- }
-
- LOG(ERROR) << kCompOsVerifyPath << " returned " << result;
- return false;
-}
-
-Result<std::vector<uint8_t>> verifyCompOsKey(const SigningKey& signingKey) {
- 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.
- if (startCompOsAndVerifyKey(CompOsInstance::kPending)) {
- verified = true;
- }
-
- 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 =
- extractRsaPublicKeyFromLeafCert(signingKey, kCompOsCert, kCompOsSubject.commonName);
- if (existing_key.ok()) {
- LOG(INFO) << "Found and verified existing CompOS public key certificate: "
- << kCompOsCert;
- return existing_key.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 (!verified && startCompOsAndVerifyKey(CompOsInstance::kCurrent)) {
- verified = true;
- }
-
- if (!verified) {
- return Error() << "No valid CompOS key present.";
- }
-
- // 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) {
- return signingKey.sign(to_be_signed);
- };
- auto certStatus = createLeafCertificate(kCompOsSubject, publicKey, signFunction,
- kSigningKeyCert, kCompOsCert);
- if (!certStatus.ok()) {
- return Error() << "Failed to create CompOS cert: " << certStatus.error();
- }
-
- LOG(INFO) << "Verified key, wrote new CompOS cert";
-
- return publicKey;
-}
-
Result<std::map<std::string, std::string>> computeDigests(const std::string& path) {
std::error_code ec;
std::map<std::string, std::string> digests;
@@ -439,27 +332,17 @@
return {};
}
-Result<std::vector<uint8_t>> addCompOsCertToFsVerityKeyring(const SigningKey& signingKey) {
- auto publicKey = verifyCompOsKey(signingKey);
- if (!publicKey.ok()) {
- return publicKey.error();
- }
-
- auto cert_add_result = addCertToFsVerityKeyring(kCompOsCert, "fsv_compos");
- if (!cert_add_result.ok()) {
- // Best efforts only - nothing we can do if deletion fails.
- unlink(kCompOsCert.c_str());
- return Error() << "Failed to add CompOS certificate to fs-verity keyring: "
- << cert_add_result.error();
- }
-
- return publicKey;
+Result<std::vector<uint8_t>> addCompOsCertToFsVerityKeyring(const SigningKey& /*signingKey*/) {
+ // TODO(b/218494522): Remove this and usages of compos_key.
+ return {};
}
-Result<OdsignInfo> getComposInfo(const std::vector<uint8_t>& compos_key) {
- std::string compos_signature;
- if (!android::base::ReadFileToString(kCompOsInfoSignature, &compos_signature)) {
- return ErrnoError() << "Failed to read " << kCompOsInfoSignature;
+Result<OdsignInfo> getComposInfo(const std::vector<uint8_t>& /*compos_key*/) {
+ const char* const argv[] = {kCompOsVerifyPath, "--instance", "current"};
+ int result =
+ logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
+ if (result != 0) {
+ return Error() << kCompOsVerifyPath << " returned " << result;
}
std::string compos_info_str;
@@ -467,21 +350,12 @@
return ErrnoError() << "Failed to read " << kCompOsInfo;
}
- // Delete the files - if they're valid we don't need them any more, and
- // they'd confuse artifact verification; if they're not we never need to
- // look at them again.
+ // Delete the files - we don't need them any more, and they'd confuse
+ // artifact verification
if (unlink(kCompOsInfo.c_str()) != 0 || unlink(kCompOsInfoSignature.c_str()) != 0) {
return ErrnoError() << "Unable to delete CompOS info/signature file";
}
- // Verify the signature
- auto verified = verifyRsaPublicKeySignature(compos_info_str, compos_signature, compos_key);
- if (!verified.ok()) {
- return Error() << kCompOsInfoSignature << " does not match.";
- } else {
- LOG(INFO) << kCompOsInfoSignature << " matches.";
- }
-
OdsignInfo compos_info;
if (!compos_info.ParseFromString(compos_info_str)) {
return Error() << "Failed to parse " << kCompOsInfo;