blob: c4a58c327c1ebec49232cac8ab5d457f3c1880d4 [file] [log] [blame]
/*
* 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 "ReaderAuthTests"
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
#include <aidl/android/hardware/keymaster/VerificationToken.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 <utility>
#include "Util.h"
namespace android::hardware::identity {
using std::endl;
using std::make_pair;
using std::map;
using std::optional;
using std::pair;
using std::string;
using std::tie;
using std::vector;
using ::android::sp;
using ::android::String16;
using ::android::binder::Status;
using ::android::hardware::keymaster::HardwareAuthToken;
using ::android::hardware::keymaster::VerificationToken;
class ReaderAuthTests : public testing::TestWithParam<string> {
public:
virtual void SetUp() override {
credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
String16(GetParam().c_str()));
ASSERT_NE(credentialStore_, nullptr);
}
void provisionData();
void retrieveData(const vector<uint8_t>& readerPrivateKey,
const vector<vector<uint8_t>>& readerCertChain, bool expectSuccess,
bool leaveOutAccessibleToAllFromRequestMessage);
// Set by provisionData
vector<uint8_t> readerPublicKey_;
vector<uint8_t> readerPrivateKey_;
vector<uint8_t> intermediateAPublicKey_;
vector<uint8_t> intermediateAPrivateKey_;
vector<uint8_t> intermediateBPublicKey_;
vector<uint8_t> intermediateBPrivateKey_;
vector<uint8_t> intermediateCPublicKey_;
vector<uint8_t> intermediateCPrivateKey_;
vector<uint8_t> cert_A_SelfSigned_;
vector<uint8_t> cert_B_SelfSigned_;
vector<uint8_t> cert_B_SignedBy_C_;
vector<uint8_t> cert_C_SelfSigned_;
vector<uint8_t> cert_reader_SelfSigned_;
vector<uint8_t> cert_reader_SignedBy_A_;
vector<uint8_t> cert_reader_SignedBy_B_;
SecureAccessControlProfile sacp0_;
SecureAccessControlProfile sacp1_;
SecureAccessControlProfile sacp2_;
SecureAccessControlProfile sacp3_;
vector<uint8_t> encContentAccessibleByA_;
vector<uint8_t> encContentAccessibleByAorB_;
vector<uint8_t> encContentAccessibleByB_;
vector<uint8_t> encContentAccessibleByC_;
vector<uint8_t> encContentAccessibleByAll_;
vector<uint8_t> encContentAccessibleByNone_;
vector<uint8_t> credentialData_;
// Set by retrieveData()
bool canGetAccessibleByA_;
bool canGetAccessibleByAorB_;
bool canGetAccessibleByB_;
bool canGetAccessibleByC_;
bool canGetAccessibleByAll_;
bool canGetAccessibleByNone_;
sp<IIdentityCredentialStore> credentialStore_;
};
pair<vector<uint8_t>, vector<uint8_t>> generateReaderKey() {
optional<vector<uint8_t>> keyPKCS8 = support::createEcKeyPair();
optional<vector<uint8_t>> publicKey = support::ecKeyPairGetPublicKey(keyPKCS8.value());
optional<vector<uint8_t>> privateKey = support::ecKeyPairGetPrivateKey(keyPKCS8.value());
return make_pair(publicKey.value(), privateKey.value());
}
vector<uint8_t> generateReaderCert(const vector<uint8_t>& publicKey,
const vector<uint8_t>& signingKey) {
time_t validityNotBefore = 0;
time_t validityNotAfter = 0xffffffff;
optional<vector<uint8_t>> cert = support::ecPublicKeyGenerateCertificate(
publicKey, signingKey, "24601", "Issuer", "Subject", validityNotBefore,
validityNotAfter, {});
return cert.value();
}
void ReaderAuthTests::provisionData() {
// Keys and certificates for intermediates.
tie(intermediateAPublicKey_, intermediateAPrivateKey_) = generateReaderKey();
tie(intermediateBPublicKey_, intermediateBPrivateKey_) = generateReaderKey();
tie(intermediateCPublicKey_, intermediateCPrivateKey_) = generateReaderKey();
cert_A_SelfSigned_ = generateReaderCert(intermediateAPublicKey_, intermediateAPrivateKey_);
cert_B_SelfSigned_ = generateReaderCert(intermediateBPublicKey_, intermediateBPrivateKey_);
cert_B_SignedBy_C_ = generateReaderCert(intermediateBPublicKey_, intermediateCPrivateKey_);
cert_C_SelfSigned_ = generateReaderCert(intermediateCPublicKey_, intermediateCPrivateKey_);
// Key and self-signed certificate reader
tie(readerPublicKey_, readerPrivateKey_) = generateReaderKey();
cert_reader_SelfSigned_ = generateReaderCert(readerPublicKey_, readerPrivateKey_);
// Certificate for reader signed by intermediates
cert_reader_SignedBy_A_ = generateReaderCert(readerPublicKey_, intermediateAPrivateKey_);
cert_reader_SignedBy_B_ = generateReaderCert(readerPublicKey_, intermediateBPrivateKey_);
string docType = "org.iso.18013-5.2019.mdl";
bool testCredential = true;
sp<IWritableIdentityCredential> wc;
ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &wc).isOk());
vector<uint8_t> attestationApplicationId = {};
vector<uint8_t> attestationChallenge = {1};
vector<Certificate> certChain;
ASSERT_TRUE(wc->getAttestationCertificate(attestationApplicationId, attestationChallenge,
&certChain)
.isOk());
size_t proofOfProvisioningSize =
465 + cert_A_SelfSigned_.size() + cert_B_SelfSigned_.size() + cert_C_SelfSigned_.size();
ASSERT_TRUE(wc->setExpectedProofOfProvisioningSize(proofOfProvisioningSize).isOk());
// Not in v1 HAL, may fail
wc->startPersonalization(4 /* numAccessControlProfiles */,
{6} /* numDataElementsPerNamespace */);
// AIDL expects certificates wrapped in the Certificate type...
Certificate cert_A;
Certificate cert_B;
Certificate cert_C;
cert_A.encodedCertificate = cert_A_SelfSigned_;
cert_B.encodedCertificate = cert_B_SelfSigned_;
cert_C.encodedCertificate = cert_C_SelfSigned_;
// Access control profile 0: accessible by A
ASSERT_TRUE(wc->addAccessControlProfile(0, cert_A, false, 0, 0, &sacp0_).isOk());
// Access control profile 1: accessible by B
ASSERT_TRUE(wc->addAccessControlProfile(1, cert_B, false, 0, 0, &sacp1_).isOk());
// Access control profile 2: accessible by C
ASSERT_TRUE(wc->addAccessControlProfile(2, cert_C, false, 0, 0, &sacp2_).isOk());
// Access control profile 3: open access
ASSERT_TRUE(wc->addAccessControlProfile(3, {}, false, 0, 0, &sacp3_).isOk());
// Data Element: "Accessible by A"
ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "Accessible by A", 1).isOk());
ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByA_).isOk());
// Data Element: "Accessible by A or B"
ASSERT_TRUE(wc->beginAddEntry({0, 1}, "ns", "Accessible by A or B", 1).isOk());
ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByAorB_).isOk());
// Data Element: "Accessible by B"
ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "Accessible by B", 1).isOk());
ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByB_).isOk());
// Data Element: "Accessible by C"
ASSERT_TRUE(wc->beginAddEntry({2}, "ns", "Accessible by C", 1).isOk());
ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByC_).isOk());
// Data Element: "Accessible by All"
ASSERT_TRUE(wc->beginAddEntry({3}, "ns", "Accessible by All", 1).isOk());
ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByAll_).isOk());
// Data Element: "Accessible by None"
ASSERT_TRUE(wc->beginAddEntry({}, "ns", "Accessible by None", 1).isOk());
ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByNone_).isOk());
vector<uint8_t> proofOfProvisioningSignature;
ASSERT_TRUE(wc->finishAddingEntries(&credentialData_, &proofOfProvisioningSignature).isOk());
}
RequestDataItem buildRequestDataItem(const string& name, size_t size,
vector<int32_t> accessControlProfileIds) {
RequestDataItem item;
item.name = name;
item.size = size;
item.accessControlProfileIds = accessControlProfileIds;
return item;
}
void ReaderAuthTests::retrieveData(const vector<uint8_t>& readerPrivateKey,
const vector<vector<uint8_t>>& readerCertChain,
bool expectSuccess,
bool leaveOutAccessibleToAllFromRequestMessage) {
canGetAccessibleByA_ = false;
canGetAccessibleByAorB_ = false;
canGetAccessibleByB_ = false;
canGetAccessibleByC_ = false;
canGetAccessibleByAll_ = false;
canGetAccessibleByNone_ = false;
sp<IIdentityCredential> c;
ASSERT_TRUE(credentialStore_
->getCredential(
CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
credentialData_, &c)
.isOk());
optional<vector<uint8_t>> readerEKeyPair = support::createEcKeyPair();
optional<vector<uint8_t>> readerEPublicKey =
support::ecKeyPairGetPublicKey(readerEKeyPair.value());
ASSERT_TRUE(c->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk());
vector<uint8_t> eKeyPair;
ASSERT_TRUE(c->createEphemeralKeyPair(&eKeyPair).isOk());
optional<vector<uint8_t>> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair);
// Calculate requestData field and sign it with the reader key.
auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey.value());
ASSERT_TRUE(getXYSuccess);
cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
.add(cppbor::SemanticTag(24, deviceEngagementBytes))
.add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes;
if (leaveOutAccessibleToAllFromRequestMessage) {
itemsRequestBytes =
cppbor::Map("nameSpaces",
cppbor::Map().add("ns", cppbor::Map()
.add("Accessible by A", false)
.add("Accessible by A or B", false)
.add("Accessible by B", false)
.add("Accessible by C", false)
.add("Accessible by None", false)))
.encode();
} else {
itemsRequestBytes =
cppbor::Map("nameSpaces",
cppbor::Map().add("ns", cppbor::Map()
.add("Accessible by A", false)
.add("Accessible by A or B", false)
.add("Accessible by B", false)
.add("Accessible by C", false)
.add("Accessible by All", false)
.add("Accessible by None", false)))
.encode();
}
vector<uint8_t> encodedReaderAuthentication =
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
.add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
optional<vector<uint8_t>> readerSignature =
support::coseSignEcDsa(readerPrivateKey, // private key for reader
{}, // content
encodedReaderAuthenticationBytes, // detached content
support::certificateChainJoin(readerCertChain));
ASSERT_TRUE(readerSignature);
// Generate the key that will be used to sign AuthenticatedData.
vector<uint8_t> signingKeyBlob;
Certificate signingKeyCertificate;
ASSERT_TRUE(c->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
RequestNamespace rns;
rns.namespaceName = "ns";
rns.items.push_back(buildRequestDataItem("Accessible by A", 1, {0}));
rns.items.push_back(buildRequestDataItem("Accessible by A or B", 1, {0, 1}));
rns.items.push_back(buildRequestDataItem("Accessible by B", 1, {1}));
rns.items.push_back(buildRequestDataItem("Accessible by C", 1, {2}));
rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {3}));
rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {}));
// OK to fail, not available in v1 HAL
c->setRequestedNamespaces({rns}).isOk();
// It doesn't matter since no user auth is needed in this particular test,
// but for good measure, clear out the tokens we pass to the HAL.
HardwareAuthToken authToken;
VerificationToken verificationToken;
authToken.challenge = 0;
authToken.userId = 0;
authToken.authenticatorId = 0;
authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
authToken.timestamp.milliSeconds = 0;
authToken.mac.clear();
verificationToken.challenge = 0;
verificationToken.timestamp.milliSeconds = 0;
verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
verificationToken.mac.clear();
// OK to fail, not available in v1 HAL
c->setVerificationToken(verificationToken);
Status status = c->startRetrieval(
{sacp0_, sacp1_, sacp2_, sacp3_}, authToken, itemsRequestBytes, signingKeyBlob,
sessionTranscriptBytes, readerSignature.value(), {6 /* numDataElementsPerNamespace */});
if (expectSuccess) {
ASSERT_TRUE(status.isOk());
} else {
ASSERT_FALSE(status.isOk());
return;
}
vector<uint8_t> decrypted;
status = c->startRetrieveEntryValue("ns", "Accessible by A", 1, {0});
if (status.isOk()) {
canGetAccessibleByA_ = true;
ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByA_, &decrypted).isOk());
}
status = c->startRetrieveEntryValue("ns", "Accessible by A or B", 1, {0, 1});
if (status.isOk()) {
canGetAccessibleByAorB_ = true;
ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByAorB_, &decrypted).isOk());
}
status = c->startRetrieveEntryValue("ns", "Accessible by B", 1, {1});
if (status.isOk()) {
canGetAccessibleByB_ = true;
ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByB_, &decrypted).isOk());
}
status = c->startRetrieveEntryValue("ns", "Accessible by C", 1, {2});
if (status.isOk()) {
canGetAccessibleByC_ = true;
ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByC_, &decrypted).isOk());
}
status = c->startRetrieveEntryValue("ns", "Accessible by All", 1, {3});
if (status.isOk()) {
canGetAccessibleByAll_ = true;
ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByAll_, &decrypted).isOk());
}
status = c->startRetrieveEntryValue("ns", "Accessible by None", 1, {});
if (status.isOk()) {
canGetAccessibleByNone_ = true;
ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByNone_, &decrypted).isOk());
}
vector<uint8_t> mac;
vector<uint8_t> deviceNameSpaces;
ASSERT_TRUE(c->finishRetrieval(&mac, &deviceNameSpaces).isOk());
}
TEST_P(ReaderAuthTests, presentingChain_Reader) {
provisionData();
retrieveData(readerPrivateKey_, {cert_reader_SelfSigned_}, true /* expectSuccess */,
false /* leaveOutAccessibleToAllFromRequestMessage */);
EXPECT_FALSE(canGetAccessibleByA_);
EXPECT_FALSE(canGetAccessibleByAorB_);
EXPECT_FALSE(canGetAccessibleByB_);
EXPECT_FALSE(canGetAccessibleByC_);
EXPECT_TRUE(canGetAccessibleByAll_);
EXPECT_FALSE(canGetAccessibleByNone_);
}
TEST_P(ReaderAuthTests, presentingChain_Reader_A) {
provisionData();
retrieveData(readerPrivateKey_, {cert_reader_SignedBy_A_, cert_A_SelfSigned_},
true /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */);
EXPECT_TRUE(canGetAccessibleByA_);
EXPECT_TRUE(canGetAccessibleByAorB_);
EXPECT_FALSE(canGetAccessibleByB_);
EXPECT_FALSE(canGetAccessibleByC_);
EXPECT_TRUE(canGetAccessibleByAll_);
EXPECT_FALSE(canGetAccessibleByNone_);
}
TEST_P(ReaderAuthTests, presentingChain_Reader_B) {
provisionData();
retrieveData(readerPrivateKey_, {cert_reader_SignedBy_B_, cert_B_SelfSigned_},
true /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */);
EXPECT_FALSE(canGetAccessibleByA_);
EXPECT_TRUE(canGetAccessibleByAorB_);
EXPECT_TRUE(canGetAccessibleByB_);
EXPECT_FALSE(canGetAccessibleByC_);
EXPECT_TRUE(canGetAccessibleByAll_);
EXPECT_FALSE(canGetAccessibleByNone_);
}
// This test proves that for the purpose of determining inclusion of an ACP certificate
// in a presented reader chain, certificate equality is done by comparing public keys,
// not bitwise comparison of the certificates.
//
// Specifically for this test, the ACP is configured with cert_B_SelfSigned_ and the
// reader is presenting cert_B_SignedBy_C_. Both certificates have the same public
// key - intermediateBPublicKey_ - but they are signed by different keys.
//
TEST_P(ReaderAuthTests, presentingChain_Reader_B_C) {
provisionData();
retrieveData(readerPrivateKey_,
{cert_reader_SignedBy_B_, cert_B_SignedBy_C_, cert_C_SelfSigned_},
true /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */);
EXPECT_FALSE(canGetAccessibleByA_);
EXPECT_TRUE(canGetAccessibleByAorB_);
EXPECT_TRUE(canGetAccessibleByB_);
EXPECT_TRUE(canGetAccessibleByC_);
EXPECT_TRUE(canGetAccessibleByAll_);
EXPECT_FALSE(canGetAccessibleByNone_);
}
// This test presents a reader chain where the chain is invalid because
// the 2nd certificate in the chain isn't signed by the 3rd one.
//
TEST_P(ReaderAuthTests, presentingInvalidChain) {
provisionData();
retrieveData(readerPrivateKey_,
{cert_reader_SignedBy_B_, cert_B_SelfSigned_, cert_C_SelfSigned_},
false /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */);
}
// This tests presents a valid reader chain but where requestMessage isn't
// signed by the private key corresponding to the public key in the top-level
// certificate.
//
TEST_P(ReaderAuthTests, presentingMessageSignedNotByTopLevel) {
provisionData();
retrieveData(intermediateBPrivateKey_,
{cert_reader_SignedBy_B_, cert_B_SignedBy_C_, cert_C_SelfSigned_},
false /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */);
}
// This test leaves out "Accessible by All" data element from the signed request
// message (the CBOR from the reader) while still including this data element at
// the API level. The call on the API level for said element will fail with
// STATUS_NOT_IN_REQUEST_MESSAGE but this doesn't prevent the other elements
// from being returned (if authorized, of course).
//
// This test verifies that.
//
TEST_P(ReaderAuthTests, limitedMessage) {
provisionData();
retrieveData(readerPrivateKey_, {cert_reader_SelfSigned_}, true /* expectSuccess */,
true /* leaveOutAccessibleToAllFromRequestMessage */);
EXPECT_FALSE(canGetAccessibleByA_);
EXPECT_FALSE(canGetAccessibleByAorB_);
EXPECT_FALSE(canGetAccessibleByB_);
EXPECT_FALSE(canGetAccessibleByC_);
EXPECT_FALSE(canGetAccessibleByAll_);
EXPECT_FALSE(canGetAccessibleByNone_);
}
TEST_P(ReaderAuthTests, ephemeralKeyNotInSessionTranscript) {
provisionData();
sp<IIdentityCredential> c;
ASSERT_TRUE(credentialStore_
->getCredential(
CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
credentialData_, &c)
.isOk());
optional<vector<uint8_t>> readerEKeyPair = support::createEcKeyPair();
optional<vector<uint8_t>> readerEPublicKey =
support::ecKeyPairGetPublicKey(readerEKeyPair.value());
ASSERT_TRUE(c->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk());
vector<uint8_t> eKeyPair;
ASSERT_TRUE(c->createEphemeralKeyPair(&eKeyPair).isOk());
optional<vector<uint8_t>> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair);
// Calculate requestData field and sign it with the reader key.
auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey.value());
ASSERT_TRUE(getXYSuccess);
// Instead of include the X and Y coordinates (|ephX| and |ephY|), add NUL bytes instead.
vector<uint8_t> nulls(32);
cppbor::Map deviceEngagement = cppbor::Map().add("ephX", nulls).add("ephY", nulls);
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
.add(cppbor::SemanticTag(24, deviceEngagementBytes))
.add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes;
itemsRequestBytes =
cppbor::Map("nameSpaces",
cppbor::Map().add("ns", cppbor::Map()
.add("Accessible by A", false)
.add("Accessible by A or B", false)
.add("Accessible by B", false)
.add("Accessible by C", false)
.add("Accessible by None", false)))
.encode();
vector<uint8_t> encodedReaderAuthentication =
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
.add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
vector<vector<uint8_t>> readerCertChain = {cert_reader_SelfSigned_};
optional<vector<uint8_t>> readerSignature =
support::coseSignEcDsa(readerPrivateKey_, // private key for reader
{}, // content
encodedReaderAuthenticationBytes, // detached content
support::certificateChainJoin(readerCertChain));
ASSERT_TRUE(readerSignature);
// Generate the key that will be used to sign AuthenticatedData.
vector<uint8_t> signingKeyBlob;
Certificate signingKeyCertificate;
ASSERT_TRUE(c->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
RequestNamespace rns;
rns.namespaceName = "ns";
rns.items.push_back(buildRequestDataItem("Accessible by A", 1, {0}));
rns.items.push_back(buildRequestDataItem("Accessible by A or B", 1, {0, 1}));
rns.items.push_back(buildRequestDataItem("Accessible by B", 1, {1}));
rns.items.push_back(buildRequestDataItem("Accessible by C", 1, {2}));
rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {3}));
rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {}));
// OK to fail, not available in v1 HAL
c->setRequestedNamespaces({rns}).isOk();
// It doesn't matter since no user auth is needed in this particular test,
// but for good measure, clear out the tokens we pass to the HAL.
HardwareAuthToken authToken;
VerificationToken verificationToken;
authToken.challenge = 0;
authToken.userId = 0;
authToken.authenticatorId = 0;
authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
authToken.timestamp.milliSeconds = 0;
authToken.mac.clear();
verificationToken.challenge = 0;
verificationToken.timestamp.milliSeconds = 0;
verificationToken.securityLevel =
::android::hardware::keymaster::SecurityLevel::TRUSTED_ENVIRONMENT;
verificationToken.mac.clear();
// OK to fail, not available in v1 HAL
c->setVerificationToken(verificationToken);
// Finally check that STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND is returned.
// This proves that the TA checked for X and Y coordinatets and didn't find
// them.
Status status = c->startRetrieval(
{sacp0_, sacp1_, sacp2_, sacp3_}, authToken, itemsRequestBytes, signingKeyBlob,
sessionTranscriptBytes, readerSignature.value(), {6 /* numDataElementsPerNamespace */});
ASSERT_FALSE(status.isOk());
ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
ASSERT_EQ(IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
status.serviceSpecificErrorCode());
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ReaderAuthTests);
INSTANTIATE_TEST_SUITE_P(
Identity, ReaderAuthTests,
testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
android::PrintInstanceNameToString);
} // namespace android::hardware::identity