Files
hardware_interfaces/identity/aidl/vts/ReaderAuthTests.cpp
David Zeuthen f90b7d8363 Identity: Update for changes to ISO 18013-5.
Key derivation for session encryption and MACing now involves mixing
in SessionTranscriptBytes. Update docs, default implementation, and
VTS tests to reflect this.

Also, the standard changed such that instead of DeviceAuthentication
being MACed or signed, it's instead DeviceAuthenticationBytes which is
defined as #6.24(bstr .cbor DeviceAuthentication). The same also for
ReaderAuthentication, now ReaderAuthenticationBytes is the CBOR which
is signed by the reader.

Also update the URL for CDDL since it's now a published RFC.

Bug: 159482543
Test: atest VtsHalIdentityTargetTest
Test: atest android.security.identity.cts
Merged-In: I73fc7eb48ffb71e00a8b54849266ed814295fa39
Change-Id: I4bb5040895cf24a7089b7e36e05eeaf26496381e
2020-06-24 10:21:11 -04:00

603 lines
26 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 "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 "VtsIdentityTestUtils.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::Semantic(24, deviceEngagementBytes))
.add(cppbor::Semantic(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::Semantic(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
cppbor::Semantic(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::Semantic(24, deviceEngagementBytes))
.add(cppbor::Semantic(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::Semantic(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
cppbor::Semantic(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());
}
INSTANTIATE_TEST_SUITE_P(
Identity, ReaderAuthTests,
testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
android::PrintInstanceNameToString);
} // namespace android::hardware::identity