blob: 464ab0c6d07ecb4fdeaab0b1a9eb0bb9593fa7ea [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>
30
Selene Huang92b61d62020-03-04 02:24:16 -080031#include "VtsIdentityTestUtils.h"
32
David Zeuthen81603152020-02-11 22:04:24 -050033namespace android::hardware::identity {
34
Selene Huang92b61d62020-03-04 02:24:16 -080035using std::endl;
David Zeuthen81603152020-02-11 22:04:24 -050036using std::map;
37using std::optional;
38using std::string;
39using std::vector;
40
41using ::android::sp;
42using ::android::String16;
43using ::android::binder::Status;
44
45using ::android::hardware::keymaster::HardwareAuthToken;
David Zeuthena8ed82c2020-05-08 10:03:28 -040046using ::android::hardware::keymaster::VerificationToken;
David Zeuthen81603152020-02-11 22:04:24 -050047
Selene Huangcab019a2020-03-11 04:37:48 -070048using test_utils::validateAttestationCertificate;
49
David Zeuthen81603152020-02-11 22:04:24 -050050class IdentityAidl : public testing::TestWithParam<std::string> {
51 public:
52 virtual void SetUp() override {
53 credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
54 String16(GetParam().c_str()));
55 ASSERT_NE(credentialStore_, nullptr);
56 }
57
58 sp<IIdentityCredentialStore> credentialStore_;
59};
60
61TEST_P(IdentityAidl, hardwareInformation) {
62 HardwareInformation info;
63 ASSERT_TRUE(credentialStore_->getHardwareInformation(&info).isOk());
64 ASSERT_GT(info.credentialStoreName.size(), 0);
65 ASSERT_GT(info.credentialStoreAuthorName.size(), 0);
66 ASSERT_GE(info.dataChunkSize, 256);
67}
68
69TEST_P(IdentityAidl, createAndRetrieveCredential) {
70 // First, generate a key-pair for the reader since its public key will be
71 // part of the request data.
Selene Huang92b61d62020-03-04 02:24:16 -080072 vector<uint8_t> readerKey;
73 optional<vector<uint8_t>> readerCertificate =
Selene Huangcab019a2020-03-11 04:37:48 -070074 test_utils::generateReaderCertificate("1234", &readerKey);
David Zeuthen81603152020-02-11 22:04:24 -050075 ASSERT_TRUE(readerCertificate);
76
77 // Make the portrait image really big (just shy of 256 KiB) to ensure that
78 // the chunking code gets exercised.
79 vector<uint8_t> portraitImage;
Selene Huangcab019a2020-03-11 04:37:48 -070080 test_utils::setImageData(portraitImage);
David Zeuthen81603152020-02-11 22:04:24 -050081
82 // Access control profiles:
Selene Huang92b61d62020-03-04 02:24:16 -080083 const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
84 {0, readerCertificate.value(), false, 0},
85 // Profile 1 (no authentication)
86 {1, {}, false, 0}};
David Zeuthen81603152020-02-11 22:04:24 -050087
David Zeuthena8ed82c2020-05-08 10:03:28 -040088 // It doesn't matter since no user auth is needed in this particular test,
89 // but for good measure, clear out the tokens we pass to the HAL.
David Zeuthen81603152020-02-11 22:04:24 -050090 HardwareAuthToken authToken;
David Zeuthena8ed82c2020-05-08 10:03:28 -040091 VerificationToken verificationToken;
92 authToken.challenge = 0;
93 authToken.userId = 0;
94 authToken.authenticatorId = 0;
95 authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
96 authToken.timestamp.milliSeconds = 0;
97 authToken.mac.clear();
98 verificationToken.challenge = 0;
99 verificationToken.timestamp.milliSeconds = 0;
100 verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
101 verificationToken.mac.clear();
David Zeuthen81603152020-02-11 22:04:24 -0500102
103 // Here's the actual test data:
Selene Huang92b61d62020-03-04 02:24:16 -0800104 const vector<test_utils::TestEntryData> testEntries = {
David Zeuthen81603152020-02-11 22:04:24 -0500105 {"PersonalData", "Last name", string("Turing"), vector<int32_t>{0, 1}},
106 {"PersonalData", "Birth date", string("19120623"), vector<int32_t>{0, 1}},
107 {"PersonalData", "First name", string("Alan"), vector<int32_t>{0, 1}},
108 {"PersonalData", "Home address", string("Maida Vale, London, England"),
109 vector<int32_t>{0}},
110 {"Image", "Portrait image", portraitImage, vector<int32_t>{0, 1}},
111 };
112 const vector<int32_t> testEntriesEntryCounts = {static_cast<int32_t>(testEntries.size() - 1),
113 1u};
114 HardwareInformation hwInfo;
115 ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
116
117 string cborPretty;
118 sp<IWritableIdentityCredential> writableCredential;
Selene Huangcab019a2020-03-11 04:37:48 -0700119 ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
David Zeuthen81603152020-02-11 22:04:24 -0500120
121 string challenge = "attestationChallenge";
Selene Huang92b61d62020-03-04 02:24:16 -0800122 test_utils::AttestationData attData(writableCredential, challenge, {});
123 ASSERT_TRUE(attData.result.isOk())
124 << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
Selene Huang92b61d62020-03-04 02:24:16 -0800125
Selene Huangcab019a2020-03-11 04:37:48 -0700126 EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
127 attData.attestationChallenge,
128 attData.attestationApplicationId, hwInfo));
David Zeuthen81603152020-02-11 22:04:24 -0500129
David Zeuthen28edb102020-04-28 18:54:55 -0400130 // This is kinda of a hack but we need to give the size of
131 // ProofOfProvisioning that we'll expect to receive.
132 const int32_t expectedProofOfProvisioningSize = 262861 - 326 + readerCertificate.value().size();
133 // OK to fail, not available in v1 HAL
134 writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
David Zeuthen81603152020-02-11 22:04:24 -0500135 ASSERT_TRUE(
136 writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
137 .isOk());
138
Selene Huang92b61d62020-03-04 02:24:16 -0800139 optional<vector<SecureAccessControlProfile>> secureProfiles =
Selene Huangcab019a2020-03-11 04:37:48 -0700140 test_utils::addAccessControlProfiles(writableCredential, testProfiles);
Selene Huang92b61d62020-03-04 02:24:16 -0800141 ASSERT_TRUE(secureProfiles);
David Zeuthen81603152020-02-11 22:04:24 -0500142
143 // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
144 // is a little hacky but it works well enough.
Selene Huang92b61d62020-03-04 02:24:16 -0800145 map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
David Zeuthen81603152020-02-11 22:04:24 -0500146
147 for (const auto& entry : testEntries) {
Selene Huangcab019a2020-03-11 04:37:48 -0700148 ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
Selene Huang92b61d62020-03-04 02:24:16 -0800149 encryptedBlobs, true));
David Zeuthen81603152020-02-11 22:04:24 -0500150 }
151
152 vector<uint8_t> credentialData;
153 vector<uint8_t> proofOfProvisioningSignature;
154 ASSERT_TRUE(
155 writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
156 .isOk());
157
158 optional<vector<uint8_t>> proofOfProvisioning =
159 support::coseSignGetPayload(proofOfProvisioningSignature);
160 ASSERT_TRUE(proofOfProvisioning);
161 cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
162 EXPECT_EQ(
163 "[\n"
164 " 'ProofOfProvisioning',\n"
165 " 'org.iso.18013-5.2019.mdl',\n"
166 " [\n"
167 " {\n"
168 " 'id' : 0,\n"
169 " 'readerCertificate' : <not printed>,\n"
170 " },\n"
171 " {\n"
172 " 'id' : 1,\n"
173 " },\n"
174 " ],\n"
175 " {\n"
176 " 'PersonalData' : [\n"
177 " {\n"
178 " 'name' : 'Last name',\n"
179 " 'value' : 'Turing',\n"
180 " 'accessControlProfiles' : [0, 1, ],\n"
181 " },\n"
182 " {\n"
183 " 'name' : 'Birth date',\n"
184 " 'value' : '19120623',\n"
185 " 'accessControlProfiles' : [0, 1, ],\n"
186 " },\n"
187 " {\n"
188 " 'name' : 'First name',\n"
189 " 'value' : 'Alan',\n"
190 " 'accessControlProfiles' : [0, 1, ],\n"
191 " },\n"
192 " {\n"
193 " 'name' : 'Home address',\n"
194 " 'value' : 'Maida Vale, London, England',\n"
195 " 'accessControlProfiles' : [0, ],\n"
196 " },\n"
197 " ],\n"
198 " 'Image' : [\n"
199 " {\n"
200 " 'name' : 'Portrait image',\n"
201 " 'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
202 " 'accessControlProfiles' : [0, 1, ],\n"
203 " },\n"
204 " ],\n"
205 " },\n"
206 " true,\n"
207 "]",
208 cborPretty);
209
Selene Huang92b61d62020-03-04 02:24:16 -0800210 optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
211 attData.attestationCertificate[0].encodedCertificate);
David Zeuthen81603152020-02-11 22:04:24 -0500212 ASSERT_TRUE(credentialPubKey);
213 EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
214 {}, // Additional data
215 credentialPubKey.value()));
216 writableCredential = nullptr;
217
218 // Now that the credential has been provisioned, read it back and check the
219 // correct data is returned.
220 sp<IIdentityCredential> credential;
221 ASSERT_TRUE(credentialStore_
222 ->getCredential(
223 CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
224 credentialData, &credential)
225 .isOk());
226 ASSERT_NE(credential, nullptr);
227
228 optional<vector<uint8_t>> readerEphemeralKeyPair = support::createEcKeyPair();
229 ASSERT_TRUE(readerEphemeralKeyPair);
230 optional<vector<uint8_t>> readerEphemeralPublicKey =
231 support::ecKeyPairGetPublicKey(readerEphemeralKeyPair.value());
232 ASSERT_TRUE(credential->setReaderEphemeralPublicKey(readerEphemeralPublicKey.value()).isOk());
233
234 vector<uint8_t> ephemeralKeyPair;
235 ASSERT_TRUE(credential->createEphemeralKeyPair(&ephemeralKeyPair).isOk());
236 optional<vector<uint8_t>> ephemeralPublicKey = support::ecKeyPairGetPublicKey(ephemeralKeyPair);
237
238 // Calculate requestData field and sign it with the reader key.
239 auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ephemeralPublicKey.value());
240 ASSERT_TRUE(getXYSuccess);
241 cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
242 vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
243 vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
244 cppbor::Array sessionTranscript = cppbor::Array()
245 .add(cppbor::Semantic(24, deviceEngagementBytes))
246 .add(cppbor::Semantic(24, eReaderPubBytes));
247 vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
248
249 vector<uint8_t> itemsRequestBytes =
250 cppbor::Map("nameSpaces",
251 cppbor::Map()
252 .add("PersonalData", cppbor::Map()
253 .add("Last name", false)
254 .add("Birth date", false)
255 .add("First name", false)
256 .add("Home address", true))
257 .add("Image", cppbor::Map().add("Portrait image", false)))
258 .encode();
259 cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
260 EXPECT_EQ(
261 "{\n"
262 " 'nameSpaces' : {\n"
263 " 'PersonalData' : {\n"
264 " 'Last name' : false,\n"
265 " 'Birth date' : false,\n"
266 " 'First name' : false,\n"
267 " 'Home address' : true,\n"
268 " },\n"
269 " 'Image' : {\n"
270 " 'Portrait image' : false,\n"
271 " },\n"
272 " },\n"
273 "}",
274 cborPretty);
275 vector<uint8_t> dataToSign = cppbor::Array()
276 .add("ReaderAuthentication")
277 .add(sessionTranscript.clone())
278 .add(cppbor::Semantic(24, itemsRequestBytes))
279 .encode();
280 optional<vector<uint8_t>> readerSignature =
Selene Huang92b61d62020-03-04 02:24:16 -0800281 support::coseSignEcDsa(readerKey, {}, // content
282 dataToSign, // detached content
David Zeuthen81603152020-02-11 22:04:24 -0500283 readerCertificate.value());
284 ASSERT_TRUE(readerSignature);
285
David Zeuthene35797f2020-02-27 14:25:54 -0500286 // Generate the key that will be used to sign AuthenticatedData.
287 vector<uint8_t> signingKeyBlob;
288 Certificate signingKeyCertificate;
289 ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
290
David Zeuthen28edb102020-04-28 18:54:55 -0400291 vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
David Zeuthena8ed82c2020-05-08 10:03:28 -0400292 // OK to fail, not available in v1 HAL
293 credential->setRequestedNamespaces(requestedNamespaces).isOk();
294 // OK to fail, not available in v1 HAL
295 credential->setVerificationToken(verificationToken);
David Zeuthen81603152020-02-11 22:04:24 -0500296 ASSERT_TRUE(credential
Selene Huang92b61d62020-03-04 02:24:16 -0800297 ->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
David Zeuthene35797f2020-02-27 14:25:54 -0500298 signingKeyBlob, sessionTranscriptBytes,
299 readerSignature.value(), testEntriesEntryCounts)
David Zeuthen81603152020-02-11 22:04:24 -0500300 .isOk());
301
302 for (const auto& entry : testEntries) {
303 ASSERT_TRUE(credential
304 ->startRetrieveEntryValue(entry.nameSpace, entry.name,
305 entry.valueCbor.size(), entry.profileIds)
306 .isOk());
307
308 auto it = encryptedBlobs.find(&entry);
309 ASSERT_NE(it, encryptedBlobs.end());
310 const vector<vector<uint8_t>>& encryptedChunks = it->second;
311
312 vector<uint8_t> content;
313 for (const auto& encryptedChunk : encryptedChunks) {
314 vector<uint8_t> chunk;
315 ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
316 content.insert(content.end(), chunk.begin(), chunk.end());
317 }
318 EXPECT_EQ(content, entry.valueCbor);
319 }
320
David Zeuthen81603152020-02-11 22:04:24 -0500321 vector<uint8_t> mac;
322 vector<uint8_t> deviceNameSpacesBytes;
David Zeuthene35797f2020-02-27 14:25:54 -0500323 ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
David Zeuthen81603152020-02-11 22:04:24 -0500324 cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
325 ASSERT_EQ(
326 "{\n"
327 " 'PersonalData' : {\n"
328 " 'Last name' : 'Turing',\n"
329 " 'Birth date' : '19120623',\n"
330 " 'First name' : 'Alan',\n"
331 " 'Home address' : 'Maida Vale, London, England',\n"
332 " },\n"
333 " 'Image' : {\n"
334 " 'Portrait image' : <bstr size=262134 "
335 "sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
336 " },\n"
337 "}",
338 cborPretty);
339 // The data that is MACed is ["DeviceAuthentication", sessionTranscriptBytes, docType,
340 // deviceNameSpacesBytes] so build up that structure
341 cppbor::Array deviceAuthentication;
342 deviceAuthentication.add("DeviceAuthentication");
343 deviceAuthentication.add(sessionTranscript.clone());
Selene Huang92b61d62020-03-04 02:24:16 -0800344
345 string docType = "org.iso.18013-5.2019.mdl";
David Zeuthen81603152020-02-11 22:04:24 -0500346 deviceAuthentication.add(docType);
347 deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
348 vector<uint8_t> encodedDeviceAuthentication = deviceAuthentication.encode();
349 optional<vector<uint8_t>> signingPublicKey =
350 support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
351 EXPECT_TRUE(signingPublicKey);
352
353 // Derive the key used for MACing.
354 optional<vector<uint8_t>> readerEphemeralPrivateKey =
355 support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
356 optional<vector<uint8_t>> sharedSecret =
357 support::ecdh(signingPublicKey.value(), readerEphemeralPrivateKey.value());
358 ASSERT_TRUE(sharedSecret);
359 vector<uint8_t> salt = {0x00};
360 vector<uint8_t> info = {};
361 optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
362 ASSERT_TRUE(derivedKey);
363 optional<vector<uint8_t>> calculatedMac =
364 support::coseMac0(derivedKey.value(), {}, // payload
365 encodedDeviceAuthentication); // detached content
366 ASSERT_TRUE(calculatedMac);
367 EXPECT_EQ(mac, calculatedMac);
368}
369
370INSTANTIATE_TEST_SUITE_P(
371 Identity, IdentityAidl,
372 testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
373 android::PrintInstanceNameToString);
374// INSTANTIATE_TEST_SUITE_P(Identity, IdentityAidl,
375// testing::Values("android.hardware.identity.IIdentityCredentialStore/default"));
376
377} // namespace android::hardware::identity
378
379int main(int argc, char** argv) {
380 ::testing::InitGoogleTest(&argc, argv);
381 ::android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
382 ::android::ProcessState::self()->startThreadPool();
383 return RUN_ALL_TESTS();
384}