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