mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "KeyMint VTS tests for module hash feature" into main am: 76418972da
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/3342780 Change-Id: Ibf4606b1601c7be9f6045dbeaefa97557904ca7a Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -30,6 +30,7 @@ cc_library {
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-DKEYMINT_HAL_V4",
|
||||
],
|
||||
srcs: [
|
||||
"attestation_record.cpp",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,15 @@ DECLARE_TYPED_TAG(MAC_LENGTH);
|
||||
DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
|
||||
DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
|
||||
DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
|
||||
// TODO: remove special case macro once v4 HAL is frozen
|
||||
#ifdef KEYMINT_HAL_V4
|
||||
DECLARE_TYPED_TAG(MODULE_HASH);
|
||||
#else
|
||||
// When building for previous frozen HAL, the `Tag::MODULE_NAME` constant is not available.
|
||||
static const Tag Tag_MODULE_HASH = static_cast<Tag>(-1879047468);
|
||||
typedef typename Tag2TypedTag<Tag_MODULE_HASH>::type TAG_MODULE_HASH_t;
|
||||
static TAG_MODULE_HASH_t TAG_MODULE_HASH;
|
||||
#endif
|
||||
DECLARE_TYPED_TAG(NONCE);
|
||||
DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
|
||||
DECLARE_TYPED_TAG(ORIGIN);
|
||||
|
||||
Reference in New Issue
Block a user