mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge changes I48840207,Idc5de13c,I8f2b7ab3,I2460106c
* changes: Keymaster 4.1 VTS tests Update KM4 VTS tests to allow s/w implementation to pass. Remove service death test. Change finish input test to avoid large sizes.
This commit is contained in:
committed by
Android (Google) Code Review
commit
c78e55d510
@@ -321,19 +321,20 @@ ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc
|
||||
LOG(ERROR) << AT << "Failed record parsing";
|
||||
return ErrorCode::UNKNOWN_ERROR;
|
||||
}
|
||||
if (!record->tee_enforced) {
|
||||
LOG(ERROR) << AT << "Failed hardware characteristic parsing";
|
||||
|
||||
KM_ROOT_OF_TRUST* root_of_trust = nullptr;
|
||||
if (record->tee_enforced && record->tee_enforced->root_of_trust) {
|
||||
root_of_trust = record->tee_enforced->root_of_trust;
|
||||
} else if (record->software_enforced && record->software_enforced->root_of_trust) {
|
||||
root_of_trust = record->software_enforced->root_of_trust;
|
||||
} else {
|
||||
LOG(ERROR) << AT << " Failed root of trust parsing";
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
if (!record->tee_enforced->root_of_trust) {
|
||||
LOG(ERROR) << AT << "Failed root of trust parsing";
|
||||
if (!root_of_trust->verified_boot_key) {
|
||||
LOG(ERROR) << AT << " Failed verified boot key parsing";
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
if (!record->tee_enforced->root_of_trust->verified_boot_key) {
|
||||
LOG(ERROR) << AT << "Failed verified boot key parsing";
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust;
|
||||
|
||||
auto& vb_key = root_of_trust->verified_boot_key;
|
||||
verified_boot_key->resize(vb_key->length);
|
||||
@@ -342,19 +343,19 @@ ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc
|
||||
*verified_boot_state = static_cast<keymaster_verified_boot_t>(
|
||||
ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
|
||||
if (!verified_boot_state) {
|
||||
LOG(ERROR) << AT << "Failed verified boot state parsing";
|
||||
LOG(ERROR) << AT << " Failed verified boot state parsing";
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*device_locked = root_of_trust->device_locked;
|
||||
if (!device_locked) {
|
||||
LOG(ERROR) << AT << "Failed device locked parsing";
|
||||
LOG(ERROR) << AT << " Failed device locked parsing";
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
auto& vb_hash = root_of_trust->verified_boot_hash;
|
||||
if (!vb_hash) {
|
||||
LOG(ERROR) << AT << "Failed verified boot hash parsing";
|
||||
LOG(ERROR) << AT << " Failed verified boot hash parsing";
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
verified_boot_hash->resize(vb_hash->length);
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace hardware {
|
||||
namespace keymaster {
|
||||
namespace V4_0 {
|
||||
|
||||
inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
|
||||
bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
|
||||
if (a.tag != b.tag) return a.tag < b.tag;
|
||||
int retval;
|
||||
switch (typeFromTag(a.tag)) {
|
||||
@@ -58,7 +58,7 @@ inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
|
||||
bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
|
||||
if (a.tag != b.tag) return false;
|
||||
|
||||
switch (typeFromTag(a.tag)) {
|
||||
|
||||
@@ -355,95 +355,61 @@ inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&>
|
||||
return accessTagValue(ttag, param);
|
||||
}
|
||||
|
||||
inline bool operator<(const KeyParameter& a, const KeyParameter& b) {
|
||||
if (a.tag != b.tag) return a.tag < b.tag;
|
||||
int retval;
|
||||
switch (typeFromTag(a.tag)) {
|
||||
case TagType::INVALID:
|
||||
case TagType::BOOL:
|
||||
return false;
|
||||
case TagType::ENUM:
|
||||
case TagType::ENUM_REP:
|
||||
case TagType::UINT:
|
||||
case TagType::UINT_REP:
|
||||
return a.f.integer < b.f.integer;
|
||||
case TagType::ULONG:
|
||||
case TagType::ULONG_REP:
|
||||
return a.f.longInteger < b.f.longInteger;
|
||||
case TagType::DATE:
|
||||
return a.f.dateTime < b.f.dateTime;
|
||||
case TagType::BIGNUM:
|
||||
case TagType::BYTES:
|
||||
// Handle the empty cases.
|
||||
if (a.blob.size() == 0) return b.blob.size() != 0;
|
||||
if (b.blob.size() == 0) return false;
|
||||
|
||||
retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
|
||||
// if one is the prefix of the other the longer wins
|
||||
if (retval == 0) return a.blob.size() < b.blob.size();
|
||||
// Otherwise a is less if a is less.
|
||||
else
|
||||
return retval < 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
|
||||
if (a.tag != b.tag) {
|
||||
return false;
|
||||
}
|
||||
if (a.tag != b.tag) return false;
|
||||
|
||||
switch (a.tag) {
|
||||
/* Boolean tags */
|
||||
case Tag::INVALID:
|
||||
case Tag::CALLER_NONCE:
|
||||
case Tag::INCLUDE_UNIQUE_ID:
|
||||
case Tag::BOOTLOADER_ONLY:
|
||||
case Tag::NO_AUTH_REQUIRED:
|
||||
case Tag::ALLOW_WHILE_ON_BODY:
|
||||
case Tag::UNLOCKED_DEVICE_REQUIRED:
|
||||
case Tag::ROLLBACK_RESISTANCE:
|
||||
case Tag::RESET_SINCE_ID_ROTATION:
|
||||
case Tag::TRUSTED_CONFIRMATION_REQUIRED:
|
||||
case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
|
||||
switch (typeFromTag(a.tag)) {
|
||||
case TagType::INVALID:
|
||||
case TagType::BOOL:
|
||||
return true;
|
||||
|
||||
/* Integer tags */
|
||||
case Tag::KEY_SIZE:
|
||||
case Tag::MIN_MAC_LENGTH:
|
||||
case Tag::MIN_SECONDS_BETWEEN_OPS:
|
||||
case Tag::MAX_USES_PER_BOOT:
|
||||
case Tag::OS_VERSION:
|
||||
case Tag::OS_PATCHLEVEL:
|
||||
case Tag::MAC_LENGTH:
|
||||
case Tag::USER_ID:
|
||||
case Tag::AUTH_TIMEOUT:
|
||||
case Tag::VENDOR_PATCHLEVEL:
|
||||
case Tag::BOOT_PATCHLEVEL:
|
||||
case TagType::ENUM:
|
||||
case TagType::ENUM_REP:
|
||||
case TagType::UINT:
|
||||
case TagType::UINT_REP:
|
||||
return a.f.integer == b.f.integer;
|
||||
|
||||
/* Long integer tags */
|
||||
case Tag::RSA_PUBLIC_EXPONENT:
|
||||
case Tag::USER_SECURE_ID:
|
||||
case TagType::ULONG:
|
||||
case TagType::ULONG_REP:
|
||||
return a.f.longInteger == b.f.longInteger;
|
||||
|
||||
/* Date-time tags */
|
||||
case Tag::ACTIVE_DATETIME:
|
||||
case Tag::ORIGINATION_EXPIRE_DATETIME:
|
||||
case Tag::USAGE_EXPIRE_DATETIME:
|
||||
case Tag::CREATION_DATETIME:
|
||||
case TagType::DATE:
|
||||
return a.f.dateTime == b.f.dateTime;
|
||||
|
||||
/* Bytes tags */
|
||||
case Tag::APPLICATION_ID:
|
||||
case Tag::APPLICATION_DATA:
|
||||
case Tag::ROOT_OF_TRUST:
|
||||
case Tag::UNIQUE_ID:
|
||||
case Tag::ATTESTATION_CHALLENGE:
|
||||
case Tag::ATTESTATION_APPLICATION_ID:
|
||||
case Tag::ATTESTATION_ID_BRAND:
|
||||
case Tag::ATTESTATION_ID_DEVICE:
|
||||
case Tag::ATTESTATION_ID_PRODUCT:
|
||||
case Tag::ATTESTATION_ID_SERIAL:
|
||||
case Tag::ATTESTATION_ID_IMEI:
|
||||
case Tag::ATTESTATION_ID_MEID:
|
||||
case Tag::ATTESTATION_ID_MANUFACTURER:
|
||||
case Tag::ATTESTATION_ID_MODEL:
|
||||
case Tag::ASSOCIATED_DATA:
|
||||
case Tag::CONFIRMATION_TOKEN:
|
||||
case Tag::NONCE:
|
||||
return a.blob == b.blob;
|
||||
|
||||
/* Enum tags */
|
||||
case Tag::PURPOSE:
|
||||
return a.f.purpose == b.f.purpose;
|
||||
case Tag::ALGORITHM:
|
||||
return a.f.algorithm == b.f.algorithm;
|
||||
case Tag::BLOCK_MODE:
|
||||
return a.f.blockMode == b.f.blockMode;
|
||||
case Tag::DIGEST:
|
||||
return a.f.digest == b.f.digest;
|
||||
case Tag::PADDING:
|
||||
return a.f.paddingMode == b.f.paddingMode;
|
||||
case Tag::EC_CURVE:
|
||||
return a.f.ecCurve == b.f.ecCurve;
|
||||
case Tag::BLOB_USAGE_REQUIREMENTS:
|
||||
return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
|
||||
case Tag::USER_AUTH_TYPE:
|
||||
return a.f.integer == b.f.integer;
|
||||
case Tag::ORIGIN:
|
||||
return a.f.origin == b.f.origin;
|
||||
case Tag::HARDWARE_TYPE:
|
||||
return a.f.hardwareType == b.f.hardwareType;
|
||||
case TagType::BIGNUM:
|
||||
case TagType::BYTES:
|
||||
if (a.blob.size() != b.blob.size()) return false;
|
||||
return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
|
||||
|
||||
#include <android/hardware/keymaster/4.0/types.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
template <typename T, void (*F)(T*)>
|
||||
struct UniquePtrDeleter {
|
||||
|
||||
@@ -19,7 +19,6 @@ cc_test {
|
||||
defaults: ["VtsHalTargetTestDefaults"],
|
||||
srcs: [
|
||||
"HmacKeySharingTest.cpp",
|
||||
"KeymasterHidlTest.cpp",
|
||||
"VerificationTokenTest.cpp",
|
||||
"keymaster_hidl_hal_test.cpp",
|
||||
],
|
||||
@@ -27,9 +26,25 @@ cc_test {
|
||||
"android.hardware.keymaster@4.0",
|
||||
"libcrypto_static",
|
||||
"libkeymaster4support",
|
||||
"libkeymaster4vtstest",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts-core",
|
||||
],
|
||||
}
|
||||
|
||||
cc_test_library {
|
||||
name: "libkeymaster4vtstest",
|
||||
defaults: ["VtsHalTargetTestDefaults"],
|
||||
srcs: [
|
||||
"KeymasterHidlTest.cpp",
|
||||
],
|
||||
export_include_dirs: [
|
||||
".",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.keymaster@4.0",
|
||||
"libkeymaster4support",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -44,10 +44,9 @@ namespace test {
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
void KeymasterHidlTest::InitializeKeymaster() {
|
||||
keymaster_ = IKeymasterDevice::getService(GetParam());
|
||||
ASSERT_NE(keymaster_, nullptr);
|
||||
|
||||
void KeymasterHidlTest::InitializeKeymaster(sp<IKeymasterDevice> keymaster) {
|
||||
ASSERT_NE(keymaster, nullptr);
|
||||
keymaster_ = keymaster;
|
||||
ASSERT_TRUE(keymaster_
|
||||
->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
|
||||
const hidl_string& author) {
|
||||
@@ -56,15 +55,15 @@ void KeymasterHidlTest::InitializeKeymaster() {
|
||||
author_ = author;
|
||||
})
|
||||
.isOk());
|
||||
}
|
||||
|
||||
void KeymasterHidlTest::SetUp() {
|
||||
InitializeKeymaster();
|
||||
|
||||
os_version_ = support::getOsVersion();
|
||||
os_patch_level_ = support::getOsPatchlevel();
|
||||
}
|
||||
|
||||
void KeymasterHidlTest::SetUp() {
|
||||
InitializeKeymaster(IKeymasterDevice::getService(GetParam()));
|
||||
}
|
||||
|
||||
ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
|
||||
KeyCharacteristics* key_characteristics) {
|
||||
EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
|
||||
@@ -127,7 +126,7 @@ ErrorCode KeymasterHidlTest::ImportWrappedKey(string wrapped_key, string wrappin
|
||||
string masking_key,
|
||||
const AuthorizationSet& unwrapping_params) {
|
||||
ErrorCode error;
|
||||
ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
|
||||
EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
|
||||
EXPECT_TRUE(keymaster_
|
||||
->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
|
||||
unwrapping_params.hidl_data(), 0 /* passwordSid */,
|
||||
@@ -196,7 +195,9 @@ void KeymasterHidlTest::CheckGetCharacteristics(const HidlBuf& key_blob, const H
|
||||
HidlBuf empty_buf = {};
|
||||
EXPECT_EQ(ErrorCode::OK,
|
||||
GetCharacteristics(key_blob, client_id, app_data, key_characteristics));
|
||||
EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
|
||||
if (SecLevel() != SecurityLevel::SOFTWARE) {
|
||||
EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
|
||||
}
|
||||
EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
|
||||
|
||||
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
|
||||
@@ -636,23 +637,25 @@ std::vector<uint32_t> KeymasterHidlTest::ValidKeySizes(Algorithm algorithm) {
|
||||
switch (algorithm) {
|
||||
case Algorithm::RSA:
|
||||
switch (SecLevel()) {
|
||||
case SecurityLevel::SOFTWARE:
|
||||
case SecurityLevel::TRUSTED_ENVIRONMENT:
|
||||
return {2048, 3072, 4096};
|
||||
case SecurityLevel::STRONGBOX:
|
||||
return {2048};
|
||||
default:
|
||||
CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
|
||||
ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Algorithm::EC:
|
||||
switch (SecLevel()) {
|
||||
case SecurityLevel::SOFTWARE:
|
||||
case SecurityLevel::TRUSTED_ENVIRONMENT:
|
||||
return {224, 256, 384, 521};
|
||||
case SecurityLevel::STRONGBOX:
|
||||
return {256};
|
||||
default:
|
||||
CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
|
||||
ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -667,25 +670,27 @@ std::vector<uint32_t> KeymasterHidlTest::ValidKeySizes(Algorithm algorithm) {
|
||||
return retval;
|
||||
}
|
||||
default:
|
||||
CHECK(false) << "Invalid Algorithm: " << algorithm;
|
||||
ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
|
||||
return {};
|
||||
}
|
||||
CHECK(false) << "Should be impossible to get here";
|
||||
ADD_FAILURE() << "Should be impossible to get here";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> KeymasterHidlTest::InvalidKeySizes(Algorithm algorithm) {
|
||||
if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
|
||||
CHECK(SecLevel() == SecurityLevel::STRONGBOX);
|
||||
switch (algorithm) {
|
||||
case Algorithm::RSA:
|
||||
return {3072, 4096};
|
||||
case Algorithm::EC:
|
||||
return {224, 384, 521};
|
||||
case Algorithm::AES:
|
||||
return {192};
|
||||
default:
|
||||
return {};
|
||||
if (SecLevel() == SecurityLevel::STRONGBOX) {
|
||||
switch (algorithm) {
|
||||
case Algorithm::RSA:
|
||||
return {3072, 4096};
|
||||
case Algorithm::EC:
|
||||
return {224, 384, 521};
|
||||
case Algorithm::AES:
|
||||
return {192};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<EcCurve> KeymasterHidlTest::ValidCurves() {
|
||||
@@ -704,6 +709,7 @@ std::vector<EcCurve> KeymasterHidlTest::InvalidCurves() {
|
||||
|
||||
std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
|
||||
switch (SecLevel()) {
|
||||
case SecurityLevel::SOFTWARE:
|
||||
case SecurityLevel::TRUSTED_ENVIRONMENT:
|
||||
if (withNone) {
|
||||
if (withMD5)
|
||||
@@ -729,10 +735,10 @@ std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5)
|
||||
return {Digest::SHA_2_256};
|
||||
break;
|
||||
default:
|
||||
CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
|
||||
ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
|
||||
break;
|
||||
}
|
||||
CHECK(false) << "Should be impossible to get here";
|
||||
ADD_FAILURE() << "Should be impossible to get here";
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,14 @@ using hidl::base::V1_0::DebugInfo;
|
||||
using ::std::string;
|
||||
|
||||
class HidlBuf : public hidl_vec<uint8_t> {
|
||||
typedef hidl_vec<uint8_t> super;
|
||||
using super = hidl_vec<uint8_t>;
|
||||
|
||||
public:
|
||||
HidlBuf() {}
|
||||
HidlBuf(const super& other) : super(other) {}
|
||||
HidlBuf(super&& other) : super(std::move(other)) {}
|
||||
HidlBuf(super&& other) : super(std::move(other)) { other = {}; }
|
||||
HidlBuf(const HidlBuf& other) : super(other) {}
|
||||
HidlBuf(HidlBuf&& other) : super(std::move(other)) { other = HidlBuf(); }
|
||||
explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
|
||||
|
||||
HidlBuf& operator=(const super& other) {
|
||||
@@ -53,6 +55,18 @@ class HidlBuf : public hidl_vec<uint8_t> {
|
||||
|
||||
HidlBuf& operator=(super&& other) {
|
||||
super::operator=(std::move(other));
|
||||
other = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
HidlBuf& operator=(const HidlBuf& other) {
|
||||
super::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HidlBuf& operator=(HidlBuf&& other) {
|
||||
super::operator=(std::move(other));
|
||||
other.super::operator=({});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -77,7 +91,7 @@ class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
|
||||
AbortIfNeeded();
|
||||
}
|
||||
|
||||
void InitializeKeymaster();
|
||||
void InitializeKeymaster(sp<IKeymasterDevice> keymaster);
|
||||
IKeymasterDevice& keymaster() { return *keymaster_; }
|
||||
uint32_t os_version() { return os_version_; }
|
||||
uint32_t os_patch_level() { return os_patch_level_; }
|
||||
@@ -204,6 +218,11 @@ class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
|
||||
KeyCharacteristics key_characteristics_;
|
||||
OperationHandle op_handle_ = kOpHandleSentinel;
|
||||
|
||||
static std::vector<std::string> build_params() {
|
||||
auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
|
||||
return params;
|
||||
}
|
||||
|
||||
private:
|
||||
sp<IKeymasterDevice> keymaster_;
|
||||
uint32_t os_version_;
|
||||
@@ -214,10 +233,9 @@ class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
|
||||
hidl_string author_;
|
||||
};
|
||||
|
||||
#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \
|
||||
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames( \
|
||||
IKeymasterDevice::descriptor)), \
|
||||
#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \
|
||||
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
|
||||
testing::ValuesIn(KeymasterHidlTest::build_params()), \
|
||||
android::hardware::PrintInstanceNameToString)
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -352,11 +352,11 @@ bool verify_attestation_record(const string& challenge, const string& app_id,
|
||||
EXPECT_EQ(ErrorCode::OK, error);
|
||||
if (error != ErrorCode::OK) return false;
|
||||
|
||||
EXPECT_TRUE(att_attestation_version == 3);
|
||||
EXPECT_GE(att_attestation_version, 3U);
|
||||
|
||||
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
|
||||
|
||||
EXPECT_EQ(att_keymaster_version, 4U);
|
||||
EXPECT_GE(att_keymaster_version, 4U);
|
||||
EXPECT_EQ(security_level, att_keymaster_security_level);
|
||||
EXPECT_EQ(security_level, att_attestation_security_level);
|
||||
|
||||
@@ -397,10 +397,16 @@ bool verify_attestation_record(const string& challenge, const string& app_id,
|
||||
// true. A provided boolean tag that can be pulled back out of the certificate indicates correct
|
||||
// encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
|
||||
// will handle mismatches of tags.
|
||||
EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
|
||||
if (security_level == SecurityLevel::SOFTWARE) {
|
||||
EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
|
||||
} else {
|
||||
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));
|
||||
|
||||
@@ -461,10 +467,10 @@ bool verify_attestation_record(const string& challenge, const string& app_id,
|
||||
verified_boot_key.size()));
|
||||
} else if (!strcmp(property_value, "red")) {
|
||||
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED);
|
||||
EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
|
||||
verified_boot_key.size()));
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED);
|
||||
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
|
||||
verified_boot_key.size()));
|
||||
}
|
||||
|
||||
att_sw_enforced.Sort();
|
||||
@@ -4557,53 +4563,14 @@ TEST_P(ClearOperationsTest, TooManyOperations) {
|
||||
AbortIfNeeded();
|
||||
}
|
||||
|
||||
/*
|
||||
* ClearSlotsTest.ServiceDeath
|
||||
*
|
||||
* Verifies that the service is restarted after death and the ongoing
|
||||
* operations are cleared.
|
||||
*/
|
||||
TEST_P(ClearOperationsTest, ServiceDeath) {
|
||||
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.RsaEncryptionKey(2048, 65537)
|
||||
.Padding(PaddingMode::NONE)));
|
||||
|
||||
auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
|
||||
int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
|
||||
OperationHandle op_handles[max_operations];
|
||||
AuthorizationSet out_params;
|
||||
for(int i=0; i<max_operations; i++) {
|
||||
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
|
||||
}
|
||||
EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
|
||||
Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
|
||||
|
||||
DebugInfo debug_info;
|
||||
GetDebugInfo(&debug_info);
|
||||
kill(debug_info.pid, SIGKILL);
|
||||
// wait 1 second for keymaster to restart
|
||||
sleep(1);
|
||||
InitializeKeymaster();
|
||||
|
||||
for(int i=0; i<max_operations; i++) {
|
||||
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
|
||||
}
|
||||
EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
|
||||
Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
|
||||
for(int i=0; i<max_operations; i++) {
|
||||
EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest);
|
||||
|
||||
typedef KeymasterHidlTest TransportLimitTest;
|
||||
|
||||
/*
|
||||
* TransportLimitTest.LargeFinishInput
|
||||
* TransportLimitTest.FinishInput
|
||||
*
|
||||
* Verifies that passing large input data to finish either succeeds or fails as expected.
|
||||
* Verifies that passing input data to finish succeeds as expected.
|
||||
*/
|
||||
TEST_P(TransportLimitTest, LargeFinishInput) {
|
||||
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
|
||||
@@ -4612,7 +4579,7 @@ TEST_P(TransportLimitTest, LargeFinishInput) {
|
||||
.BlockMode(BlockMode::ECB)
|
||||
.Padding(PaddingMode::NONE)));
|
||||
|
||||
for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
|
||||
for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
|
||||
auto cipher_params =
|
||||
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
|
||||
|
||||
@@ -4623,31 +4590,19 @@ TEST_P(TransportLimitTest, LargeFinishInput) {
|
||||
string encrypted_message;
|
||||
auto rc = Finish(plain_message, &encrypted_message);
|
||||
|
||||
if (rc == ErrorCode::OK) {
|
||||
EXPECT_EQ(plain_message.size(), encrypted_message.size())
|
||||
<< "Encrypt finish returned OK, but did not consume all of the given input";
|
||||
} else {
|
||||
EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
|
||||
<< "Encrypt finish failed in an unexpected way when given a large input";
|
||||
continue;
|
||||
}
|
||||
EXPECT_EQ(ErrorCode::OK, rc);
|
||||
EXPECT_EQ(plain_message.size(), encrypted_message.size())
|
||||
<< "Encrypt finish returned OK, but did not consume all of the given input";
|
||||
cipher_params.push_back(out_params);
|
||||
|
||||
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
|
||||
|
||||
string decrypted_message;
|
||||
rc = Finish(encrypted_message, &decrypted_message);
|
||||
|
||||
if (rc == ErrorCode::OK) {
|
||||
EXPECT_EQ(plain_message.size(), decrypted_message.size())
|
||||
<< "Decrypt finish returned OK, did not consume all of the given input";
|
||||
} else {
|
||||
EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
|
||||
<< "Encrypt finish failed in an unexpected way when given a large input";
|
||||
}
|
||||
EXPECT_EQ(ErrorCode::OK, rc);
|
||||
EXPECT_EQ(plain_message.size(), decrypted_message.size())
|
||||
<< "Decrypt finish returned OK, did not consume all of the given input";
|
||||
}
|
||||
|
||||
CheckedDeleteKey();
|
||||
}
|
||||
|
||||
INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
|
||||
|
||||
@@ -22,11 +22,17 @@ cc_library {
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
],
|
||||
srcs: [
|
||||
"attestation_record.cpp",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
shared_libs: [
|
||||
"android.hardware.keymaster@3.0",
|
||||
"android.hardware.keymaster@4.0",
|
||||
"android.hardware.keymaster@4.1",
|
||||
"libbase",
|
||||
"libcrypto",
|
||||
"libhidlbase",
|
||||
"libkeymaster4support",
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
387
keymaster/4.1/support/attestation_record.cpp
Normal file
387
keymaster/4.1/support/attestation_record.cpp
Normal file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <keymasterV4_1/attestation_record.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <keymasterV4_0/authorization_set.h>
|
||||
#include <keymasterV4_0/openssl_utils.h>
|
||||
|
||||
#define AT __FILE__ ":" << __LINE__
|
||||
|
||||
/*
|
||||
* NOTE: The contents of this file are *extremely* similar to the contents of the V4_0 copy of the
|
||||
* same support file. Unfortunately, small changes in the scheme mean that the schema types have to
|
||||
* be distinct, which drives almost everything else to be different as well. In the next version we
|
||||
* plan to abandon not just this openssl mechanism for parsing ASN.1, but ASN.1 entirely, so
|
||||
* eventually all of this duplication can be removed.
|
||||
*/
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace keymaster {
|
||||
namespace V4_1 {
|
||||
|
||||
struct stack_st_ASN1_TYPE_Delete {
|
||||
void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
|
||||
};
|
||||
|
||||
struct ASN1_STRING_Delete {
|
||||
void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
|
||||
};
|
||||
|
||||
struct ASN1_TYPE_Delete {
|
||||
void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
|
||||
};
|
||||
|
||||
#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
|
||||
|
||||
typedef struct km_root_of_trust {
|
||||
ASN1_OCTET_STRING* verified_boot_key;
|
||||
ASN1_BOOLEAN* device_locked;
|
||||
ASN1_ENUMERATED* verified_boot_state;
|
||||
ASN1_OCTET_STRING* verified_boot_hash;
|
||||
} KM_ROOT_OF_TRUST;
|
||||
|
||||
ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
|
||||
ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
|
||||
ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
|
||||
ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
|
||||
ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
|
||||
} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
|
||||
IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
|
||||
|
||||
typedef struct km_auth_list {
|
||||
ASN1_INTEGER_SET* purpose;
|
||||
ASN1_INTEGER* algorithm;
|
||||
ASN1_INTEGER* key_size;
|
||||
ASN1_INTEGER_SET* digest;
|
||||
ASN1_INTEGER_SET* padding;
|
||||
ASN1_INTEGER* ec_curve;
|
||||
ASN1_INTEGER* rsa_public_exponent;
|
||||
ASN1_INTEGER* active_date_time;
|
||||
ASN1_INTEGER* origination_expire_date_time;
|
||||
ASN1_INTEGER* usage_expire_date_time;
|
||||
ASN1_NULL* no_auth_required;
|
||||
ASN1_INTEGER* user_auth_type;
|
||||
ASN1_INTEGER* auth_timeout;
|
||||
ASN1_NULL* allow_while_on_body;
|
||||
ASN1_NULL* all_applications;
|
||||
ASN1_OCTET_STRING* application_id;
|
||||
ASN1_INTEGER* creation_date_time;
|
||||
ASN1_INTEGER* origin;
|
||||
ASN1_NULL* rollback_resistance;
|
||||
KM_ROOT_OF_TRUST* root_of_trust;
|
||||
ASN1_INTEGER* os_version;
|
||||
ASN1_INTEGER* os_patchlevel;
|
||||
ASN1_OCTET_STRING* attestation_application_id;
|
||||
ASN1_NULL* trusted_user_presence_required;
|
||||
ASN1_NULL* trusted_confirmation_required;
|
||||
ASN1_NULL* unlocked_device_required;
|
||||
ASN1_INTEGER* vendor_patchlevel;
|
||||
ASN1_INTEGER* boot_patchlevel;
|
||||
ASN1_NULL* early_boot_only;
|
||||
ASN1_NULL* device_unique_attestation;
|
||||
} KM_AUTH_LIST;
|
||||
|
||||
ASN1_SEQUENCE(KM_AUTH_LIST) = {
|
||||
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
|
||||
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
|
||||
ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
|
||||
TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
|
||||
TAG_ROLLBACK_RESISTANCE.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
|
||||
TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
|
||||
TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
|
||||
TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
|
||||
TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
|
||||
TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
|
||||
TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
|
||||
TAG_CREATION_DATETIME.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
|
||||
TAG_VENDOR_PATCHLEVEL.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
|
||||
TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
|
||||
ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
|
||||
TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
|
||||
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
|
||||
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
|
||||
|
||||
typedef struct km_key_description {
|
||||
ASN1_INTEGER* attestation_version;
|
||||
ASN1_ENUMERATED* attestation_security_level;
|
||||
ASN1_INTEGER* keymaster_version;
|
||||
ASN1_ENUMERATED* keymaster_security_level;
|
||||
ASN1_OCTET_STRING* attestation_challenge;
|
||||
KM_AUTH_LIST* software_enforced;
|
||||
KM_AUTH_LIST* tee_enforced;
|
||||
ASN1_INTEGER* unique_id;
|
||||
} KM_KEY_DESCRIPTION;
|
||||
|
||||
ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
|
||||
ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
|
||||
} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
|
||||
IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
|
||||
for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
|
||||
auth_list->push_back(
|
||||
ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
|
||||
}
|
||||
}
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
|
||||
if (!asn1_int) return;
|
||||
auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
|
||||
}
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
if (!asn1_int) return;
|
||||
auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
|
||||
}
|
||||
|
||||
BIGNUM* construct_uint_max() {
|
||||
BIGNUM* value = BN_new();
|
||||
BIGNUM_Ptr one(BN_new());
|
||||
BN_one(one.get());
|
||||
BN_lshift(value, one.get(), 32);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64_t BignumToUint64(BIGNUM* num) {
|
||||
static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
|
||||
"This implementation only supports 32 and 64-bit BN_ULONG");
|
||||
if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
|
||||
BIGNUM_Ptr uint_max(construct_uint_max());
|
||||
BIGNUM_Ptr hi(BN_new()), lo(BN_new());
|
||||
BN_CTX_Ptr ctx(BN_CTX_new());
|
||||
BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
|
||||
return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
|
||||
} else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
|
||||
return BN_get_word(num);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
if (!asn1_int) return;
|
||||
BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
|
||||
auth_list->push_back(ttag, BignumToUint64(num.get()));
|
||||
}
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
if (!asn1_int) return;
|
||||
BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
|
||||
auth_list->push_back(ttag, BignumToUint64(num.get()));
|
||||
}
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
if (!asn1_null) return;
|
||||
auth_list->push_back(ttag);
|
||||
}
|
||||
|
||||
template <V4_0::Tag tag>
|
||||
void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
|
||||
AuthorizationSet* auth_list) {
|
||||
if (!asn1_string) return;
|
||||
hidl_vec<uint8_t> buf;
|
||||
buf.setToExternal(asn1_string->data, asn1_string->length);
|
||||
auth_list->push_back(ttag, buf);
|
||||
}
|
||||
|
||||
// Extract the values from the specified ASN.1 record and place them in auth_list.
|
||||
static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
|
||||
if (!record) return ErrorCode::OK;
|
||||
|
||||
copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
|
||||
copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
|
||||
copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
|
||||
copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
|
||||
copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
|
||||
copyAuthTag(record->digest, TAG_DIGEST, auth_list);
|
||||
copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
|
||||
copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
|
||||
copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
|
||||
copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
|
||||
copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
|
||||
copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
|
||||
copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
|
||||
copyAuthTag(record->padding, TAG_PADDING, auth_list);
|
||||
copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
|
||||
copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
|
||||
copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
|
||||
copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
|
||||
copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
|
||||
copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
|
||||
copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
|
||||
copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
|
||||
copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
|
||||
auth_list);
|
||||
copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
|
||||
auth_list);
|
||||
copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
|
||||
copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
|
||||
copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
|
||||
|
||||
return ErrorCode::OK;
|
||||
}
|
||||
|
||||
MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
|
||||
|
||||
// Parse the DER-encoded attestation record, placing the results in keymaster_version,
|
||||
// attestation_challenge, software_enforced, tee_enforced and unique_id.
|
||||
std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
|
||||
const uint8_t* p = cert.data();
|
||||
X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
|
||||
|
||||
ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
|
||||
if (!oid.get()) {
|
||||
LOG(ERROR) << "Error parsing OID";
|
||||
return {ErrorCode::UNKNOWN_ERROR, {}};
|
||||
}
|
||||
|
||||
int location = X509_get_ext_by_OBJ(x509.get(), oid.get(), -1 /* search from beginning */);
|
||||
if (location == -1) {
|
||||
LOG(ERROR) << "Attestation extension not found in certificate";
|
||||
return {ErrorCode::UNKNOWN_ERROR, {}};
|
||||
}
|
||||
|
||||
X509_EXTENSION* attest_rec_ext = X509_get_ext(x509.get(), location);
|
||||
if (!attest_rec_ext) {
|
||||
LOG(ERROR) << "Found extension but couldn't retrieve it. Probably BoringSSL bug.";
|
||||
return {ErrorCode::UNKNOWN_ERROR, {}};
|
||||
}
|
||||
|
||||
ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
|
||||
if (!attest_rec_ext) {
|
||||
LOG(ERROR) << "Attestation extension contained no data";
|
||||
return {ErrorCode::UNKNOWN_ERROR, {}};
|
||||
}
|
||||
|
||||
p = attest_rec->data;
|
||||
KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
|
||||
if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
|
||||
|
||||
AttestationRecord result;
|
||||
|
||||
result.attestation_version = ASN1_INTEGER_get(record->attestation_version);
|
||||
result.attestation_security_level =
|
||||
static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
|
||||
result.keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
|
||||
result.keymaster_security_level =
|
||||
static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
|
||||
|
||||
auto& chall = record->attestation_challenge;
|
||||
result.attestation_challenge.resize(chall->length);
|
||||
memcpy(result.attestation_challenge.data(), chall->data, chall->length);
|
||||
auto& uid = record->unique_id;
|
||||
result.unique_id.resize(uid->length);
|
||||
memcpy(result.unique_id.data(), uid->data, uid->length);
|
||||
|
||||
ErrorCode error = extract_auth_list(record->software_enforced, &result.software_enforced);
|
||||
if (error != ErrorCode::OK) return {error, {}};
|
||||
|
||||
error = extract_auth_list(record->tee_enforced, &result.hardware_enforced);
|
||||
if (error != ErrorCode::OK) return {error, {}};
|
||||
|
||||
KM_ROOT_OF_TRUST* root_of_trust = nullptr;
|
||||
if (record->tee_enforced && record->tee_enforced->root_of_trust) {
|
||||
root_of_trust = record->tee_enforced->root_of_trust;
|
||||
} else if (record->software_enforced && record->software_enforced->root_of_trust) {
|
||||
root_of_trust = record->software_enforced->root_of_trust;
|
||||
} else {
|
||||
LOG(ERROR) << AT << " Failed root of trust parsing";
|
||||
return {ErrorCode::INVALID_ARGUMENT, {}};
|
||||
}
|
||||
if (!root_of_trust->verified_boot_key) {
|
||||
LOG(ERROR) << AT << " Failed verified boot key parsing";
|
||||
return {ErrorCode::INVALID_ARGUMENT, {}};
|
||||
}
|
||||
|
||||
RootOfTrust& rot = result.root_of_trust;
|
||||
auto& vb_key = root_of_trust->verified_boot_key;
|
||||
rot.verified_boot_key.resize(vb_key->length);
|
||||
memcpy(rot.verified_boot_key.data(), vb_key->data, vb_key->length);
|
||||
|
||||
rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
|
||||
ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
|
||||
rot.device_locked = root_of_trust->device_locked;
|
||||
|
||||
auto& vb_hash = root_of_trust->verified_boot_hash;
|
||||
if (!vb_hash) {
|
||||
LOG(ERROR) << AT << " Failed verified boot hash parsing";
|
||||
return {ErrorCode::INVALID_ARGUMENT, {}};
|
||||
}
|
||||
rot.verified_boot_hash.resize(vb_hash->length);
|
||||
memcpy(rot.verified_boot_hash.data(), vb_hash->data, vb_hash->length);
|
||||
|
||||
return {ErrorCode::OK, result};
|
||||
}
|
||||
|
||||
} // namespace V4_1
|
||||
} // namespace keymaster
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
|
||||
#include <keymasterV4_0/attestation_record.h>
|
||||
#include <keymasterV4_0/openssl_utils.h>
|
||||
#include <keymasterV4_1/authorization_set.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace keymaster {
|
||||
namespace V4_1 {
|
||||
|
||||
using V4_0::kAttestionRecordOid;
|
||||
using V4_0::keymaster_verified_boot_t;
|
||||
|
||||
struct RootOfTrust {
|
||||
SecurityLevel security_level;
|
||||
hidl_vec<uint8_t> verified_boot_key;
|
||||
hidl_vec<uint8_t> verified_boot_hash;
|
||||
keymaster_verified_boot_t verified_boot_state;
|
||||
bool device_locked;
|
||||
};
|
||||
|
||||
struct AttestationRecord {
|
||||
RootOfTrust root_of_trust;
|
||||
uint32_t attestation_version;
|
||||
SecurityLevel attestation_security_level;
|
||||
uint32_t keymaster_version;
|
||||
SecurityLevel keymaster_security_level;
|
||||
hidl_vec<uint8_t> attestation_challenge;
|
||||
AuthorizationSet software_enforced;
|
||||
AuthorizationSet hardware_enforced;
|
||||
hidl_vec<uint8_t> unique_id;
|
||||
};
|
||||
|
||||
std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert);
|
||||
|
||||
} // namespace V4_1
|
||||
} // namespace keymaster
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
@@ -26,10 +26,13 @@ namespace android::hardware::keymaster::V4_1 {
|
||||
using V4_0::BlockMode;
|
||||
using V4_0::Digest;
|
||||
using V4_0::EcCurve;
|
||||
using V4_0::ErrorCode;
|
||||
using V4_0::HardwareAuthToken;
|
||||
using V4_0::KeyCharacteristics;
|
||||
using V4_0::KeyOrigin;
|
||||
using V4_0::KeyParameter;
|
||||
using V4_0::KeyPurpose;
|
||||
using V4_0::PaddingMode;
|
||||
using V4_0::SecurityLevel;
|
||||
using V4_0::TagType;
|
||||
using V4_0::VerificationToken;
|
||||
|
||||
|
||||
@@ -19,12 +19,24 @@ cc_test {
|
||||
defaults: ["VtsHalTargetTestDefaults"],
|
||||
srcs: [
|
||||
"EarlyBootKeyTest.cpp",
|
||||
"DeviceUniqueAttestationTest.cpp",
|
||||
"Keymaster4_1HidlTest.cpp",
|
||||
"UnlockedDeviceRequiredTest.cpp",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.keymaster@4.0",
|
||||
"android.hardware.keymaster@4.1",
|
||||
"libkeymaster4support",
|
||||
"libcrypto_static",
|
||||
"libkeymaster4_1support",
|
||||
"libkeymaster4support",
|
||||
"libkeymaster4vtstest",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-O0",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts-core",
|
||||
],
|
||||
test_suites: ["vts-core"],
|
||||
}
|
||||
|
||||
278
keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
Normal file
278
keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Keymaster4_1HidlTest.h"
|
||||
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <keymasterV4_1/attestation_record.h>
|
||||
#include <keymasterV4_1/authorization_set.h>
|
||||
|
||||
namespace android::hardware::keymaster::V4_0 {
|
||||
|
||||
bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
|
||||
return std::equal(a.begin(), a.end(), b.begin(), b.end());
|
||||
}
|
||||
|
||||
} // namespace android::hardware::keymaster::V4_0
|
||||
|
||||
namespace android::hardware::keymaster::V4_1 {
|
||||
|
||||
inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
|
||||
return os << toString(tag);
|
||||
}
|
||||
|
||||
namespace test {
|
||||
|
||||
using std::string;
|
||||
using std::tuple;
|
||||
|
||||
namespace {
|
||||
|
||||
char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
string bin2hex(const hidl_vec<uint8_t>& data) {
|
||||
string retval;
|
||||
retval.reserve(data.size() * 2 + 1);
|
||||
for (uint8_t byte : data) {
|
||||
retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
|
||||
retval.push_back(nibble2hex[0x0F & byte]);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct AuthorizationSetDifferences {
|
||||
string aName;
|
||||
string bName;
|
||||
AuthorizationSet aWhackB;
|
||||
AuthorizationSet bWhackA;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const AuthorizationSetDifferences& diffs) {
|
||||
if (!diffs.aWhackB.empty()) {
|
||||
o << "Set " << diffs.aName << " contains the following that " << diffs.bName << " does not"
|
||||
<< diffs.aWhackB;
|
||||
if (!diffs.bWhackA.empty()) o << std::endl;
|
||||
}
|
||||
|
||||
if (!diffs.bWhackA.empty()) {
|
||||
o << "Set " << diffs.bName << " contains the following that " << diffs.aName << " does not"
|
||||
<< diffs.bWhackA;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Computes and returns a \ b and b \ a ('\' is the set-difference operator, a \ b means all the
|
||||
// elements that are in a but not b, i.e. take a and whack all the elements in b) to the provided
|
||||
// stream. The sets must be sorted.
|
||||
//
|
||||
// This provides a simple and clear view of how the two sets differ, generally much
|
||||
// easier than scrutinizing printouts of the two sets.
|
||||
AuthorizationSetDifferences difference(string aName, const AuthorizationSet& a, string bName,
|
||||
const AuthorizationSet& b) {
|
||||
AuthorizationSetDifferences diffs = {std::move(aName), std::move(bName), {}, {}};
|
||||
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(diffs.aWhackB));
|
||||
std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(diffs.bWhackA));
|
||||
return diffs;
|
||||
}
|
||||
|
||||
#define DIFFERENCE(a, b) difference(#a, a, #b, b)
|
||||
|
||||
void check_root_of_trust(const RootOfTrust& root_of_trust) {
|
||||
char vb_meta_device_state[PROPERTY_VALUE_MAX];
|
||||
if (property_get("ro.boot.vbmeta.device_state", vb_meta_device_state, "") == 0) return;
|
||||
|
||||
char vb_meta_digest[PROPERTY_VALUE_MAX];
|
||||
EXPECT_GT(property_get("ro.boot.vbmeta.digest", vb_meta_digest, ""), 0);
|
||||
EXPECT_EQ(vb_meta_digest, bin2hex(root_of_trust.verified_boot_hash));
|
||||
|
||||
// Verified boot key should be all 0's if the boot state is not verified or self signed
|
||||
HidlBuf empty_boot_key(string(32, '\0'));
|
||||
|
||||
char vb_meta_bootstate[PROPERTY_VALUE_MAX];
|
||||
auto& verified_boot_key = root_of_trust.verified_boot_key;
|
||||
auto& verified_boot_state = root_of_trust.verified_boot_state;
|
||||
EXPECT_GT(property_get("ro.boot.verifiedbootstate", vb_meta_bootstate, ""), 0);
|
||||
if (!strcmp(vb_meta_bootstate, "green")) {
|
||||
EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_VERIFIED);
|
||||
EXPECT_NE(verified_boot_key, empty_boot_key);
|
||||
} else if (!strcmp(vb_meta_bootstate, "yellow")) {
|
||||
EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_SELF_SIGNED);
|
||||
EXPECT_NE(verified_boot_key, empty_boot_key);
|
||||
} else if (!strcmp(vb_meta_bootstate, "orange")) {
|
||||
EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
|
||||
EXPECT_EQ(verified_boot_key, empty_boot_key);
|
||||
} else if (!strcmp(vb_meta_bootstate, "red")) {
|
||||
EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_FAILED);
|
||||
} else {
|
||||
EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
|
||||
EXPECT_EQ(verified_boot_key, empty_boot_key);
|
||||
}
|
||||
}
|
||||
|
||||
void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
|
||||
AuthorizationSet expected_sw_enforced,
|
||||
AuthorizationSet expected_hw_enforced,
|
||||
SecurityLevel expected_security_level) {
|
||||
EXPECT_EQ(41U, attestation.keymaster_version);
|
||||
EXPECT_EQ(4U, attestation.attestation_version);
|
||||
EXPECT_EQ(expected_security_level, attestation.attestation_security_level);
|
||||
EXPECT_EQ(expected_security_level, attestation.keymaster_security_level);
|
||||
EXPECT_EQ(challenge, attestation.attestation_challenge);
|
||||
|
||||
check_root_of_trust(attestation.root_of_trust);
|
||||
|
||||
// Sort all of the authorization lists, so that equality matching works.
|
||||
expected_sw_enforced.Sort();
|
||||
expected_hw_enforced.Sort();
|
||||
attestation.software_enforced.Sort();
|
||||
attestation.hardware_enforced.Sort();
|
||||
|
||||
EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
|
||||
<< DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
|
||||
EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
|
||||
<< DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using std::string;
|
||||
using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;
|
||||
|
||||
TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
|
||||
if (SecLevel() != SecurityLevel::STRONGBOX) return;
|
||||
|
||||
ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.RsaSigningKey(2048, 65537)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
|
||||
.Authorization(TAG_INCLUDE_UNIQUE_ID))));
|
||||
|
||||
hidl_vec<hidl_vec<uint8_t>> cert_chain;
|
||||
EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
|
||||
convert(AttestKey(
|
||||
AuthorizationSetBuilder()
|
||||
.Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
|
||||
.Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
|
||||
.Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
|
||||
&cert_chain)));
|
||||
CheckedDeleteKey();
|
||||
|
||||
ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.EcdsaSigningKey(EcCurve::P_256)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Authorization(TAG_INCLUDE_UNIQUE_ID))));
|
||||
|
||||
EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
|
||||
convert(AttestKey(
|
||||
AuthorizationSetBuilder()
|
||||
.Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
|
||||
.Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
|
||||
&cert_chain)));
|
||||
}
|
||||
|
||||
TEST_P(DeviceUniqueAttestationTest, Rsa) {
|
||||
if (SecLevel() != SecurityLevel::STRONGBOX) return;
|
||||
ASSERT_EQ(ErrorCode::OK,
|
||||
convert(GenerateKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.RsaSigningKey(2048, 65537)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
|
||||
.Authorization(TAG_CREATION_DATETIME, 1))));
|
||||
|
||||
hidl_vec<hidl_vec<uint8_t>> cert_chain;
|
||||
HidlBuf challenge("challenge");
|
||||
HidlBuf app_id("foo");
|
||||
EXPECT_EQ(ErrorCode::OK,
|
||||
convert(AttestKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
|
||||
.Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
|
||||
.Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
|
||||
&cert_chain)));
|
||||
|
||||
EXPECT_EQ(1U, cert_chain.size());
|
||||
auto [err, attestation] = parse_attestation_record(cert_chain[0]);
|
||||
EXPECT_EQ(ErrorCode::OK, err);
|
||||
|
||||
check_attestation_record(attestation, challenge,
|
||||
/* sw_enforced */
|
||||
AuthorizationSetBuilder()
|
||||
.Authorization(TAG_CREATION_DATETIME, 1)
|
||||
.Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
|
||||
/* hw_enforced */
|
||||
AuthorizationSetBuilder()
|
||||
.Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.RsaSigningKey(2048, 65537)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
|
||||
.Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
|
||||
.Authorization(TAG_OS_VERSION, os_version())
|
||||
.Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
|
||||
SecLevel());
|
||||
}
|
||||
|
||||
TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
|
||||
if (SecLevel() != SecurityLevel::STRONGBOX) return;
|
||||
ASSERT_EQ(ErrorCode::OK,
|
||||
convert(GenerateKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.EcdsaSigningKey(256)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Authorization(TAG_CREATION_DATETIME, 1))));
|
||||
|
||||
hidl_vec<hidl_vec<uint8_t>> cert_chain;
|
||||
HidlBuf challenge("challenge");
|
||||
HidlBuf app_id("foo");
|
||||
EXPECT_EQ(ErrorCode::OK,
|
||||
convert(AttestKey(AuthorizationSetBuilder()
|
||||
.Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
|
||||
.Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
|
||||
.Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
|
||||
&cert_chain)));
|
||||
|
||||
EXPECT_EQ(1U, cert_chain.size());
|
||||
auto [err, attestation] = parse_attestation_record(cert_chain[0]);
|
||||
EXPECT_EQ(ErrorCode::OK, err);
|
||||
|
||||
check_attestation_record(attestation, challenge,
|
||||
/* sw_enforced */
|
||||
AuthorizationSetBuilder()
|
||||
.Authorization(TAG_CREATION_DATETIME, 1)
|
||||
.Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
|
||||
/* hw_enforced */
|
||||
AuthorizationSetBuilder()
|
||||
.Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED)
|
||||
.EcdsaSigningKey(256)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Authorization(TAG_EC_CURVE, EcCurve::P_256)
|
||||
.Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
|
||||
.Authorization(TAG_OS_VERSION, os_version())
|
||||
.Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
|
||||
SecLevel());
|
||||
}
|
||||
|
||||
INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
|
||||
|
||||
} // namespace test
|
||||
} // namespace android::hardware::keymaster::V4_1
|
||||
@@ -14,8 +14,78 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Keymaster4_1HidlTest.h"
|
||||
|
||||
#include <keymasterV4_1/authorization_set.h>
|
||||
|
||||
namespace android::hardware::keymaster::V4_1::test {
|
||||
|
||||
using std::string;
|
||||
|
||||
using EarlyBootKeyTest = Keymaster4_1HidlTest;
|
||||
|
||||
// Because VTS tests are run on fully-booted machines, we can only run negative tests for early boot
|
||||
// keys, which cannot be created or used after /data is mounted. This is the only test we can run
|
||||
// in the normal case. The positive test will have to be done by the Android system, when it
|
||||
// creates/uses early boot keys during boot. It should fail to boot if the early boot key usage
|
||||
// fails.
|
||||
TEST_P(EarlyBootKeyTest, CannotCreateEarlyBootKeys) {
|
||||
auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
|
||||
CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
|
||||
|
||||
CheckedDeleteKeyData(&aesKeyData);
|
||||
CheckedDeleteKeyData(&hmacKeyData);
|
||||
CheckedDeleteKeyData(&rsaKeyData);
|
||||
CheckedDeleteKeyData(&ecdsaKeyData);
|
||||
}
|
||||
|
||||
// This is a more comprenhensive test, but it can only be run on a machine which is still in early
|
||||
// boot stage, which no proper Android device is by the time we can run VTS. To use this,
|
||||
// un-disable it and modify vold to remove the call to earlyBootEnded(). Running the test will end
|
||||
// early boot, so you'll have to reboot between runs.
|
||||
TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
|
||||
// Should be able to create keys, since early boot has not ended
|
||||
auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
|
||||
CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
|
||||
|
||||
// TAG_EARLY_BOOT_ONLY should be in hw-enforced.
|
||||
EXPECT_TRUE(contains(aesKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
|
||||
EXPECT_TRUE(contains(hmacKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
|
||||
EXPECT_TRUE(contains(rsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
|
||||
EXPECT_TRUE(contains(ecdsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
|
||||
|
||||
// Should be able to use keys, since early boot has not ended
|
||||
EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
|
||||
|
||||
// End early boot
|
||||
Return<ErrorCode> earlyBootResult = keymaster().earlyBootEnded();
|
||||
EXPECT_TRUE(earlyBootResult.isOk());
|
||||
EXPECT_EQ(earlyBootResult, ErrorCode::OK);
|
||||
|
||||
// Should not be able to use already-created keys.
|
||||
EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
|
||||
|
||||
CheckedDeleteKeyData(&aesKeyData);
|
||||
CheckedDeleteKeyData(&hmacKeyData);
|
||||
CheckedDeleteKeyData(&rsaKeyData);
|
||||
CheckedDeleteKeyData(&ecdsaKeyData);
|
||||
|
||||
// Should not be able to create new keys
|
||||
std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
|
||||
CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
|
||||
|
||||
CheckedDeleteKeyData(&aesKeyData);
|
||||
CheckedDeleteKeyData(&hmacKeyData);
|
||||
CheckedDeleteKeyData(&rsaKeyData);
|
||||
CheckedDeleteKeyData(&ecdsaKeyData);
|
||||
}
|
||||
|
||||
INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(EarlyBootKeyTest);
|
||||
|
||||
} // namespace android::hardware::keymaster::V4_1::test
|
||||
|
||||
59
keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
Normal file
59
keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Keymaster4_1HidlTest.h"
|
||||
|
||||
namespace android::hardware::keymaster::V4_1::test {
|
||||
|
||||
using std::string;
|
||||
|
||||
void Keymaster4_1HidlTest::SetUp() {
|
||||
keymaster41_ = IKeymasterDevice::getService(GetParam());
|
||||
InitializeKeymaster(keymaster41_);
|
||||
}
|
||||
|
||||
auto Keymaster4_1HidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
|
||||
const string& message, const AuthorizationSet& in_params)
|
||||
-> std::tuple<ErrorCode, string, AuthorizationSet /* out_params */> {
|
||||
AuthorizationSet begin_out_params;
|
||||
V4_0::ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_);
|
||||
AuthorizationSet out_params(std::move(begin_out_params));
|
||||
if (result != V4_0::ErrorCode::OK) {
|
||||
return {convert(result), {}, out_params};
|
||||
}
|
||||
|
||||
string output;
|
||||
size_t consumed = 0;
|
||||
AuthorizationSet update_params;
|
||||
AuthorizationSet update_out_params;
|
||||
result = Update(op_handle_, update_params, message, &update_out_params, &output, &consumed);
|
||||
out_params.push_back(update_out_params);
|
||||
if (result != V4_0::ErrorCode::OK) {
|
||||
return {convert(result), output, out_params};
|
||||
}
|
||||
|
||||
string unused;
|
||||
AuthorizationSet finish_params;
|
||||
AuthorizationSet finish_out_params;
|
||||
result = Finish(op_handle_, finish_params, message.substr(consumed), unused, &finish_out_params,
|
||||
&output);
|
||||
op_handle_ = V4_0::test::kOpHandleSentinel;
|
||||
out_params.push_back(finish_out_params);
|
||||
|
||||
return {convert(result), output, out_params};
|
||||
}
|
||||
|
||||
} // namespace android::hardware::keymaster::V4_1::test
|
||||
158
keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
Normal file
158
keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
|
||||
|
||||
#include <KeymasterHidlTest.h>
|
||||
#include <keymasterV4_1/authorization_set.h>
|
||||
|
||||
namespace android::hardware::keymaster::V4_1::test {
|
||||
|
||||
using V4_0::test::HidlBuf;
|
||||
|
||||
class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest {
|
||||
public:
|
||||
using super = V4_0::test::KeymasterHidlTest;
|
||||
|
||||
ErrorCode convert(V4_0::ErrorCode error_code) { return static_cast<ErrorCode>(error_code); }
|
||||
|
||||
// These methods hide the base class versions.
|
||||
void SetUp();
|
||||
IKeymasterDevice& keymaster() { return *keymaster41_; };
|
||||
|
||||
struct KeyData {
|
||||
HidlBuf blob;
|
||||
KeyCharacteristics characteristics;
|
||||
};
|
||||
|
||||
std::tuple<ErrorCode, KeyData> GenerateKeyData(const AuthorizationSet& keyDescription) {
|
||||
KeyData keyData;
|
||||
ErrorCode errorCode = convert(
|
||||
super::GenerateKey(keyDescription, &keyData.blob, &keyData.characteristics));
|
||||
return {errorCode, keyData};
|
||||
}
|
||||
|
||||
void CheckedDeleteKeyData(KeyData* keyData) { CheckedDeleteKey(&keyData->blob); }
|
||||
|
||||
template <typename TagType>
|
||||
std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
|
||||
KeyData /* ecdsaKey */>
|
||||
CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
|
||||
ErrorCode errorCode;
|
||||
|
||||
/* AES */
|
||||
KeyData aesKeyData;
|
||||
std::tie(errorCode, aesKeyData) =
|
||||
GenerateKeyData(AuthorizationSetBuilder()
|
||||
.AesEncryptionKey(128)
|
||||
.Authorization(tagToTest)
|
||||
.BlockMode(BlockMode::ECB)
|
||||
.Padding(PaddingMode::NONE)
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED));
|
||||
EXPECT_EQ(expectedReturn, errorCode);
|
||||
|
||||
/* HMAC */
|
||||
KeyData hmacKeyData;
|
||||
std::tie(errorCode, hmacKeyData) =
|
||||
GenerateKeyData(AuthorizationSetBuilder()
|
||||
.HmacKey(128)
|
||||
.Authorization(tagToTest)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Authorization(TAG_MIN_MAC_LENGTH, 128)
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED));
|
||||
EXPECT_EQ(expectedReturn, errorCode);
|
||||
|
||||
/* RSA */
|
||||
KeyData rsaKeyData;
|
||||
std::tie(errorCode, rsaKeyData) =
|
||||
GenerateKeyData(AuthorizationSetBuilder()
|
||||
.RsaSigningKey(2048, 65537)
|
||||
.Authorization(tagToTest)
|
||||
.Digest(Digest::NONE)
|
||||
.Padding(PaddingMode::NONE)
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED));
|
||||
EXPECT_EQ(expectedReturn, errorCode);
|
||||
|
||||
/* ECDSA */
|
||||
KeyData ecdsaKeyData;
|
||||
std::tie(errorCode, ecdsaKeyData) =
|
||||
GenerateKeyData(AuthorizationSetBuilder()
|
||||
.EcdsaSigningKey(256)
|
||||
.Authorization(tagToTest)
|
||||
.Digest(Digest::SHA_2_256)
|
||||
.Authorization(TAG_NO_AUTH_REQUIRED));
|
||||
EXPECT_EQ(expectedReturn, errorCode);
|
||||
|
||||
return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
|
||||
}
|
||||
|
||||
std::tuple<ErrorCode, std::string /* processedMessage */, AuthorizationSet /* out_params */>
|
||||
ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const std::string& message,
|
||||
const AuthorizationSet& in_params);
|
||||
|
||||
ErrorCode UseAesKey(const HidlBuf& aesKeyBlob) {
|
||||
auto [result, ciphertext, out_params] = ProcessMessage(
|
||||
aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
|
||||
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) {
|
||||
auto [result, mac, out_params] =
|
||||
ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
|
||||
AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorCode UseRsaKey(const HidlBuf& rsaKeyBlob) {
|
||||
std::string message(2048 / 8, 'a');
|
||||
auto [result, signature, out_params] = ProcessMessage(
|
||||
rsaKeyBlob, KeyPurpose::SIGN, message,
|
||||
AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorCode UseEcdsaKey(const HidlBuf& ecdsaKeyBlob) {
|
||||
auto [result, signature, out_params] =
|
||||
ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a",
|
||||
AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<std::string> build_params() {
|
||||
auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
|
||||
return params;
|
||||
}
|
||||
|
||||
private:
|
||||
sp<IKeymasterDevice> keymaster41_;
|
||||
};
|
||||
|
||||
template <typename TypedTag>
|
||||
bool contains(hidl_vec<KeyParameter>& set, TypedTag typedTag) {
|
||||
return std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
|
||||
return param.tag == static_cast<V4_0::Tag>(typedTag);
|
||||
}) != set.end();
|
||||
}
|
||||
|
||||
#define INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(name) \
|
||||
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
|
||||
testing::ValuesIn(Keymaster4_1HidlTest::build_params()), \
|
||||
android::hardware::PrintInstanceNameToString)
|
||||
|
||||
} // namespace android::hardware::keymaster::V4_1::test
|
||||
63
keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
Normal file
63
keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Keymaster4_1HidlTest.h"
|
||||
|
||||
#include <keymasterV4_1/authorization_set.h>
|
||||
|
||||
namespace android::hardware::keymaster::V4_1::test {
|
||||
|
||||
using UnlockedDeviceRequiredTest = Keymaster4_1HidlTest;
|
||||
|
||||
// This may be a problematic test. It can't be run repeatedly without unlocking the device in
|
||||
// between runs... and on most test devices there are no enrolled credentials so it can't be
|
||||
// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
|
||||
// device is to reboot it. For that reason, this is disabled by default. It can be used as part of
|
||||
// a manual test process, which includes unlocking between runs, which is why it's included here.
|
||||
// Well, that and the fact that it's the only test we can do without also making calls into the
|
||||
// Gatekeeper HAL. We haven't written any cross-HAL tests, and don't know what all of the
|
||||
// implications might be, so that may or may not be a solution.
|
||||
//
|
||||
// TODO(swillden): Use the Gatekeeper HAL to enroll some test credentials which we can verify to get
|
||||
// an unlock auth token. If that works, enable the improved test.
|
||||
TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
|
||||
auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
|
||||
CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
|
||||
|
||||
EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
|
||||
|
||||
Return<ErrorCode> rc =
|
||||
keymaster().deviceLocked(false /* passwordOnly */, {} /* verificationToken */);
|
||||
ASSERT_TRUE(rc.isOk());
|
||||
ASSERT_EQ(ErrorCode::OK, static_cast<ErrorCode>(rc));
|
||||
|
||||
EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
|
||||
EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
|
||||
|
||||
CheckedDeleteKeyData(&aesKeyData);
|
||||
CheckedDeleteKeyData(&hmacKeyData);
|
||||
CheckedDeleteKeyData(&rsaKeyData);
|
||||
CheckedDeleteKeyData(&ecdsaKeyData);
|
||||
}
|
||||
|
||||
INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(UnlockedDeviceRequiredTest);
|
||||
|
||||
} // namespace android::hardware::keymaster::V4_1::test
|
||||
Reference in New Issue
Block a user