ba4d532fee
Bug: 162052785 Test: m -j vts Change-Id: I8c1a48e6fbd7c8161137902b5332911fa0d7b8b3
474 lines
20 KiB
C++
474 lines
20 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 "UserAuthTests"
|
|
|
|
#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 UserAuthTests : public testing::TestWithParam<string> {
|
|
public:
|
|
virtual void SetUp() override {
|
|
credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
|
|
String16(GetParam().c_str()));
|
|
ASSERT_NE(credentialStore_, nullptr);
|
|
}
|
|
|
|
void provisionData();
|
|
void setupRetrieveData();
|
|
pair<HardwareAuthToken, VerificationToken> mintTokens(uint64_t challengeForAuthToken,
|
|
int64_t ageOfAuthTokenMilliSeconds);
|
|
void retrieveData(HardwareAuthToken authToken, VerificationToken verificationToken,
|
|
bool expectSuccess, bool useSessionTranscript);
|
|
|
|
// Set by provisionData
|
|
SecureAccessControlProfile sacp0_;
|
|
SecureAccessControlProfile sacp1_;
|
|
SecureAccessControlProfile sacp2_;
|
|
|
|
vector<uint8_t> encContentUserAuthPerSession_;
|
|
vector<uint8_t> encContentUserAuthTimeout_;
|
|
vector<uint8_t> encContentAccessibleByAll_;
|
|
vector<uint8_t> encContentAccessibleByNone_;
|
|
|
|
vector<uint8_t> credentialData_;
|
|
|
|
// Set by setupRetrieveData().
|
|
int64_t authChallenge_;
|
|
cppbor::Map sessionTranscript_;
|
|
sp<IIdentityCredential> credential_;
|
|
|
|
// Set by retrieveData()
|
|
bool canGetUserAuthPerSession_;
|
|
bool canGetUserAuthTimeout_;
|
|
bool canGetAccessibleByAll_;
|
|
bool canGetAccessibleByNone_;
|
|
|
|
sp<IIdentityCredentialStore> credentialStore_;
|
|
};
|
|
|
|
void UserAuthTests::provisionData() {
|
|
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 = 381;
|
|
// Not in v1 HAL, may fail
|
|
wc->setExpectedProofOfProvisioningSize(proofOfProvisioningSize);
|
|
|
|
ASSERT_TRUE(wc->startPersonalization(3 /* numAccessControlProfiles */,
|
|
{4} /* numDataElementsPerNamespace */)
|
|
.isOk());
|
|
|
|
// Access control profile 0: user auth every session (timeout = 0)
|
|
ASSERT_TRUE(wc->addAccessControlProfile(0, {}, true, 0, 65 /* secureUserId */, &sacp0_).isOk());
|
|
|
|
// Access control profile 1: user auth, 60 seconds timeout
|
|
ASSERT_TRUE(
|
|
wc->addAccessControlProfile(1, {}, true, 60000, 65 /* secureUserId */, &sacp1_).isOk());
|
|
|
|
// Access control profile 2: open access
|
|
ASSERT_TRUE(wc->addAccessControlProfile(2, {}, false, 0, 0, &sacp2_).isOk());
|
|
|
|
// Data Element: "UserAuth Per Session"
|
|
ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "UserAuth Per Session", 1).isOk());
|
|
ASSERT_TRUE(wc->addEntryValue({9}, &encContentUserAuthPerSession_).isOk());
|
|
|
|
// Data Element: "UserAuth Timeout"
|
|
ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "UserAuth Timeout", 1).isOk());
|
|
ASSERT_TRUE(wc->addEntryValue({9}, &encContentUserAuthTimeout_).isOk());
|
|
|
|
// Data Element: "Accessible by All"
|
|
ASSERT_TRUE(wc->beginAddEntry({2}, "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;
|
|
Status status = wc->finishAddingEntries(&credentialData_, &proofOfProvisioningSignature);
|
|
EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
|
|
}
|
|
|
|
// From ReaderAuthTest.cpp - TODO: consolidate with VtsIdentityTestUtils.h
|
|
pair<vector<uint8_t>, vector<uint8_t>> generateReaderKey();
|
|
vector<uint8_t> generateReaderCert(const vector<uint8_t>& publicKey,
|
|
const vector<uint8_t>& signingKey);
|
|
RequestDataItem buildRequestDataItem(const string& name, size_t size,
|
|
vector<int32_t> accessControlProfileIds);
|
|
|
|
cppbor::Map calcSessionTranscript(const vector<uint8_t>& ePublicKey) {
|
|
auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey);
|
|
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();
|
|
// Let SessionTranscript be a map here (it's an array in EndToEndTest) just
|
|
// to check that the implementation can deal with either.
|
|
cppbor::Map sessionTranscript;
|
|
sessionTranscript.add(42, cppbor::Semantic(24, deviceEngagementBytes));
|
|
sessionTranscript.add(43, cppbor::Semantic(24, eReaderPubBytes));
|
|
return sessionTranscript;
|
|
}
|
|
|
|
void UserAuthTests::setupRetrieveData() {
|
|
ASSERT_TRUE(credentialStore_
|
|
->getCredential(
|
|
CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
|
|
credentialData_, &credential_)
|
|
.isOk());
|
|
|
|
optional<vector<uint8_t>> readerEKeyPair = support::createEcKeyPair();
|
|
optional<vector<uint8_t>> readerEPublicKey =
|
|
support::ecKeyPairGetPublicKey(readerEKeyPair.value());
|
|
ASSERT_TRUE(credential_->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk());
|
|
|
|
vector<uint8_t> eKeyPair;
|
|
ASSERT_TRUE(credential_->createEphemeralKeyPair(&eKeyPair).isOk());
|
|
optional<vector<uint8_t>> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair);
|
|
sessionTranscript_ = calcSessionTranscript(ePublicKey.value());
|
|
|
|
Status status = credential_->createAuthChallenge(&authChallenge_);
|
|
EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
|
|
}
|
|
|
|
void UserAuthTests::retrieveData(HardwareAuthToken authToken, VerificationToken verificationToken,
|
|
bool expectSuccess, bool useSessionTranscript) {
|
|
canGetUserAuthPerSession_ = false;
|
|
canGetUserAuthTimeout_ = false;
|
|
canGetAccessibleByAll_ = false;
|
|
canGetAccessibleByNone_ = false;
|
|
|
|
vector<uint8_t> itemsRequestBytes;
|
|
vector<uint8_t> sessionTranscriptBytes;
|
|
if (useSessionTranscript) {
|
|
sessionTranscriptBytes = sessionTranscript_.encode();
|
|
|
|
itemsRequestBytes =
|
|
cppbor::Map("nameSpaces",
|
|
cppbor::Map().add("ns", cppbor::Map()
|
|
.add("UserAuth Per Session", false)
|
|
.add("UserAuth Timeout", false)
|
|
.add("Accessible by All", false)
|
|
.add("Accessible by None", false)))
|
|
.encode();
|
|
vector<uint8_t> dataToSign = cppbor::Array()
|
|
.add("ReaderAuthentication")
|
|
.add(sessionTranscript_.clone())
|
|
.add(cppbor::Semantic(24, itemsRequestBytes))
|
|
.encode();
|
|
}
|
|
|
|
// Generate the key that will be used to sign AuthenticatedData.
|
|
vector<uint8_t> signingKeyBlob;
|
|
Certificate signingKeyCertificate;
|
|
ASSERT_TRUE(
|
|
credential_->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
|
|
|
|
RequestNamespace rns;
|
|
rns.namespaceName = "ns";
|
|
rns.items.push_back(buildRequestDataItem("UserAuth Per Session", 1, {0}));
|
|
rns.items.push_back(buildRequestDataItem("UserAuth Timeout", 1, {1}));
|
|
rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {2}));
|
|
rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {}));
|
|
// OK to fail, not available in v1 HAL
|
|
credential_->setRequestedNamespaces({rns}).isOk();
|
|
|
|
// OK to fail, not available in v1 HAL
|
|
credential_->setVerificationToken(verificationToken);
|
|
|
|
Status status = credential_->startRetrieval({sacp0_, sacp1_, sacp2_}, authToken,
|
|
itemsRequestBytes, signingKeyBlob,
|
|
sessionTranscriptBytes, {} /* readerSignature */,
|
|
{4 /* numDataElementsPerNamespace */});
|
|
if (expectSuccess) {
|
|
ASSERT_TRUE(status.isOk());
|
|
} else {
|
|
ASSERT_FALSE(status.isOk());
|
|
return;
|
|
}
|
|
|
|
vector<uint8_t> decrypted;
|
|
|
|
status = credential_->startRetrieveEntryValue("ns", "UserAuth Per Session", 1, {0});
|
|
if (status.isOk()) {
|
|
canGetUserAuthPerSession_ = true;
|
|
ASSERT_TRUE(
|
|
credential_->retrieveEntryValue(encContentUserAuthPerSession_, &decrypted).isOk());
|
|
}
|
|
|
|
status = credential_->startRetrieveEntryValue("ns", "UserAuth Timeout", 1, {1});
|
|
if (status.isOk()) {
|
|
canGetUserAuthTimeout_ = true;
|
|
ASSERT_TRUE(credential_->retrieveEntryValue(encContentUserAuthTimeout_, &decrypted).isOk());
|
|
}
|
|
|
|
status = credential_->startRetrieveEntryValue("ns", "Accessible by All", 1, {2});
|
|
if (status.isOk()) {
|
|
canGetAccessibleByAll_ = true;
|
|
ASSERT_TRUE(credential_->retrieveEntryValue(encContentAccessibleByAll_, &decrypted).isOk());
|
|
}
|
|
|
|
status = credential_->startRetrieveEntryValue("ns", "Accessible by None", 1, {});
|
|
if (status.isOk()) {
|
|
canGetAccessibleByNone_ = true;
|
|
ASSERT_TRUE(
|
|
credential_->retrieveEntryValue(encContentAccessibleByNone_, &decrypted).isOk());
|
|
}
|
|
|
|
vector<uint8_t> mac;
|
|
vector<uint8_t> deviceNameSpaces;
|
|
ASSERT_TRUE(credential_->finishRetrieval(&mac, &deviceNameSpaces).isOk());
|
|
}
|
|
|
|
pair<HardwareAuthToken, VerificationToken> UserAuthTests::mintTokens(
|
|
uint64_t challengeForAuthToken, int64_t ageOfAuthTokenMilliSeconds) {
|
|
HardwareAuthToken authToken;
|
|
VerificationToken verificationToken;
|
|
|
|
uint64_t epochMilliseconds = 1000ULL * 1000ULL * 1000ULL * 1000ULL;
|
|
|
|
authToken.challenge = challengeForAuthToken;
|
|
authToken.userId = 65;
|
|
authToken.authenticatorId = 0;
|
|
authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
|
|
authToken.timestamp.milliSeconds = epochMilliseconds - ageOfAuthTokenMilliSeconds;
|
|
authToken.mac.clear();
|
|
verificationToken.challenge = authChallenge_;
|
|
verificationToken.timestamp.milliSeconds = epochMilliseconds;
|
|
verificationToken.securityLevel =
|
|
::android::hardware::keymaster::SecurityLevel::TRUSTED_ENVIRONMENT;
|
|
verificationToken.mac.clear();
|
|
return make_pair(authToken, verificationToken);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, GoodChallenge) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(authChallenge_, // challengeForAuthToken
|
|
0); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_TRUE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, OtherChallenge) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
uint64_t otherChallenge = authChallenge_ ^ 0x12345678;
|
|
auto [authToken, verificationToken] = mintTokens(otherChallenge, // challengeForAuthToken
|
|
0); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, NoChallenge) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
0); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, AuthTokenAgeZero) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
0); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, AuthTokenFromTheFuture) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
-1 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_FALSE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, AuthTokenInsideTimeout) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
30 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
TEST_P(UserAuthTests, AuthTokenOutsideTimeout) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
61 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_FALSE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
// The API works even when there's no SessionTranscript / itemsRequest.
|
|
// Verify that.
|
|
TEST_P(UserAuthTests, NoSessionTranscript) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
1 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
false /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
// This test verifies that it's possible to do multiple requests as long
|
|
// as the sessionTranscript doesn't change.
|
|
//
|
|
TEST_P(UserAuthTests, MultipleRequestsSameSessionTranscript) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
|
|
// First we try with a stale authToken
|
|
//
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
61 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_FALSE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
|
|
// Then we get a new authToken and try again.
|
|
tie(authToken, verificationToken) = mintTokens(0, // challengeForAuthToken
|
|
5 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_TRUE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
}
|
|
|
|
// Like MultipleRequestsSameSessionTranscript but we change the sessionTranscript
|
|
// between the two calls. This test verifies that change is detected and the
|
|
// second request fails.
|
|
//
|
|
TEST_P(UserAuthTests, MultipleRequestsSessionTranscriptChanges) {
|
|
provisionData();
|
|
setupRetrieveData();
|
|
|
|
// First we try with a stale authToken
|
|
//
|
|
auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
|
|
61 * 1000); // ageOfAuthTokenMilliSeconds
|
|
retrieveData(authToken, verificationToken, true /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
EXPECT_FALSE(canGetUserAuthPerSession_);
|
|
EXPECT_FALSE(canGetUserAuthTimeout_);
|
|
EXPECT_TRUE(canGetAccessibleByAll_);
|
|
EXPECT_FALSE(canGetAccessibleByNone_);
|
|
|
|
// Then we get a new authToken and try again.
|
|
tie(authToken, verificationToken) = mintTokens(0, // challengeForAuthToken
|
|
5 * 1000); // ageOfAuthTokenMilliSeconds
|
|
|
|
// Change sessionTranscript...
|
|
optional<vector<uint8_t>> eKeyPairNew = support::createEcKeyPair();
|
|
optional<vector<uint8_t>> ePublicKeyNew = support::ecKeyPairGetPublicKey(eKeyPairNew.value());
|
|
sessionTranscript_ = calcSessionTranscript(ePublicKeyNew.value());
|
|
|
|
// ... and expect failure.
|
|
retrieveData(authToken, verificationToken, false /* expectSuccess */,
|
|
true /* useSessionTranscript */);
|
|
}
|
|
|
|
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UserAuthTests);
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
Identity, UserAuthTests,
|
|
testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
|
|
android::PrintInstanceNameToString);
|
|
|
|
} // namespace android::hardware::identity
|