1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "UserAuthTests"
18
19 #include <aidl/Gtest.h>
20 #include <aidl/Vintf.h>
21 #include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
22 #include <aidl/android/hardware/keymaster/VerificationToken.h>
23 #include <android-base/logging.h>
24 #include <android/hardware/identity/IIdentityCredentialStore.h>
25 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
26 #include <binder/IServiceManager.h>
27 #include <binder/ProcessState.h>
28 #include <cppbor.h>
29 #include <cppbor_parse.h>
30 #include <gtest/gtest.h>
31 #include <future>
32 #include <map>
33 #include <utility>
34
35 #include "VtsIdentityTestUtils.h"
36
37 namespace android::hardware::identity {
38
39 using std::endl;
40 using std::make_pair;
41 using std::map;
42 using std::optional;
43 using std::pair;
44 using std::string;
45 using std::tie;
46 using std::vector;
47
48 using ::android::sp;
49 using ::android::String16;
50 using ::android::binder::Status;
51
52 using ::android::hardware::keymaster::HardwareAuthToken;
53 using ::android::hardware::keymaster::VerificationToken;
54
55 class UserAuthTests : public testing::TestWithParam<string> {
56 public:
SetUp()57 virtual void SetUp() override {
58 credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
59 String16(GetParam().c_str()));
60 ASSERT_NE(credentialStore_, nullptr);
61 }
62
63 void provisionData();
64 void setupRetrieveData();
65 pair<HardwareAuthToken, VerificationToken> mintTokens(uint64_t challengeForAuthToken,
66 int64_t ageOfAuthTokenMilliSeconds);
67 void retrieveData(HardwareAuthToken authToken, VerificationToken verificationToken,
68 bool expectSuccess, bool useSessionTranscript);
69
70 // Set by provisionData
71 SecureAccessControlProfile sacp0_;
72 SecureAccessControlProfile sacp1_;
73 SecureAccessControlProfile sacp2_;
74
75 vector<uint8_t> encContentUserAuthPerSession_;
76 vector<uint8_t> encContentUserAuthTimeout_;
77 vector<uint8_t> encContentAccessibleByAll_;
78 vector<uint8_t> encContentAccessibleByNone_;
79
80 vector<uint8_t> credentialData_;
81
82 // Set by setupRetrieveData().
83 int64_t authChallenge_;
84 cppbor::Map sessionTranscript_;
85 sp<IIdentityCredential> credential_;
86
87 // Set by retrieveData()
88 bool canGetUserAuthPerSession_;
89 bool canGetUserAuthTimeout_;
90 bool canGetAccessibleByAll_;
91 bool canGetAccessibleByNone_;
92
93 sp<IIdentityCredentialStore> credentialStore_;
94 };
95
provisionData()96 void UserAuthTests::provisionData() {
97 string docType = "org.iso.18013-5.2019.mdl";
98 bool testCredential = true;
99 sp<IWritableIdentityCredential> wc;
100 ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &wc).isOk());
101
102 vector<uint8_t> attestationApplicationId = {};
103 vector<uint8_t> attestationChallenge = {1};
104 vector<Certificate> certChain;
105 ASSERT_TRUE(wc->getAttestationCertificate(attestationApplicationId, attestationChallenge,
106 &certChain)
107 .isOk());
108
109 size_t proofOfProvisioningSize = 381;
110 // Not in v1 HAL, may fail
111 wc->setExpectedProofOfProvisioningSize(proofOfProvisioningSize);
112
113 ASSERT_TRUE(wc->startPersonalization(3 /* numAccessControlProfiles */,
114 {4} /* numDataElementsPerNamespace */)
115 .isOk());
116
117 // Access control profile 0: user auth every session (timeout = 0)
118 ASSERT_TRUE(wc->addAccessControlProfile(0, {}, true, 0, 65 /* secureUserId */, &sacp0_).isOk());
119
120 // Access control profile 1: user auth, 60 seconds timeout
121 ASSERT_TRUE(
122 wc->addAccessControlProfile(1, {}, true, 60000, 65 /* secureUserId */, &sacp1_).isOk());
123
124 // Access control profile 2: open access
125 ASSERT_TRUE(wc->addAccessControlProfile(2, {}, false, 0, 0, &sacp2_).isOk());
126
127 // Data Element: "UserAuth Per Session"
128 ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "UserAuth Per Session", 1).isOk());
129 ASSERT_TRUE(wc->addEntryValue({9}, &encContentUserAuthPerSession_).isOk());
130
131 // Data Element: "UserAuth Timeout"
132 ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "UserAuth Timeout", 1).isOk());
133 ASSERT_TRUE(wc->addEntryValue({9}, &encContentUserAuthTimeout_).isOk());
134
135 // Data Element: "Accessible by All"
136 ASSERT_TRUE(wc->beginAddEntry({2}, "ns", "Accessible by All", 1).isOk());
137 ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByAll_).isOk());
138
139 // Data Element: "Accessible by None"
140 ASSERT_TRUE(wc->beginAddEntry({}, "ns", "Accessible by None", 1).isOk());
141 ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByNone_).isOk());
142
143 vector<uint8_t> proofOfProvisioningSignature;
144 Status status = wc->finishAddingEntries(&credentialData_, &proofOfProvisioningSignature);
145 EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
146 }
147
148 // From ReaderAuthTest.cpp - TODO: consolidate with VtsIdentityTestUtils.h
149 pair<vector<uint8_t>, vector<uint8_t>> generateReaderKey();
150 vector<uint8_t> generateReaderCert(const vector<uint8_t>& publicKey,
151 const vector<uint8_t>& signingKey);
152 RequestDataItem buildRequestDataItem(const string& name, size_t size,
153 vector<int32_t> accessControlProfileIds);
154
calcSessionTranscript(const vector<uint8_t> & ePublicKey)155 cppbor::Map calcSessionTranscript(const vector<uint8_t>& ePublicKey) {
156 auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey);
157 cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
158 vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
159 vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
160 // Let SessionTranscript be a map here (it's an array in EndToEndTest) just
161 // to check that the implementation can deal with either.
162 cppbor::Map sessionTranscript;
163 sessionTranscript.add(42, cppbor::Semantic(24, deviceEngagementBytes));
164 sessionTranscript.add(43, cppbor::Semantic(24, eReaderPubBytes));
165 return sessionTranscript;
166 }
167
setupRetrieveData()168 void UserAuthTests::setupRetrieveData() {
169 ASSERT_TRUE(credentialStore_
170 ->getCredential(
171 CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
172 credentialData_, &credential_)
173 .isOk());
174
175 optional<vector<uint8_t>> readerEKeyPair = support::createEcKeyPair();
176 optional<vector<uint8_t>> readerEPublicKey =
177 support::ecKeyPairGetPublicKey(readerEKeyPair.value());
178 ASSERT_TRUE(credential_->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk());
179
180 vector<uint8_t> eKeyPair;
181 ASSERT_TRUE(credential_->createEphemeralKeyPair(&eKeyPair).isOk());
182 optional<vector<uint8_t>> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair);
183 sessionTranscript_ = calcSessionTranscript(ePublicKey.value());
184
185 Status status = credential_->createAuthChallenge(&authChallenge_);
186 EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
187 }
188
retrieveData(HardwareAuthToken authToken,VerificationToken verificationToken,bool expectSuccess,bool useSessionTranscript)189 void UserAuthTests::retrieveData(HardwareAuthToken authToken, VerificationToken verificationToken,
190 bool expectSuccess, bool useSessionTranscript) {
191 canGetUserAuthPerSession_ = false;
192 canGetUserAuthTimeout_ = false;
193 canGetAccessibleByAll_ = false;
194 canGetAccessibleByNone_ = false;
195
196 vector<uint8_t> itemsRequestBytes;
197 vector<uint8_t> sessionTranscriptBytes;
198 if (useSessionTranscript) {
199 sessionTranscriptBytes = sessionTranscript_.encode();
200
201 itemsRequestBytes =
202 cppbor::Map("nameSpaces",
203 cppbor::Map().add("ns", cppbor::Map()
204 .add("UserAuth Per Session", false)
205 .add("UserAuth Timeout", false)
206 .add("Accessible by All", false)
207 .add("Accessible by None", false)))
208 .encode();
209 vector<uint8_t> dataToSign = cppbor::Array()
210 .add("ReaderAuthentication")
211 .add(sessionTranscript_.clone())
212 .add(cppbor::Semantic(24, itemsRequestBytes))
213 .encode();
214 }
215
216 // Generate the key that will be used to sign AuthenticatedData.
217 vector<uint8_t> signingKeyBlob;
218 Certificate signingKeyCertificate;
219 ASSERT_TRUE(
220 credential_->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
221
222 RequestNamespace rns;
223 rns.namespaceName = "ns";
224 rns.items.push_back(buildRequestDataItem("UserAuth Per Session", 1, {0}));
225 rns.items.push_back(buildRequestDataItem("UserAuth Timeout", 1, {1}));
226 rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {2}));
227 rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {}));
228 // OK to fail, not available in v1 HAL
229 credential_->setRequestedNamespaces({rns}).isOk();
230
231 // OK to fail, not available in v1 HAL
232 credential_->setVerificationToken(verificationToken);
233
234 Status status = credential_->startRetrieval({sacp0_, sacp1_, sacp2_}, authToken,
235 itemsRequestBytes, signingKeyBlob,
236 sessionTranscriptBytes, {} /* readerSignature */,
237 {4 /* numDataElementsPerNamespace */});
238 if (expectSuccess) {
239 ASSERT_TRUE(status.isOk());
240 } else {
241 ASSERT_FALSE(status.isOk());
242 return;
243 }
244
245 vector<uint8_t> decrypted;
246
247 status = credential_->startRetrieveEntryValue("ns", "UserAuth Per Session", 1, {0});
248 if (status.isOk()) {
249 canGetUserAuthPerSession_ = true;
250 ASSERT_TRUE(
251 credential_->retrieveEntryValue(encContentUserAuthPerSession_, &decrypted).isOk());
252 }
253
254 status = credential_->startRetrieveEntryValue("ns", "UserAuth Timeout", 1, {1});
255 if (status.isOk()) {
256 canGetUserAuthTimeout_ = true;
257 ASSERT_TRUE(credential_->retrieveEntryValue(encContentUserAuthTimeout_, &decrypted).isOk());
258 }
259
260 status = credential_->startRetrieveEntryValue("ns", "Accessible by All", 1, {2});
261 if (status.isOk()) {
262 canGetAccessibleByAll_ = true;
263 ASSERT_TRUE(credential_->retrieveEntryValue(encContentAccessibleByAll_, &decrypted).isOk());
264 }
265
266 status = credential_->startRetrieveEntryValue("ns", "Accessible by None", 1, {});
267 if (status.isOk()) {
268 canGetAccessibleByNone_ = true;
269 ASSERT_TRUE(
270 credential_->retrieveEntryValue(encContentAccessibleByNone_, &decrypted).isOk());
271 }
272
273 vector<uint8_t> mac;
274 vector<uint8_t> deviceNameSpaces;
275 ASSERT_TRUE(credential_->finishRetrieval(&mac, &deviceNameSpaces).isOk());
276 }
277
mintTokens(uint64_t challengeForAuthToken,int64_t ageOfAuthTokenMilliSeconds)278 pair<HardwareAuthToken, VerificationToken> UserAuthTests::mintTokens(
279 uint64_t challengeForAuthToken, int64_t ageOfAuthTokenMilliSeconds) {
280 HardwareAuthToken authToken;
281 VerificationToken verificationToken;
282
283 uint64_t epochMilliseconds = 1000ULL * 1000ULL * 1000ULL * 1000ULL;
284
285 authToken.challenge = challengeForAuthToken;
286 authToken.userId = 65;
287 authToken.authenticatorId = 0;
288 authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
289 authToken.timestamp.milliSeconds = epochMilliseconds - ageOfAuthTokenMilliSeconds;
290 authToken.mac.clear();
291 verificationToken.challenge = authChallenge_;
292 verificationToken.timestamp.milliSeconds = epochMilliseconds;
293 verificationToken.securityLevel =
294 ::android::hardware::keymaster::SecurityLevel::TRUSTED_ENVIRONMENT;
295 verificationToken.mac.clear();
296 return make_pair(authToken, verificationToken);
297 }
298
TEST_P(UserAuthTests,GoodChallenge)299 TEST_P(UserAuthTests, GoodChallenge) {
300 provisionData();
301 setupRetrieveData();
302 auto [authToken, verificationToken] = mintTokens(authChallenge_, // challengeForAuthToken
303 0); // ageOfAuthTokenMilliSeconds
304 retrieveData(authToken, verificationToken, true /* expectSuccess */,
305 true /* useSessionTranscript */);
306 EXPECT_TRUE(canGetUserAuthPerSession_);
307 EXPECT_TRUE(canGetUserAuthTimeout_);
308 EXPECT_TRUE(canGetAccessibleByAll_);
309 EXPECT_FALSE(canGetAccessibleByNone_);
310 }
311
TEST_P(UserAuthTests,OtherChallenge)312 TEST_P(UserAuthTests, OtherChallenge) {
313 provisionData();
314 setupRetrieveData();
315 uint64_t otherChallenge = authChallenge_ ^ 0x12345678;
316 auto [authToken, verificationToken] = mintTokens(otherChallenge, // challengeForAuthToken
317 0); // ageOfAuthTokenMilliSeconds
318 retrieveData(authToken, verificationToken, true /* expectSuccess */,
319 true /* useSessionTranscript */);
320 EXPECT_FALSE(canGetUserAuthPerSession_);
321 EXPECT_TRUE(canGetUserAuthTimeout_);
322 EXPECT_TRUE(canGetAccessibleByAll_);
323 EXPECT_FALSE(canGetAccessibleByNone_);
324 }
325
TEST_P(UserAuthTests,NoChallenge)326 TEST_P(UserAuthTests, NoChallenge) {
327 provisionData();
328 setupRetrieveData();
329 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
330 0); // ageOfAuthTokenMilliSeconds
331 retrieveData(authToken, verificationToken, true /* expectSuccess */,
332 true /* useSessionTranscript */);
333 EXPECT_FALSE(canGetUserAuthPerSession_);
334 EXPECT_TRUE(canGetUserAuthTimeout_);
335 EXPECT_TRUE(canGetAccessibleByAll_);
336 EXPECT_FALSE(canGetAccessibleByNone_);
337 }
338
TEST_P(UserAuthTests,AuthTokenAgeZero)339 TEST_P(UserAuthTests, AuthTokenAgeZero) {
340 provisionData();
341 setupRetrieveData();
342 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
343 0); // ageOfAuthTokenMilliSeconds
344 retrieveData(authToken, verificationToken, true /* expectSuccess */,
345 true /* useSessionTranscript */);
346 EXPECT_FALSE(canGetUserAuthPerSession_);
347 EXPECT_TRUE(canGetUserAuthTimeout_);
348 EXPECT_TRUE(canGetAccessibleByAll_);
349 EXPECT_FALSE(canGetAccessibleByNone_);
350 }
351
TEST_P(UserAuthTests,AuthTokenFromTheFuture)352 TEST_P(UserAuthTests, AuthTokenFromTheFuture) {
353 provisionData();
354 setupRetrieveData();
355 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
356 -1 * 1000); // ageOfAuthTokenMilliSeconds
357 retrieveData(authToken, verificationToken, true /* expectSuccess */,
358 true /* useSessionTranscript */);
359 EXPECT_FALSE(canGetUserAuthPerSession_);
360 EXPECT_FALSE(canGetUserAuthTimeout_);
361 EXPECT_TRUE(canGetAccessibleByAll_);
362 EXPECT_FALSE(canGetAccessibleByNone_);
363 }
364
TEST_P(UserAuthTests,AuthTokenInsideTimeout)365 TEST_P(UserAuthTests, AuthTokenInsideTimeout) {
366 provisionData();
367 setupRetrieveData();
368 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
369 30 * 1000); // ageOfAuthTokenMilliSeconds
370 retrieveData(authToken, verificationToken, true /* expectSuccess */,
371 true /* useSessionTranscript */);
372 EXPECT_FALSE(canGetUserAuthPerSession_);
373 EXPECT_TRUE(canGetUserAuthTimeout_);
374 EXPECT_TRUE(canGetAccessibleByAll_);
375 EXPECT_FALSE(canGetAccessibleByNone_);
376 }
377
TEST_P(UserAuthTests,AuthTokenOutsideTimeout)378 TEST_P(UserAuthTests, AuthTokenOutsideTimeout) {
379 provisionData();
380 setupRetrieveData();
381 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
382 61 * 1000); // ageOfAuthTokenMilliSeconds
383 retrieveData(authToken, verificationToken, true /* expectSuccess */,
384 true /* useSessionTranscript */);
385 EXPECT_FALSE(canGetUserAuthPerSession_);
386 EXPECT_FALSE(canGetUserAuthTimeout_);
387 EXPECT_TRUE(canGetAccessibleByAll_);
388 EXPECT_FALSE(canGetAccessibleByNone_);
389 }
390
391 // The API works even when there's no SessionTranscript / itemsRequest.
392 // Verify that.
TEST_P(UserAuthTests,NoSessionTranscript)393 TEST_P(UserAuthTests, NoSessionTranscript) {
394 provisionData();
395 setupRetrieveData();
396 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
397 1 * 1000); // ageOfAuthTokenMilliSeconds
398 retrieveData(authToken, verificationToken, true /* expectSuccess */,
399 false /* useSessionTranscript */);
400 EXPECT_FALSE(canGetUserAuthPerSession_);
401 EXPECT_TRUE(canGetUserAuthTimeout_);
402 EXPECT_TRUE(canGetAccessibleByAll_);
403 EXPECT_FALSE(canGetAccessibleByNone_);
404 }
405
406 // This test verifies that it's possible to do multiple requests as long
407 // as the sessionTranscript doesn't change.
408 //
TEST_P(UserAuthTests,MultipleRequestsSameSessionTranscript)409 TEST_P(UserAuthTests, MultipleRequestsSameSessionTranscript) {
410 provisionData();
411 setupRetrieveData();
412
413 // First we try with a stale authToken
414 //
415 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
416 61 * 1000); // ageOfAuthTokenMilliSeconds
417 retrieveData(authToken, verificationToken, true /* expectSuccess */,
418 true /* useSessionTranscript */);
419 EXPECT_FALSE(canGetUserAuthPerSession_);
420 EXPECT_FALSE(canGetUserAuthTimeout_);
421 EXPECT_TRUE(canGetAccessibleByAll_);
422 EXPECT_FALSE(canGetAccessibleByNone_);
423
424 // Then we get a new authToken and try again.
425 tie(authToken, verificationToken) = mintTokens(0, // challengeForAuthToken
426 5 * 1000); // ageOfAuthTokenMilliSeconds
427 retrieveData(authToken, verificationToken, true /* expectSuccess */,
428 true /* useSessionTranscript */);
429 EXPECT_FALSE(canGetUserAuthPerSession_);
430 EXPECT_TRUE(canGetUserAuthTimeout_);
431 EXPECT_TRUE(canGetAccessibleByAll_);
432 EXPECT_FALSE(canGetAccessibleByNone_);
433 }
434
435 // Like MultipleRequestsSameSessionTranscript but we change the sessionTranscript
436 // between the two calls. This test verifies that change is detected and the
437 // second request fails.
438 //
TEST_P(UserAuthTests,MultipleRequestsSessionTranscriptChanges)439 TEST_P(UserAuthTests, MultipleRequestsSessionTranscriptChanges) {
440 provisionData();
441 setupRetrieveData();
442
443 // First we try with a stale authToken
444 //
445 auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken
446 61 * 1000); // ageOfAuthTokenMilliSeconds
447 retrieveData(authToken, verificationToken, true /* expectSuccess */,
448 true /* useSessionTranscript */);
449 EXPECT_FALSE(canGetUserAuthPerSession_);
450 EXPECT_FALSE(canGetUserAuthTimeout_);
451 EXPECT_TRUE(canGetAccessibleByAll_);
452 EXPECT_FALSE(canGetAccessibleByNone_);
453
454 // Then we get a new authToken and try again.
455 tie(authToken, verificationToken) = mintTokens(0, // challengeForAuthToken
456 5 * 1000); // ageOfAuthTokenMilliSeconds
457
458 // Change sessionTranscript...
459 optional<vector<uint8_t>> eKeyPairNew = support::createEcKeyPair();
460 optional<vector<uint8_t>> ePublicKeyNew = support::ecKeyPairGetPublicKey(eKeyPairNew.value());
461 sessionTranscript_ = calcSessionTranscript(ePublicKeyNew.value());
462
463 // ... and expect failure.
464 retrieveData(authToken, verificationToken, false /* expectSuccess */,
465 true /* useSessionTranscript */);
466 }
467
468 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UserAuthTests);
469 INSTANTIATE_TEST_SUITE_P(
470 Identity, UserAuthTests,
471 testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
472 android::PrintInstanceNameToString);
473
474 } // namespace android::hardware::identity
475