From f0d516d28181eb51b7654ca2a4e7170bdd406a0c Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Mon, 22 Mar 2021 07:51:43 +0000 Subject: [PATCH] Test that provisioned keys can be used with KeyMint Test: VtsRemotelyProvisionedComponentTests Change-Id: I2f5187bfb4fd1572d10c306377e07a6d167689fa --- .../keymint/aidl/vts/functional/Android.bp | 5 +- .../aidl/vts/functional/AttestKeyTest.cpp | 23 ---- .../vts/functional/KeyMintAidlTestBase.cpp | 69 +++++++----- .../aidl/vts/functional/KeyMintAidlTestBase.h | 7 +- .../VtsRemotelyProvisionedComponentTests.cpp | 100 +++++++++++++++++- .../include/keymint_support/openssl_utils.h | 1 + 6 files changed, 148 insertions(+), 57 deletions(-) diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp index 991d77a43b..c1affa6f07 100644 --- a/security/keymint/aidl/vts/functional/Android.bp +++ b/security/keymint/aidl/vts/functional/Android.bp @@ -94,11 +94,14 @@ cc_test { ], static_libs: [ "android.hardware.security.keymint-V1-ndk_platform", + "android.hardware.security.secureclock-V1-ndk_platform", "libcppcose", "libgmock_ndk", - "libremote_provisioner", "libkeymint", + "libkeymint_support", "libkeymint_remote_prov_support", + "libkeymint_vts_test_utils", + "libremote_provisioner", ], test_suites: [ "general-tests", diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp index 7e7a466566..1e907dbbee 100644 --- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp +++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp @@ -26,29 +26,6 @@ namespace aidl::android::hardware::security::keymint::test { namespace { -vector make_name_from_str(const string& name) { - X509_NAME_Ptr x509_name(X509_NAME_new()); - EXPECT_TRUE(x509_name.get() != nullptr); - if (!x509_name) return {}; - - EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), // - "CN", // - MBSTRING_ASC, - reinterpret_cast(name.c_str()), - -1, // len - -1, // loc - 0 /* set */)); - - int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */); - EXPECT_GT(len, 0); - - vector retval(len); - uint8_t* p = retval.data(); - i2d_X509_NAME(x509_name.get(), &p); - - return retval; -} - bool IsSelfSigned(const vector& chain) { if (chain.size() != 1) return false; return ChainSignaturesAreValid(chain); diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index 3e87b6b2da..ce6f67a84a 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -811,30 +811,6 @@ const vector& KeyMintAidlTestBase::SecLevelAuthorizations( return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations; } -AuthorizationSet KeyMintAidlTestBase::HwEnforcedAuthorizations( - const vector& key_characteristics) { - AuthorizationSet authList; - for (auto& entry : key_characteristics) { - if (entry.securityLevel == SecurityLevel::STRONGBOX || - entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) { - authList.push_back(AuthorizationSet(entry.authorizations)); - } - } - return authList; -} - -AuthorizationSet KeyMintAidlTestBase::SwEnforcedAuthorizations( - const vector& key_characteristics) { - AuthorizationSet authList; - for (auto& entry : key_characteristics) { - if (entry.securityLevel == SecurityLevel::SOFTWARE || - entry.securityLevel == SecurityLevel::KEYSTORE) { - authList.push_back(AuthorizationSet(entry.authorizations)); - } - } - return authList; -} - ErrorCode KeyMintAidlTestBase::UseAesKey(const vector& aesKeyBlob) { auto [result, ciphertext] = ProcessMessage( aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456", @@ -1046,6 +1022,28 @@ string bin2hex(const vector& data) { return retval; } +AuthorizationSet HwEnforcedAuthorizations(const vector& key_characteristics) { + AuthorizationSet authList; + for (auto& entry : key_characteristics) { + if (entry.securityLevel == SecurityLevel::STRONGBOX || + entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) { + authList.push_back(AuthorizationSet(entry.authorizations)); + } + } + return authList; +} + +AuthorizationSet SwEnforcedAuthorizations(const vector& key_characteristics) { + AuthorizationSet authList; + for (auto& entry : key_characteristics) { + if (entry.securityLevel == SecurityLevel::SOFTWARE || + entry.securityLevel == SecurityLevel::KEYSTORE) { + authList.push_back(AuthorizationSet(entry.authorizations)); + } + } + return authList; +} + AssertionResult ChainSignaturesAreValid(const vector& chain) { std::stringstream cert_data; @@ -1097,6 +1095,29 @@ X509_Ptr parse_cert_blob(const vector& blob) { return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size())); } +vector make_name_from_str(const string& name) { + X509_NAME_Ptr x509_name(X509_NAME_new()); + EXPECT_TRUE(x509_name.get() != nullptr); + if (!x509_name) return {}; + + EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), // + "CN", // + MBSTRING_ASC, + reinterpret_cast(name.c_str()), + -1, // len + -1, // loc + 0 /* set */)); + + int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */); + EXPECT_GT(len, 0); + + vector retval(len); + uint8_t* p = retval.data(); + i2d_X509_NAME(x509_name.get(), &p); + + return retval; +} + } // namespace test } // namespace aidl::android::hardware::security::keymint diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h index 0aef81bd6f..86bc9c4f2a 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -252,10 +252,6 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam { const vector& SecLevelAuthorizations( const vector& key_characteristics, SecurityLevel securityLevel); - AuthorizationSet HwEnforcedAuthorizations( - const vector& key_characteristics); - AuthorizationSet SwEnforcedAuthorizations( - const vector& key_characteristics); ErrorCode UseAesKey(const vector& aesKeyBlob); ErrorCode UseHmacKey(const vector& hmacKeyBlob); ErrorCode UseRsaKey(const vector& rsaKeyBlob); @@ -280,6 +276,9 @@ bool verify_attestation_record(const string& challenge, // const vector& attestation_cert); string bin2hex(const vector& data); X509_Ptr parse_cert_blob(const vector& blob); +vector make_name_from_str(const string& name); +AuthorizationSet HwEnforcedAuthorizations(const vector& key_characteristics); +AuthorizationSet SwEnforcedAuthorizations(const vector& key_characteristics); ::testing::AssertionResult ChainSignaturesAreValid(const vector& chain); #define INSTANTIATE_KEYMINT_AIDL_TEST(name) \ diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp index 14702fa9bf..e4c4a22243 100644 --- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp +++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp @@ -17,18 +17,21 @@ #define LOG_TAG "VtsRemotelyProvisionableComponentTests" #include -#include -#include #include #include #include #include #include #include -#include #include +#include +#include +#include +#include #include +#include "KeyMintAidlTestBase.h" + namespace aidl::android::hardware::security::keymint::test { using ::std::string; @@ -52,6 +55,41 @@ bytevec string_to_bytevec(const char* s) { return bytevec(p, p + strlen(s)); } +void p256_pub_key(const vector& coseKeyData, EVP_PKEY_Ptr* signingKey) { + // Extract x and y affine coordinates from the encoded Cose_Key. + auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData); + ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr; + auto coseKey = parsedPayload->asMap(); + const std::unique_ptr& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X); + ASSERT_NE(xItem->asBstr(), nullptr); + vector x = xItem->asBstr()->value(); + const std::unique_ptr& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y); + ASSERT_NE(yItem->asBstr(), nullptr); + vector y = yItem->asBstr()->value(); + + // Concatenate: 0x04 (uncompressed form marker) | x | y + vector pubKeyData{0x04}; + pubKeyData.insert(pubKeyData.end(), x.begin(), x.end()); + pubKeyData.insert(pubKeyData.end(), y.begin(), y.end()); + + EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new()); + ASSERT_NE(ecKey, nullptr); + EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + ASSERT_NE(group, nullptr); + ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1); + EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get())); + ASSERT_NE(point, nullptr); + ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(), + nullptr), + 1); + ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1); + + EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new()); + ASSERT_NE(pubKey, nullptr); + EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release()); + *signingKey = std::move(pubKey); +} + void check_cose_key(const vector& data, bool testMode) { auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data); ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr; @@ -227,7 +265,8 @@ using GenerateKeyTests = VtsRemotelyProvisionedComponentTests; INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests); /** - * Generate and validate a production-mode key. MAC tag can't be verified. + * Generate and validate a production-mode key. MAC tag can't be verified, but + * the private key blob should be usable in KeyMint operations. */ TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) { MacedPublicKey macedPubKey; @@ -235,8 +274,59 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) { bool testMode = false; auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob); ASSERT_TRUE(status.isOk()); + vector coseKeyData; + check_maced_pubkey(macedPubKey, testMode, &coseKeyData); + AttestationKey attestKey; + attestKey.keyBlob = std::move(privateKeyBlob); + attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key"); - check_maced_pubkey(macedPubKey, testMode, nullptr); + // Also talk to an IKeyMintDevice. + // TODO: if there were multiple instances of IRemotelyProvisionedComponent and IKeyMintDevice, + // what should the correlation between them be? + vector params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor); + ASSERT_GT(params.size(), 0U); + ASSERT_TRUE(AServiceManager_isDeclared(params[0].c_str())); + ::ndk::SpAIBinder binder(AServiceManager_waitForService(params[0].c_str())); + std::shared_ptr keyMint = IKeyMintDevice::fromBinder(binder); + KeyMintHardwareInfo info; + ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk()); + + // Generate an ECDSA key that is attested by the generated P256 keypair. + AuthorizationSet keyDesc = AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .AttestationChallenge("foo") + .AttestationApplicationId("bar") + .Digest(Digest::NONE) + .SetDefaultValidity(); + KeyCreationResult creationResult; + auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult); + ASSERT_TRUE(result.isOk()); + vector attested_key_blob = std::move(creationResult.keyBlob); + vector attested_key_characteristics = + std::move(creationResult.keyCharacteristics); + vector attested_key_cert_chain = std::move(creationResult.certificateChain); + EXPECT_EQ(attested_key_cert_chain.size(), 1); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics); + EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, + info.securityLevel, + attested_key_cert_chain[0].encodedCertificate)); + + // Attestation by itself is not valid (last entry is not self-signed). + EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain)); + + // The signature over the attested key should correspond to the P256 public key. + X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate)); + ASSERT_TRUE(key_cert.get()); + EVP_PKEY_Ptr signing_pubkey; + p256_pub_key(coseKeyData, &signing_pubkey); + ASSERT_TRUE(signing_pubkey.get()); + + ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get())) + << "Verification of attested certificate failed " + << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL); } /** diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h index a0212aabd4..dee28baf81 100644 --- a/security/keymint/support/include/keymint_support/openssl_utils.h +++ b/security/keymint/support/include/keymint_support/openssl_utils.h @@ -37,6 +37,7 @@ MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT) MAKE_OPENSSL_PTR_TYPE(BN_CTX) MAKE_OPENSSL_PTR_TYPE(EC_GROUP) MAKE_OPENSSL_PTR_TYPE(EC_KEY) +MAKE_OPENSSL_PTR_TYPE(EC_POINT) MAKE_OPENSSL_PTR_TYPE(EVP_PKEY) MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX) MAKE_OPENSSL_PTR_TYPE(RSA)