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

Commit f45e60a2 authored by David Drysdale's avatar David Drysdale Committed by Automerger Merge Worker
Browse files

Merge "KeyMint VTS tests for module hash feature" into main am: 76418972 am: 5b0c5e5f

parents a97d6bd8 5b0c5e5f
Loading
Loading
Loading
Loading
+109 −15
Original line number Diff line number Diff line
@@ -160,12 +160,13 @@ bool avb_verification_enabled() {
char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

// Attestations don't contain everything in key authorization lists, so we need to filter the key
// lists to produce the lists that we expect to match the attestations.
// Attestations don't completely align with key authorization lists, so we need to filter the lists
// to include only the tags that are in both.
auto kTagsToFilter = {
        Tag::CREATION_DATETIME,
        Tag::HARDWARE_TYPE,
        Tag::INCLUDE_UNIQUE_ID,
        Tag::MODULE_HASH,
};

AuthorizationSet filtered_tags(const AuthorizationSet& set) {
@@ -234,6 +235,83 @@ uint32_t KeyMintAidlTestBase::boot_patch_level() {
    return boot_patch_level(key_characteristics_);
}

std::optional<vector<uint8_t>> KeyMintAidlTestBase::getModuleHash() {
    if (AidlVersion() < 4) {
        // The `MODULE_HASH` tag was introduced in v4 of the HAL; earlier versions should never
        // expect to encounter it.
        return std::nullopt;
    }

    // The KeyMint instance should already have been informed of the `MODULE_HASH` value for the
    // currently running system. Generate a single attestation so we can find out what the value
    // is.
    auto challenge = "hello";
    auto app_id = "foo";
    auto params = AuthorizationSetBuilder()
                          .EcdsaSigningKey(EcCurve::P_256)
                          .Digest(Digest::NONE)
                          .Authorization(TAG_NO_AUTH_REQUIRED)
                          .AttestationChallenge(challenge)
                          .AttestationApplicationId(app_id)
                          .SetDefaultValidity();
    vector<uint8_t> key_blob;
    vector<KeyCharacteristics> key_characteristics;
    vector<Certificate> chain;
    auto result = GenerateKey(params, &key_blob, &key_characteristics, &chain);
    if (result != ErrorCode::OK) {
        ADD_FAILURE() << "Failed to generate attestation:" << result;
        return std::nullopt;
    }
    KeyBlobDeleter deleter(keymint_, key_blob);
    if (chain.empty()) {
        ADD_FAILURE() << "No attestation cert";
        return std::nullopt;
    }

    // Parse the attestation record in the leaf cert.
    X509_Ptr cert(parse_cert_blob(chain[0].encodedCertificate));
    if (cert.get() == nullptr) {
        ADD_FAILURE() << "Failed to parse attestation cert";
        return std::nullopt;
    }
    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
    if (attest_rec == nullptr) {
        ADD_FAILURE() << "Failed to find attestation extension";
        return std::nullopt;
    }
    AuthorizationSet att_sw_enforced;
    AuthorizationSet att_hw_enforced;
    uint32_t att_attestation_version;
    uint32_t att_keymint_version;
    SecurityLevel att_attestation_security_level;
    SecurityLevel att_keymint_security_level;
    vector<uint8_t> att_challenge;
    vector<uint8_t> att_unique_id;
    vector<uint8_t> att_app_id;

    auto error = parse_attestation_record(attest_rec->data,                 //
                                          attest_rec->length,               //
                                          &att_attestation_version,         //
                                          &att_attestation_security_level,  //
                                          &att_keymint_version,             //
                                          &att_keymint_security_level,      //
                                          &att_challenge,                   //
                                          &att_sw_enforced,                 //
                                          &att_hw_enforced,                 //
                                          &att_unique_id);
    if (error != ErrorCode::OK) {
        ADD_FAILURE() << "Failed to parse attestation extension";
        return std::nullopt;
    }

    // The module hash should be present in the software-enforced list.
    if (!att_sw_enforced.Contains(TAG_MODULE_HASH)) {
        ADD_FAILURE() << "No TAG_MODULE_HASH in attestation extension";
        return std::nullopt;
    }
    return att_sw_enforced.GetTagValue(TAG_MODULE_HASH);
}

/**
 * An API to determine device IDs attestation is required or not,
 * which is mandatory for KeyMint version 2 and first_api_level 33 or greater.
@@ -270,12 +348,7 @@ bool KeyMintAidlTestBase::Curve25519Supported() {
    }

    // Curve 25519 was included in version 2 of the KeyMint interface.
    int32_t version = 0;
    auto status = keymint_->getInterfaceVersion(&version);
    if (!status.isOk()) {
        ADD_FAILURE() << "Failed to determine interface version";
    }
    return version >= 2;
    return AidlVersion() >= 2;
}

void KeyMintAidlTestBase::InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyMint) {
@@ -293,6 +366,20 @@ void KeyMintAidlTestBase::InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyM
    os_version_ = getOsVersion();
    os_patch_level_ = getOsPatchlevel();
    vendor_patch_level_ = getVendorPatchlevel();

    // TODO(b/369375199): temporary code, remove when apexd -> keystore2 -> KeyMint transmission
    // of module info happens.
    {
        GTEST_LOG_(INFO) << "Setting MODULE_HASH to fake value as fallback";
        // Ensure that a MODULE_HASH value is definitely present in KeyMint (if it's >= v4).
        vector<uint8_t> fakeModuleHash = {
                0xf3, 0xf1, 0x1f, 0xe5, 0x13, 0x05, 0xfe, 0xfa, 0xe9, 0xc3, 0x53,
                0xef, 0x69, 0xdf, 0x9f, 0xd7, 0x0c, 0x1e, 0xcc, 0x2c, 0x2c, 0x62,
                0x1f, 0x5e, 0x2c, 0x1d, 0x19, 0xa1, 0xfd, 0xac, 0xa1, 0xb4,
        };
        vector<KeyParameter> info = {Authorization(TAG_MODULE_HASH, fakeModuleHash)};
        keymint_->setAdditionalAttestationInfo(info);
    }
}

int32_t KeyMintAidlTestBase::AidlVersion() const {
@@ -320,6 +407,13 @@ ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
                                           vector<uint8_t>* key_blob,
                                           vector<KeyCharacteristics>* key_characteristics) {
    return GenerateKey(key_desc, key_blob, key_characteristics, &cert_chain_);
}

ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
                                           vector<uint8_t>* key_blob,
                                           vector<KeyCharacteristics>* key_characteristics,
                                           vector<Certificate>* cert_chain) {
    std::optional<AttestationKey> attest_key = std::nullopt;
    vector<Certificate> attest_cert_chain;
    // If an attestation is requested, but the system is RKP-only, we need to supply an explicit
@@ -340,11 +434,10 @@ ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
        attest_key.value().issuerSubjectName = make_name_from_str("Android Keystore Key");
    }

    ErrorCode error =
            GenerateKey(key_desc, attest_key, key_blob, key_characteristics, &cert_chain_);
    ErrorCode error = GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);

    if (error == ErrorCode::OK && attest_cert_chain.size() > 0) {
        cert_chain_.push_back(attest_cert_chain[0]);
        cert_chain->push_back(attest_cert_chain[0]);
    }

    return error;
@@ -2353,7 +2446,7 @@ std::string exec_command(const std::string& command) {

    FILE* pipe = popen(command.c_str(), "r");
    if (!pipe) {
        LOG(ERROR) << "popen failed.";
        GTEST_LOG_(ERROR) << "popen failed.";
        return result;
    }

@@ -2379,7 +2472,7 @@ std::string get_imei(int slot) {
    std::string output = exec_command(cmd);

    if (output.empty()) {
        LOG(ERROR) << "Command failed. Cmd: " << cmd;
        GTEST_LOG_(ERROR) << "Command failed. Cmd: " << cmd;
        return "";
    }

@@ -2387,13 +2480,14 @@ std::string get_imei(int slot) {
            ::android::base::Tokenize(::android::base::Trim(output), "Device IMEI:");

    if (out.size() != 1) {
        LOG(ERROR) << "Error in parsing the command output. Cmd: " << cmd;
        GTEST_LOG_(ERROR) << "Error in parsing the command output. Cmd: " << cmd;
        return "";
    }

    std::string imei = ::android::base::Trim(out[0]);
    if (imei.compare("null") == 0) {
        LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
        GTEST_LOG_(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: "
                            << cmd;
        return "";
    }

+5 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
    uint32_t vendor_patch_level() { return vendor_patch_level_; }
    uint32_t boot_patch_level(const vector<KeyCharacteristics>& key_characteristics);
    uint32_t boot_patch_level();
    std::optional<vector<uint8_t>> getModuleHash();
    bool isDeviceIdAttestationRequired();
    bool isSecondImeiIdAttestationRequired();
    std::optional<bool> isRkpOnly();
@@ -114,6 +115,10 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
    ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
                          vector<KeyCharacteristics>* key_characteristics);

    ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
                          vector<KeyCharacteristics>* key_characteristics,
                          vector<Certificate>* cert_chain);

    ErrorCode GenerateKey(const AuthorizationSet& key_desc,
                          const optional<AttestationKey>& attest_key, vector<uint8_t>* key_blob,
                          vector<KeyCharacteristics>* key_characteristics,
+56 −0
Original line number Diff line number Diff line
@@ -643,6 +643,7 @@ class NewKeyGenerationTest : public KeyMintAidlTestBase {
        // Verify that App data, ROT and auth timeout are NOT included.
        EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
        EXPECT_FALSE(auths.Contains(TAG_MODULE_HASH));
        EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U));

        // None of the tests specify CREATION_DATETIME so check that the KeyMint implementation
@@ -8892,6 +8893,49 @@ TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {

INSTANTIATE_KEYMINT_AIDL_TEST(EarlyBootKeyTest);

using ModuleHashTest = KeyMintAidlTestBase;

TEST_P(ModuleHashTest, SetSameValue) {
    if (AidlVersion() < 4) {
        GTEST_SKIP() << "Module hash only available for >= v4, this device is v" << AidlVersion();
    }
    auto module_hash = getModuleHash();
    ASSERT_TRUE(module_hash.has_value());

    // Setting the same value that's already there should work.
    vector<KeyParameter> info = {Authorization(TAG_MODULE_HASH, module_hash.value())};
    EXPECT_TRUE(keymint_->setAdditionalAttestationInfo(info).isOk());
}

TEST_P(ModuleHashTest, SetDifferentValue) {
    if (AidlVersion() < 4) {
        GTEST_SKIP() << "Module hash only available for >= v4, this device is v" << AidlVersion();
    }
    auto module_hash = getModuleHash();
    ASSERT_TRUE(module_hash.has_value());
    vector<uint8_t> wrong_hash = module_hash.value();
    ASSERT_EQ(wrong_hash.size(), 32);

    // Setting a slightly different value should fail.
    wrong_hash[0] ^= 0x01;
    vector<KeyParameter> info = {Authorization(TAG_MODULE_HASH, wrong_hash)};
    EXPECT_EQ(GetReturnErrorCode(keymint_->setAdditionalAttestationInfo(info)),
              ErrorCode::MODULE_HASH_ALREADY_SET);
}

TEST_P(ModuleHashTest, SetUnrelatedTag) {
    if (AidlVersion() < 4) {
        GTEST_SKIP() << "Module hash only available for >= v4, this device is v" << AidlVersion();
    }

    // Trying to set an unexpected tag should be silently ignored..
    vector<uint8_t> data = {0, 1, 2, 3, 4};
    vector<KeyParameter> info = {Authorization(TAG_ROOT_OF_TRUST, data)};
    EXPECT_EQ(GetReturnErrorCode(keymint_->setAdditionalAttestationInfo(info)), ErrorCode::OK);
}

INSTANTIATE_KEYMINT_AIDL_TEST(ModuleHashTest);

using VsrRequirementTest = KeyMintAidlTestBase;

// @VsrTest = VSR-3.10-008
@@ -8912,6 +8956,18 @@ TEST_P(VsrRequirementTest, Vsr14Test) {
    EXPECT_GE(AidlVersion(), 3) << "VSR 14+ requires KeyMint version 3";
}

// @VsrTest = GMS-VSR-3.10-019
TEST_P(VsrRequirementTest, Vsr16Test) {
    int vsr_api_level = get_vsr_api_level();
    if (vsr_api_level <= __ANDROID_API_V__) {
        GTEST_SKIP() << "Applies only to VSR API level > 35, this device is: " << vsr_api_level;
    }
    if (SecLevel() == SecurityLevel::STRONGBOX) {
        GTEST_SKIP() << "Applies only to TEE KeyMint, not StrongBox KeyMint";
    }
    EXPECT_GE(AidlVersion(), 4) << "VSR 16+ requires KeyMint version 4 in TEE";
}

INSTANTIATE_KEYMINT_AIDL_TEST(VsrRequirementTest);

class InstanceTest : public testing::Test {
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ cc_library {
        "-Wall",
        "-Wextra",
        "-Werror",
        "-DKEYMINT_HAL_V4",
    ],
    srcs: [
        "attestation_record.cpp",
+3 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ typedef struct km_auth_list {
    ASN1_NULL* device_unique_attestation;
    ASN1_NULL* identity_credential;
    ASN1_OCTET_STRING* attestation_id_second_imei;
    ASN1_OCTET_STRING* module_hash;
} KM_AUTH_LIST;

ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -173,6 +174,7 @@ ASN1_SEQUENCE(KM_AUTH_LIST) = {
                     TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_second_imei, ASN1_OCTET_STRING,
                     TAG_ATTESTATION_ID_SECOND_IMEI.maskedTag()),
        ASN1_EXP_OPT(KM_AUTH_LIST, module_hash, ASN1_OCTET_STRING, TAG_MODULE_HASH.maskedTag()),
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);

@@ -327,6 +329,7 @@ static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet*
    copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
    copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
    copyAuthTag(record->attestation_id_second_imei, TAG_ATTESTATION_ID_SECOND_IMEI, auth_list);
    copyAuthTag(record->module_hash, TAG_MODULE_HASH, auth_list);

    return ErrorCode::OK;
}
Loading