mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
KeyMint VTS: more attestation info tests
Try all tags in attestion extension one by one Test: VtsAidlKeyMintTargetTest on CF Bug: 186735514 Change-Id: I63ca8d298d2d16f707f2437ab48aaa69c1d7563d
This commit is contained in:
@@ -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;
|
||||
@@ -126,10 +129,9 @@ char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
// 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.
|
||||
auto kTagsToFilter = {
|
||||
Tag::CREATION_DATETIME,
|
||||
Tag::EC_CURVE,
|
||||
Tag::HARDWARE_TYPE,
|
||||
Tag::INCLUDE_UNIQUE_ID,
|
||||
Tag::CREATION_DATETIME,
|
||||
Tag::HARDWARE_TYPE,
|
||||
Tag::INCLUDE_UNIQUE_ID,
|
||||
};
|
||||
|
||||
AuthorizationSet filtered_tags(const AuthorizationSet& set) {
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user