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

Commit 37af4b36 authored by David Drysdale's avatar David Drysdale
Browse files

KeyMint VTS: more attestation info tests

Try all tags in attestion extension one by one

Test: VtsAidlKeyMintTargetTest on CF
Bug: 186735514
Change-Id: I63ca8d298d2d16f707f2437ab48aaa69c1d7563d
parent 66b8018f
Loading
Loading
Loading
Loading
+36 −21
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ namespace test {

namespace {

// Invalid value for a patchlevel (which is of form YYYYMMDD).
const uint32_t kInvalidPatchlevel = 99998877;

// Overhead for PKCS#1 v1.5 signature padding of undigested messages.  Digested messages have
// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
@@ -127,7 +130,6 @@ char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
// lists to produce the lists that we expect to match the attestations.
auto kTagsToFilter = {
        Tag::CREATION_DATETIME,
    Tag::EC_CURVE,
        Tag::HARDWARE_TYPE,
        Tag::INCLUDE_UNIQUE_ID,
};
@@ -163,6 +165,28 @@ string x509NameToStr(X509_NAME* name) {
bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
bool KeyMintAidlTestBase::dump_Attestations = false;

uint32_t KeyMintAidlTestBase::boot_patch_level(
        const vector<KeyCharacteristics>& key_characteristics) {
    // The boot patchlevel is not available as a property, but should be present
    // in the key characteristics of any created key.
    AuthorizationSet allAuths;
    for (auto& entry : key_characteristics) {
        allAuths.push_back(AuthorizationSet(entry.authorizations));
    }
    auto patchlevel = allAuths.GetTagValue(TAG_BOOT_PATCHLEVEL);
    if (patchlevel.has_value()) {
        return patchlevel.value();
    } else {
        // No boot patchlevel is available. Return a value that won't match anything
        // and so will trigger test failures.
        return kInvalidPatchlevel;
    }
}

uint32_t KeyMintAidlTestBase::boot_patch_level() {
    return boot_patch_level(key_characteristics_);
}

ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
    if (result.isOk()) return ErrorCode::OK;

@@ -1293,9 +1317,9 @@ bool verify_attestation_record(const string& challenge, //
    AuthorizationSet att_sw_enforced;
    AuthorizationSet att_hw_enforced;
    uint32_t att_attestation_version;
    uint32_t att_keymaster_version;
    uint32_t att_keymint_version;
    SecurityLevel att_attestation_security_level;
    SecurityLevel att_keymaster_security_level;
    SecurityLevel att_keymint_security_level;
    vector<uint8_t> att_challenge;
    vector<uint8_t> att_unique_id;
    vector<uint8_t> att_app_id;
@@ -1304,8 +1328,8 @@ bool verify_attestation_record(const string& challenge, //
                                          attest_rec->length,               //
                                          &att_attestation_version,         //
                                          &att_attestation_security_level,  //
                                          &att_keymaster_version,           //
                                          &att_keymaster_security_level,    //
                                          &att_keymint_version,             //
                                          &att_keymint_security_level,      //
                                          &att_challenge,                   //
                                          &att_sw_enforced,                 //
                                          &att_hw_enforced,                 //
@@ -1324,14 +1348,14 @@ bool verify_attestation_record(const string& challenge, //
        expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, appId);
    }

    EXPECT_EQ(att_keymaster_version, 100U);
    EXPECT_EQ(security_level, att_keymaster_security_level);
    EXPECT_EQ(att_keymint_version, 100U);
    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
    // keymaster implementation will report YYYYMM dates instead of YYYYMMDD
    // keymint implementation will report YYYYMM dates instead of YYYYMMDD
    // for the BOOT_PATCH_LEVEL.
    if (avb_verification_enabled()) {
        for (int i = 0; i < att_hw_enforced.size(); i++) {
@@ -1370,13 +1394,6 @@ bool verify_attestation_record(const string& challenge, //
        EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
    }

    // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
    // the authorization list during key generation) isn't being attested to in the certificate.
    EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
    EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
    EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
    EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));

    if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
        // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
        EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
@@ -1442,9 +1459,7 @@ bool verify_attestation_record(const string& challenge, //

    att_sw_enforced.Sort();
    expected_sw_enforced.Sort();
    auto a = filtered_tags(expected_sw_enforced);
    auto b = filtered_tags(att_sw_enforced);
    EXPECT_EQ(a, b);
    EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced));

    att_hw_enforced.Sort();
    expected_hw_enforced.Sort();
+2 −0
Original line number Diff line number Diff line
@@ -76,6 +76,8 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
    uint32_t os_version() { return os_version_; }
    uint32_t os_patch_level() { return os_patch_level_; }
    uint32_t vendor_patch_level() { return vendor_patch_level_; }
    uint32_t boot_patch_level(const vector<KeyCharacteristics>& key_characteristics);
    uint32_t boot_patch_level();

    ErrorCode GetReturnErrorCode(const Status& result);

+166 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <cutils/log.h>

#include <signal.h>

#include <algorithm>
#include <iostream>

#include <openssl/ec.h>
@@ -1438,6 +1440,170 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestation) {
    }
}

/*
 * NewKeyGenerationTest.EcdsaAttestationTags
 *
 * Verifies that creation of an attested ECDSA key includes various tags in the
 * attestation extension.
 */
TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
    auto challenge = "hello";
    auto app_id = "foo";
    auto subject = "cert subj 2";
    vector<uint8_t> subject_der(make_name_from_str(subject));
    uint64_t serial_int = 0x1010;
    vector<uint8_t> serial_blob(build_serial_blob(serial_int));
    const AuthorizationSetBuilder base_builder =
            AuthorizationSetBuilder()
                    .Authorization(TAG_NO_AUTH_REQUIRED)
                    .EcdsaSigningKey(256)
                    .Digest(Digest::NONE)
                    .AttestationChallenge(challenge)
                    .AttestationApplicationId(app_id)
                    .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
                    .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                    .SetDefaultValidity();

    // Various tags that map to fields in the attestation extension ASN.1 schema.
    auto extra_tags = AuthorizationSetBuilder()
                              .Authorization(TAG_ROLLBACK_RESISTANCE)
                              .Authorization(TAG_EARLY_BOOT_ONLY)
                              .Authorization(TAG_ACTIVE_DATETIME, 1619621648000)
                              .Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, 1619621648000)
                              .Authorization(TAG_USAGE_EXPIRE_DATETIME, 1619621999000)
                              .Authorization(TAG_USAGE_COUNT_LIMIT, 42)
                              .Authorization(TAG_AUTH_TIMEOUT, 100000)
                              .Authorization(TAG_ALLOW_WHILE_ON_BODY)
                              .Authorization(TAG_TRUSTED_USER_PRESENCE_REQUIRED)
                              .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)
                              .Authorization(TAG_UNLOCKED_DEVICE_REQUIRED)
                              .Authorization(TAG_CREATION_DATETIME, 1619621648000);
    for (const KeyParameter& tag : extra_tags) {
        SCOPED_TRACE(testing::Message() << "tag-" << tag);
        vector<uint8_t> key_blob;
        vector<KeyCharacteristics> key_characteristics;
        AuthorizationSetBuilder builder = base_builder;
        builder.push_back(tag);
        auto result = GenerateKey(builder, &key_blob, &key_characteristics);
        if (result == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE &&
            tag.tag == TAG_ROLLBACK_RESISTANCE) {
            continue;
        }
        if (result == ErrorCode::UNSUPPORTED_TAG &&
            (tag.tag == TAG_ALLOW_WHILE_ON_BODY || tag.tag == TAG_TRUSTED_USER_PRESENCE_REQUIRED)) {
            // Optional tag not supported by this KeyMint implementation.
            continue;
        }
        ASSERT_EQ(result, ErrorCode::OK);
        ASSERT_GT(key_blob.size(), 0U);

        EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
        ASSERT_GT(cert_chain_.size(), 0);
        verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);

        AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
        AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
        if (tag.tag != TAG_ATTESTATION_APPLICATION_ID) {
            // Expect to find most of the extra tags in the key characteristics
            // of the generated key (but not for ATTESTATION_APPLICATION_ID).
            EXPECT_TRUE(hw_enforced.Contains(tag.tag) || sw_enforced.Contains(tag.tag))
                    << tag << " not in hw:" << hw_enforced << " nor sw:" << sw_enforced;
        }

        // Verifying the attestation record will check for the specific tag because
        // it's included in the authorizations.
        EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
                                              SecLevel(), cert_chain_[0].encodedCertificate));

        CheckedDeleteKey(&key_blob);
    }

    // Device attestation IDs should be rejected for normal attestation requests; these fields
    // are only used for device unique attestation.
    auto invalid_tags = AuthorizationSetBuilder()
                                .Authorization(TAG_ATTESTATION_ID_BRAND, "brand")
                                .Authorization(TAG_ATTESTATION_ID_DEVICE, "device")
                                .Authorization(TAG_ATTESTATION_ID_PRODUCT, "product")
                                .Authorization(TAG_ATTESTATION_ID_SERIAL, "serial")
                                .Authorization(TAG_ATTESTATION_ID_IMEI, "imei")
                                .Authorization(TAG_ATTESTATION_ID_MEID, "meid")
                                .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer")
                                .Authorization(TAG_ATTESTATION_ID_MODEL, "model");
    for (const KeyParameter& tag : invalid_tags) {
        SCOPED_TRACE(testing::Message() << "tag-" << tag);
        vector<uint8_t> key_blob;
        vector<KeyCharacteristics> key_characteristics;
        AuthorizationSetBuilder builder =
                AuthorizationSetBuilder()
                        .Authorization(TAG_NO_AUTH_REQUIRED)
                        .EcdsaSigningKey(256)
                        .Digest(Digest::NONE)
                        .AttestationChallenge(challenge)
                        .AttestationApplicationId(app_id)
                        .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
                        .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                        .SetDefaultValidity();
        builder.push_back(tag);
        ASSERT_EQ(ErrorCode::CANNOT_ATTEST_IDS,
                  GenerateKey(builder, &key_blob, &key_characteristics));
    }
}

/*
 * NewKeyGenerationTest.EcdsaAttestationTagNoApplicationId
 *
 * Verifies that creation of an attested ECDSA key does not include APPLICATION_ID.
 */
TEST_P(NewKeyGenerationTest, EcdsaAttestationTagNoApplicationId) {
    auto challenge = "hello";
    auto attest_app_id = "foo";
    auto subject = "cert subj 2";
    vector<uint8_t> subject_der(make_name_from_str(subject));
    uint64_t serial_int = 0x1010;
    vector<uint8_t> serial_blob(build_serial_blob(serial_int));

    // Earlier versions of the attestation extension schema included a slot:
    //     applicationId  [601] EXPLICIT OCTET_STRING OPTIONAL,
    // This should never have been included, and should never be filled in.
    // Generate an attested key that include APPLICATION_ID and APPLICATION_DATA,
    // to confirm that this field never makes it into the attestation extension.
    vector<uint8_t> key_blob;
    vector<KeyCharacteristics> key_characteristics;
    auto result = GenerateKey(AuthorizationSetBuilder()
                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                      .EcdsaSigningKey(EcCurve::P_256)
                                      .Digest(Digest::NONE)
                                      .AttestationChallenge(challenge)
                                      .AttestationApplicationId(attest_app_id)
                                      .Authorization(TAG_APPLICATION_ID, "client_id")
                                      .Authorization(TAG_APPLICATION_DATA, "appdata")
                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                                      .SetDefaultValidity(),
                              &key_blob, &key_characteristics);
    ASSERT_EQ(result, ErrorCode::OK);
    ASSERT_GT(key_blob.size(), 0U);

    EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
    ASSERT_GT(cert_chain_.size(), 0);
    verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);

    AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
    AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
    EXPECT_TRUE(verify_attestation_record(challenge, attest_app_id, sw_enforced, hw_enforced,
                                          SecLevel(), cert_chain_[0].encodedCertificate));

    // Check that the app id is not in the cert.
    string app_id = "clientid";
    std::vector<uint8_t> needle(reinterpret_cast<const uint8_t*>(app_id.data()),
                                reinterpret_cast<const uint8_t*>(app_id.data()) + app_id.size());
    ASSERT_EQ(std::search(cert_chain_[0].encodedCertificate.begin(),
                          cert_chain_[0].encodedCertificate.end(), needle.begin(), needle.end()),
              cert_chain_[0].encodedCertificate.end());

    CheckedDeleteKey(&key_blob);
}

/*
 * NewKeyGenerationTest.EcdsaSelfSignAttestation
 *