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

Commit 20bb4274 authored by Tri Vo's avatar Tri Vo Committed by Gerrit Code Review
Browse files

Merge "Add test for IRPC DeviceInfo"

parents 7a7baedb ec50ee16
Loading
Loading
Loading
Loading
+21 −21
Original line number Diff line number Diff line
@@ -108,27 +108,6 @@ bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
    return true;
}

// Extract attestation record from cert. Returned object is still part of cert; don't free it
// separately.
ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
    EXPECT_TRUE(!!oid.get());
    if (!oid.get()) return nullptr;

    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
    if (location == -1) return nullptr;

    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
    EXPECT_TRUE(!!attest_rec_ext)
            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
    if (!attest_rec_ext) return nullptr;

    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
    return attest_rec;
}

void check_attestation_version(uint32_t attestation_version, int32_t aidl_version) {
    // Version numbers in attestation extensions should be a multiple of 100.
    EXPECT_EQ(attestation_version % 100, 0);
@@ -1901,6 +1880,27 @@ X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
    return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
}

// Extract attestation record from cert. Returned object is still part of cert; don't free it
// separately.
ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
    EXPECT_TRUE(!!oid.get());
    if (!oid.get()) return nullptr;

    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
    if (location == -1) return nullptr;

    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
    EXPECT_TRUE(!!attest_rec_ext)
            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
    if (!attest_rec_ext) return nullptr;

    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
    return attest_rec;
}

vector<uint8_t> make_name_from_str(const string& name) {
    X509_NAME_Ptr x509_name(X509_NAME_new());
    EXPECT_TRUE(x509_name.get() != nullptr);
+1 −0
Original line number Diff line number Diff line
@@ -401,6 +401,7 @@ bool verify_attestation_record(int aidl_version, //

string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
ASN1_OCTET_STRING* get_attestation_record(X509* certificate);
vector<uint8_t> make_name_from_str(const string& name);
void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
                        vector<uint8_t>* payload_value);
+123 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
#include <cppbor.h>
#include <cppbor_parse.h>
#include <gmock/gmock.h>
#include <keymaster/cppcose/cppcose.h>
@@ -797,6 +798,128 @@ TEST_P(CertificateRequestV2Test, NonEmptyRequest_testKeyInProdCert) {
              BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
}

void parse_root_of_trust(const vector<uint8_t>& attestation_cert,
                         vector<uint8_t>* verified_boot_key, VerifiedBoot* verified_boot_state,
                         bool* device_locked, vector<uint8_t>* verified_boot_hash) {
    X509_Ptr cert(parse_cert_blob(attestation_cert));
    ASSERT_TRUE(cert.get());

    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
    ASSERT_TRUE(attest_rec);

    auto error = parse_root_of_trust(attest_rec->data, attest_rec->length, verified_boot_key,
                                     verified_boot_state, device_locked, verified_boot_hash);
    ASSERT_EQ(error, ErrorCode::OK);
}

/**
 * Generate a CSR and verify DeviceInfo against IDs attested by KeyMint.
 */
TEST_P(CertificateRequestV2Test, DeviceInfo) {
    // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
    std::shared_ptr<IKeyMintDevice> keyMint;
    if (!matching_keymint_device(GetParam(), &keyMint)) {
        // No matching IKeyMintDevice.
        GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
        return;
    }
    KeyMintHardwareInfo info;
    ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());

    // Get IDs attested by KeyMint.
    MacedPublicKey macedPubKey;
    bytevec privateKeyBlob;
    auto irpcStatus =
            provisionable_->generateEcdsaP256KeyPair(false, &macedPubKey, &privateKeyBlob);
    ASSERT_TRUE(irpcStatus.isOk());

    AttestationKey attestKey;
    attestKey.keyBlob = std::move(privateKeyBlob);
    attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");

    // Generate an ECDSA key that is attested by the generated P256 keypair.
    AuthorizationSet keyDesc = AuthorizationSetBuilder()
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
                                       .EcdsaSigningKey(EcCurve::P_256)
                                       .AttestationChallenge("foo")
                                       .AttestationApplicationId("bar")
                                       .Digest(Digest::NONE)
                                       .SetDefaultValidity();
    KeyCreationResult creationResult;
    auto kmStatus = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
    ASSERT_TRUE(kmStatus.isOk());

    vector<KeyCharacteristics> key_characteristics = std::move(creationResult.keyCharacteristics);
    vector<Certificate> key_cert_chain = std::move(creationResult.certificateChain);
    // We didn't provision the attestation key.
    ASSERT_EQ(key_cert_chain.size(), 1);

    // Parse attested patch levels.
    auto auths = HwEnforcedAuthorizations(key_characteristics);

    auto attestedSystemPatchLevel = auths.GetTagValue(TAG_OS_PATCHLEVEL);
    auto attestedVendorPatchLevel = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
    auto attestedBootPatchLevel = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);

    ASSERT_TRUE(attestedSystemPatchLevel.has_value());
    ASSERT_TRUE(attestedVendorPatchLevel.has_value());
    ASSERT_TRUE(attestedBootPatchLevel.has_value());

    // Parse attested AVB values.
    vector<uint8_t> key;
    VerifiedBoot attestedVbState;
    bool attestedBootloaderState;
    vector<uint8_t> attestedVbmetaDigest;
    parse_root_of_trust(key_cert_chain[0].encodedCertificate, &key, &attestedVbState,
                        &attestedBootloaderState, &attestedVbmetaDigest);

    // Get IDs from DeviceInfo.
    bytevec csr;
    irpcStatus =
            provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
    ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getMessage();

    auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
    ASSERT_TRUE(result) << result.message();

    std::unique_ptr<cppbor::Array> csrPayload = std::move(*result);
    ASSERT_TRUE(csrPayload);

    auto deviceInfo = csrPayload->get(2)->asMap();
    ASSERT_TRUE(deviceInfo);

    auto vbState = deviceInfo->get("vb_state")->asTstr();
    auto bootloaderState = deviceInfo->get("bootloader_state")->asTstr();
    auto vbmetaDigest = deviceInfo->get("vbmeta_digest")->asBstr();
    auto systemPatchLevel = deviceInfo->get("system_patch_level")->asUint();
    auto vendorPatchLevel = deviceInfo->get("vendor_patch_level")->asUint();
    auto bootPatchLevel = deviceInfo->get("boot_patch_level")->asUint();
    auto securityLevel = deviceInfo->get("security_level")->asTstr();

    ASSERT_TRUE(vbState);
    ASSERT_TRUE(bootloaderState);
    ASSERT_TRUE(vbmetaDigest);
    ASSERT_TRUE(systemPatchLevel);
    ASSERT_TRUE(vendorPatchLevel);
    ASSERT_TRUE(bootPatchLevel);
    ASSERT_TRUE(securityLevel);

    auto kmDeviceName = device_suffix(GetParam());

    // Compare DeviceInfo against IDs attested by KeyMint.
    ASSERT_TRUE((securityLevel->value() == "tee" && kmDeviceName == "default") ||
                (securityLevel->value() == "strongbox" && kmDeviceName == "strongbox"));
    ASSERT_TRUE((vbState->value() == "green" && attestedVbState == VerifiedBoot::VERIFIED) ||
                (vbState->value() == "yellow" && attestedVbState == VerifiedBoot::SELF_SIGNED) ||
                (vbState->value() == "orange" && attestedVbState == VerifiedBoot::UNVERIFIED));
    ASSERT_TRUE((bootloaderState->value() == "locked" && attestedBootloaderState) ||
                (bootloaderState->value() == "unlocked" && !attestedBootloaderState));
    ASSERT_EQ(vbmetaDigest->value(), attestedVbmetaDigest);
    ASSERT_EQ(systemPatchLevel->value(), attestedSystemPatchLevel.value());
    ASSERT_EQ(vendorPatchLevel->value(), attestedVendorPatchLevel.value());
    ASSERT_EQ(bootPatchLevel->value(), attestedBootPatchLevel.value());
}

INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestV2Test);

using VsrRequirementTest = VtsRemotelyProvisionedComponentTests;