Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1a7cc01 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Implement alternate SE RoT provisioning"

parents 5adaa1e8 4315e135
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -873,7 +873,7 @@ interface IKeyMintDevice {
     * The returned data is an encoded COSE_Mac0 structure, denoted MacedRootOfTrust in the
     * following CDDL schema.  Note that K_mac is the shared HMAC key used for auth tokens, etc.:
     *
     *     MacedRootOfTrust = [               ; COSE_Mac0 (untagged)
     *     MacedRootOfTrust = #6.17 [         ; COSE_Mac0 (tagged)
     *         protected: bstr .cbor {
     *             1 : 5,                     ; Algorithm : HMAC-256
     *         },
@@ -891,7 +891,7 @@ interface IKeyMintDevice {
     *         payload : bstr .cbor RootOfTrust,
     *     ]
     *
     *     RootOfTrust = [
     *     RootOfTrust = #6.40001 [           ; Tag 40001 indicates RoT v1.
     *         verifiedBootKey : bstr .size 32,
     *         deviceLocked : bool,
     *         verifiedBootState : &VerifiedBootState,
+55 −51
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@
#include <remote_prov/remote_prov_utils.h>

#include <keymaster/cppcose/cppcose.h>
#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
#include <keymint_support/openssl_utils.h>
@@ -1497,6 +1496,60 @@ void verify_subject_and_serial(const Certificate& certificate, //
    verify_subject(cert.get(), subject, self_signed);
}

void verify_root_of_trust(const vector<uint8_t>& verified_boot_key, bool device_locked,
                          VerifiedBoot verified_boot_state,
                          const vector<uint8_t>& verified_boot_hash) {
    char property_value[PROPERTY_VALUE_MAX] = {};

    if (avb_verification_enabled()) {
        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
        string prop_string(property_value);
        EXPECT_EQ(prop_string.size(), 64);
        EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));

        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
        if (!strcmp(property_value, "unlocked")) {
            EXPECT_FALSE(device_locked);
        } else {
            EXPECT_TRUE(device_locked);
        }

        // Check that the device is locked if not debuggable, e.g., user build
        // images in CTS. For VTS, debuggable images are used to allow adb root
        // and the device is unlocked.
        if (!property_get_bool("ro.debuggable", false)) {
            EXPECT_TRUE(device_locked);
        } else {
            EXPECT_FALSE(device_locked);
        }
    }

    // Verified boot key should be all 0's if the boot state is not verified or self signed
    std::string empty_boot_key(32, '\0');
    std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                      verified_boot_key.size());
    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
    if (!strcmp(property_value, "green")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    } else if (!strcmp(property_value, "yellow")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    } else if (!strcmp(property_value, "orange")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    } else if (!strcmp(property_value, "red")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
    } else {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    }
}

bool verify_attestation_record(int32_t aidl_version,                   //
                               const string& challenge,                //
                               const string& app_id,                   //
@@ -1551,8 +1604,6 @@ bool verify_attestation_record(int32_t aidl_version, //
    EXPECT_EQ(security_level, att_keymint_security_level);
    EXPECT_EQ(security_level, att_attestation_security_level);


    char property_value[PROPERTY_VALUE_MAX] = {};
    // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
    // keymint implementation will report YYYYMM dates instead of YYYYMMDD
    // for the BOOT_PATCH_LEVEL.
@@ -1612,54 +1663,7 @@ bool verify_attestation_record(int32_t aidl_version, //
    error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
                                &verified_boot_state, &device_locked, &verified_boot_hash);
    EXPECT_EQ(ErrorCode::OK, error);

    if (avb_verification_enabled()) {
        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
        string prop_string(property_value);
        EXPECT_EQ(prop_string.size(), 64);
        EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));

        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
        if (!strcmp(property_value, "unlocked")) {
            EXPECT_FALSE(device_locked);
        } else {
            EXPECT_TRUE(device_locked);
        }

        // Check that the device is locked if not debuggable, e.g., user build
        // images in CTS. For VTS, debuggable images are used to allow adb root
        // and the device is unlocked.
        if (!property_get_bool("ro.debuggable", false)) {
            EXPECT_TRUE(device_locked);
        } else {
            EXPECT_FALSE(device_locked);
        }
    }

    // Verified boot key should be all 0's if the boot state is not verified or self signed
    std::string empty_boot_key(32, '\0');
    std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                      verified_boot_key.size());
    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
    if (!strcmp(property_value, "green")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    } else if (!strcmp(property_value, "yellow")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    } else if (!strcmp(property_value, "orange")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    } else if (!strcmp(property_value, "red")) {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
    } else {
        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                            verified_boot_key.size()));
    }
    verify_root_of_trust(verified_boot_key, device_locked, verified_boot_state, verified_boot_hash);

    att_sw_enforced.Sort();
    expected_sw_enforced.Sort();
+5 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>

#include <keymint_support/attestation_record.h>
#include <keymint_support/authorization_set.h>
#include <keymint_support/openssl_utils.h>

@@ -363,7 +364,10 @@ void verify_serial(X509* cert, const uint64_t expected_serial);
void verify_subject_and_serial(const Certificate& certificate,  //
                               const uint64_t expected_serial,  //
                               const string& subject, bool self_signed);

void verify_root_of_trust(const vector<uint8_t>& verified_boot_key,  //
                          bool device_locked,                        //
                          VerifiedBoot verified_boot_state,          //
                          const vector<uint8_t>& verified_boot_hash);
bool verify_attestation_record(int aidl_version,                       //
                               const string& challenge,                //
                               const string& app_id,                   //
+85 −14
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ using std::map;
using std::shared_ptr;
using std::vector;

constexpr int kRoTVersion1 = 40001;

class SecureElementProvisioningTest : public testing::Test {
  protected:
    static void SetUpTestSuite() {
@@ -57,6 +59,83 @@ class SecureElementProvisioningTest : public testing::Test {
        }
    }

    void validateMacedRootOfTrust(const vector<uint8_t>& rootOfTrust) {
        SCOPED_TRACE(testing::Message() << "RoT: " << bin2hex(rootOfTrust));

        const auto [macItem, macEndPos, macErrMsg] = cppbor::parse(rootOfTrust);
        ASSERT_TRUE(macItem) << "Root of trust parsing failed: " << macErrMsg;
        ASSERT_EQ(macItem->semanticTagCount(), 1);
        ASSERT_EQ(macItem->semanticTag(0), cppcose::kCoseMac0SemanticTag);
        ASSERT_TRUE(macItem->asArray());
        ASSERT_EQ(macItem->asArray()->size(), cppcose::kCoseMac0EntryCount);

        const auto& protectedItem = macItem->asArray()->get(cppcose::kCoseMac0ProtectedParams);
        ASSERT_TRUE(protectedItem);
        ASSERT_TRUE(protectedItem->asBstr());
        const auto [protMap, protEndPos, protErrMsg] = cppbor::parse(protectedItem->asBstr());
        ASSERT_TRUE(protMap);
        ASSERT_TRUE(protMap->asMap());
        ASSERT_EQ(protMap->asMap()->size(), 1);

        const auto& algorithm = protMap->asMap()->get(cppcose::ALGORITHM);
        ASSERT_TRUE(algorithm);
        ASSERT_TRUE(algorithm->asInt());
        ASSERT_EQ(algorithm->asInt()->value(), cppcose::HMAC_256);

        const auto& unprotItem = macItem->asArray()->get(cppcose::kCoseMac0UnprotectedParams);
        ASSERT_TRUE(unprotItem);
        ASSERT_TRUE(unprotItem->asMap());
        ASSERT_EQ(unprotItem->asMap()->size(), 0);

        const auto& payload = macItem->asArray()->get(cppcose::kCoseMac0Payload);
        ASSERT_TRUE(payload);
        ASSERT_TRUE(payload->asBstr());
        validateRootOfTrust(payload->asBstr()->value());

        const auto& tag = macItem->asArray()->get(cppcose::kCoseMac0Tag);
        ASSERT_TRUE(tag);
        ASSERT_TRUE(tag->asBstr());
        ASSERT_EQ(tag->asBstr()->value().size(), 32);
        // Cannot validate tag correctness.  Only the secure side has the necessary key.
    }

    void validateRootOfTrust(const vector<uint8_t>& payload) {
        SCOPED_TRACE(testing::Message() << "RoT payload: " << bin2hex(payload));

        const auto [rot, rotPos, rotErrMsg] = cppbor::parse(payload);
        ASSERT_TRUE(rot);
        ASSERT_EQ(rot->semanticTagCount(), 1);
        ASSERT_EQ(rot->semanticTag(), kRoTVersion1);
        ASSERT_TRUE(rot->asArray());
        ASSERT_EQ(rot->asArray()->size(), 5);

        size_t pos = 0;

        const auto& vbKey = rot->asArray()->get(pos++);
        ASSERT_TRUE(vbKey);
        ASSERT_TRUE(vbKey->asBstr());

        const auto& deviceLocked = rot->asArray()->get(pos++);
        ASSERT_TRUE(deviceLocked);
        ASSERT_TRUE(deviceLocked->asBool());

        const auto& verifiedBootState = rot->asArray()->get(pos++);
        ASSERT_TRUE(verifiedBootState);
        ASSERT_TRUE(verifiedBootState->asInt());

        const auto& verifiedBootHash = rot->asArray()->get(pos++);
        ASSERT_TRUE(verifiedBootHash);
        ASSERT_TRUE(verifiedBootHash->asBstr());

        const auto& bootPatchLevel = rot->asArray()->get(pos++);
        ASSERT_TRUE(bootPatchLevel);
        ASSERT_TRUE(bootPatchLevel->asInt());

        verify_root_of_trust(vbKey->asBstr()->value(), deviceLocked->asBool()->value(),
                             static_cast<VerifiedBoot>(verifiedBootState->asInt()->value()),
                             verifiedBootHash->asBstr()->value());
    }

    int32_t AidlVersion(shared_ptr<IKeyMintDevice> keymint) {
        int32_t version = 0;
        auto status = keymint->getInterfaceVersion(&version);
@@ -96,29 +175,19 @@ TEST_F(SecureElementProvisioningTest, TeeOnly) {

    vector<uint8_t> rootOfTrust1;
    Status result = tee->getRootOfTrust(challenge1, &rootOfTrust1);

    // TODO: Remove the next line to require TEEs to succeed.
    if (!result.isOk()) return;

    ASSERT_TRUE(result.isOk());

    // TODO:  Parse and validate rootOfTrust1 here
    ASSERT_TRUE(result.isOk()) << "getRootOfTrust returned " << result.getServiceSpecificError();
    validateMacedRootOfTrust(rootOfTrust1);

    vector<uint8_t> rootOfTrust2;
    result = tee->getRootOfTrust(challenge2, &rootOfTrust2);
    ASSERT_TRUE(result.isOk());

    // TODO:  Parse and validate rootOfTrust2 here

    validateMacedRootOfTrust(rootOfTrust2);
    ASSERT_NE(rootOfTrust1, rootOfTrust2);

    vector<uint8_t> rootOfTrust3;
    result = tee->getRootOfTrust(challenge1, &rootOfTrust3);
    ASSERT_TRUE(result.isOk());

    ASSERT_EQ(rootOfTrust1, rootOfTrust3);

    // TODO:  Parse and validate rootOfTrust3 here
}

TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
@@ -252,7 +321,7 @@ TEST_F(SecureElementProvisioningTest, ProvisioningTest) {
    result = tee->getRootOfTrust(challenge, &rootOfTrust);
    ASSERT_TRUE(result.isOk());

    // TODO: Verify COSE_Mac0 structure and content here.
    validateMacedRootOfTrust(rootOfTrust);

    result = sb->sendRootOfTrust(rootOfTrust);
    ASSERT_TRUE(result.isOk());
@@ -296,6 +365,8 @@ TEST_F(SecureElementProvisioningTest, InvalidProvisioningTest) {
    result = tee->getRootOfTrust(challenge, &rootOfTrust);
    ASSERT_TRUE(result.isOk());

    validateMacedRootOfTrust(rootOfTrust);

    vector<uint8_t> corruptedRootOfTrust = rootOfTrust;
    corruptedRootOfTrust[corruptedRootOfTrust.size() / 2]++;
    result = sb->sendRootOfTrust(corruptedRootOfTrust);