diff options
author | Selene Huang <seleneh@google.com> | 2020-03-11 04:37:48 -0700 |
---|---|---|
committer | Selene Huang <seleneh@google.com> | 2020-04-30 21:33:48 -0700 |
commit | cab019aae56b7f7cd329fe0d99231d29a661c64c (patch) | |
tree | bce1750cae22b5eea9abe4354e6d365eb84c135d | |
parent | 75bea4b6dcdac7840207c33ddace1adac084950b (diff) | |
download | platform_hardware_interfaces-cab019aae56b7f7cd329fe0d99231d29a661c64c.tar.gz platform_hardware_interfaces-cab019aae56b7f7cd329fe0d99231d29a661c64c.tar.bz2 platform_hardware_interfaces-cab019aae56b7f7cd329fe0d99231d29a661c64c.zip |
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
Change-Id: Ibe770e6eaf0b0018d60876926d824204e4eaf732
-rw-r--r-- | identity/aidl/vts/Android.bp | 6 | ||||
-rw-r--r-- | identity/aidl/vts/VtsAttestationParserSupport.cpp | 187 | ||||
-rw-r--r-- | identity/aidl/vts/VtsAttestationParserSupport.h | 122 | ||||
-rw-r--r-- | identity/aidl/vts/VtsAttestationTests.cpp | 188 | ||||
-rw-r--r-- | identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp | 21 | ||||
-rw-r--r-- | identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp | 98 | ||||
-rw-r--r-- | identity/aidl/vts/VtsIdentityTestUtils.cpp | 86 | ||||
-rw-r--r-- | identity/aidl/vts/VtsIdentityTestUtils.h | 19 |
8 files changed, 654 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/VtsAttestationParserSupport.cpp b/identity/aidl/vts/VtsAttestationParserSupport.cpp new file mode 100644 index 0000000000..71fe7331ba --- /dev/null +++ b/identity/aidl/vts/VtsAttestationParserSupport.cpp @@ -0,0 +1,187 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VtsAttestationParserSupport.h" + +#include <aidl/Gtest.h> +#include <map> + +namespace android::hardware::identity::test_utils { + +using std::endl; +using std::map; +using std::optional; +using std::string; +using std::vector; + +using ::android::sp; +using ::android::String16; +using ::android::binder::Status; + +using ::keymaster::ASN1_OBJECT_Ptr; +using ::keymaster::AuthorizationSet; +using ::keymaster::EVP_PKEY_Ptr; +using ::keymaster::kAttestionRecordOid; +using ::keymaster::TAG_ATTESTATION_APPLICATION_ID; +using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY; +using ::keymaster::TAG_INCLUDE_UNIQUE_ID; +using ::keymaster::TypedTag; +using ::keymaster::X509_Ptr; + +using support::certificateChainSplit; + +optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain( + const vector<Certificate>& certificates) { + if (certificates.size() <= 0) { + return {}; + } + + keymaster_cert_chain_t kCert; + kCert.entry_count = certificates.size(); + kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count); + + int index = 0; + for (const auto& c : certificates) { + kCert.entries[index].data_length = c.encodedCertificate.size(); + uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size()); + + memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size()); + kCert.entries[index].data = (const uint8_t*)data; + index++; + } + + return kCert; +} + +bool AttestationCertificateParser::parse() { + optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_); + if (!cert_chain) { + return false; + } + + if (cert_chain.value().entry_count < 3) { + return false; + } + + if (!verifyChain(cert_chain.value())) { + return false; + } + + if (!verifyAttestationRecord(cert_chain.value().entries[0])) { + return false; + } + + keymaster_free_cert_chain(&cert_chain.value()); + return true; +} + +ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) { + ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1)); + if (!oid.get()) return nullptr; + + int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1); + if (location == -1) return nullptr; + + X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location); + if (!attest_rec_ext) return nullptr; + + ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); + return attest_rec; +} + +X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) { + const uint8_t* p = blob.data; + return d2i_X509(nullptr, &p, blob.data_length); +} + +bool AttestationCertificateParser::verifyAttestationRecord( + const keymaster_blob_t& attestation_cert) { + X509_Ptr cert(parseCertBlob(attestation_cert)); + if (!cert.get()) { + return false; + } + + ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get()); + if (!attest_rec) { + return false; + } + + keymaster_blob_t att_unique_id = {}; + keymaster_blob_t att_challenge; + keymaster_error_t ret = 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); + if (ret) { + return false; + } + + att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length); + return true; +} + +uint32_t AttestationCertificateParser::getKeymasterVersion() { + return att_keymaster_version_; +} + +uint32_t AttestationCertificateParser::getAttestationVersion() { + return att_attestation_version_; +} + +vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() { + return att_challenge_; +} + +keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() { + return att_keymaster_security_level_; +} + +keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() { + return att_attestation_security_level_; +} + +// Verify the Attestation certificates are correctly chained. +bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) { + for (size_t i = 0; i < chain.entry_count - 1; ++i) { + keymaster_blob_t& key_cert_blob = chain.entries[i]; + keymaster_blob_t& signing_cert_blob = chain.entries[i + 1]; + + X509_Ptr key_cert(parseCertBlob(key_cert_blob)); + X509_Ptr signing_cert(parseCertBlob(signing_cert_blob)); + if (!key_cert.get() || !signing_cert.get()) { + return false; + } + + EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get())); + if (!signing_pubkey.get()) return false; + + if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) { + return false; + } + + if (i + 1 == chain.entry_count - 1) { + // Last entry is self-signed. + if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) { + return false; + } + } + } + + return true; +} + +} // namespace android::hardware::identity::test_utils diff --git a/identity/aidl/vts/VtsAttestationParserSupport.h b/identity/aidl/vts/VtsAttestationParserSupport.h new file mode 100644 index 0000000000..7c7e1b6ec1 --- /dev/null +++ b/identity/aidl/vts/VtsAttestationParserSupport.h @@ -0,0 +1,122 @@ + +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VTS_ATTESTATION_PARSER_SUPPORT_H +#define VTS_ATTESTATION_PARSER_SUPPORT_H + +//#include <aidl/Gtest.h> +#include <android/hardware/identity/IIdentityCredentialStore.h> +#include <android/hardware/identity/support/IdentityCredentialSupport.h> +#include <android/hardware/keymaster/4.0/types.h> +#include <hardware/keymaster_defs.h> +#include <keymaster/android_keymaster_utils.h> +#include <keymaster/authorization_set.h> +#include <keymaster/contexts/pure_soft_keymaster_context.h> +#include <keymaster/contexts/soft_attestation_cert.h> +#include <keymaster/keymaster_tags.h> +#include <keymaster/km_openssl/attestation_utils.h> +#include <vector> + +namespace android::hardware::identity::test_utils { + +using ::std::optional; +using ::std::string; +using ::std::vector; + +using ::keymaster::AuthorizationSet; +using ::keymaster::TypedTag; + +class AttestationCertificateParser { + public: + AttestationCertificateParser(const vector<Certificate>& certChain) + : origCertChain_(certChain) {} + + bool parse(); + + uint32_t getKeymasterVersion(); + uint32_t getAttestationVersion(); + vector<uint8_t> getAttestationChallenge(); + keymaster_security_level_t getKeymasterSecurityLevel(); + keymaster_security_level_t getAttestationSecurityLevel(); + + template <keymaster_tag_t Tag> + bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) { + if (att_sw_enforced_.GetTagValue(tag)) { + return true; + } + + return false; + } + + template <keymaster_tag_t Tag> + bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) { + if (att_hw_enforced_.GetTagValue(tag)) { + return true; + } + + return false; + } + + template <keymaster_tag_t Tag> + optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) { + keymaster_blob_t blob; + if (att_hw_enforced_.GetTagValue(tag, &blob)) { + return {}; + } + + vector<uint8_t> ret(blob.data, blob.data + blob.data_length); + return ret; + } + + template <keymaster_tag_t Tag> + optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) { + keymaster_blob_t blob; + if (!att_sw_enforced_.GetTagValue(tag, &blob)) { + return {}; + } + + vector<uint8_t> ret(blob.data, blob.data + blob.data_length); + return ret; + } + + private: + // Helper functions. + bool verifyChain(const keymaster_cert_chain_t& chain); + + ASN1_OCTET_STRING* getAttestationRecord(X509* certificate); + + X509* parseCertBlob(const keymaster_blob_t& blob); + + bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert); + + optional<keymaster_cert_chain_t> certificateChainToKeymasterChain( + const vector<Certificate>& certificates); + + // Private variables. + vector<Certificate> origCertChain_; + AuthorizationSet att_sw_enforced_; + AuthorizationSet att_hw_enforced_; + uint32_t att_attestation_version_; + uint32_t att_keymaster_version_; + keymaster_security_level_t att_attestation_security_level_; + keymaster_security_level_t att_keymaster_security_level_; + vector<uint8_t> att_challenge_; +}; + +} // namespace android::hardware::identity::test_utils + +#endif // VTS_ATTESTATION_PARSER_SUPPORT_H diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp new file mode 100644 index 0000000000..00b5893d47 --- /dev/null +++ b/identity/aidl/vts/VtsAttestationTests.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VtsAttestationTests" + +#include <aidl/Gtest.h> +#include <aidl/Vintf.h> +#include <android-base/logging.h> +#include <android/hardware/identity/IIdentityCredentialStore.h> +#include <android/hardware/identity/support/IdentityCredentialSupport.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <cppbor.h> +#include <cppbor_parse.h> +#include <gtest/gtest.h> +#include <future> +#include <map> + +#include "VtsAttestationParserSupport.h" +#include "VtsIdentityTestUtils.h" + +namespace android::hardware::identity { + +using std::endl; +using std::map; +using std::optional; +using std::string; +using std::vector; + +using ::android::sp; +using ::android::String16; +using ::android::binder::Status; + +using test_utils::AttestationCertificateParser; +using test_utils::setupWritableCredential; +using test_utils::validateAttestationCertificate; + +// This file verifies the Identity Credential VTS Attestation Certificate +// generated. +class VtsAttestationTests : public testing::TestWithParam<std::string> { + public: + virtual void SetUp() override { + credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>( + String16(GetParam().c_str())); + ASSERT_NE(credentialStore_, nullptr); + } + + sp<IIdentityCredentialStore> credentialStore_; +}; + +TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeEmptyId) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp<IWritableIdentityCredential> writableCredential; + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); + + vector<uint8_t> attestationChallenge; + vector<Certificate> attestationCertificate; + vector<uint8_t> attestationApplicationId = {}; + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, + attestationApplicationId, hwInfo)); +} + +TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeNonemptyId) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp<IWritableIdentityCredential> writableCredential; + ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_)); + + vector<uint8_t> attestationChallenge; + vector<Certificate> attestationCertificate; + string applicationId = "Attestation Verification"; + vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()}; + + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, + attestationApplicationId, hwInfo)); +} + +TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp<IWritableIdentityCredential> writableCredential; + ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge"; + vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end()); + vector<Certificate> attestationCertificate; + vector<uint8_t> attestationApplicationId = {}; + + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, + attestationApplicationId, hwInfo)); +} + +TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp<IWritableIdentityCredential> writableCredential; + ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1"; + vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end()); + vector<Certificate> attestationCertificate; + string applicationId = "Attestation Verification"; + vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()}; + + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, + attestationApplicationId, hwInfo)); +} + +TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) { + Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + + sp<IWritableIdentityCredential> writableCredential; + ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_)); + + string challenge = "c"; + vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end()); + vector<Certificate> attestationCertificate; + string applicationId = "i"; + vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()}; + + result = writableCredential->getAttestationCertificate( + attestationApplicationId, attestationChallenge, &attestationCertificate); + + ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + + EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, + attestationApplicationId, hwInfo)); +} + +INSTANTIATE_TEST_SUITE_P( + Identity, VtsAttestationTests, + testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)), + android::PrintInstanceNameToString); + +} // namespace android::hardware::identity diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp index 807feabf80..6b40473fa9 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 <aidl/Gtest.h> #include <aidl/Vintf.h> @@ -44,6 +44,8 @@ using ::android::binder::Status; using ::android::hardware::keymaster::HardwareAuthToken; +using test_utils::validateAttestationCertificate; + class IdentityAidl : public testing::TestWithParam<std::string> { public: virtual void SetUp() override { @@ -68,13 +70,13 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { // part of the request data. vector<uint8_t> readerKey; optional<vector<uint8_t>> 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<uint8_t> portraitImage; - test_utils::SetImageData(portraitImage); + test_utils::setImageData(portraitImage); // Access control profiles: const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication) @@ -100,17 +102,16 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { string cborPretty; sp<IWritableIdentityCredential> 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. @@ -122,7 +123,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { .isOk()); optional<vector<SecureAccessControlProfile>> 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 @@ -130,7 +131,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> 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<string> { TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) { Status result; + + HardwareInformation hwInfo; + ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); + sp<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); vector<uint8_t> attestationChallenge; vector<Certificate> 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<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1"; vector<uint8_t> 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<IWritableIdentityCredential> 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<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // First call should go through const vector<int32_t> entryCounts = {2, 4}; @@ -131,7 +147,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalization) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) { Status result; sp<IWritableIdentityCredential> 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<int32_t> entryCounts = {1, 1}; @@ -143,7 +159,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) { Status result; sp<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector<int32_t> entryCounts = {0}; writableCredential->startPersonalization(0, entryCounts); @@ -154,7 +170,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) { Status result; sp<IWritableIdentityCredential> 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<int32_t> entryCounts = {1}; @@ -166,7 +182,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) { TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) { Status result; sp<IWritableIdentityCredential> 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<int32_t> entryCounts = {3000}; @@ -178,7 +194,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) { TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { Status result; sp<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); // Enter mismatched entry and profile numbers const vector<int32_t> entryCounts = {5, 6}; @@ -186,7 +202,7 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; - optional<vector<uint8_t>> readerCertificate = test_utils::GenerateReaderCertificate("12345"); + optional<vector<uint8_t>> readerCertificate = test_utils::generateReaderCertificate("12345"); ASSERT_TRUE(readerCertificate); const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication) @@ -196,7 +212,7 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { {4, {}, false, 0}}; optional<vector<SecureAccessControlProfile>> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); vector<uint8_t> 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<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector<int32_t> entryCounts = {3, 6}; writableCredential->startPersonalization(3, entryCounts); @@ -272,14 +288,14 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); sp<IWritableIdentityCredential> 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<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); const vector<int32_t> entryCounts = {1u}; @@ -293,7 +309,7 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { const vector<test_utils::TestProfile> testProfiles = {{1, readerCertificate1.value(), true, 1}}; optional<vector<SecureAccessControlProfile>> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); const vector<test_utils::TestEntryData> testEntries1 = { @@ -302,7 +318,7 @@ TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) { map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> 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<IWritableIdentityCredential> 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<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); - optional<vector<uint8_t>> readerCertificate2 = test_utils::GenerateReaderCertificate("1256"); + optional<vector<uint8_t>> readerCertificate2 = test_utils::generateReaderCertificate("1256"); ASSERT_TRUE(readerCertificate2); const vector<test_utils::TestProfile> testProfiles = { @@ -386,14 +402,14 @@ TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { << endl; optional<vector<SecureAccessControlProfile>> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); vector<uint8_t> portraitImage1; - test_utils::SetImageData(portraitImage1); + test_utils::setImageData(portraitImage1); vector<uint8_t> portraitImage2; - test_utils::SetImageData(portraitImage2); + test_utils::setImageData(portraitImage2); const vector<test_utils::TestEntryData> testEntries1 = { {"Name Space 1", "Last name", string("Turing"), vector<int32_t>{1, 2}}, @@ -411,7 +427,7 @@ TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) { map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> 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<IWritableIdentityCredential> 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<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); optional<vector<uint8_t>> readerCertificate2 = - test_utils::GenerateReaderCertificate("123456987987987987987987"); + test_utils::generateReaderCertificate("123456987987987987987987"); ASSERT_TRUE(readerCertificate2); const vector<int32_t> entryCounts = {2u, 2u}; @@ -547,7 +563,7 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { {2, {}, false, 0}}; optional<vector<SecureAccessControlProfile>> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); const vector<test_utils::TestEntryData> testEntries1 = { @@ -560,7 +576,7 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> 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<IWritableIdentityCredential> 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<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456"); + optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456"); ASSERT_TRUE(readerCertificate1); optional<vector<uint8_t>> readerCertificate2 = - test_utils::GenerateReaderCertificate("123456987987987987987987"); + test_utils::generateReaderCertificate("123456987987987987987987"); ASSERT_TRUE(readerCertificate2); const vector<test_utils::TestProfile> testProfiles = {{0, readerCertificate1.value(), false, 0}, @@ -608,7 +624,7 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { {2, {}, false, 0}}; optional<vector<SecureAccessControlProfile>> secureProfiles = - test_utils::AddAccessControlProfiles(writableCredential, testProfiles); + test_utils::addAccessControlProfiles(writableCredential, testProfiles); ASSERT_TRUE(secureProfiles); const vector<test_utils::TestEntryData> testEntries1 = { @@ -619,13 +635,13 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> 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<int32_t>{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<IWritableIdentityCredential> writableCredential; - ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_)); + ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector<int32_t> 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 <aidl/Gtest.h> #include <map> +#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<IWritableIdentityCredential>& writableCredential, +bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential, sp<IIdentityCredentialStore>& credentialStore) { if (credentialStore == nullptr) { return false; @@ -48,13 +50,13 @@ bool SetupWritableCredential(sp<IWritableIdentityCredential>& writableCredential } } -optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal) { +optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal) { vector<uint8_t> privKey; - return GenerateReaderCertificate(serialDecimal, privKey); + return generateReaderCertificate(serialDecimal, &privKey); } -optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal, - vector<uint8_t>& readerPrivateKey) { +optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal, + vector<uint8_t>* outReaderPrivateKey) { optional<vector<uint8_t>> readerKeyPKCS8 = support::createEcKeyPair(); if (!readerKeyPKCS8) { return {}; @@ -67,7 +69,11 @@ optional<vector<uint8_t>> 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<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal, validityNotBefore, validityNotAfter); } -optional<vector<SecureAccessControlProfile>> AddAccessControlProfiles( +optional<vector<SecureAccessControlProfile>> addAccessControlProfiles( sp<IWritableIdentityCredential>& writableCredential, const vector<TestProfile>& testProfiles) { Status result; @@ -120,7 +126,7 @@ optional<vector<SecureAccessControlProfile>> 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<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry, +bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry, int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs, bool expectSuccess) { Status result; @@ -164,18 +170,70 @@ bool AddEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEnt return true; } -bool ValidateAttestationCertificate(vector<Certificate>& inputCertificates) { - return (inputCertificates.size() >= 2); - // TODO: add parsing of the certificate and make sure it is genuine. -} - -void SetImageData(vector<uint8_t>& image) { +void setImageData(vector<uint8_t>& image) { image.resize(256 * 1024 - 10); for (size_t n = 0; n < image.size(); n++) { image[n] = (uint8_t)n; } } +bool validateAttestationCertificate(const vector<Certificate>& inputCertificates, + const vector<uint8_t>& expectedChallenge, + const vector<uint8_t>& 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<vector<uint8_t>> 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<uint8_t> 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<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) { vector<RequestNamespace> 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<IWritableIdentityCredential>& writableCredential, +bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential, sp<IIdentityCredentialStore>& credentialStore); -optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal); +optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal); -optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal, - vector<uint8_t>& readerPrivateKey); +optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal, + vector<uint8_t>* outReaderPrivateKey); -optional<vector<SecureAccessControlProfile>> AddAccessControlProfiles( +optional<vector<SecureAccessControlProfile>> addAccessControlProfiles( sp<IWritableIdentityCredential>& writableCredential, const vector<TestProfile>& testProfiles); -bool AddEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry, +bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry, int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs, bool expectSuccess); -bool ValidateAttestationCertificate(vector<Certificate>& inputCertificates); +void setImageData(vector<uint8_t>& image); -void SetImageData(vector<uint8_t>& image); +bool validateAttestationCertificate(const vector<Certificate>& inputCertificates, + const vector<uint8_t>& expectedChallenge, + const vector<uint8_t>& expectedAppId, + const HardwareInformation& hwInfo); vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries); |