Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2114dca2 authored by Prashant Patil's avatar Prashant Patil
Browse files

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
parent 13de1b68
Loading
Loading
Loading
Loading
+36 −21
Original line number Diff line number Diff line
@@ -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;
        }

        // 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,25 +2074,34 @@ 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) {
        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 {
+10 −6
Original line number Diff line number Diff line
@@ -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);
+41 −30
Original line number Diff line number Diff line
@@ -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,7 +5400,7 @@ 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_);
@@ -5407,7 +5414,7 @@ TEST_P(EncryptionOperationsTest, RsaOaepWithMGFDigestSuccess) {
        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!";