Loading identity/aidl/vts/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -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", Loading identity/aidl/vts/VtsAttestationParserSupport.cpp 0 → 100644 +187 −0 Original line number Diff line number Diff line /* * 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 identity/aidl/vts/VtsAttestationParserSupport.h 0 → 100644 +122 −0 Original line number Diff line number Diff line /* * 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 identity/aidl/vts/VtsAttestationTests.cpp 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * 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 identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp +11 −10 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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<std::string> { public: virtual void SetUp() override { Loading @@ -69,13 +71,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) Loading Loading @@ -114,17 +116,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. Loading @@ -136,7 +137,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 Loading @@ -144,7 +145,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)); } Loading Loading
identity/aidl/vts/Android.bp +6 −0 Original line number Diff line number Diff line Loading @@ -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", Loading
identity/aidl/vts/VtsAttestationParserSupport.cpp 0 → 100644 +187 −0 Original line number Diff line number Diff line /* * 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
identity/aidl/vts/VtsAttestationParserSupport.h 0 → 100644 +122 −0 Original line number Diff line number Diff line /* * 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
identity/aidl/vts/VtsAttestationTests.cpp 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * 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
identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp +11 −10 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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<std::string> { public: virtual void SetUp() override { Loading @@ -69,13 +71,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) Loading Loading @@ -114,17 +116,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. Loading @@ -136,7 +137,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 Loading @@ -144,7 +145,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)); } Loading