blob: 15772935217cada756597a23568e0df2b1a6fa23 [file] [log] [blame]
David Zeuthen81603152020-02-11 22:04:24 -05001/*
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 */
Selene Huangcab019a2020-03-11 04:37:48 -070016#define LOG_TAG "VtsHalIdentityEndToEndTest"
David Zeuthen81603152020-02-11 22:04:24 -050017
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>
David Zeuthenef739512020-06-03 13:24:52 -040030#include <tuple>
David Zeuthen81603152020-02-11 22:04:24 -050031
Selene Huang92b61d62020-03-04 02:24:16 -080032#include "VtsIdentityTestUtils.h"
33
David Zeuthen81603152020-02-11 22:04:24 -050034namespace android::hardware::identity {
35
Selene Huang92b61d62020-03-04 02:24:16 -080036using std::endl;
David Zeuthenef739512020-06-03 13:24:52 -040037using std::make_tuple;
David Zeuthen81603152020-02-11 22:04:24 -050038using std::map;
39using std::optional;
40using std::string;
David Zeuthenef739512020-06-03 13:24:52 -040041using std::tuple;
David Zeuthen81603152020-02-11 22:04:24 -050042using std::vector;
43
44using ::android::sp;
45using ::android::String16;
46using ::android::binder::Status;
47
48using ::android::hardware::keymaster::HardwareAuthToken;
David Zeuthena8ed82c2020-05-08 10:03:28 -040049using ::android::hardware::keymaster::VerificationToken;
David Zeuthen81603152020-02-11 22:04:24 -050050
Selene Huangcab019a2020-03-11 04:37:48 -070051using test_utils::validateAttestationCertificate;
52
David Zeuthen81603152020-02-11 22:04:24 -050053class IdentityAidl : public testing::TestWithParam<std::string> {
54 public:
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
64TEST_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
David Zeuthenef739512020-06-03 13:24:52 -040072tuple<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
David Zeuthen81603152020-02-11 22:04:24 -0500127TEST_P(IdentityAidl, createAndRetrieveCredential) {
128 // First, generate a key-pair for the reader since its public key will be
129 // part of the request data.
Selene Huang92b61d62020-03-04 02:24:16 -0800130 vector<uint8_t> readerKey;
131 optional<vector<uint8_t>> readerCertificate =
Selene Huangcab019a2020-03-11 04:37:48 -0700132 test_utils::generateReaderCertificate("1234", &readerKey);
David Zeuthen81603152020-02-11 22:04:24 -0500133 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;
Selene Huangcab019a2020-03-11 04:37:48 -0700138 test_utils::setImageData(portraitImage);
David Zeuthen81603152020-02-11 22:04:24 -0500139
140 // Access control profiles:
Selene Huang92b61d62020-03-04 02:24:16 -0800141 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}};
David Zeuthen81603152020-02-11 22:04:24 -0500145
David Zeuthena8ed82c2020-05-08 10:03:28 -0400146 // 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.
David Zeuthen81603152020-02-11 22:04:24 -0500148 HardwareAuthToken authToken;
David Zeuthena8ed82c2020-05-08 10:03:28 -0400149 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();
David Zeuthen81603152020-02-11 22:04:24 -0500160
161 // Here's the actual test data:
Selene Huang92b61d62020-03-04 02:24:16 -0800162 const vector<test_utils::TestEntryData> testEntries = {
David Zeuthen81603152020-02-11 22:04:24 -0500163 {"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;
Selene Huangcab019a2020-03-11 04:37:48 -0700177 ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
David Zeuthen81603152020-02-11 22:04:24 -0500178
179 string challenge = "attestationChallenge";
Selene Huang92b61d62020-03-04 02:24:16 -0800180 test_utils::AttestationData attData(writableCredential, challenge, {});
181 ASSERT_TRUE(attData.result.isOk())
182 << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
Selene Huang92b61d62020-03-04 02:24:16 -0800183
Selene Huangcab019a2020-03-11 04:37:48 -0700184 EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
185 attData.attestationChallenge,
186 attData.attestationApplicationId, hwInfo));
David Zeuthen81603152020-02-11 22:04:24 -0500187
David Zeuthen28edb102020-04-28 18:54:55 -0400188 // This is kinda of a hack but we need to give the size of
189 // ProofOfProvisioning that we'll expect to receive.
190 const int32_t expectedProofOfProvisioningSize = 262861 - 326 + readerCertificate.value().size();
191 // OK to fail, not available in v1 HAL
192 writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
David Zeuthen81603152020-02-11 22:04:24 -0500193 ASSERT_TRUE(
194 writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
195 .isOk());
196
Selene Huang92b61d62020-03-04 02:24:16 -0800197 optional<vector<SecureAccessControlProfile>> secureProfiles =
Selene Huangcab019a2020-03-11 04:37:48 -0700198 test_utils::addAccessControlProfiles(writableCredential, testProfiles);
Selene Huang92b61d62020-03-04 02:24:16 -0800199 ASSERT_TRUE(secureProfiles);
David Zeuthen81603152020-02-11 22:04:24 -0500200
201 // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
202 // is a little hacky but it works well enough.
Selene Huang92b61d62020-03-04 02:24:16 -0800203 map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
David Zeuthen81603152020-02-11 22:04:24 -0500204
205 for (const auto& entry : testEntries) {
Selene Huangcab019a2020-03-11 04:37:48 -0700206 ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
Selene Huang92b61d62020-03-04 02:24:16 -0800207 encryptedBlobs, true));
David Zeuthen81603152020-02-11 22:04:24 -0500208 }
209
210 vector<uint8_t> credentialData;
211 vector<uint8_t> proofOfProvisioningSignature;
212 ASSERT_TRUE(
213 writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
214 .isOk());
215
David Zeuthenef739512020-06-03 13:24:52 -0400216 // Validate the proofOfProvisioning which was returned
David Zeuthen81603152020-02-11 22:04:24 -0500217 optional<vector<uint8_t>> proofOfProvisioning =
218 support::coseSignGetPayload(proofOfProvisioningSignature);
219 ASSERT_TRUE(proofOfProvisioning);
220 cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
221 EXPECT_EQ(
222 "[\n"
223 " 'ProofOfProvisioning',\n"
224 " 'org.iso.18013-5.2019.mdl',\n"
225 " [\n"
226 " {\n"
227 " 'id' : 0,\n"
228 " 'readerCertificate' : <not printed>,\n"
229 " },\n"
230 " {\n"
231 " 'id' : 1,\n"
232 " },\n"
233 " ],\n"
234 " {\n"
235 " 'PersonalData' : [\n"
236 " {\n"
237 " 'name' : 'Last name',\n"
238 " 'value' : 'Turing',\n"
239 " 'accessControlProfiles' : [0, 1, ],\n"
240 " },\n"
241 " {\n"
242 " 'name' : 'Birth date',\n"
243 " 'value' : '19120623',\n"
244 " 'accessControlProfiles' : [0, 1, ],\n"
245 " },\n"
246 " {\n"
247 " 'name' : 'First name',\n"
248 " 'value' : 'Alan',\n"
249 " 'accessControlProfiles' : [0, 1, ],\n"
250 " },\n"
251 " {\n"
252 " 'name' : 'Home address',\n"
253 " 'value' : 'Maida Vale, London, England',\n"
254 " 'accessControlProfiles' : [0, ],\n"
255 " },\n"
256 " ],\n"
257 " 'Image' : [\n"
258 " {\n"
259 " 'name' : 'Portrait image',\n"
260 " 'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
261 " 'accessControlProfiles' : [0, 1, ],\n"
262 " },\n"
263 " ],\n"
264 " },\n"
265 " true,\n"
266 "]",
267 cborPretty);
268
Selene Huang92b61d62020-03-04 02:24:16 -0800269 optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
270 attData.attestationCertificate[0].encodedCertificate);
David Zeuthen81603152020-02-11 22:04:24 -0500271 ASSERT_TRUE(credentialPubKey);
272 EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
273 {}, // Additional data
274 credentialPubKey.value()));
275 writableCredential = nullptr;
276
David Zeuthenef739512020-06-03 13:24:52 -0400277 // Extract doctype, storage key, and credentialPrivKey from credentialData... this works
278 // only because we asked for a test-credential meaning that the HBK is all zeroes.
279 auto [exSuccess, exDocType, exStorageKey, exCredentialPrivKey] =
280 extractFromTestCredentialData(credentialData);
281 ASSERT_TRUE(exSuccess);
282 ASSERT_EQ(exDocType, "org.iso.18013-5.2019.mdl");
283 // ... check that the public key derived from the private key matches what was
284 // in the certificate.
285 optional<vector<uint8_t>> exCredentialKeyPair =
286 support::ecPrivateKeyToKeyPair(exCredentialPrivKey);
287 ASSERT_TRUE(exCredentialKeyPair);
288 optional<vector<uint8_t>> exCredentialPubKey =
289 support::ecKeyPairGetPublicKey(exCredentialKeyPair.value());
290 ASSERT_TRUE(exCredentialPubKey);
291 ASSERT_EQ(exCredentialPubKey.value(), credentialPubKey.value());
292
David Zeuthen81603152020-02-11 22:04:24 -0500293 // Now that the credential has been provisioned, read it back and check the
294 // correct data is returned.
295 sp<IIdentityCredential> credential;
296 ASSERT_TRUE(credentialStore_
297 ->getCredential(
298 CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
299 credentialData, &credential)
300 .isOk());
301 ASSERT_NE(credential, nullptr);
302
303 optional<vector<uint8_t>> readerEphemeralKeyPair = support::createEcKeyPair();
304 ASSERT_TRUE(readerEphemeralKeyPair);
305 optional<vector<uint8_t>> readerEphemeralPublicKey =
306 support::ecKeyPairGetPublicKey(readerEphemeralKeyPair.value());
307 ASSERT_TRUE(credential->setReaderEphemeralPublicKey(readerEphemeralPublicKey.value()).isOk());
308
309 vector<uint8_t> ephemeralKeyPair;
310 ASSERT_TRUE(credential->createEphemeralKeyPair(&ephemeralKeyPair).isOk());
311 optional<vector<uint8_t>> ephemeralPublicKey = support::ecKeyPairGetPublicKey(ephemeralKeyPair);
312
313 // Calculate requestData field and sign it with the reader key.
314 auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ephemeralPublicKey.value());
315 ASSERT_TRUE(getXYSuccess);
316 cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
317 vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
318 vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
319 cppbor::Array sessionTranscript = cppbor::Array()
320 .add(cppbor::Semantic(24, deviceEngagementBytes))
321 .add(cppbor::Semantic(24, eReaderPubBytes));
David Zeuthen2e4533e2020-06-20 17:04:41 -0400322 vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
David Zeuthen81603152020-02-11 22:04:24 -0500323
324 vector<uint8_t> itemsRequestBytes =
325 cppbor::Map("nameSpaces",
326 cppbor::Map()
327 .add("PersonalData", cppbor::Map()
328 .add("Last name", false)
329 .add("Birth date", false)
330 .add("First name", false)
331 .add("Home address", true))
332 .add("Image", cppbor::Map().add("Portrait image", false)))
333 .encode();
334 cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
335 EXPECT_EQ(
336 "{\n"
337 " 'nameSpaces' : {\n"
338 " 'PersonalData' : {\n"
339 " 'Last name' : false,\n"
340 " 'Birth date' : false,\n"
341 " 'First name' : false,\n"
342 " 'Home address' : true,\n"
343 " },\n"
344 " 'Image' : {\n"
345 " 'Portrait image' : false,\n"
346 " },\n"
347 " },\n"
348 "}",
349 cborPretty);
David Zeuthen2e4533e2020-06-20 17:04:41 -0400350 vector<uint8_t> encodedReaderAuthentication =
351 cppbor::Array()
352 .add("ReaderAuthentication")
353 .add(sessionTranscript.clone())
354 .add(cppbor::Semantic(24, itemsRequestBytes))
355 .encode();
356 vector<uint8_t> encodedReaderAuthenticationBytes =
357 cppbor::Semantic(24, encodedReaderAuthentication).encode();
David Zeuthen81603152020-02-11 22:04:24 -0500358 optional<vector<uint8_t>> readerSignature =
David Zeuthen2e4533e2020-06-20 17:04:41 -0400359 support::coseSignEcDsa(readerKey, {}, // content
360 encodedReaderAuthenticationBytes, // detached content
David Zeuthen81603152020-02-11 22:04:24 -0500361 readerCertificate.value());
362 ASSERT_TRUE(readerSignature);
363
David Zeuthene35797f2020-02-27 14:25:54 -0500364 // Generate the key that will be used to sign AuthenticatedData.
365 vector<uint8_t> signingKeyBlob;
366 Certificate signingKeyCertificate;
367 ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
David Zeuthenef739512020-06-03 13:24:52 -0400368 optional<vector<uint8_t>> signingPubKey =
369 support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
370 EXPECT_TRUE(signingPubKey);
371
372 // Since we're using a test-credential we know storageKey meaning we can get the
373 // private key. Do this, derive the public key from it, and check this matches what
374 // is in the certificate...
375 const vector<uint8_t> exDocTypeVec(exDocType.begin(), exDocType.end());
376 optional<vector<uint8_t>> exSigningPrivKey =
377 support::decryptAes128Gcm(exStorageKey, signingKeyBlob, exDocTypeVec);
378 ASSERT_TRUE(exSigningPrivKey);
379 optional<vector<uint8_t>> exSigningKeyPair =
380 support::ecPrivateKeyToKeyPair(exSigningPrivKey.value());
381 ASSERT_TRUE(exSigningKeyPair);
382 optional<vector<uint8_t>> exSigningPubKey =
383 support::ecKeyPairGetPublicKey(exSigningKeyPair.value());
384 ASSERT_TRUE(exSigningPubKey);
385 ASSERT_EQ(exSigningPubKey.value(), signingPubKey.value());
David Zeuthene35797f2020-02-27 14:25:54 -0500386
David Zeuthen28edb102020-04-28 18:54:55 -0400387 vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
David Zeuthena8ed82c2020-05-08 10:03:28 -0400388 // OK to fail, not available in v1 HAL
389 credential->setRequestedNamespaces(requestedNamespaces).isOk();
390 // OK to fail, not available in v1 HAL
391 credential->setVerificationToken(verificationToken);
David Zeuthen81603152020-02-11 22:04:24 -0500392 ASSERT_TRUE(credential
Selene Huang92b61d62020-03-04 02:24:16 -0800393 ->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
David Zeuthen2e4533e2020-06-20 17:04:41 -0400394 signingKeyBlob, sessionTranscriptEncoded,
David Zeuthene35797f2020-02-27 14:25:54 -0500395 readerSignature.value(), testEntriesEntryCounts)
David Zeuthen81603152020-02-11 22:04:24 -0500396 .isOk());
397
398 for (const auto& entry : testEntries) {
399 ASSERT_TRUE(credential
400 ->startRetrieveEntryValue(entry.nameSpace, entry.name,
401 entry.valueCbor.size(), entry.profileIds)
402 .isOk());
403
404 auto it = encryptedBlobs.find(&entry);
405 ASSERT_NE(it, encryptedBlobs.end());
406 const vector<vector<uint8_t>>& encryptedChunks = it->second;
407
408 vector<uint8_t> content;
409 for (const auto& encryptedChunk : encryptedChunks) {
410 vector<uint8_t> chunk;
411 ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
412 content.insert(content.end(), chunk.begin(), chunk.end());
413 }
414 EXPECT_EQ(content, entry.valueCbor);
David Zeuthenef739512020-06-03 13:24:52 -0400415
416 // TODO: also use |exStorageKey| to decrypt data and check it's the same as whatt
417 // the HAL returns...
David Zeuthen81603152020-02-11 22:04:24 -0500418 }
419
David Zeuthen81603152020-02-11 22:04:24 -0500420 vector<uint8_t> mac;
421 vector<uint8_t> deviceNameSpacesBytes;
David Zeuthene35797f2020-02-27 14:25:54 -0500422 ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
David Zeuthen81603152020-02-11 22:04:24 -0500423 cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
424 ASSERT_EQ(
425 "{\n"
426 " 'PersonalData' : {\n"
427 " 'Last name' : 'Turing',\n"
428 " 'Birth date' : '19120623',\n"
429 " 'First name' : 'Alan',\n"
430 " 'Home address' : 'Maida Vale, London, England',\n"
431 " },\n"
432 " 'Image' : {\n"
433 " 'Portrait image' : <bstr size=262134 "
434 "sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
435 " },\n"
436 "}",
437 cborPretty);
David Zeuthen2e4533e2020-06-20 17:04:41 -0400438 // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
David Zeuthen81603152020-02-11 22:04:24 -0500439 // deviceNameSpacesBytes] so build up that structure
440 cppbor::Array deviceAuthentication;
441 deviceAuthentication.add("DeviceAuthentication");
442 deviceAuthentication.add(sessionTranscript.clone());
Selene Huang92b61d62020-03-04 02:24:16 -0800443
444 string docType = "org.iso.18013-5.2019.mdl";
David Zeuthen81603152020-02-11 22:04:24 -0500445 deviceAuthentication.add(docType);
446 deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
David Zeuthen2e4533e2020-06-20 17:04:41 -0400447 vector<uint8_t> deviceAuthenticationBytes =
448 cppbor::Semantic(24, deviceAuthentication.encode()).encode();
David Zeuthen81603152020-02-11 22:04:24 -0500449
450 // Derive the key used for MACing.
451 optional<vector<uint8_t>> readerEphemeralPrivateKey =
452 support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
453 optional<vector<uint8_t>> sharedSecret =
David Zeuthenef739512020-06-03 13:24:52 -0400454 support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value());
David Zeuthen81603152020-02-11 22:04:24 -0500455 ASSERT_TRUE(sharedSecret);
David Zeuthen2e4533e2020-06-20 17:04:41 -0400456 // Mix-in SessionTranscriptBytes
457 vector<uint8_t> sessionTranscriptBytes =
458 cppbor::Semantic(24, sessionTranscript.encode()).encode();
459 vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
460 std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
461 std::back_inserter(sharedSecretWithSessionTranscriptBytes));
David Zeuthen81603152020-02-11 22:04:24 -0500462 vector<uint8_t> salt = {0x00};
463 vector<uint8_t> info = {};
David Zeuthen2e4533e2020-06-20 17:04:41 -0400464 optional<vector<uint8_t>> derivedKey =
465 support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
David Zeuthen81603152020-02-11 22:04:24 -0500466 ASSERT_TRUE(derivedKey);
467 optional<vector<uint8_t>> calculatedMac =
David Zeuthen2e4533e2020-06-20 17:04:41 -0400468 support::coseMac0(derivedKey.value(), {}, // payload
469 deviceAuthenticationBytes); // detached content
David Zeuthen81603152020-02-11 22:04:24 -0500470 ASSERT_TRUE(calculatedMac);
471 EXPECT_EQ(mac, calculatedMac);
472}
473
474INSTANTIATE_TEST_SUITE_P(
475 Identity, IdentityAidl,
476 testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
477 android::PrintInstanceNameToString);
478// INSTANTIATE_TEST_SUITE_P(Identity, IdentityAidl,
479// testing::Values("android.hardware.identity.IIdentityCredentialStore/default"));
480
481} // namespace android::hardware::identity
482
483int main(int argc, char** argv) {
484 ::testing::InitGoogleTest(&argc, argv);
485 ::android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
486 ::android::ProcessState::self()->startThreadPool();
487 return RUN_ALL_TESTS();
488}