Loading security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +55 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ using std::optional; os << "(Empty)" << ::std::endl; else { os << "\n"; for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl; for (auto& entry : set) os << entry << ::std::endl; } return os; } Loading Loading @@ -131,6 +131,17 @@ ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc, *key_blob = std::move(creationResult.keyBlob); *key_characteristics = std::move(creationResult.keyCharacteristics); cert_chain_ = std::move(creationResult.certificateChain); auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM); EXPECT_TRUE(algorithm); if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) { EXPECT_GE(cert_chain_.size(), 1); if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1); } else { // For symmetric keys there should be no certificates. EXPECT_EQ(cert_chain_.size(), 0); } } return GetReturnErrorCode(result); Loading Loading @@ -162,6 +173,17 @@ ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFo *key_blob = std::move(creationResult.keyBlob); *key_characteristics = std::move(creationResult.keyCharacteristics); cert_chain_ = std::move(creationResult.certificateChain); auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM); EXPECT_TRUE(algorithm); if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) { EXPECT_GE(cert_chain_.size(), 1); if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1); } else { // For symmetric keys there should be no certificates. EXPECT_EQ(cert_chain_.size(), 0); } } return GetReturnErrorCode(result); Loading Loading @@ -195,6 +217,20 @@ ErrorCode KeyMintAidlTestBase::ImportWrappedKey(string wrapped_key, string wrapp key_blob_ = std::move(creationResult.keyBlob); key_characteristics_ = std::move(creationResult.keyCharacteristics); cert_chain_ = std::move(creationResult.certificateChain); AuthorizationSet allAuths; for (auto& entry : key_characteristics_) { allAuths.push_back(AuthorizationSet(entry.authorizations)); } auto algorithm = allAuths.GetTagValue(TAG_ALGORITHM); EXPECT_TRUE(algorithm); if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) { EXPECT_GE(cert_chain_.size(), 1); } else { // For symmetric keys there should be no certificates. EXPECT_EQ(cert_chain_.size(), 0); } } return GetReturnErrorCode(result); Loading Loading @@ -788,6 +824,24 @@ const vector<KeyParameter>& KeyMintAidlTestBase::SecLevelAuthorizations( return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } const vector<KeyParameter>& KeyMintAidlTestBase::HwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics) { auto found = std::find_if(key_characteristics.begin(), key_characteristics.end(), [](auto& entry) { return entry.securityLevel == SecurityLevel::STRONGBOX || entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT; }); return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } const vector<KeyParameter>& KeyMintAidlTestBase::SwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics) { auto found = std::find_if( key_characteristics.begin(), key_characteristics.end(), [](auto& entry) { return entry.securityLevel == SecurityLevel::SOFTWARE; }); return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } } // namespace test } // namespace aidl::android::hardware::security::keymint security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +12 −4 Original line number Diff line number Diff line Loading @@ -27,7 +27,11 @@ #include <keymint_support/authorization_set.h> namespace aidl::android::hardware::security::keymint::test { namespace aidl::android::hardware::security::keymint { ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set); namespace test { using ::android::sp; using Status = ::ndk::ScopedAStatus; Loading @@ -37,8 +41,6 @@ using ::std::vector; constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF; ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set); class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { public: void SetUp() override; Loading Loading @@ -173,6 +175,10 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { inline const vector<KeyParameter>& SecLevelAuthorizations() { return SecLevelAuthorizations(key_characteristics_); } const vector<KeyParameter>& HwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics); const vector<KeyParameter>& SwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics); private: std::shared_ptr<IKeyMintDevice> keymint_; Loading @@ -190,4 +196,6 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { testing::ValuesIn(KeyMintAidlTestBase::build_params()), \ ::android::PrintInstanceNameToString) } // namespace aidl::android::hardware::security::keymint::test } // namespace test } // namespace aidl::android::hardware::security::keymint security/keymint/aidl/vts/functional/KeyMintTest.cpp +319 −13 Original line number Diff line number Diff line Loading @@ -180,9 +180,280 @@ struct RSA_Delete { void operator()(RSA* p) { RSA_free(p); } }; /* TODO(seleneh) add attestation verification codes like verify_chain() and * attestation tests after we decided on the keymint 1 attestation changes. */ char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; string bin2hex(const vector<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; } X509* parse_cert_blob(const vector<uint8_t>& blob) { const uint8_t* p = blob.data(); return d2i_X509(nullptr, &p, blob.size()); } bool verify_chain(const vector<Certificate>& chain) { for (size_t i = 0; i < chain.size(); ++i) { X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate)); X509_Ptr signing_cert; if (i < chain.size() - 1) { signing_cert.reset(parse_cert_blob(chain[i + 1].encodedCertificate)); } else { signing_cert.reset(parse_cert_blob(chain[i].encodedCertificate)); } EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get()); if (!key_cert.get() || !signing_cert.get()) return false; EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get())); EXPECT_TRUE(!!signing_pubkey.get()); if (!signing_pubkey.get()) return false; EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get())) << "Verification of certificate " << i << " failed " << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL); char* cert_issuer = // X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0); char* signer_subj = X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0); EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer."; if (i == 0) { char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0); EXPECT_STREQ("/CN=Android Keystore Key", cert_sub) << "Cert " << i << " has wrong subject."; OPENSSL_free(cert_sub); } OPENSSL_free(cert_issuer); OPENSSL_free(signer_subj); if (dump_Attestations) std::cout << bin2hex(chain[i].encodedCertificate) << std::endl; } return true; } // Extract attestation record from cert. Returned object is still part of cert; don't free it // separately. ASN1_OCTET_STRING* get_attestation_record(X509* certificate) { ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); EXPECT_TRUE(!!oid.get()); if (!oid.get()) return nullptr; int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */); EXPECT_NE(-1, location) << "Attestation extension not found in certificate"; if (location == -1) return nullptr; X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location); EXPECT_TRUE(!!attest_rec_ext) << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug."; if (!attest_rec_ext) return nullptr; ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data"; return attest_rec; } bool tag_in_list(const KeyParameter& entry) { // 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 tag_list = { Tag::BLOB_USAGE_REQUIREMENTS, // Tag::CREATION_DATETIME, // Tag::EC_CURVE, Tag::HARDWARE_TYPE, Tag::INCLUDE_UNIQUE_ID, }; return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end(); } AuthorizationSet filtered_tags(const AuthorizationSet& set) { AuthorizationSet filtered; std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list); return filtered; } bool avb_verification_enabled() { char value[PROPERTY_VALUE_MAX]; return property_get("ro.boot.vbmeta.device_state", value, "") != 0; } bool verify_attestation_record(const string& challenge, // const string& app_id, // AuthorizationSet expected_sw_enforced, // AuthorizationSet expected_hw_enforced, // SecurityLevel security_level, const vector<uint8_t>& attestation_cert) { X509_Ptr cert(parse_cert_blob(attestation_cert)); EXPECT_TRUE(!!cert.get()); if (!cert.get()) return false; ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get()); EXPECT_TRUE(!!attest_rec); if (!attest_rec) return false; AuthorizationSet att_sw_enforced; AuthorizationSet att_hw_enforced; uint32_t att_attestation_version; uint32_t att_keymaster_version; SecurityLevel att_attestation_security_level; SecurityLevel att_keymaster_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_keymaster_version, // &att_keymaster_security_level, // &att_challenge, // &att_sw_enforced, // &att_hw_enforced, // &att_unique_id); EXPECT_EQ(ErrorCode::OK, error); if (error != ErrorCode::OK) return false; EXPECT_GE(att_attestation_version, 3U); expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, vector<uint8_t>(app_id.begin(), app_id.end())); EXPECT_GE(att_keymaster_version, 4U); EXPECT_EQ(security_level, att_keymaster_security_level); EXPECT_EQ(security_level, att_attestation_security_level); EXPECT_EQ(challenge.length(), att_challenge.size()); EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length())); 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 // for the BOOT_PATCH_LEVEL. if (avb_verification_enabled()) { for (int i = 0; i < att_hw_enforced.size(); i++) { if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL || att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) { std::string date = std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>()); // strptime seems to require delimiters, but the tag value will // be YYYYMMDD date.insert(6, "-"); date.insert(4, "-"); EXPECT_EQ(date.size(), 10); struct tm time; strptime(date.c_str(), "%Y-%m-%d", &time); // Day of the month (0-31) EXPECT_GE(time.tm_mday, 0); EXPECT_LT(time.tm_mday, 32); // Months since Jan (0-11) EXPECT_GE(time.tm_mon, 0); EXPECT_LT(time.tm_mon, 12); // Years since 1900 EXPECT_GT(time.tm_year, 110); EXPECT_LT(time.tm_year, 200); } } } // Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates // 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. 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)); 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) || att_hw_enforced.Contains(TAG_KEY_SIZE)); } // Test root of trust elements vector<uint8_t> verified_boot_key; VerifiedBoot verified_boot_state; bool device_locked; vector<uint8_t> verified_boot_hash; error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key, &verified_boot_state, &device_locked, &verified_boot_hash); EXPECT_EQ(ErrorCode::OK, error); if (avb_verification_enabled()) { EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0); string prop_string(property_value); EXPECT_EQ(prop_string.size(), 64); EXPECT_EQ(prop_string, bin2hex(verified_boot_hash)); EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0); if (!strcmp(property_value, "unlocked")) { EXPECT_FALSE(device_locked); } else { EXPECT_TRUE(device_locked); } // Check that the device is locked if not debuggable, e.g., user build // images in CTS. For VTS, debuggable images are used to allow adb root // and the device is unlocked. if (!property_get_bool("ro.debuggable", false)) { EXPECT_TRUE(device_locked); } else { EXPECT_FALSE(device_locked); } } // Verified boot key should be all 0's if the boot state is not verified or self signed std::string empty_boot_key(32, '\0'); std::string verified_boot_key_str((const char*)verified_boot_key.data(), verified_boot_key.size()); EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0); if (!strcmp(property_value, "green")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED); EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } else if (!strcmp(property_value, "yellow")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED); EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } else if (!strcmp(property_value, "orange")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED); EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } else if (!strcmp(property_value, "red")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED); } else { EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED); EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } att_sw_enforced.Sort(); expected_sw_enforced.Sort(); EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced)); att_hw_enforced.Sort(); expected_hw_enforced.Sort(); EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced)); return true; } std::string make_string(const uint8_t* data, size_t length) { return std::string(reinterpret_cast<const char*>(data), length); Loading Loading @@ -288,6 +559,51 @@ TEST_P(NewKeyGenerationTest, Rsa) { } } /* * NewKeyGenerationTest.Rsa * * Verifies that keymint can generate all required RSA key sizes, and that the resulting keys * have correct characteristics. */ TEST_P(NewKeyGenerationTest, RsaWithAttestation) { for (auto key_size : ValidKeySizes(Algorithm::RSA)) { auto challenge = "hello"; auto app_id = "foo"; vector<uint8_t> key_blob; vector<KeyCharacteristics> key_characteristics; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .RsaSigningKey(key_size, 65537) .Digest(Digest::NONE) .Padding(PaddingMode::NONE) .AttestationChallenge(challenge) .AttestationApplicationId(app_id) .Authorization(TAG_NO_AUTH_REQUIRED), &key_blob, &key_characteristics)); ASSERT_GT(key_blob.size(), 0U); CheckBaseParams(key_characteristics); AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA)); EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) << "Key size " << key_size << "missing"; EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U)); EXPECT_TRUE(verify_chain(cert_chain_)); ASSERT_GT(cert_chain_.size(), 0); AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); EXPECT_TRUE(verify_attestation_record(challenge, app_id, // sw_enforced, hw_enforced, SecLevel(), cert_chain_[0].encodedCertificate)); CheckedDeleteKey(&key_blob); } } /* * NewKeyGenerationTest.NoInvalidRsaSizes * Loading Loading @@ -3895,16 +4211,6 @@ TEST_P(AddEntropyTest, AddLargeEntropy) { INSTANTIATE_KEYMINT_AIDL_TEST(AddEntropyTest); typedef KeyMintAidlTestBase AttestationTest; /* * AttestationTest.RsaAttestation * * Verifies that attesting to RSA keys works and generates the expected output. */ // TODO(seleneh) add attestation tests back after decided on the new attestation // behavior under generateKey and importKey typedef KeyMintAidlTestBase KeyDeletionTest; /** Loading security/keymint/support/include/keymint_support/authorization_set.h +20 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,12 @@ class AuthorizationSetBuilder : public AuthorizationSet { size - 1); // drop the terminating '\0' } template <Tag tag> AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const std::string& data) { return Authorization(ttag, reinterpret_cast<const uint8_t*>(data.data()), data.size()); } AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) { for (const auto& entry : set) { push_back(entry); Loading Loading @@ -294,6 +300,20 @@ class AuthorizationSetBuilder : public AuthorizationSet { AuthorizationSetBuilder& Digest(std::vector<Digest> digests); AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings); AuthorizationSetBuilder& AttestationChallenge(const std::string& challenge) { return Authorization(TAG_ATTESTATION_CHALLENGE, challenge); } AuthorizationSetBuilder& AttestationChallenge(std::vector<uint8_t> challenge) { return Authorization(TAG_ATTESTATION_CHALLENGE, challenge); } AuthorizationSetBuilder& AttestationApplicationId(const std::string& id) { return Authorization(TAG_ATTESTATION_APPLICATION_ID, id); } AuthorizationSetBuilder& AttestationApplicationId(std::vector<uint8_t> id) { return Authorization(TAG_ATTESTATION_APPLICATION_ID, id); } template <typename... T> AuthorizationSetBuilder& BlockMode(T&&... a) { return BlockMode({std::forward<T>(a)...}); Loading Loading
security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +55 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ using std::optional; os << "(Empty)" << ::std::endl; else { os << "\n"; for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl; for (auto& entry : set) os << entry << ::std::endl; } return os; } Loading Loading @@ -131,6 +131,17 @@ ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc, *key_blob = std::move(creationResult.keyBlob); *key_characteristics = std::move(creationResult.keyCharacteristics); cert_chain_ = std::move(creationResult.certificateChain); auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM); EXPECT_TRUE(algorithm); if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) { EXPECT_GE(cert_chain_.size(), 1); if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1); } else { // For symmetric keys there should be no certificates. EXPECT_EQ(cert_chain_.size(), 0); } } return GetReturnErrorCode(result); Loading Loading @@ -162,6 +173,17 @@ ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFo *key_blob = std::move(creationResult.keyBlob); *key_characteristics = std::move(creationResult.keyCharacteristics); cert_chain_ = std::move(creationResult.certificateChain); auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM); EXPECT_TRUE(algorithm); if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) { EXPECT_GE(cert_chain_.size(), 1); if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1); } else { // For symmetric keys there should be no certificates. EXPECT_EQ(cert_chain_.size(), 0); } } return GetReturnErrorCode(result); Loading Loading @@ -195,6 +217,20 @@ ErrorCode KeyMintAidlTestBase::ImportWrappedKey(string wrapped_key, string wrapp key_blob_ = std::move(creationResult.keyBlob); key_characteristics_ = std::move(creationResult.keyCharacteristics); cert_chain_ = std::move(creationResult.certificateChain); AuthorizationSet allAuths; for (auto& entry : key_characteristics_) { allAuths.push_back(AuthorizationSet(entry.authorizations)); } auto algorithm = allAuths.GetTagValue(TAG_ALGORITHM); EXPECT_TRUE(algorithm); if (algorithm && (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) { EXPECT_GE(cert_chain_.size(), 1); } else { // For symmetric keys there should be no certificates. EXPECT_EQ(cert_chain_.size(), 0); } } return GetReturnErrorCode(result); Loading Loading @@ -788,6 +824,24 @@ const vector<KeyParameter>& KeyMintAidlTestBase::SecLevelAuthorizations( return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } const vector<KeyParameter>& KeyMintAidlTestBase::HwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics) { auto found = std::find_if(key_characteristics.begin(), key_characteristics.end(), [](auto& entry) { return entry.securityLevel == SecurityLevel::STRONGBOX || entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT; }); return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } const vector<KeyParameter>& KeyMintAidlTestBase::SwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics) { auto found = std::find_if( key_characteristics.begin(), key_characteristics.end(), [](auto& entry) { return entry.securityLevel == SecurityLevel::SOFTWARE; }); return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } } // namespace test } // namespace aidl::android::hardware::security::keymint
security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +12 −4 Original line number Diff line number Diff line Loading @@ -27,7 +27,11 @@ #include <keymint_support/authorization_set.h> namespace aidl::android::hardware::security::keymint::test { namespace aidl::android::hardware::security::keymint { ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set); namespace test { using ::android::sp; using Status = ::ndk::ScopedAStatus; Loading @@ -37,8 +41,6 @@ using ::std::vector; constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF; ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set); class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { public: void SetUp() override; Loading Loading @@ -173,6 +175,10 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { inline const vector<KeyParameter>& SecLevelAuthorizations() { return SecLevelAuthorizations(key_characteristics_); } const vector<KeyParameter>& HwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics); const vector<KeyParameter>& SwEnforcedAuthorizations( const vector<KeyCharacteristics>& key_characteristics); private: std::shared_ptr<IKeyMintDevice> keymint_; Loading @@ -190,4 +196,6 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { testing::ValuesIn(KeyMintAidlTestBase::build_params()), \ ::android::PrintInstanceNameToString) } // namespace aidl::android::hardware::security::keymint::test } // namespace test } // namespace aidl::android::hardware::security::keymint
security/keymint/aidl/vts/functional/KeyMintTest.cpp +319 −13 Original line number Diff line number Diff line Loading @@ -180,9 +180,280 @@ struct RSA_Delete { void operator()(RSA* p) { RSA_free(p); } }; /* TODO(seleneh) add attestation verification codes like verify_chain() and * attestation tests after we decided on the keymint 1 attestation changes. */ char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; string bin2hex(const vector<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; } X509* parse_cert_blob(const vector<uint8_t>& blob) { const uint8_t* p = blob.data(); return d2i_X509(nullptr, &p, blob.size()); } bool verify_chain(const vector<Certificate>& chain) { for (size_t i = 0; i < chain.size(); ++i) { X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate)); X509_Ptr signing_cert; if (i < chain.size() - 1) { signing_cert.reset(parse_cert_blob(chain[i + 1].encodedCertificate)); } else { signing_cert.reset(parse_cert_blob(chain[i].encodedCertificate)); } EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get()); if (!key_cert.get() || !signing_cert.get()) return false; EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get())); EXPECT_TRUE(!!signing_pubkey.get()); if (!signing_pubkey.get()) return false; EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get())) << "Verification of certificate " << i << " failed " << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL); char* cert_issuer = // X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0); char* signer_subj = X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0); EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer."; if (i == 0) { char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0); EXPECT_STREQ("/CN=Android Keystore Key", cert_sub) << "Cert " << i << " has wrong subject."; OPENSSL_free(cert_sub); } OPENSSL_free(cert_issuer); OPENSSL_free(signer_subj); if (dump_Attestations) std::cout << bin2hex(chain[i].encodedCertificate) << std::endl; } return true; } // Extract attestation record from cert. Returned object is still part of cert; don't free it // separately. ASN1_OCTET_STRING* get_attestation_record(X509* certificate) { ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); EXPECT_TRUE(!!oid.get()); if (!oid.get()) return nullptr; int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */); EXPECT_NE(-1, location) << "Attestation extension not found in certificate"; if (location == -1) return nullptr; X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location); EXPECT_TRUE(!!attest_rec_ext) << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug."; if (!attest_rec_ext) return nullptr; ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data"; return attest_rec; } bool tag_in_list(const KeyParameter& entry) { // 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 tag_list = { Tag::BLOB_USAGE_REQUIREMENTS, // Tag::CREATION_DATETIME, // Tag::EC_CURVE, Tag::HARDWARE_TYPE, Tag::INCLUDE_UNIQUE_ID, }; return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end(); } AuthorizationSet filtered_tags(const AuthorizationSet& set) { AuthorizationSet filtered; std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list); return filtered; } bool avb_verification_enabled() { char value[PROPERTY_VALUE_MAX]; return property_get("ro.boot.vbmeta.device_state", value, "") != 0; } bool verify_attestation_record(const string& challenge, // const string& app_id, // AuthorizationSet expected_sw_enforced, // AuthorizationSet expected_hw_enforced, // SecurityLevel security_level, const vector<uint8_t>& attestation_cert) { X509_Ptr cert(parse_cert_blob(attestation_cert)); EXPECT_TRUE(!!cert.get()); if (!cert.get()) return false; ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get()); EXPECT_TRUE(!!attest_rec); if (!attest_rec) return false; AuthorizationSet att_sw_enforced; AuthorizationSet att_hw_enforced; uint32_t att_attestation_version; uint32_t att_keymaster_version; SecurityLevel att_attestation_security_level; SecurityLevel att_keymaster_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_keymaster_version, // &att_keymaster_security_level, // &att_challenge, // &att_sw_enforced, // &att_hw_enforced, // &att_unique_id); EXPECT_EQ(ErrorCode::OK, error); if (error != ErrorCode::OK) return false; EXPECT_GE(att_attestation_version, 3U); expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, vector<uint8_t>(app_id.begin(), app_id.end())); EXPECT_GE(att_keymaster_version, 4U); EXPECT_EQ(security_level, att_keymaster_security_level); EXPECT_EQ(security_level, att_attestation_security_level); EXPECT_EQ(challenge.length(), att_challenge.size()); EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length())); 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 // for the BOOT_PATCH_LEVEL. if (avb_verification_enabled()) { for (int i = 0; i < att_hw_enforced.size(); i++) { if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL || att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) { std::string date = std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>()); // strptime seems to require delimiters, but the tag value will // be YYYYMMDD date.insert(6, "-"); date.insert(4, "-"); EXPECT_EQ(date.size(), 10); struct tm time; strptime(date.c_str(), "%Y-%m-%d", &time); // Day of the month (0-31) EXPECT_GE(time.tm_mday, 0); EXPECT_LT(time.tm_mday, 32); // Months since Jan (0-11) EXPECT_GE(time.tm_mon, 0); EXPECT_LT(time.tm_mon, 12); // Years since 1900 EXPECT_GT(time.tm_year, 110); EXPECT_LT(time.tm_year, 200); } } } // Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates // 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. 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)); 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) || att_hw_enforced.Contains(TAG_KEY_SIZE)); } // Test root of trust elements vector<uint8_t> verified_boot_key; VerifiedBoot verified_boot_state; bool device_locked; vector<uint8_t> verified_boot_hash; error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key, &verified_boot_state, &device_locked, &verified_boot_hash); EXPECT_EQ(ErrorCode::OK, error); if (avb_verification_enabled()) { EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0); string prop_string(property_value); EXPECT_EQ(prop_string.size(), 64); EXPECT_EQ(prop_string, bin2hex(verified_boot_hash)); EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0); if (!strcmp(property_value, "unlocked")) { EXPECT_FALSE(device_locked); } else { EXPECT_TRUE(device_locked); } // Check that the device is locked if not debuggable, e.g., user build // images in CTS. For VTS, debuggable images are used to allow adb root // and the device is unlocked. if (!property_get_bool("ro.debuggable", false)) { EXPECT_TRUE(device_locked); } else { EXPECT_FALSE(device_locked); } } // Verified boot key should be all 0's if the boot state is not verified or self signed std::string empty_boot_key(32, '\0'); std::string verified_boot_key_str((const char*)verified_boot_key.data(), verified_boot_key.size()); EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0); if (!strcmp(property_value, "green")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED); EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } else if (!strcmp(property_value, "yellow")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED); EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } else if (!strcmp(property_value, "orange")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED); EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } else if (!strcmp(property_value, "red")) { EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED); } else { EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED); EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(), verified_boot_key.size())); } att_sw_enforced.Sort(); expected_sw_enforced.Sort(); EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced)); att_hw_enforced.Sort(); expected_hw_enforced.Sort(); EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced)); return true; } std::string make_string(const uint8_t* data, size_t length) { return std::string(reinterpret_cast<const char*>(data), length); Loading Loading @@ -288,6 +559,51 @@ TEST_P(NewKeyGenerationTest, Rsa) { } } /* * NewKeyGenerationTest.Rsa * * Verifies that keymint can generate all required RSA key sizes, and that the resulting keys * have correct characteristics. */ TEST_P(NewKeyGenerationTest, RsaWithAttestation) { for (auto key_size : ValidKeySizes(Algorithm::RSA)) { auto challenge = "hello"; auto app_id = "foo"; vector<uint8_t> key_blob; vector<KeyCharacteristics> key_characteristics; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() .RsaSigningKey(key_size, 65537) .Digest(Digest::NONE) .Padding(PaddingMode::NONE) .AttestationChallenge(challenge) .AttestationApplicationId(app_id) .Authorization(TAG_NO_AUTH_REQUIRED), &key_blob, &key_characteristics)); ASSERT_GT(key_blob.size(), 0U); CheckBaseParams(key_characteristics); AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics); EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA)); EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) << "Key size " << key_size << "missing"; EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U)); EXPECT_TRUE(verify_chain(cert_chain_)); ASSERT_GT(cert_chain_.size(), 0); AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics); AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics); EXPECT_TRUE(verify_attestation_record(challenge, app_id, // sw_enforced, hw_enforced, SecLevel(), cert_chain_[0].encodedCertificate)); CheckedDeleteKey(&key_blob); } } /* * NewKeyGenerationTest.NoInvalidRsaSizes * Loading Loading @@ -3895,16 +4211,6 @@ TEST_P(AddEntropyTest, AddLargeEntropy) { INSTANTIATE_KEYMINT_AIDL_TEST(AddEntropyTest); typedef KeyMintAidlTestBase AttestationTest; /* * AttestationTest.RsaAttestation * * Verifies that attesting to RSA keys works and generates the expected output. */ // TODO(seleneh) add attestation tests back after decided on the new attestation // behavior under generateKey and importKey typedef KeyMintAidlTestBase KeyDeletionTest; /** Loading
security/keymint/support/include/keymint_support/authorization_set.h +20 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,12 @@ class AuthorizationSetBuilder : public AuthorizationSet { size - 1); // drop the terminating '\0' } template <Tag tag> AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const std::string& data) { return Authorization(ttag, reinterpret_cast<const uint8_t*>(data.data()), data.size()); } AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) { for (const auto& entry : set) { push_back(entry); Loading Loading @@ -294,6 +300,20 @@ class AuthorizationSetBuilder : public AuthorizationSet { AuthorizationSetBuilder& Digest(std::vector<Digest> digests); AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings); AuthorizationSetBuilder& AttestationChallenge(const std::string& challenge) { return Authorization(TAG_ATTESTATION_CHALLENGE, challenge); } AuthorizationSetBuilder& AttestationChallenge(std::vector<uint8_t> challenge) { return Authorization(TAG_ATTESTATION_CHALLENGE, challenge); } AuthorizationSetBuilder& AttestationApplicationId(const std::string& id) { return Authorization(TAG_ATTESTATION_APPLICATION_ID, id); } AuthorizationSetBuilder& AttestationApplicationId(std::vector<uint8_t> id) { return Authorization(TAG_ATTESTATION_APPLICATION_ID, id); } template <typename... T> AuthorizationSetBuilder& BlockMode(T&&... a) { return BlockMode({std::forward<T>(a)...}); Loading