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 #define LOG_TAG "VtsHalIdentityEndToEndTest"
17 
18 #include <aidl/Gtest.h>
19 #include <aidl/Vintf.h>
20 #include <android-base/logging.h>
21 #include <android/hardware/identity/IIdentityCredentialStore.h>
22 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
23 #include <binder/IServiceManager.h>
24 #include <binder/ProcessState.h>
25 #include <cppbor.h>
26 #include <cppbor_parse.h>
27 #include <gtest/gtest.h>
28 #include <future>
29 #include <map>
30 #include <tuple>
31 
32 #include "Util.h"
33 
34 namespace android::hardware::identity {
35 
36 using std::endl;
37 using std::make_tuple;
38 using std::map;
39 using std::optional;
40 using std::string;
41 using std::tuple;
42 using std::vector;
43 
44 using ::android::sp;
45 using ::android::String16;
46 using ::android::binder::Status;
47 
48 using ::android::hardware::keymaster::HardwareAuthToken;
49 using ::android::hardware::keymaster::VerificationToken;
50 
51 using test_utils::validateAttestationCertificate;
52 
53 class EndToEndTests : public testing::TestWithParam<std::string> {
54   public:
SetUp()55     virtual void SetUp() override {
56         credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
57                 String16(GetParam().c_str()));
58         ASSERT_NE(credentialStore_, nullptr);
59         halApiVersion_ = credentialStore_->getInterfaceVersion();
60     }
61 
62     sp<IIdentityCredentialStore> credentialStore_;
63     int halApiVersion_;
64 };
65 
TEST_P(EndToEndTests,hardwareInformation)66 TEST_P(EndToEndTests, hardwareInformation) {
67     HardwareInformation info;
68     ASSERT_TRUE(credentialStore_->getHardwareInformation(&info).isOk());
69     ASSERT_GT(info.credentialStoreName.size(), 0);
70     ASSERT_GT(info.credentialStoreAuthorName.size(), 0);
71     ASSERT_GE(info.dataChunkSize, 256);
72 }
73 
74 tuple<bool, string, vector<uint8_t>, vector<uint8_t>, vector<uint8_t>>
extractFromTestCredentialData(const vector<uint8_t> & credentialData)75 extractFromTestCredentialData(const vector<uint8_t>& credentialData) {
76     string docType;
77     vector<uint8_t> storageKey;
78     vector<uint8_t> credentialPrivKey;
79     vector<uint8_t> sha256Pop;
80 
81     auto [item, _, message] = cppbor::parse(credentialData);
82     if (item == nullptr) {
83         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
84     }
85 
86     const cppbor::Array* arrayItem = item->asArray();
87     if (arrayItem == nullptr || arrayItem->size() != 3) {
88         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
89     }
90 
91     const cppbor::Tstr* docTypeItem = (*arrayItem)[0]->asTstr();
92     const cppbor::Bool* testCredentialItem =
93             ((*arrayItem)[1]->asSimple() != nullptr ? ((*arrayItem)[1]->asSimple()->asBool())
94                                                     : nullptr);
95     const cppbor::Bstr* encryptedCredentialKeysItem = (*arrayItem)[2]->asBstr();
96     if (docTypeItem == nullptr || testCredentialItem == nullptr ||
97         encryptedCredentialKeysItem == nullptr) {
98         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
99     }
100 
101     docType = docTypeItem->value();
102 
103     vector<uint8_t> hardwareBoundKey = support::getTestHardwareBoundKey();
104     const vector<uint8_t>& encryptedCredentialKeys = encryptedCredentialKeysItem->value();
105     const vector<uint8_t> docTypeVec(docType.begin(), docType.end());
106     optional<vector<uint8_t>> decryptedCredentialKeys =
107             support::decryptAes128Gcm(hardwareBoundKey, encryptedCredentialKeys, docTypeVec);
108     if (!decryptedCredentialKeys) {
109         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
110     }
111 
112     auto [dckItem, dckPos, dckMessage] = cppbor::parse(decryptedCredentialKeys.value());
113     if (dckItem == nullptr) {
114         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
115     }
116     const cppbor::Array* dckArrayItem = dckItem->asArray();
117     if (dckArrayItem == nullptr) {
118         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
119     }
120     if (dckArrayItem->size() < 2) {
121         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
122     }
123     const cppbor::Bstr* storageKeyItem = (*dckArrayItem)[0]->asBstr();
124     const cppbor::Bstr* credentialPrivKeyItem = (*dckArrayItem)[1]->asBstr();
125     if (storageKeyItem == nullptr || credentialPrivKeyItem == nullptr) {
126         return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
127     }
128     storageKey = storageKeyItem->value();
129     credentialPrivKey = credentialPrivKeyItem->value();
130     if (dckArrayItem->size() == 3) {
131         const cppbor::Bstr* sha256PopItem = (*dckArrayItem)[2]->asBstr();
132         if (sha256PopItem == nullptr) {
133             return make_tuple(false, docType, storageKey, credentialPrivKey, sha256Pop);
134         }
135         sha256Pop = sha256PopItem->value();
136     }
137     return make_tuple(true, docType, storageKey, credentialPrivKey, sha256Pop);
138 }
139 
TEST_P(EndToEndTests,createAndRetrieveCredential)140 TEST_P(EndToEndTests, createAndRetrieveCredential) {
141     // First, generate a key-pair for the reader since its public key will be
142     // part of the request data.
143     vector<uint8_t> readerKey;
144     optional<vector<uint8_t>> readerCertificate =
145             test_utils::generateReaderCertificate("1234", &readerKey);
146     ASSERT_TRUE(readerCertificate);
147 
148     // Make the portrait image really big (just shy of 256 KiB) to ensure that
149     // the chunking code gets exercised.
150     vector<uint8_t> portraitImage;
151     test_utils::setImageData(portraitImage);
152 
153     // Access control profiles:
154     const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
155                                                           {0, readerCertificate.value(), false, 0},
156                                                           // Profile 1 (no authentication)
157                                                           {1, {}, false, 0}};
158 
159     // It doesn't matter since no user auth is needed in this particular test,
160     // but for good measure, clear out the tokens we pass to the HAL.
161     HardwareAuthToken authToken;
162     VerificationToken verificationToken;
163     authToken.challenge = 0;
164     authToken.userId = 0;
165     authToken.authenticatorId = 0;
166     authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
167     authToken.timestamp.milliSeconds = 0;
168     authToken.mac.clear();
169     verificationToken.challenge = 0;
170     verificationToken.timestamp.milliSeconds = 0;
171     verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
172     verificationToken.mac.clear();
173 
174     // Here's the actual test data:
175     const vector<test_utils::TestEntryData> testEntries = {
176             {"PersonalData", "Last name", string("Turing"), vector<int32_t>{0, 1}},
177             {"PersonalData", "Birth date", string("19120623"), vector<int32_t>{0, 1}},
178             {"PersonalData", "First name", string("Alan"), vector<int32_t>{0, 1}},
179             {"PersonalData", "Home address", string("Maida Vale, London, England"),
180              vector<int32_t>{0}},
181             {"Image", "Portrait image", portraitImage, vector<int32_t>{0, 1}},
182     };
183     const vector<int32_t> testEntriesEntryCounts = {static_cast<int32_t>(testEntries.size() - 1),
184                                                     1u};
185     HardwareInformation hwInfo;
186     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
187 
188     string cborPretty;
189     sp<IWritableIdentityCredential> writableCredential;
190     ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
191                                                     true /* testCredential */));
192 
193     string challenge = "attestationChallenge";
194     test_utils::AttestationData attData(writableCredential, challenge,
195                                         {1} /* atteestationApplicationId */);
196     ASSERT_TRUE(attData.result.isOk())
197             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
198 
199     validateAttestationCertificate(attData.attestationCertificate, attData.attestationChallenge,
200                                    attData.attestationApplicationId, true);
201 
202     // This is kinda of a hack but we need to give the size of
203     // ProofOfProvisioning that we'll expect to receive.
204     const int32_t expectedProofOfProvisioningSize = 262861 - 326 + readerCertificate.value().size();
205     // OK to fail, not available in v1 HAL
206     writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
207     ASSERT_TRUE(
208             writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
209                     .isOk());
210 
211     optional<vector<SecureAccessControlProfile>> secureProfiles =
212             test_utils::addAccessControlProfiles(writableCredential, testProfiles);
213     ASSERT_TRUE(secureProfiles);
214 
215     // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
216     // is a little hacky but it works well enough.
217     map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
218 
219     for (const auto& entry : testEntries) {
220         ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
221                                          encryptedBlobs, true));
222     }
223 
224     vector<uint8_t> credentialData;
225     vector<uint8_t> proofOfProvisioningSignature;
226     ASSERT_TRUE(
227             writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
228                     .isOk());
229 
230     // Validate the proofOfProvisioning which was returned
231     optional<vector<uint8_t>> proofOfProvisioning =
232             support::coseSignGetPayload(proofOfProvisioningSignature);
233     ASSERT_TRUE(proofOfProvisioning);
234     cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
235     EXPECT_EQ(
236             "[\n"
237             "  'ProofOfProvisioning',\n"
238             "  'org.iso.18013-5.2019.mdl',\n"
239             "  [\n"
240             "    {\n"
241             "      'id' : 0,\n"
242             "      'readerCertificate' : <not printed>,\n"
243             "    },\n"
244             "    {\n"
245             "      'id' : 1,\n"
246             "    },\n"
247             "  ],\n"
248             "  {\n"
249             "    'PersonalData' : [\n"
250             "      {\n"
251             "        'name' : 'Last name',\n"
252             "        'value' : 'Turing',\n"
253             "        'accessControlProfiles' : [0, 1, ],\n"
254             "      },\n"
255             "      {\n"
256             "        'name' : 'Birth date',\n"
257             "        'value' : '19120623',\n"
258             "        'accessControlProfiles' : [0, 1, ],\n"
259             "      },\n"
260             "      {\n"
261             "        'name' : 'First name',\n"
262             "        'value' : 'Alan',\n"
263             "        'accessControlProfiles' : [0, 1, ],\n"
264             "      },\n"
265             "      {\n"
266             "        'name' : 'Home address',\n"
267             "        'value' : 'Maida Vale, London, England',\n"
268             "        'accessControlProfiles' : [0, ],\n"
269             "      },\n"
270             "    ],\n"
271             "    'Image' : [\n"
272             "      {\n"
273             "        'name' : 'Portrait image',\n"
274             "        'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
275             "        'accessControlProfiles' : [0, 1, ],\n"
276             "      },\n"
277             "    ],\n"
278             "  },\n"
279             "  true,\n"
280             "]",
281             cborPretty);
282 
283     optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
284             attData.attestationCertificate[0].encodedCertificate);
285     ASSERT_TRUE(credentialPubKey);
286     EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
287                                                  {},  // Additional data
288                                                  credentialPubKey.value()));
289     writableCredential = nullptr;
290 
291     // Extract doctype, storage key, and credentialPrivKey from credentialData... this works
292     // only because we asked for a test-credential meaning that the HBK is all zeroes.
293     auto [exSuccess, exDocType, exStorageKey, exCredentialPrivKey, exSha256Pop] =
294             extractFromTestCredentialData(credentialData);
295 
296     ASSERT_TRUE(exSuccess);
297     ASSERT_EQ(exDocType, "org.iso.18013-5.2019.mdl");
298     // ... check that the public key derived from the private key matches what was
299     // in the certificate.
300     optional<vector<uint8_t>> exCredentialKeyPair =
301             support::ecPrivateKeyToKeyPair(exCredentialPrivKey);
302     ASSERT_TRUE(exCredentialKeyPair);
303     optional<vector<uint8_t>> exCredentialPubKey =
304             support::ecKeyPairGetPublicKey(exCredentialKeyPair.value());
305     ASSERT_TRUE(exCredentialPubKey);
306     ASSERT_EQ(exCredentialPubKey.value(), credentialPubKey.value());
307 
308     // Starting with API version 3 (feature version 202101) we require SHA-256(ProofOfProvisioning)
309     // to be in CredentialKeys (which is stored encrypted in CredentialData). Check
310     // that it's there with the expected value.
311     if (halApiVersion_ >= 3) {
312         ASSERT_EQ(exSha256Pop, support::sha256(proofOfProvisioning.value()));
313     }
314 
315     // Now that the credential has been provisioned, read it back and check the
316     // correct data is returned.
317     sp<IIdentityCredential> credential;
318     ASSERT_TRUE(credentialStore_
319                         ->getCredential(
320                                 CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
321                                 credentialData, &credential)
322                         .isOk());
323     ASSERT_NE(credential, nullptr);
324 
325     optional<vector<uint8_t>> readerEphemeralKeyPair = support::createEcKeyPair();
326     ASSERT_TRUE(readerEphemeralKeyPair);
327     optional<vector<uint8_t>> readerEphemeralPublicKey =
328             support::ecKeyPairGetPublicKey(readerEphemeralKeyPair.value());
329     ASSERT_TRUE(credential->setReaderEphemeralPublicKey(readerEphemeralPublicKey.value()).isOk());
330 
331     vector<uint8_t> ephemeralKeyPair;
332     ASSERT_TRUE(credential->createEphemeralKeyPair(&ephemeralKeyPair).isOk());
333     optional<vector<uint8_t>> ephemeralPublicKey = support::ecKeyPairGetPublicKey(ephemeralKeyPair);
334 
335     // Calculate requestData field and sign it with the reader key.
336     auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ephemeralPublicKey.value());
337     ASSERT_TRUE(getXYSuccess);
338     cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
339     vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
340     vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
341     cppbor::Array sessionTranscript = cppbor::Array()
342                                               .add(cppbor::SemanticTag(24, deviceEngagementBytes))
343                                               .add(cppbor::SemanticTag(24, eReaderPubBytes));
344     vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
345 
346     vector<uint8_t> itemsRequestBytes =
347             cppbor::Map("nameSpaces",
348                         cppbor::Map()
349                                 .add("PersonalData", cppbor::Map()
350                                                              .add("Last name", false)
351                                                              .add("Birth date", false)
352                                                              .add("First name", false)
353                                                              .add("Home address", true))
354                                 .add("Image", cppbor::Map().add("Portrait image", false)))
355                     .encode();
356     cborPretty = cppbor::prettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
357     EXPECT_EQ(
358             "{\n"
359             "  'nameSpaces' : {\n"
360             "    'PersonalData' : {\n"
361             "      'Last name' : false,\n"
362             "      'Birth date' : false,\n"
363             "      'First name' : false,\n"
364             "      'Home address' : true,\n"
365             "    },\n"
366             "    'Image' : {\n"
367             "      'Portrait image' : false,\n"
368             "    },\n"
369             "  },\n"
370             "}",
371             cborPretty);
372     vector<uint8_t> encodedReaderAuthentication =
373             cppbor::Array()
374                     .add("ReaderAuthentication")
375                     .add(sessionTranscript.clone())
376                     .add(cppbor::SemanticTag(24, itemsRequestBytes))
377                     .encode();
378     vector<uint8_t> encodedReaderAuthenticationBytes =
379             cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
380     optional<vector<uint8_t>> readerSignature =
381             support::coseSignEcDsa(readerKey, {},                     // content
382                                    encodedReaderAuthenticationBytes,  // detached content
383                                    readerCertificate.value());
384     ASSERT_TRUE(readerSignature);
385 
386     // Generate the key that will be used to sign AuthenticatedData.
387     vector<uint8_t> signingKeyBlob;
388     Certificate signingKeyCertificate;
389     ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
390     optional<vector<uint8_t>> signingPubKey =
391             support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
392     EXPECT_TRUE(signingPubKey);
393     test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
394 
395     // Since we're using a test-credential we know storageKey meaning we can get the
396     // private key. Do this, derive the public key from it, and check this matches what
397     // is in the certificate...
398     const vector<uint8_t> exDocTypeVec(exDocType.begin(), exDocType.end());
399     optional<vector<uint8_t>> exSigningPrivKey =
400             support::decryptAes128Gcm(exStorageKey, signingKeyBlob, exDocTypeVec);
401     ASSERT_TRUE(exSigningPrivKey);
402     optional<vector<uint8_t>> exSigningKeyPair =
403             support::ecPrivateKeyToKeyPair(exSigningPrivKey.value());
404     ASSERT_TRUE(exSigningKeyPair);
405     optional<vector<uint8_t>> exSigningPubKey =
406             support::ecKeyPairGetPublicKey(exSigningKeyPair.value());
407     ASSERT_TRUE(exSigningPubKey);
408     ASSERT_EQ(exSigningPubKey.value(), signingPubKey.value());
409 
410     vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
411     // OK to fail, not available in v1 HAL
412     credential->setRequestedNamespaces(requestedNamespaces);
413     // OK to fail, not available in v1 HAL
414     credential->setVerificationToken(verificationToken);
415     ASSERT_TRUE(credential
416                         ->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
417                                          signingKeyBlob, sessionTranscriptEncoded,
418                                          readerSignature.value(), testEntriesEntryCounts)
419                         .isOk());
420 
421     for (const auto& entry : testEntries) {
422         ASSERT_TRUE(credential
423                             ->startRetrieveEntryValue(entry.nameSpace, entry.name,
424                                                       entry.valueCbor.size(), entry.profileIds)
425                             .isOk());
426 
427         auto it = encryptedBlobs.find(&entry);
428         ASSERT_NE(it, encryptedBlobs.end());
429         const vector<vector<uint8_t>>& encryptedChunks = it->second;
430 
431         vector<uint8_t> content;
432         for (const auto& encryptedChunk : encryptedChunks) {
433             vector<uint8_t> chunk;
434             ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
435             content.insert(content.end(), chunk.begin(), chunk.end());
436         }
437         EXPECT_EQ(content, entry.valueCbor);
438 
439         // TODO: also use |exStorageKey| to decrypt data and check it's the same as whatt
440         // the HAL returns...
441     }
442 
443     vector<uint8_t> mac;
444     vector<uint8_t> deviceNameSpacesEncoded;
445     ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
446     cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
447     ASSERT_EQ(
448             "{\n"
449             "  'PersonalData' : {\n"
450             "    'Last name' : 'Turing',\n"
451             "    'Birth date' : '19120623',\n"
452             "    'First name' : 'Alan',\n"
453             "    'Home address' : 'Maida Vale, London, England',\n"
454             "  },\n"
455             "  'Image' : {\n"
456             "    'Portrait image' : <bstr size=262134 "
457             "sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
458             "  },\n"
459             "}",
460             cborPretty);
461 
462     string docType = "org.iso.18013-5.2019.mdl";
463     optional<vector<uint8_t>> readerEphemeralPrivateKey =
464             support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
465     optional<vector<uint8_t>> eMacKey =
466             support::calcEMacKey(readerEphemeralPrivateKey.value(),  // Private Key
467                                  signingPubKey.value(),              // Public Key
468                                  cppbor::SemanticTag(24, sessionTranscript.encode())
469                                          .encode());  // SessionTranscriptBytes
470     optional<vector<uint8_t>> calculatedMac =
471             support::calcMac(sessionTranscript.encode(),  // SessionTranscript
472                              docType,                     // DocType
473                              deviceNameSpacesEncoded,     // DeviceNamespaces
474                              eMacKey.value());            // EMacKey
475     ASSERT_TRUE(calculatedMac);
476     EXPECT_EQ(mac, calculatedMac);
477 
478     // Also perform an additional empty request. This is what mDL applications
479     // are envisioned to do - one call to get the data elements, another to get
480     // an empty DeviceSignedItems and corresponding MAC.
481     //
482     credential->setRequestedNamespaces({});  // OK to fail, not available in v1 HAL
483     ASSERT_TRUE(credential
484                         ->startRetrieval(
485                                 secureProfiles.value(), authToken, {},         // itemsRequestBytes
486                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
487                                 testEntriesEntryCounts)
488                         .isOk());
489     ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
490     cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
491     ASSERT_EQ("{}", cborPretty);
492     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
493     calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
494                                      docType,                     // DocType
495                                      deviceNameSpacesEncoded,     // DeviceNamespaces
496                                      eMacKey.value());            // EMacKey
497     ASSERT_TRUE(calculatedMac);
498     EXPECT_EQ(mac, calculatedMac);
499 
500     // Some mDL apps might send a request but with a single empty
501     // namespace. Check that too.
502     RequestNamespace emptyRequestNS;
503     emptyRequestNS.namespaceName = "PersonalData";
504     credential->setRequestedNamespaces({emptyRequestNS});  // OK to fail, not available in v1 HAL
505     ASSERT_TRUE(credential
506                         ->startRetrieval(
507                                 secureProfiles.value(), authToken, {},         // itemsRequestBytes
508                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
509                                 testEntriesEntryCounts)
510                         .isOk());
511     ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
512     cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
513     ASSERT_EQ("{}", cborPretty);
514     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
515     calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
516                                      docType,                     // DocType
517                                      deviceNameSpacesEncoded,     // DeviceNamespaces
518                                      eMacKey.value());            // EMacKey
519     ASSERT_TRUE(calculatedMac);
520     EXPECT_EQ(mac, calculatedMac);
521 }
522 
523 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EndToEndTests);
524 INSTANTIATE_TEST_SUITE_P(
525         Identity, EndToEndTests,
526         testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
527         android::PrintInstanceNameToString);
528 
529 }  // namespace android::hardware::identity
530 
main(int argc,char ** argv)531 int main(int argc, char** argv) {
532     ::testing::InitGoogleTest(&argc, argv);
533     ::android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
534     ::android::ProcessState::self()->startThreadPool();
535     return RUN_ALL_TESTS();
536 }
537