From 57b347939482e062f452af292a08f8c784d9d252 Mon Sep 17 00:00:00 2001 From: Selene Huang Date: Fri, 29 May 2020 15:43:11 -0400 Subject: [PATCH] Add attestation certificate parsing and validate for IC vts. - Added attestation certificate parsing support. - Added various certificate conversion support. - Added certification verification support. - Added tests for the attestation certificate verification. - Updated the old tests to use the new attestation validation implementation. - Updated GenerateReaderCertificate to use pointer reader private key. Bug: 154909726 Test: VtsHalIdentityTargetTest Test: atest android.security.identity.cts Merged-In: Ibe770e6eaf0b0018d60876926d824204e4eaf732 Change-Id: I07c2eaf92ed60fa31761816c4b45684806c3305e --- identity/aidl/vts/Android.bp | 6 ++ .../aidl/vts/VtsHalIdentityEndToEndTest.cpp | 21 ++-- .../VtsIWritableIdentityCredentialTests.cpp | 98 +++++++++++-------- identity/aidl/vts/VtsIdentityTestUtils.cpp | 86 +++++++++++++--- identity/aidl/vts/VtsIdentityTestUtils.h | 19 ++-- 5 files changed, 157 insertions(+), 73 deletions(-) diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp index e4780bf89c..5b075c6e67 100644 --- a/identity/aidl/vts/Android.bp +++ b/identity/aidl/vts/Android.bp @@ -8,10 +8,16 @@ cc_test { "VtsHalIdentityEndToEndTest.cpp", "VtsIWritableIdentityCredentialTests.cpp", "VtsIdentityTestUtils.cpp", + "VtsAttestationTests.cpp", + "VtsAttestationParserSupport.cpp", ], shared_libs: [ + "android.hardware.keymaster@4.0", "libbinder", "libcrypto", + "libkeymaster_portable", + "libsoft_attestation_cert", + "libpuresoftkeymasterdevice", ], static_libs: [ "libcppbor", diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp index 17145b4154..464ab0c6d0 100644 --- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp +++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "VtsHalIdentityTargetTest" +#define LOG_TAG "VtsHalIdentityEndToEndTest" #include #include @@ -45,6 +45,8 @@ using ::android::binder::Status; using ::android::hardware::keymaster::HardwareAuthToken; using ::android::hardware::keymaster::VerificationToken; +using test_utils::validateAttestationCertificate; + class IdentityAidl : public testing::TestWithParam { public: virtual void SetUp() override { @@ -69,13 +71,13 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { // part of the request data. vector readerKey; optional> readerCertificate = - test_utils::GenerateReaderCertificate("1234", readerKey); + test_utils::generateReaderCertificate("1234", &readerKey); ASSERT_TRUE(readerCertificate); // Make the portrait image really big (just shy of 256 KiB) to ensure that // the chunking code gets exercised. vector portraitImage; - test_utils::SetImageData(portraitImage); + test_utils::setImageData(portraitImage); // Access control profiles: const vector testProfiles = {// Profile 0 (reader authentication) @@ -114,17 +116,16 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { string cborPretty; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "attestationChallenge"; test_utils::AttestationData attData(writableCredential, challenge, {}); ASSERT_TRUE(attData.result.isOk()) << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; - ASSERT_EQ(binder::Status::EX_NONE, attData.result.exceptionCode()); - ASSERT_EQ(IIdentityCredentialStore::STATUS_OK, attData.result.serviceSpecificErrorCode()); - // TODO: set it to something random and check it's in the cert chain - ASSERT_GE(attData.attestationCertificate.size(), 2); + EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate, + attData.attestationChallenge, + attData.attestationApplicationId, hwInfo)); // This is kinda of a hack but we need to give the size of // ProofOfProvisioning that we'll expect to receive. @@ -136,7 +137,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { .isOk()); optional> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); // Uses TestEntryData* pointer as key and values are the encrypted blobs. This @@ -144,7 +145,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { map>> encryptedBlobs; for (const auto& entry : testEntries) { - ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize, encryptedBlobs, true)); } diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp index 724aaa1643..8b0c050226 100644 --- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp +++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp @@ -56,8 +56,12 @@ class IdentityCredentialTests : public testing::TestWithParam { TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) { Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); vector attestationChallenge; vector attestationCertificate; @@ -68,13 +72,18 @@ TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) { EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; - EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate)); + EXPECT_TRUE(test_utils::validateAttestationCertificate( + attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo)); } TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) { Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1"; vector attestationChallenge(challenge.begin(), challenge.end()); @@ -87,17 +96,24 @@ TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) { EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; - EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate)); + EXPECT_TRUE(test_utils::validateAttestationCertificate( + attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo)); } TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) { Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge1"; test_utils::AttestationData attData(writableCredential, challenge, {}); - ASSERT_TRUE(test_utils::ValidateAttestationCertificate(attData.attestationCertificate)); + ASSERT_TRUE(test_utils::validateAttestationCertificate( + attData.attestationCertificate, attData.attestationChallenge, + attData.attestationApplicationId, hwInfo)); string challenge2 = "NotSoRandomChallenge2"; test_utils::AttestationData attData2(writableCredential, challenge2, {}); @@ -110,7 +126,7 @@ TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) { TEST_P(IdentityCredentialTests, verifyStartPersonalization) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // First call should go through const vector entryCounts = {2, 4}; @@ -131,7 +147,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalization) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // Verify minimal number of profile count and entry count const vector entryCounts = {1, 1}; @@ -143,7 +159,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector entryCounts = {0}; writableCredential->startPersonalization(0, entryCounts); @@ -154,7 +170,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // Verify minimal number of profile count and entry count const vector entryCounts = {1}; @@ -166,7 +182,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // Verify set a large number of profile count and entry count is ok const vector entryCounts = {3000}; @@ -178,7 +194,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) { TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // Enter mismatched entry and profile numbers const vector entryCounts = {5, 6}; @@ -186,7 +202,7 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; - optional> readerCertificate = test_utils::GenerateReaderCertificate("12345"); + optional> readerCertificate = test_utils::generateReaderCertificate("12345"); ASSERT_TRUE(readerCertificate); const vector testProfiles = {// Profile 0 (reader authentication) @@ -196,7 +212,7 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { {4, {}, false, 0}}; optional> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); vector credentialData; @@ -205,7 +221,7 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); // finishAddingEntries should fail because the number of addAccessControlProfile mismatched with - // startPersonalization, and begintest_utils::AddEntry was not called. + // startPersonalization, and begintest_utils::addEntry was not called. EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); @@ -215,7 +231,7 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) { Status result; sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector entryCounts = {3, 6}; writableCredential->startPersonalization(3, entryCounts); @@ -272,14 +288,14 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge1"; test_utils::AttestationData attData(writableCredential, challenge, {}); EXPECT_TRUE(attData.result.isOk()) << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; - optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); const vector entryCounts = {1u}; @@ -293,7 +309,7 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { const vector testProfiles = {{1, readerCertificate1.value(), true, 1}}; optional> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); const vector testEntries1 = { @@ -302,7 +318,7 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { map>> encryptedBlobs; for (const auto& entry : testEntries1) { - ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize, encryptedBlobs, true)); } @@ -359,17 +375,17 @@ TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge"; test_utils::AttestationData attData(writableCredential, challenge, {}); EXPECT_TRUE(attData.result.isOk()) << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; - optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); - optional> readerCertificate2 = test_utils::GenerateReaderCertificate("1256"); + optional> readerCertificate2 = test_utils::generateReaderCertificate("1256"); ASSERT_TRUE(readerCertificate2); const vector testProfiles = { @@ -386,14 +402,14 @@ TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { << endl; optional> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); vector portraitImage1; - test_utils::SetImageData(portraitImage1); + test_utils::setImageData(portraitImage1); vector portraitImage2; - test_utils::SetImageData(portraitImage2); + test_utils::setImageData(portraitImage2); const vector testEntries1 = { {"Name Space 1", "Last name", string("Turing"), vector{1, 2}}, @@ -411,7 +427,7 @@ TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { map>> encryptedBlobs; for (const auto& entry : testEntries1) { - EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize, encryptedBlobs, true)); } @@ -518,18 +534,18 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge"; test_utils::AttestationData attData(writableCredential, challenge, {}); ASSERT_TRUE(attData.result.isOk()) << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl; - optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); optional> readerCertificate2 = - test_utils::GenerateReaderCertificate("123456987987987987987987"); + test_utils::generateReaderCertificate("123456987987987987987987"); ASSERT_TRUE(readerCertificate2); const vector entryCounts = {2u, 2u}; @@ -547,7 +563,7 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { {2, {}, false, 0}}; optional> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); const vector testEntries1 = { @@ -560,7 +576,7 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { map>> encryptedBlobs; for (const auto& entry : testEntries1) { - EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize, encryptedBlobs, true)); } @@ -580,7 +596,7 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge"; test_utils::AttestationData attData(writableCredential, challenge, {}); @@ -596,11 +612,11 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; - optional> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); optional> readerCertificate2 = - test_utils::GenerateReaderCertificate("123456987987987987987987"); + test_utils::generateReaderCertificate("123456987987987987987987"); ASSERT_TRUE(readerCertificate2); const vector testProfiles = {{0, readerCertificate1.value(), false, 0}, @@ -608,7 +624,7 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { {2, {}, false, 0}}; optional> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); const vector testEntries1 = { @@ -619,13 +635,13 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { map>> encryptedBlobs; for (const auto& entry : testEntries1) { - EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize, encryptedBlobs, true)); } const test_utils::TestEntryData testEntry2 = {"Image", "Portrait image", string("asdfs"), vector{0, 1}}; - EXPECT_TRUE(test_utils::AddEntry(writableCredential, testEntry2, hwInfo.dataChunkSize, + EXPECT_TRUE(test_utils::addEntry(writableCredential, testEntry2, hwInfo.dataChunkSize, encryptedBlobs, true)); // We expect this to fail because the namespace is out of order, all "Name Space" @@ -637,7 +653,7 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { }; for (const auto& entry : testEntries3) { - EXPECT_FALSE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize, + EXPECT_FALSE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize, encryptedBlobs, false)); } @@ -646,7 +662,7 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { result = writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature); - // should fail because test_utils::AddEntry should have failed earlier. + // should fail because test_utils::addEntry should have failed earlier. EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); @@ -655,7 +671,7 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) { sp writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector entryCounts = {1}; Status result = writableCredential->startPersonalization(1, entryCounts); diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp index 48e47dc735..aaebcbe3c9 100644 --- a/identity/aidl/vts/VtsIdentityTestUtils.cpp +++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp @@ -19,6 +19,8 @@ #include #include +#include "VtsAttestationParserSupport.h" + namespace android::hardware::identity::test_utils { using std::endl; @@ -31,7 +33,7 @@ using ::android::sp; using ::android::String16; using ::android::binder::Status; -bool SetupWritableCredential(sp& writableCredential, +bool setupWritableCredential(sp& writableCredential, sp& credentialStore) { if (credentialStore == nullptr) { return false; @@ -48,13 +50,13 @@ bool SetupWritableCredential(sp& writableCredential } } -optional> GenerateReaderCertificate(string serialDecimal) { +optional> generateReaderCertificate(string serialDecimal) { vector privKey; - return GenerateReaderCertificate(serialDecimal, privKey); + return generateReaderCertificate(serialDecimal, &privKey); } -optional> GenerateReaderCertificate(string serialDecimal, - vector& readerPrivateKey) { +optional> generateReaderCertificate(string serialDecimal, + vector* outReaderPrivateKey) { optional> readerKeyPKCS8 = support::createEcKeyPair(); if (!readerKeyPKCS8) { return {}; @@ -67,7 +69,11 @@ optional> GenerateReaderCertificate(string serialDecimal, return {}; } - readerPrivateKey = readerKey.value(); + if (outReaderPrivateKey == nullptr) { + return {}; + } + + *outReaderPrivateKey = readerKey.value(); string issuer = "Android Open Source Project"; string subject = "Android IdentityCredential VTS Test"; @@ -79,7 +85,7 @@ optional> GenerateReaderCertificate(string serialDecimal, validityNotBefore, validityNotAfter); } -optional> AddAccessControlProfiles( +optional> addAccessControlProfiles( sp& writableCredential, const vector& testProfiles) { Status result; @@ -120,7 +126,7 @@ optional> AddAccessControlProfiles( // Most test expects this function to pass. So we will print out additional // value if failed so more debug data can be provided. -bool AddEntry(sp& writableCredential, const TestEntryData& entry, +bool addEntry(sp& writableCredential, const TestEntryData& entry, int dataChunkSize, map>>& encryptedBlobs, bool expectSuccess) { Status result; @@ -164,18 +170,70 @@ bool AddEntry(sp& writableCredential, const TestEnt return true; } -bool ValidateAttestationCertificate(vector& inputCertificates) { - return (inputCertificates.size() >= 2); - // TODO: add parsing of the certificate and make sure it is genuine. -} - -void SetImageData(vector& image) { +void setImageData(vector& image) { image.resize(256 * 1024 - 10); for (size_t n = 0; n < image.size(); n++) { image[n] = (uint8_t)n; } } +bool validateAttestationCertificate(const vector& inputCertificates, + const vector& expectedChallenge, + const vector& expectedAppId, + const HardwareInformation& hwInfo) { + AttestationCertificateParser certParser_(inputCertificates); + bool ret = certParser_.parse(); + EXPECT_TRUE(ret); + if (!ret) { + return false; + } + + // As per the IC HAL, the version of the Identity + // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by + // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0) + // and integers greater or equal than 41 (for KM starting with 4.1). + // + // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM + // version isn't errornously returned. + EXPECT_LE(10, certParser_.getKeymasterVersion()); + EXPECT_GT(40, certParser_.getKeymasterVersion()); + EXPECT_LE(3, certParser_.getAttestationVersion()); + + // Verify the app id matches to whatever we set it to be. + optional> appId = + certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID); + if (appId) { + EXPECT_EQ(expectedAppId.size(), appId.value().size()); + EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size())); + } else { + // app id not found + EXPECT_EQ(0, expectedAppId.size()); + } + + EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY)); + EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID)); + + // Verify the challenge always matches in size and data of what is passed + // in. + vector attChallenge = certParser_.getAttestationChallenge(); + EXPECT_EQ(expectedChallenge.size(), attChallenge.size()); + EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size())); + + // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out + // for the reference implementation which cannot be implemented in secure hardware). + if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" && + hwInfo.credentialStoreAuthorName == "Google") { + EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel()); + EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel()); + + } else { + // Actual devices should use TrustedEnvironment or StrongBox. + EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel()); + EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel()); + } + return true; +} + vector buildRequestNamespaces(const vector entries) { vector ret; RequestNamespace curNs; diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h index 9e1f35271d..673b736842 100644 --- a/identity/aidl/vts/VtsIdentityTestUtils.h +++ b/identity/aidl/vts/VtsIdentityTestUtils.h @@ -93,25 +93,28 @@ struct TestProfile { uint64_t timeoutMillis; }; -bool SetupWritableCredential(sp& writableCredential, +bool setupWritableCredential(sp& writableCredential, sp& credentialStore); -optional> GenerateReaderCertificate(string serialDecimal); +optional> generateReaderCertificate(string serialDecimal); -optional> GenerateReaderCertificate(string serialDecimal, - vector& readerPrivateKey); +optional> generateReaderCertificate(string serialDecimal, + vector* outReaderPrivateKey); -optional> AddAccessControlProfiles( +optional> addAccessControlProfiles( sp& writableCredential, const vector& testProfiles); -bool AddEntry(sp& writableCredential, const TestEntryData& entry, +bool addEntry(sp& writableCredential, const TestEntryData& entry, int dataChunkSize, map>>& encryptedBlobs, bool expectSuccess); -bool ValidateAttestationCertificate(vector& inputCertificates); +void setImageData(vector& image); -void SetImageData(vector& image); +bool validateAttestationCertificate(const vector& inputCertificates, + const vector& expectedChallenge, + const vector& expectedAppId, + const HardwareInformation& hwInfo); vector buildRequestNamespaces(const vector entries);