RSA OAEP MGF1 digest VTS relaxed for keymint < V3

Since there were no VTS test to strictly check RSA_OAEP_MGF_DIGEST,
there are released devices with Keymint which do not include this tag in
key characteristics, hence these test fails on such Keymint and UDC
Android framework.

Hence version check is added before asserting MGF digest checks.

Bug: 297306437
Test: atest VtsAidlKeyMintTargetTest
Change-Id: I43054f8dbbd46de53deef5e6771c736e770280e0
This commit is contained in:
Prashant Patil
2023-09-21 14:57:10 +00:00
parent 13de1b68b4
commit 2114dca2aa
3 changed files with 87 additions and 57 deletions

View File

@@ -79,7 +79,8 @@ size_t count_tag_invalid_entries(const std::vector<KeyParameter>& authorizations
typedef KeyMintAidlTestBase::KeyData KeyData;
// Predicate for testing basic characteristics validity in generation or import.
bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
const vector<KeyCharacteristics>& key_characteristics) {
const vector<KeyCharacteristics>& key_characteristics,
int32_t aidl_version) {
if (key_characteristics.empty()) return false;
std::unordered_set<SecurityLevel> levels_seen;
@@ -89,7 +90,12 @@ bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
return false;
}
EXPECT_EQ(count_tag_invalid_entries(entry.authorizations), 0);
// There was no test to assert that INVALID tag should not present in authorization list
// before Keymint V3, so there are some Keymint implementations where asserting for INVALID
// tag fails(b/297306437), hence skipping for Keymint < 3.
if (aidl_version >= 3) {
EXPECT_EQ(count_tag_invalid_entries(entry.authorizations), 0);
}
// Just ignore the SecurityLevel::KEYSTORE as the KM won't do any enforcement on this.
if (entry.securityLevel == SecurityLevel::KEYSTORE) continue;
@@ -264,7 +270,7 @@ void KeyMintAidlTestBase::InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyM
vendor_patch_level_ = getVendorPatchlevel();
}
int32_t KeyMintAidlTestBase::AidlVersion() {
int32_t KeyMintAidlTestBase::AidlVersion() const {
int32_t version = 0;
auto status = keymint_->getInterfaceVersion(&version);
if (!status.isOk()) {
@@ -294,8 +300,8 @@ ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
KeyCreationResult creationResult;
Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics);
EXPECT_PRED3(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics, AidlVersion());
EXPECT_GT(creationResult.keyBlob.size(), 0);
*key_blob = std::move(creationResult.keyBlob);
*key_characteristics = std::move(creationResult.keyCharacteristics);
@@ -367,8 +373,8 @@ ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFo
{} /* attestationSigningKeyBlob */, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics);
EXPECT_PRED3(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics, AidlVersion());
EXPECT_GT(creationResult.keyBlob.size(), 0);
*key_blob = std::move(creationResult.keyBlob);
@@ -411,8 +417,8 @@ ErrorCode KeyMintAidlTestBase::ImportWrappedKey(string wrapped_key, string wrapp
unwrapping_params.vector_data(), password_sid, biometric_sid, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics);
EXPECT_PRED3(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics, AidlVersion());
EXPECT_GT(creationResult.keyBlob.size(), 0);
key_blob_ = std::move(creationResult.keyBlob);
@@ -2068,27 +2074,36 @@ vector<uint8_t> make_name_from_str(const string& name) {
return retval;
}
void assert_mgf_digests_present_in_key_characteristics(
void KeyMintAidlTestBase::assert_mgf_digests_present_or_not_in_key_characteristics(
std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
bool is_mgf_digest_expected) const {
assert_mgf_digests_present_or_not_in_key_characteristics(
key_characteristics_, expected_mgf_digests, is_mgf_digest_expected);
}
void KeyMintAidlTestBase::assert_mgf_digests_present_or_not_in_key_characteristics(
const vector<KeyCharacteristics>& key_characteristics,
std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests) {
std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
bool is_mgf_digest_expected) const {
// There was no test to assert that MGF1 digest was present in generated/imported key
// characteristics before Keymint V3, so there are some Keymint implementations where
// asserting for MGF1 digest fails(b/297306437), hence skipping for Keymint < 3.
if (AidlVersion() < 3) {
return;
}
AuthorizationSet auths;
for (auto& entry : key_characteristics) {
auths.push_back(AuthorizationSet(entry.authorizations));
}
for (auto digest : expected_mgf_digests) {
ASSERT_TRUE(auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, digest));
if (is_mgf_digest_expected) {
ASSERT_TRUE(auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, digest));
} else {
ASSERT_FALSE(auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, digest));
}
}
}
bool is_mgf_digest_present(const vector<KeyCharacteristics>& key_characteristics,
android::hardware::security::keymint::Digest expected_mgf_digest) {
AuthorizationSet auths;
for (auto& entry : key_characteristics) {
auths.push_back(AuthorizationSet(entry.authorizations));
}
return auths.Contains(TAG_RSA_OAEP_MGF_DIGEST, expected_mgf_digest);
}
namespace {
void check_cose_key(const vector<uint8_t>& data, bool testMode) {

View File

@@ -95,7 +95,7 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
void InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyMint);
IKeyMintDevice& keyMint() { return *keymint_; }
int32_t AidlVersion();
int32_t AidlVersion() const;
uint32_t os_version() { return os_version_; }
uint32_t os_patch_level() { return os_patch_level_; }
uint32_t vendor_patch_level() { return vendor_patch_level_; }
@@ -373,6 +373,15 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
bool shouldSkipAttestKeyTest(void) const;
void skipAttestKeyTest(void) const;
void assert_mgf_digests_present_or_not_in_key_characteristics(
const vector<KeyCharacteristics>& key_characteristics,
std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
bool is_mgf_digest_expected) const;
void assert_mgf_digests_present_or_not_in_key_characteristics(
std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests,
bool is_mgf_digest_expected) const;
protected:
std::shared_ptr<IKeyMintDevice> keymint_;
uint32_t os_version_;
@@ -430,11 +439,6 @@ string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
ASN1_OCTET_STRING* get_attestation_record(X509* certificate);
vector<uint8_t> make_name_from_str(const string& name);
void assert_mgf_digests_present_in_key_characteristics(
const vector<KeyCharacteristics>& key_characteristics,
std::vector<android::hardware::security::keymint::Digest>& expected_mgf_digests);
bool is_mgf_digest_present(const vector<KeyCharacteristics>& key_characteristics,
android::hardware::security::keymint::Digest expected_mgf_digest);
void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
vector<uint8_t>* payload_value);
void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);

View File

@@ -4743,6 +4743,12 @@ TEST_P(ImportKeyTest, GetKeyCharacteristics) {
* should have the correct characteristics.
*/
TEST_P(ImportKeyTest, RsaOaepMGFDigestSuccess) {
// There was no test to assert that MGF1 digest was present in generated/imported key
// characteristics before Keymint V3, so there are some Keymint implementations where
// this test case fails(b/297306437), hence this test is skipped for Keymint < 3.
if (AidlVersion() < 3) {
GTEST_SKIP() << "Test not applicable to Keymint < V3";
}
auto mgf_digests = ValidDigests(false /* withNone */, true /* withMD5 */);
size_t key_size = 2048;
@@ -4763,7 +4769,7 @@ TEST_P(ImportKeyTest, RsaOaepMGFDigestSuccess) {
CheckOrigin();
// Make sure explicitly specified mgf-digests exist in key characteristics.
assert_mgf_digests_present_in_key_characteristics(key_characteristics_, mgf_digests);
assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digests, true);
string message = "Hello";
@@ -4827,8 +4833,9 @@ TEST_P(ImportKeyTest, RsaOaepMGFDigestDefaultSuccess) {
CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_OAEP);
CheckOrigin();
vector defaultDigest = {Digest::SHA1};
// Make sure default mgf-digest (SHA1) is not included in Key characteristics.
ASSERT_FALSE(is_mgf_digest_present(key_characteristics_, Digest::SHA1));
assert_mgf_digests_present_or_not_in_key_characteristics(defaultDigest, false);
}
INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
@@ -5256,7 +5263,7 @@ TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
*/
TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
auto mgf_digest = Digest::SHA1;
auto mgf_digest = vector{Digest::SHA1};
size_t key_size = 2048; // Need largish key for SHA-512 test.
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -5264,11 +5271,11 @@ TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
.RsaEncryptionKey(key_size, 65537)
.Padding(PaddingMode::RSA_OAEP)
.Digest(digests)
.Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
.OaepMGFDigest(mgf_digest)
.SetDefaultValidity()));
// Make sure explicitly specified mgf-digest exist in key characteristics.
ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
string message = "Hello";
@@ -5393,21 +5400,21 @@ TEST_P(EncryptionOperationsTest, RsaOaepWithMGFDigestSuccess) {
.Padding(PaddingMode::RSA_OAEP)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity()));
if (AidlVersion() >= 3) {
std::vector<Digest> mgf1DigestsInAuths;
mgf1DigestsInAuths.reserve(digests.size());
const auto& hw_auths = SecLevelAuthorizations(key_characteristics_);
std::for_each(hw_auths.begin(), hw_auths.end(), [&](auto& param) {
if (param.tag == Tag::RSA_OAEP_MGF_DIGEST) {
KeyParameterValue value = param.value;
mgf1DigestsInAuths.push_back(param.value.template get<KeyParameterValue::digest>());
}
});
std::vector<Digest> mgf1DigestsInAuths;
mgf1DigestsInAuths.reserve(digests.size());
const auto& hw_auths = SecLevelAuthorizations(key_characteristics_);
std::for_each(hw_auths.begin(), hw_auths.end(), [&](auto& param) {
if (param.tag == Tag::RSA_OAEP_MGF_DIGEST) {
KeyParameterValue value = param.value;
mgf1DigestsInAuths.push_back(param.value.template get<KeyParameterValue::digest>());
}
});
std::sort(digests.begin(), digests.end());
std::sort(mgf1DigestsInAuths.begin(), mgf1DigestsInAuths.end());
EXPECT_EQ(digests, mgf1DigestsInAuths);
std::sort(digests.begin(), digests.end());
std::sort(mgf1DigestsInAuths.begin(), mgf1DigestsInAuths.end());
EXPECT_EQ(digests, mgf1DigestsInAuths);
}
string message = "Hello";
for (auto digest : digests) {
@@ -5462,8 +5469,9 @@ TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultSuccess) {
.Digest(Digest::SHA_2_256)
.SetDefaultValidity()));
vector defaultDigest = vector{Digest::SHA1};
// Make sure default mgf-digest (SHA1) is not included in Key characteristics.
ASSERT_FALSE(is_mgf_digest_present(key_characteristics_, Digest::SHA1));
assert_mgf_digests_present_or_not_in_key_characteristics(defaultDigest, false);
// Do local RSA encryption using the default MGF digest of SHA-1.
string message = "Hello";
@@ -5499,19 +5507,20 @@ TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultSuccess) {
*/
TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultFail) {
size_t key_size = 2048;
auto mgf_digest = Digest::SHA_2_256;
auto mgf_digest = vector{Digest::SHA_2_256};
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
.OaepMGFDigest(mgf_digest)
.RsaEncryptionKey(key_size, 65537)
.Padding(PaddingMode::RSA_OAEP)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity()));
// Make sure explicitly specified mgf-digest exist in key characteristics.
ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
vector defaultDigest = vector{Digest::SHA1};
// Make sure default mgf-digest is not included in key characteristics.
ASSERT_FALSE(is_mgf_digest_present(key_characteristics_, Digest::SHA1));
assert_mgf_digests_present_or_not_in_key_characteristics(defaultDigest, false);
// Do local RSA encryption using the default MGF digest of SHA-1.
string message = "Hello";
@@ -5535,16 +5544,17 @@ TEST_P(EncryptionOperationsTest, RsaOaepMGFDigestDefaultFail) {
* with incompatible MGF digest.
*/
TEST_P(EncryptionOperationsTest, RsaOaepWithMGFIncompatibleDigest) {
auto mgf_digest = Digest::SHA_2_256;
auto mgf_digest = vector{Digest::SHA_2_256};
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
.OaepMGFDigest(mgf_digest)
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
.Padding(PaddingMode::RSA_OAEP)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity()));
// Make sure explicitly specified mgf-digest exist in key characteristics.
ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
string message = "Hello World!";
@@ -5562,16 +5572,17 @@ TEST_P(EncryptionOperationsTest, RsaOaepWithMGFIncompatibleDigest) {
* with unsupported MGF digest.
*/
TEST_P(EncryptionOperationsTest, RsaOaepWithMGFUnsupportedDigest) {
auto mgf_digest = Digest::SHA_2_256;
auto mgf_digest = vector{Digest::SHA_2_256};
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest)
.OaepMGFDigest(mgf_digest)
.Authorization(TAG_NO_AUTH_REQUIRED)
.RsaEncryptionKey(2048, 65537)
.Padding(PaddingMode::RSA_OAEP)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity()));
// Make sure explicitly specified mgf-digest exist in key characteristics.
ASSERT_TRUE(is_mgf_digest_present(key_characteristics_, mgf_digest));
assert_mgf_digests_present_or_not_in_key_characteristics(mgf_digest, true);
string message = "Hello World!";