From 60c53aeb7ef3e67b0ae18b581f443ebebbe4822b Mon Sep 17 00:00:00 2001 From: Max Bires Date: Tue, 21 Mar 2023 22:03:42 -0700 Subject: [PATCH] Strictly enforce DeviceInfo entries. Ensure that v3 HALs have exactly the expected number of entries present when returning DeviceInfo inside of the Certificate Signing Request. Do not allow for additional or fewer entries. Test: atest VtsHalRemotelyProvisionedComponentTargetTest Change-Id: I8ea628335d5eed35ca2b65e22980e13fc9806738 --- .../keymint/support/remote_prov_utils.cpp | 71 ++++++++++++++++--- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp index 086ee790e7..72142344b1 100644 --- a/security/keymint/support/remote_prov_utils.cpp +++ b/security/keymint/support/remote_prov_utils.cpp @@ -22,6 +22,7 @@ #include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h" #include +#include #include #include #include @@ -43,6 +44,7 @@ constexpr uint32_t kBccPayloadSubject = 2; constexpr int32_t kBccPayloadSubjPubKey = -4670552; constexpr int32_t kBccPayloadKeyUsage = -4670553; constexpr int kP256AffinePointSize = 32; +constexpr uint32_t kNumTeeDeviceInfoEntries = 14; using EC_KEY_Ptr = bssl::UniquePtr; using EVP_PKEY_Ptr = bssl::UniquePtr; @@ -388,6 +390,11 @@ std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::Ma return entryName + " has an invalid value.\n"; } +bool isTeeDeviceInfo(const cppbor::Map& devInfo) { + return devInfo.get("security_level") && devInfo.get("security_level")->asTstr() && + devInfo.get("security_level")->asTstr()->value() == "tee"; +} + ErrMsgOr> parseAndValidateDeviceInfo( const std::vector& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable, bool isFactory) { @@ -396,6 +403,21 @@ ErrMsgOr> parseAndValidateDeviceInfo( const cppbor::Array kValidSecurityLevels = {"tee", "strongbox"}; const cppbor::Array kValidAttIdStates = {"locked", "open"}; const cppbor::Array kValidFused = {0, 1}; + constexpr std::array kDeviceInfoKeys = { + "brand", + "manufacturer", + "product", + "model", + "device", + "vb_state", + "bootloader_state", + "vbmeta_digest", + "os_version", + "system_patch_level", + "boot_patch_level", + "vendor_patch_level", + "security_level", + "fused"}; struct AttestationIdEntry { const char* id; @@ -439,20 +461,48 @@ ErrMsgOr> parseAndValidateDeviceInfo( } std::string error; + std::string tmp; + std::set previousKeys; switch (info.versionNumber) { case 3: + if (isTeeDeviceInfo(*parsed) && parsed->size() != kNumTeeDeviceInfoEntries) { + error += fmt::format( + "Err: Incorrect number of device info entries. Expected {} but got" + "{}\n", + kNumTeeDeviceInfoEntries, parsed->size()); + } + // TEE IRPC instances require all entries to be present in DeviceInfo. Non-TEE instances + // may omit `os_version` + if (!isTeeDeviceInfo(*parsed) && (parsed->size() != kNumTeeDeviceInfoEntries || + parsed->size() != kNumTeeDeviceInfoEntries - 1)) { + error += fmt::format( + "Err: Incorrect number of device info entries. Expected {} or {} but got" + "{}\n", + kNumTeeDeviceInfoEntries - 1, kNumTeeDeviceInfoEntries, parsed->size()); + } + for (auto& [key, _] : *parsed) { + const std::string& keyValue = key->asTstr()->value(); + if (!previousKeys.insert(keyValue).second) { + error += "Err: Duplicate device info entry: <" + keyValue + ">,\n"; + } + if (std::find(kDeviceInfoKeys.begin(), kDeviceInfoKeys.end(), keyValue) == + kDeviceInfoKeys.end()) { + error += "Err: Unrecognized key entry: <" + key->asTstr()->value() + ">,\n"; + } + } + FALLTHROUGH_INTENDED; case 2: for (const auto& entry : kAttestationIdEntrySet) { - error += checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR, - entry.id); + tmp = checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR, + entry.id); } - if (!error.empty()) { - return error + - "Attestation IDs are missing or malprovisioned. If this test is being\n" - "run against an early proto or EVT build, this error is probably WAI\n" - "and indicates that Device IDs were not provisioned in the factory. If\n" - "this error is returned on a DVT or later build revision, then\n" - "something is likely wrong with the factory provisioning process."; + if (!tmp.empty()) { + error += tmp + + "Attestation IDs are missing or malprovisioned. If this test is being\n" + "run against an early proto or EVT build, this error is probably WAI\n" + "and indicates that Device IDs were not provisioned in the factory. If\n" + "this error is returned on a DVT or later build revision, then\n" + "something is likely wrong with the factory provisioning process."; } // TODO: Refactor the KeyMint code that validates these fields and include it here. error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "vb_state", kValidVbStates); @@ -465,8 +515,7 @@ ErrMsgOr> parseAndValidateDeviceInfo( error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "fused", kValidFused); error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level", kValidSecurityLevels); - if (parsed->get("security_level") && parsed->get("security_level")->asTstr() && - parsed->get("security_level")->asTstr()->value() == "tee") { + if (isTeeDeviceInfo(*parsed)) { error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "os_version"); } break;