mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 06:22:53 +00:00
This change removes hardware/interfaces/identity's dependency on its own libcppbor copy. The copy can not be fully removed until various vendor dependencies are cleaned up. Superficial changes are made to the VTS tests to match the slightly altered namespace on some of the functions. This migration is a prerequisite for getting the IRemotelyProvisionedComponent functionality into system/keymaster. Without migrating to the same library, the build system runs into issues since there are "two" libcppbor libraries with conflicting namespaces otherwise. Bug: 182445123 Test: atest VtsHalIdentityTargetTest Change-Id: I854ffa31c4adb5a3d1df06539fe66075ccc4625d
726 lines
34 KiB
C++
726 lines
34 KiB
C++
/*
|
|
* 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 "VtsIWritableIdentityCredentialTests"
|
|
|
|
#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 "Util.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;
|
|
|
|
class IdentityCredentialTests : public testing::TestWithParam<string> {
|
|
public:
|
|
virtual void SetUp() override {
|
|
credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
|
|
String16(GetParam().c_str()));
|
|
ASSERT_NE(credentialStore_, nullptr);
|
|
}
|
|
|
|
sp<IIdentityCredentialStore> credentialStore_;
|
|
};
|
|
|
|
TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) {
|
|
Status result;
|
|
|
|
HardwareInformation hwInfo;
|
|
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
vector<uint8_t> attestationChallenge;
|
|
vector<Certificate> attestationCertificate;
|
|
vector<uint8_t> attestationApplicationId = {};
|
|
result = writableCredential->getAttestationCertificate(
|
|
attestationApplicationId, attestationChallenge, &attestationCertificate);
|
|
|
|
EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
|
|
EXPECT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode());
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) {
|
|
Status result;
|
|
|
|
HardwareInformation hwInfo;
|
|
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
|
|
vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
|
|
vector<Certificate> attestationCertificate;
|
|
vector<uint8_t> attestationApplicationId = {1};
|
|
|
|
result = writableCredential->getAttestationCertificate(
|
|
attestationApplicationId, attestationChallenge, &attestationCertificate);
|
|
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
test_utils::validateAttestationCertificate(attestationCertificate, attestationChallenge,
|
|
attestationApplicationId, false);
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
|
|
Status result;
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
string challenge = "NotSoRandomChallenge1";
|
|
test_utils::AttestationData attData(writableCredential, challenge,
|
|
{1} /* atteestationApplicationId */);
|
|
test_utils::validateAttestationCertificate(attData.attestationCertificate,
|
|
attData.attestationChallenge,
|
|
attData.attestationApplicationId, false);
|
|
|
|
string challenge2 = "NotSoRandomChallenge2";
|
|
test_utils::AttestationData attData2(writableCredential, challenge2,
|
|
{} /* atteestationApplicationId */);
|
|
EXPECT_FALSE(attData2.result.isOk()) << attData2.result.exceptionCode() << "; "
|
|
<< attData2.result.exceptionMessage() << endl;
|
|
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, attData2.result.exceptionCode());
|
|
EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, attData2.result.serviceSpecificErrorCode());
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyStartPersonalization) {
|
|
Status result;
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
// First call should go through
|
|
const vector<int32_t> entryCounts = {2, 4};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(5, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
// Call personalization again to check if repeat call is allowed.
|
|
result = writableCredential->startPersonalization(7, entryCounts);
|
|
|
|
// Second call to startPersonalization should have failed.
|
|
EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
|
|
EXPECT_EQ(IIdentityCredentialStore::STATUS_FAILED, result.serviceSpecificErrorCode());
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) {
|
|
Status result;
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
// Verify minimal number of profile count and entry count
|
|
const vector<int32_t> entryCounts = {1, 1};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(1, entryCounts);
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) {
|
|
Status result;
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
// Verify minimal number of profile count and entry count
|
|
const vector<int32_t> entryCounts = {1};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(1, entryCounts);
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) {
|
|
Status result;
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
// Verify set a large number of profile count and entry count is ok
|
|
const vector<int32_t> entryCounts = {255};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(25, entryCounts);
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) {
|
|
Status result;
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
// Enter mismatched entry and profile numbers
|
|
const vector<int32_t> entryCounts = {5, 6};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(5, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
optional<vector<uint8_t>> readerCertificate = test_utils::generateReaderCertificate("12345");
|
|
ASSERT_TRUE(readerCertificate);
|
|
|
|
const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
|
|
{1, readerCertificate.value(), false, 0},
|
|
{2, readerCertificate.value(), true, 1},
|
|
// Profile 4 (no authentication)
|
|
{4, {}, false, 0}};
|
|
|
|
optional<vector<SecureAccessControlProfile>> secureProfiles =
|
|
test_utils::addAccessControlProfiles(writableCredential, testProfiles);
|
|
ASSERT_TRUE(secureProfiles);
|
|
|
|
vector<uint8_t> credentialData;
|
|
vector<uint8_t> proofOfProvisioningSignature;
|
|
result =
|
|
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
|
|
|
|
// finishAddingEntries should fail because the number of addAccessControlProfile mismatched with
|
|
// 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());
|
|
EXPECT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode());
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) {
|
|
Status result;
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
const vector<int32_t> entryCounts = {3, 6};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(3, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
const vector<test_utils::TestProfile> testProfiles = {// first profile should go though
|
|
{1, {}, true, 2},
|
|
// same id, different
|
|
// authentication requirement
|
|
{1, {}, true, 1},
|
|
// same id, different certificate
|
|
{1, {}, false, 0}};
|
|
|
|
bool expectOk = true;
|
|
for (const auto& testProfile : testProfiles) {
|
|
SecureAccessControlProfile profile;
|
|
Certificate cert;
|
|
cert.encodedCertificate = testProfile.readerCertificate;
|
|
int64_t secureUserId = testProfile.userAuthenticationRequired ? 66 : 0;
|
|
result = writableCredential->addAccessControlProfile(
|
|
testProfile.id, cert, testProfile.userAuthenticationRequired,
|
|
testProfile.timeoutMillis, secureUserId, &profile);
|
|
|
|
if (expectOk) {
|
|
expectOk = false;
|
|
// for profile should be allowed though as there are no duplications
|
|
// yet.
|
|
ASSERT_TRUE(result.isOk())
|
|
<< result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< "test profile id = " << testProfile.id << endl;
|
|
|
|
ASSERT_EQ(testProfile.id, profile.id);
|
|
ASSERT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate);
|
|
ASSERT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired);
|
|
ASSERT_EQ(testProfile.timeoutMillis, profile.timeoutMillis);
|
|
ASSERT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size());
|
|
} else {
|
|
// should not allow duplicate id profiles.
|
|
ASSERT_FALSE(result.isOk())
|
|
<< result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< ". Test profile id = " << testProfile.id
|
|
<< ", timeout=" << testProfile.timeoutMillis << endl;
|
|
ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
|
|
ASSERT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA,
|
|
result.serviceSpecificErrorCode());
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyOneProfileAndEntryPass) {
|
|
Status result;
|
|
|
|
HardwareInformation hwInfo;
|
|
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
string challenge = "NotSoRandomChallenge1";
|
|
test_utils::AttestationData attData(writableCredential, challenge,
|
|
{} /* atteestationApplicationId */);
|
|
EXPECT_TRUE(attData.result.isOk())
|
|
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
|
|
|
|
optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
|
|
ASSERT_TRUE(readerCertificate1);
|
|
|
|
const vector<int32_t> entryCounts = {1u};
|
|
size_t expectedPoPSize = 185 + readerCertificate1.value().size();
|
|
// OK to fail, not available in v1 HAL
|
|
writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
|
|
result = writableCredential->startPersonalization(1, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
const vector<test_utils::TestProfile> testProfiles = {{1, readerCertificate1.value(), true, 1}};
|
|
|
|
optional<vector<SecureAccessControlProfile>> secureProfiles =
|
|
test_utils::addAccessControlProfiles(writableCredential, testProfiles);
|
|
ASSERT_TRUE(secureProfiles);
|
|
|
|
const vector<test_utils::TestEntryData> testEntries1 = {
|
|
{"Name Space", "Last name", string("Turing"), vector<int32_t>{1}},
|
|
};
|
|
|
|
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
|
|
for (const auto& entry : testEntries1) {
|
|
ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
|
|
encryptedBlobs, true));
|
|
}
|
|
|
|
vector<uint8_t> credentialData;
|
|
vector<uint8_t> proofOfProvisioningSignature;
|
|
result =
|
|
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
|
|
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
optional<vector<uint8_t>> proofOfProvisioning =
|
|
support::coseSignGetPayload(proofOfProvisioningSignature);
|
|
ASSERT_TRUE(proofOfProvisioning);
|
|
string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
|
|
EXPECT_EQ(
|
|
"[\n"
|
|
" 'ProofOfProvisioning',\n"
|
|
" 'org.iso.18013-5.2019.mdl',\n"
|
|
" [\n"
|
|
" {\n"
|
|
" 'id' : 1,\n"
|
|
" 'readerCertificate' : <not printed>,\n"
|
|
" 'userAuthenticationRequired' : true,\n"
|
|
" 'timeoutMillis' : 1,\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" {\n"
|
|
" 'Name Space' : [\n"
|
|
" {\n"
|
|
" 'name' : 'Last name',\n"
|
|
" 'value' : 'Turing',\n"
|
|
" 'accessControlProfiles' : [1, ],\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" },\n"
|
|
" false,\n"
|
|
"]",
|
|
cborPretty);
|
|
|
|
optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
|
|
attData.attestationCertificate[0].encodedCertificate);
|
|
ASSERT_TRUE(credentialPubKey);
|
|
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
|
|
{}, // Additional data
|
|
credentialPubKey.value()));
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyManyProfilesAndEntriesPass) {
|
|
Status result;
|
|
|
|
HardwareInformation hwInfo;
|
|
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
string challenge = "NotSoRandomChallenge";
|
|
test_utils::AttestationData attData(writableCredential, challenge,
|
|
{} /* atteestationApplicationId */);
|
|
EXPECT_TRUE(attData.result.isOk())
|
|
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
|
|
|
|
optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
|
|
ASSERT_TRUE(readerCertificate1);
|
|
|
|
optional<vector<uint8_t>> readerCertificate2 = test_utils::generateReaderCertificate("1256");
|
|
ASSERT_TRUE(readerCertificate2);
|
|
|
|
const vector<test_utils::TestProfile> testProfiles = {
|
|
{1, readerCertificate1.value(), true, 1},
|
|
{2, readerCertificate2.value(), true, 2},
|
|
};
|
|
const vector<int32_t> entryCounts = {1u, 3u, 1u, 1u, 2u};
|
|
size_t expectedPoPSize =
|
|
525021 + readerCertificate1.value().size() + readerCertificate2.value().size();
|
|
// OK to fail, not available in v1 HAL
|
|
writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
|
|
result = writableCredential->startPersonalization(testProfiles.size(), entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
optional<vector<SecureAccessControlProfile>> secureProfiles =
|
|
test_utils::addAccessControlProfiles(writableCredential, testProfiles);
|
|
ASSERT_TRUE(secureProfiles);
|
|
|
|
vector<uint8_t> portraitImage1;
|
|
test_utils::setImageData(portraitImage1);
|
|
|
|
vector<uint8_t> portraitImage2;
|
|
test_utils::setImageData(portraitImage2);
|
|
|
|
const vector<test_utils::TestEntryData> testEntries1 = {
|
|
{"Name Space 1", "Last name", string("Turing"), vector<int32_t>{1, 2}},
|
|
{"Name Space2", "Home address", string("Maida Vale, London, England"),
|
|
vector<int32_t>{1}},
|
|
{"Name Space2", "Work address", string("Maida Vale2, London, England"),
|
|
vector<int32_t>{2}},
|
|
{"Name Space2", "Trailer address", string("Maida, London, England"),
|
|
vector<int32_t>{1}},
|
|
{"Image", "Portrait image", portraitImage1, vector<int32_t>{1}},
|
|
{"Image2", "Work image", portraitImage2, vector<int32_t>{1, 2}},
|
|
{"Name Space3", "xyzw", string("random stuff"), vector<int32_t>{1, 2}},
|
|
{"Name Space3", "Something", string("Some string"), vector<int32_t>{2}},
|
|
};
|
|
|
|
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
|
|
for (const auto& entry : testEntries1) {
|
|
EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
|
|
encryptedBlobs, true));
|
|
}
|
|
|
|
vector<uint8_t> credentialData;
|
|
vector<uint8_t> proofOfProvisioningSignature;
|
|
result =
|
|
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
|
|
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
optional<vector<uint8_t>> proofOfProvisioning =
|
|
support::coseSignGetPayload(proofOfProvisioningSignature);
|
|
ASSERT_TRUE(proofOfProvisioning);
|
|
string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(),
|
|
32, //
|
|
{"readerCertificate"});
|
|
EXPECT_EQ(
|
|
"[\n"
|
|
" 'ProofOfProvisioning',\n"
|
|
" 'org.iso.18013-5.2019.mdl',\n"
|
|
" [\n"
|
|
" {\n"
|
|
" 'id' : 1,\n"
|
|
" 'readerCertificate' : <not printed>,\n"
|
|
" 'userAuthenticationRequired' : true,\n"
|
|
" 'timeoutMillis' : 1,\n"
|
|
" },\n"
|
|
" {\n"
|
|
" 'id' : 2,\n"
|
|
" 'readerCertificate' : <not printed>,\n"
|
|
" 'userAuthenticationRequired' : true,\n"
|
|
" 'timeoutMillis' : 2,\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" {\n"
|
|
" 'Name Space 1' : [\n"
|
|
" {\n"
|
|
" 'name' : 'Last name',\n"
|
|
" 'value' : 'Turing',\n"
|
|
" 'accessControlProfiles' : [1, 2, ],\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" 'Name Space2' : [\n"
|
|
" {\n"
|
|
" 'name' : 'Home address',\n"
|
|
" 'value' : 'Maida Vale, London, England',\n"
|
|
" 'accessControlProfiles' : [1, ],\n"
|
|
" },\n"
|
|
" {\n"
|
|
" 'name' : 'Work address',\n"
|
|
" 'value' : 'Maida Vale2, London, England',\n"
|
|
" 'accessControlProfiles' : [2, ],\n"
|
|
" },\n"
|
|
" {\n"
|
|
" 'name' : 'Trailer address',\n"
|
|
" 'value' : 'Maida, London, England',\n"
|
|
" 'accessControlProfiles' : [1, ],\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" 'Image' : [\n"
|
|
" {\n"
|
|
" 'name' : 'Portrait image',\n"
|
|
" 'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
|
|
" 'accessControlProfiles' : [1, ],\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" 'Image2' : [\n"
|
|
" {\n"
|
|
" 'name' : 'Work image',\n"
|
|
" 'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
|
|
" 'accessControlProfiles' : [1, 2, ],\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" 'Name Space3' : [\n"
|
|
" {\n"
|
|
" 'name' : 'xyzw',\n"
|
|
" 'value' : 'random stuff',\n"
|
|
" 'accessControlProfiles' : [1, 2, ],\n"
|
|
" },\n"
|
|
" {\n"
|
|
" 'name' : 'Something',\n"
|
|
" 'value' : 'Some string',\n"
|
|
" 'accessControlProfiles' : [2, ],\n"
|
|
" },\n"
|
|
" ],\n"
|
|
" },\n"
|
|
" false,\n"
|
|
"]",
|
|
cborPretty);
|
|
|
|
optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
|
|
attData.attestationCertificate[0].encodedCertificate);
|
|
ASSERT_TRUE(credentialPubKey);
|
|
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
|
|
{}, // Additional data
|
|
credentialPubKey.value()));
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) {
|
|
Status result;
|
|
|
|
HardwareInformation hwInfo;
|
|
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
string challenge = "NotSoRandomChallenge";
|
|
test_utils::AttestationData attData(writableCredential, challenge,
|
|
{} /* atteestationApplicationId */);
|
|
ASSERT_TRUE(attData.result.isOk())
|
|
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
|
|
|
|
optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
|
|
ASSERT_TRUE(readerCertificate1);
|
|
|
|
optional<vector<uint8_t>> readerCertificate2 =
|
|
test_utils::generateReaderCertificate("123456987987987987987987");
|
|
ASSERT_TRUE(readerCertificate2);
|
|
|
|
const vector<int32_t> entryCounts = {2u, 2u};
|
|
size_t expectedPoPSize =
|
|
377 + readerCertificate1.value().size() + readerCertificate2.value().size();
|
|
;
|
|
// OK to fail, not available in v1 HAL
|
|
writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
|
|
result = writableCredential->startPersonalization(3, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
const vector<test_utils::TestProfile> testProfiles = {{0, readerCertificate1.value(), false, 0},
|
|
{1, readerCertificate2.value(), true, 1},
|
|
{2, {}, false, 0}};
|
|
|
|
optional<vector<SecureAccessControlProfile>> secureProfiles =
|
|
test_utils::addAccessControlProfiles(writableCredential, testProfiles);
|
|
ASSERT_TRUE(secureProfiles);
|
|
|
|
const vector<test_utils::TestEntryData> testEntries1 = {
|
|
// test empty name space
|
|
{"", "t name", string("Turing"), vector<int32_t>{2}},
|
|
{"", "Birth", string("19120623"), vector<int32_t>{2}},
|
|
{"Name Space", "Last name", string("Turing"), vector<int32_t>{0, 1}},
|
|
{"Name Space", "Birth date", string("19120623"), vector<int32_t>{0, 1}},
|
|
};
|
|
|
|
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
|
|
for (const auto& entry : testEntries1) {
|
|
EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
|
|
encryptedBlobs, true));
|
|
}
|
|
|
|
vector<uint8_t> credentialData;
|
|
vector<uint8_t> proofOfProvisioningSignature;
|
|
result =
|
|
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
|
|
|
|
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) {
|
|
Status result;
|
|
|
|
HardwareInformation hwInfo;
|
|
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
|
|
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
string challenge = "NotSoRandomChallenge";
|
|
test_utils::AttestationData attData(writableCredential, challenge,
|
|
{} /* atteestationApplicationId */);
|
|
ASSERT_TRUE(attData.result.isOk())
|
|
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
|
|
|
|
// Enter mismatched entry and profile numbers.
|
|
// Technically the 2nd name space of "Name Space" occurs intermittently, 2
|
|
// before "Image" and 2 after image, which is not correct. All of same name
|
|
// space should occur together. Let's see if this fails.
|
|
const vector<int32_t> entryCounts = {2u, 1u, 2u};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
result = writableCredential->startPersonalization(3, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
|
|
ASSERT_TRUE(readerCertificate1);
|
|
|
|
optional<vector<uint8_t>> readerCertificate2 =
|
|
test_utils::generateReaderCertificate("123456987987987987987987");
|
|
ASSERT_TRUE(readerCertificate2);
|
|
|
|
const vector<test_utils::TestProfile> testProfiles = {{0, readerCertificate1.value(), false, 0},
|
|
{1, readerCertificate2.value(), true, 1},
|
|
{2, {}, false, 0}};
|
|
|
|
optional<vector<SecureAccessControlProfile>> secureProfiles =
|
|
test_utils::addAccessControlProfiles(writableCredential, testProfiles);
|
|
ASSERT_TRUE(secureProfiles);
|
|
|
|
const vector<test_utils::TestEntryData> testEntries1 = {
|
|
// test empty name space
|
|
{"Name Space", "Last name", string("Turing"), vector<int32_t>{0, 1}},
|
|
{"Name Space", "Birth date", string("19120623"), vector<int32_t>{0, 1}},
|
|
};
|
|
|
|
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
|
|
for (const auto& entry : testEntries1) {
|
|
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,
|
|
encryptedBlobs, true));
|
|
|
|
// We expect this to fail because the namespace is out of order, all "Name Space"
|
|
// should have been called together
|
|
const vector<test_utils::TestEntryData> testEntries3 = {
|
|
{"Name Space", "First name", string("Alan"), vector<int32_t>{0, 1}},
|
|
{"Name Space", "Home address", string("Maida Vale, London, England"),
|
|
vector<int32_t>{0}},
|
|
};
|
|
|
|
for (const auto& entry : testEntries3) {
|
|
EXPECT_FALSE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
|
|
encryptedBlobs, false));
|
|
}
|
|
|
|
vector<uint8_t> credentialData;
|
|
vector<uint8_t> proofOfProvisioningSignature;
|
|
result =
|
|
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
|
|
|
|
// 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());
|
|
EXPECT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode());
|
|
}
|
|
|
|
TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) {
|
|
sp<IWritableIdentityCredential> writableCredential;
|
|
ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
|
|
false /* testCredential */));
|
|
|
|
const vector<int32_t> entryCounts = {1};
|
|
writableCredential->setExpectedProofOfProvisioningSize(123456);
|
|
Status result = writableCredential->startPersonalization(1, entryCounts);
|
|
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
|
|
<< endl;
|
|
|
|
SecureAccessControlProfile profile;
|
|
|
|
// This should fail because the id is >= 32
|
|
result = writableCredential->addAccessControlProfile(32, // id
|
|
{}, // readerCertificate
|
|
false, // userAuthenticationRequired
|
|
0, // timeoutMillis
|
|
42, // secureUserId
|
|
&profile);
|
|
ASSERT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
|
|
ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
|
|
ASSERT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode());
|
|
|
|
// This should fail because the id is < 0
|
|
result = writableCredential->addAccessControlProfile(-1, // id
|
|
{}, // readerCertificate
|
|
false, // userAuthenticationRequired
|
|
0, // timeoutMillis
|
|
42, // secureUserId
|
|
&profile);
|
|
ASSERT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
|
|
ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
|
|
ASSERT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode());
|
|
}
|
|
|
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IdentityCredentialTests);
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
Identity, IdentityCredentialTests,
|
|
testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
|
|
android::PrintInstanceNameToString);
|
|
|
|
} // namespace android::hardware::identity
|