blob: 266f2632039282ad7cb242b2da902864271e1fa2 [file] [log] [blame]
David Zeuthenc75ac312019-10-28 13:16:45 -04001/*
2 * Copyright (c) 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <iomanip>
18#include <iostream>
19#include <sstream>
20
21#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23
24#include <android/hardware/identity/support/IdentityCredentialSupport.h>
25
26#include <cppbor.h>
27#include <cppbor_parse.h>
28
29using std::optional;
30using std::string;
31using std::vector;
32
33namespace android {
34namespace hardware {
35namespace identity {
36
37TEST(IdentityCredentialSupport, encodeHex) {
38 EXPECT_EQ("", support::encodeHex(vector<uint8_t>({})));
39 EXPECT_EQ("01", support::encodeHex(vector<uint8_t>({1})));
40 EXPECT_EQ("000102030405060708090a0b0c0d0e0f10",
41 support::encodeHex(
42 vector<uint8_t>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})));
43 EXPECT_EQ("0102ffe060", support::encodeHex(vector<uint8_t>({1, 2, 255, 224, 96})));
44}
45
46TEST(IdentityCredentialSupport, decodeHex) {
47 EXPECT_EQ(vector<uint8_t>({}), support::decodeHex(""));
48 EXPECT_EQ(vector<uint8_t>({1}), support::decodeHex("01"));
49
50 EXPECT_EQ(vector<uint8_t>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}),
51 support::decodeHex("000102030405060708090a0b0c0d0e0f10"));
52
53 EXPECT_FALSE(support::decodeHex("0g"));
54 EXPECT_FALSE(support::decodeHex("0"));
55 EXPECT_FALSE(support::decodeHex("012"));
56}
57
58TEST(IdentityCredentialSupport, CborPrettyPrint) {
59 EXPECT_EQ("'Some text'", support::cborPrettyPrint(cppbor::Tstr("Some text").encode()));
60
61 EXPECT_EQ("''", support::cborPrettyPrint(cppbor::Tstr("").encode()));
62
63 EXPECT_EQ("{0x01, 0x00, 0x02, 0xf0, 0xff, 0x40}",
64 support::cborPrettyPrint(
65 cppbor::Bstr(vector<uint8_t>({1, 0, 2, 240, 255, 64})).encode()));
66
67 EXPECT_EQ("{}", support::cborPrettyPrint(cppbor::Bstr(vector<uint8_t>()).encode()));
68
69 EXPECT_EQ("true", support::cborPrettyPrint(cppbor::Bool(true).encode()));
70
71 EXPECT_EQ("false", support::cborPrettyPrint(cppbor::Bool(false).encode()));
72
73 EXPECT_EQ("42", support::cborPrettyPrint(cppbor::Uint(42).encode()));
74
75 EXPECT_EQ("9223372036854775807", // 0x7fff ffff ffff ffff
76 support::cborPrettyPrint(cppbor::Uint(std::numeric_limits<int64_t>::max()).encode()));
77
78 EXPECT_EQ("-42", support::cborPrettyPrint(cppbor::Nint(-42).encode()));
79
80 EXPECT_EQ("-9223372036854775808", // -0x8000 0000 0000 0000
81 support::cborPrettyPrint(cppbor::Nint(std::numeric_limits<int64_t>::min()).encode()));
82}
83
84TEST(IdentityCredentialSupport, CborPrettyPrintCompound) {
85 cppbor::Array array = cppbor::Array("foo", "bar", "baz");
86 EXPECT_EQ("['foo', 'bar', 'baz', ]", support::cborPrettyPrint(array.encode()));
87
88 cppbor::Map map = cppbor::Map().add("foo", 42).add("bar", 43).add("baz", 44);
89 EXPECT_EQ(
90 "{\n"
91 " 'foo' : 42,\n"
92 " 'bar' : 43,\n"
93 " 'baz' : 44,\n"
94 "}",
95 support::cborPrettyPrint(map.encode()));
96
97 cppbor::Array array2 = cppbor::Array(cppbor::Tstr("Some text"), cppbor::Nint(-42));
98 EXPECT_EQ("['Some text', -42, ]", support::cborPrettyPrint(array2.encode()));
99
100 cppbor::Map map2 = cppbor::Map().add(42, "foo").add(43, "bar").add(44, "baz");
101 EXPECT_EQ(
102 "{\n"
103 " 42 : 'foo',\n"
104 " 43 : 'bar',\n"
105 " 44 : 'baz',\n"
106 "}",
107 support::cborPrettyPrint(map2.encode()));
108
109 cppbor::Array deeplyNestedArrays =
110 cppbor::Array(cppbor::Array(cppbor::Array("a", "b", "c")),
111 cppbor::Array(cppbor::Array("d", "e", cppbor::Array("f", "g"))));
112 EXPECT_EQ(
113 "[\n"
114 " ['a', 'b', 'c', ],\n"
115 " [\n 'd',\n"
116 " 'e',\n"
117 " ['f', 'g', ],\n"
118 " ],\n"
119 "]",
120 support::cborPrettyPrint(deeplyNestedArrays.encode()));
121
122 EXPECT_EQ(
123 "[\n"
124 " {0x0a, 0x0b},\n"
125 " 'foo',\n"
126 " 42,\n"
127 " ['foo', 'bar', 'baz', ],\n"
128 " {\n"
129 " 'foo' : 42,\n"
130 " 'bar' : 43,\n"
131 " 'baz' : 44,\n"
132 " },\n"
133 " {\n"
134 " 'deep1' : ['Some text', -42, ],\n"
135 " 'deep2' : {\n"
136 " 42 : 'foo',\n"
137 " 43 : 'bar',\n"
138 " 44 : 'baz',\n"
139 " },\n"
140 " },\n"
141 "]",
142 support::cborPrettyPrint(cppbor::Array(cppbor::Bstr(vector<uint8_t>{10, 11}),
143 cppbor::Tstr("foo"), cppbor::Uint(42),
144 std::move(array), std::move(map),
145 (cppbor::Map()
146 .add("deep1", std::move(array2))
147 .add("deep2", std::move(map2))))
148 .encode()));
149}
150
151TEST(IdentityCredentialSupport, Signatures) {
152 vector<uint8_t> data = {1, 2, 3};
153
154 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
155 ASSERT_TRUE(keyPair);
156 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
157 ASSERT_TRUE(privKey);
158 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
159 ASSERT_TRUE(pubKey);
160
161 optional<vector<uint8_t>> signature = support::signEcDsa(privKey.value(), data);
162 ASSERT_TRUE(
163 support::checkEcDsaSignature(support::sha256(data), signature.value(), pubKey.value()));
164
165 // Manipulate the signature, check that verification fails.
166 vector<uint8_t> modifiedSignature = signature.value();
167 modifiedSignature[0] ^= 0xff;
168 ASSERT_FALSE(
169 support::checkEcDsaSignature(support::sha256(data), modifiedSignature, pubKey.value()));
170
171 // Manipulate the data being checked, check that verification fails.
172 vector<uint8_t> modifiedDigest = support::sha256(data);
173 modifiedDigest[0] ^= 0xff;
174 ASSERT_FALSE(support::checkEcDsaSignature(modifiedDigest, signature.value(), pubKey.value()));
175}
176
177string replaceLine(const string& str, ssize_t lineNumber, const string& replacement) {
178 vector<string> lines;
179 std::istringstream f(str);
180 string s;
181 while (std::getline(f, s, '\n')) {
182 lines.push_back(s);
183 }
184
185 size_t numLines = lines.size();
186 if (lineNumber < 0) {
187 lineNumber = numLines - (-lineNumber);
188 }
189
190 string ret;
191 size_t n = 0;
192 for (const string& line : lines) {
193 if (n == lineNumber) {
194 ret += replacement + "\n";
195 } else {
196 ret += line + "\n";
197 }
198 n++;
199 }
200 return ret;
201}
202
203TEST(IdentityCredentialSupport, CoseSignatures) {
204 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
205 ASSERT_TRUE(keyPair);
206 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
207 ASSERT_TRUE(privKey);
208 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
209 ASSERT_TRUE(pubKey);
210
211 vector<uint8_t> data = {1, 2, 3};
212 optional<vector<uint8_t>> coseSign1 = support::coseSignEcDsa(
213 privKey.value(), data, {} /* detachedContent */, {} /* x5chain */);
214 ASSERT_TRUE(support::coseCheckEcDsaSignature(coseSign1.value(), {} /* detachedContent */,
215 pubKey.value()));
216
217 optional<vector<uint8_t>> payload = support::coseSignGetPayload(coseSign1.value());
218 ASSERT_TRUE(payload);
219 ASSERT_EQ(data, payload.value());
220
221 // Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
222 string out = support::cborPrettyPrint(coseSign1.value());
223 out = replaceLine(out, -2, " [] // Signature Removed");
224 EXPECT_EQ(
225 "[\n"
226 " {0xa1, 0x01, 0x26},\n" // Bytes of {1:-7} 1 is 'alg' label and -7 is "ECDSA 256"
227 " {},\n"
228 " {0x01, 0x02, 0x03},\n"
229 " [] // Signature Removed\n"
230 "]\n",
231 out);
232}
233
234TEST(IdentityCredentialSupport, CoseSignaturesAdditionalData) {
235 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
236 ASSERT_TRUE(keyPair);
237 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
238 ASSERT_TRUE(privKey);
239 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
240 ASSERT_TRUE(pubKey);
241
242 vector<uint8_t> detachedContent = {1, 2, 3};
243 optional<vector<uint8_t>> coseSign1 = support::coseSignEcDsa(privKey.value(), {} /* data */,
244 detachedContent, {} /* x5chain */);
245 ASSERT_TRUE(
246 support::coseCheckEcDsaSignature(coseSign1.value(), detachedContent, pubKey.value()));
247
248 optional<vector<uint8_t>> payload = support::coseSignGetPayload(coseSign1.value());
249 ASSERT_TRUE(payload);
250 ASSERT_EQ(0, payload.value().size());
251
252 // Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
253 string out = support::cborPrettyPrint(coseSign1.value());
254 out = replaceLine(out, -2, " [] // Signature Removed");
255 EXPECT_EQ(
256 "[\n"
257 " {0xa1, 0x01, 0x26},\n" // Bytes of {1:-7} 1 is 'alg' label and -7 is "ECDSA 256"
258 " {},\n"
259 " null,\n"
260 " [] // Signature Removed\n"
261 "]\n",
262 out);
263}
264
265vector<uint8_t> generateCertChain(size_t numCerts) {
266 vector<vector<uint8_t>> certs;
267
268 for (size_t n = 0; n < numCerts; n++) {
269 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
270 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
271 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
272
273 optional<vector<uint8_t>> cert = support::ecPublicKeyGenerateCertificate(
274 pubKey.value(), privKey.value(), "0001", "someIssuer", "someSubject", 0, 0);
275 certs.push_back(cert.value());
276 }
277 return support::certificateChainJoin(certs);
278}
279
280TEST(IdentityCredentialSupport, CoseSignaturesX5ChainWithSingleCert) {
281 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
282 ASSERT_TRUE(keyPair);
283 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
284 ASSERT_TRUE(privKey);
285 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
286 ASSERT_TRUE(pubKey);
287
288 vector<uint8_t> certChain = generateCertChain(1);
289 optional<vector<vector<uint8_t>>> splitCerts = support::certificateChainSplit(certChain);
290 ASSERT_EQ(1, splitCerts.value().size());
291
292 vector<uint8_t> detachedContent = {1, 2, 3};
293 optional<vector<uint8_t>> coseSign1 =
294 support::coseSignEcDsa(privKey.value(), {} /* data */, detachedContent, certChain);
295 ASSERT_TRUE(
296 support::coseCheckEcDsaSignature(coseSign1.value(), detachedContent, pubKey.value()));
297
298 optional<vector<uint8_t>> payload = support::coseSignGetPayload(coseSign1.value());
299 ASSERT_TRUE(payload);
300 ASSERT_EQ(0, payload.value().size());
301
302 optional<vector<uint8_t>> certsRecovered = support::coseSignGetX5Chain(coseSign1.value());
303 EXPECT_EQ(certsRecovered.value(), certChain);
304}
305
306TEST(IdentityCredentialSupport, CoseSignaturesX5ChainWithMultipleCerts) {
307 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
308 ASSERT_TRUE(keyPair);
309 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
310 ASSERT_TRUE(privKey);
311 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
312 ASSERT_TRUE(pubKey);
313
314 vector<uint8_t> certChain = generateCertChain(5);
315 optional<vector<vector<uint8_t>>> splitCerts = support::certificateChainSplit(certChain);
316 ASSERT_EQ(5, splitCerts.value().size());
317
318 vector<uint8_t> detachedContent = {1, 2, 3};
319 optional<vector<uint8_t>> coseSign1 =
320 support::coseSignEcDsa(privKey.value(), {} /* data */, detachedContent, certChain);
321 ASSERT_TRUE(
322 support::coseCheckEcDsaSignature(coseSign1.value(), detachedContent, pubKey.value()));
323
324 optional<vector<uint8_t>> payload = support::coseSignGetPayload(coseSign1.value());
325 ASSERT_TRUE(payload);
326 ASSERT_EQ(0, payload.value().size());
327
328 optional<vector<uint8_t>> certsRecovered = support::coseSignGetX5Chain(coseSign1.value());
329 EXPECT_EQ(certsRecovered.value(), certChain);
330}
331
332TEST(IdentityCredentialSupport, CertificateChain) {
333 optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
334 ASSERT_TRUE(keyPair);
335 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
336 ASSERT_TRUE(privKey);
337 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
338 ASSERT_TRUE(pubKey);
339
340 optional<vector<uint8_t>> cert = support::ecPublicKeyGenerateCertificate(
341 pubKey.value(), privKey.value(), "0001", "someIssuer", "someSubject", 0, 0);
342
343 optional<vector<uint8_t>> extractedPubKey =
344 support::certificateChainGetTopMostKey(cert.value());
345 ASSERT_TRUE(extractedPubKey);
346 ASSERT_EQ(pubKey.value(), extractedPubKey.value());
347
348 // We expect to the chain returned by ecPublicKeyGenerateCertificate() to only have a
349 // single element
350 optional<vector<vector<uint8_t>>> splitCerts = support::certificateChainSplit(cert.value());
351 ASSERT_EQ(1, splitCerts.value().size());
352 ASSERT_EQ(splitCerts.value()[0], cert.value());
353
354 optional<vector<uint8_t>> otherKeyPair = support::createEcKeyPair();
355 ASSERT_TRUE(otherKeyPair);
356 optional<vector<uint8_t>> otherPrivKey = support::ecKeyPairGetPrivateKey(keyPair.value());
357 ASSERT_TRUE(otherPrivKey);
358 optional<vector<uint8_t>> otherPubKey = support::ecKeyPairGetPublicKey(keyPair.value());
359 ASSERT_TRUE(otherPubKey);
360 optional<vector<uint8_t>> otherCert = support::ecPublicKeyGenerateCertificate(
361 otherPubKey.value(), privKey.value(), "0001", "someIssuer", "someSubject", 0, 0);
362
363 // Now both cert and otherCert are two distinct certificates. Let's make a
364 // chain and check that certificateChainSplit() works as expected.
365 ASSERT_NE(cert.value(), otherCert.value());
366 const vector<vector<uint8_t>> certs2 = {cert.value(), otherCert.value()};
367 vector<uint8_t> certs2combined = support::certificateChainJoin(certs2);
368 ASSERT_EQ(certs2combined.size(), cert.value().size() + otherCert.value().size());
369 optional<vector<vector<uint8_t>>> splitCerts2 = support::certificateChainSplit(certs2combined);
370 ASSERT_EQ(certs2, splitCerts2.value());
371}
372
373vector<uint8_t> strToVec(const string& str) {
374 vector<uint8_t> ret;
375 size_t size = str.size();
376 ret.resize(size);
377 memcpy(ret.data(), str.data(), size);
378 return ret;
379}
380
381// Test vector from https://en.wikipedia.org/wiki/HMAC
382TEST(IdentityCredentialSupport, hmacSha256) {
383 vector<uint8_t> key = strToVec("key");
384 vector<uint8_t> data = strToVec("The quick brown fox jumps over the lazy dog");
385
386 vector<uint8_t> expected =
387 support::decodeHex("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8")
388 .value();
389
390 optional<vector<uint8_t>> hmac = support::hmacSha256(key, data);
391 ASSERT_TRUE(hmac);
392 ASSERT_EQ(expected, hmac.value());
393}
394
395// See also CoseMac0 test in UtilUnitTest.java inside cts/tests/tests/identity/
396TEST(IdentityCredentialSupport, CoseMac0) {
397 vector<uint8_t> key;
398 key.resize(32);
399 vector<uint8_t> data = {0x10, 0x11, 0x12, 0x13};
400 vector<uint8_t> detachedContent = {};
401
402 optional<vector<uint8_t>> mac = support::coseMac0(key, data, detachedContent);
403 ASSERT_TRUE(mac);
404
405 EXPECT_EQ(
406 "[\n"
407 " {0xa1, 0x01, 0x05},\n"
408 " {},\n"
409 " {0x10, 0x11, 0x12, 0x13},\n"
410 " {0x6c, 0xec, 0xb5, 0x6a, 0xc9, 0x5c, 0xae, 0x3b, 0x41, 0x13, 0xde, 0xa4, 0xd8, "
411 "0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
412 "0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
413 "]",
414 support::cborPrettyPrint(mac.value()));
415}
416
417TEST(IdentityCredentialSupport, CoseMac0DetachedContent) {
418 vector<uint8_t> key;
419 key.resize(32);
420 vector<uint8_t> data = {};
421 vector<uint8_t> detachedContent = {0x10, 0x11, 0x12, 0x13};
422
423 optional<vector<uint8_t>> mac = support::coseMac0(key, data, detachedContent);
424 ASSERT_TRUE(mac);
425
426 // Same HMAC as in CoseMac0 test, only difference is that payload is null.
427 EXPECT_EQ(
428 "[\n"
429 " {0xa1, 0x01, 0x05},\n"
430 " {},\n"
431 " null,\n"
432 " {0x6c, 0xec, 0xb5, 0x6a, 0xc9, 0x5c, 0xae, 0x3b, 0x41, 0x13, 0xde, 0xa4, 0xd8, "
433 "0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
434 "0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
435 "]",
436 support::cborPrettyPrint(mac.value()));
437}
438
David Zeuthen34abaae2020-10-26 20:26:36 -0400439// Generates a private key in DER format for a small value of 'd'.
440//
441// Used for test vectors.
442//
443vector<uint8_t> p256PrivateKeyFromD(uint8_t d) {
444 vector<uint8_t> privateUncompressed;
445 privateUncompressed.resize(32);
446 privateUncompressed[31] = d;
447 optional<vector<uint8_t>> privateKey = support::ecPrivateKeyToKeyPair(privateUncompressed);
448 return privateKey.value();
449}
450
451std::pair<vector<uint8_t>, vector<uint8_t>> p256PrivateKeyGetXandY(
452 const vector<uint8_t> privateKey) {
453 optional<vector<uint8_t>> publicUncompressed = support::ecKeyPairGetPublicKey(privateKey);
454 vector<uint8_t> x = vector<uint8_t>(publicUncompressed.value().begin() + 1,
455 publicUncompressed.value().begin() + 33);
456 vector<uint8_t> y = vector<uint8_t>(publicUncompressed.value().begin() + 33,
457 publicUncompressed.value().begin() + 65);
458 return std::make_pair(x, y);
459}
460
461const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
462 // TODO: Need cast until libcppbor's Map::get() is marked as const
463 auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
464 if (!found) {
465 return nullptr;
466 }
467 return item.get();
468}
469
470const cppbor::Array* findArrayValueForTstr(const cppbor::Map* map, const string& keyValue) {
471 const cppbor::Item* item = findValueForTstr(map, keyValue);
472 if (item == nullptr) {
473 return nullptr;
474 }
475 return item->asArray();
476}
477
478const cppbor::Map* findMapValueForTstr(const cppbor::Map* map, const string& keyValue) {
479 const cppbor::Item* item = findValueForTstr(map, keyValue);
480 if (item == nullptr) {
481 return nullptr;
482 }
483 return item->asMap();
484}
485
486const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
487 const cppbor::Item* item = findValueForTstr(map, keyValue);
488 if (item == nullptr) {
489 return nullptr;
490 }
491 return item->asSemantic();
492}
493
494const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
495 const cppbor::Item* item = findValueForTstr(map, keyValue);
496 if (item == nullptr) {
497 return nullptr;
498 }
499 const cppbor::Tstr* tstr = item->asTstr();
500 if (tstr == nullptr) {
501 return "";
502 }
503 return tstr->value();
504}
505
506TEST(IdentityCredentialSupport, testVectors_18013_5) {
507 // This is a test against known vectors for ISO 18013-5.
508 //
509 // The objective of this test is to verify that support::calcEMacKey() and
510 // support::calcMac() agree with the given test vectors.
511 //
512
513 // We're given static device key:
514 //
515 // x: 28412803729898893058558238221310261427084375743576167377786533380249859400145
516 // y: 65403602826180996396520286939226973026599920614829401631985882360676038096704
517 // d: 11
518 //
519 vector<uint8_t> deviceKey = p256PrivateKeyFromD(11);
520 auto [deviceKeyX, deviceKeyY] = p256PrivateKeyGetXandY(deviceKey);
521 EXPECT_EQ(support::encodeHex(deviceKeyX),
522 "3ed113b7883b4c590638379db0c21cda16742ed0255048bf433391d374bc21d1");
523 EXPECT_EQ(support::encodeHex(deviceKeyY),
524 "9099209accc4c8a224c843afa4f4c68a090d04da5e9889dae2f8eefce82a3740");
525
526 // We're given Ephemeral reader key:
527 //
528 // x: 59535862115950685744176693329402396749019581632805653266809849538337418304154
529 // y: 53776829996815113213100700404832701936765102413212294632483274374518863708344
530 // d: 20
531 //
532 vector<uint8_t> ephemeralReaderKey = p256PrivateKeyFromD(20);
533 auto [ephemeralReaderKeyX, ephemeralReaderKeyY] = p256PrivateKeyGetXandY(ephemeralReaderKey);
534 EXPECT_EQ(support::encodeHex(ephemeralReaderKeyX),
535 "83a01a9378395bab9bcd6a0ad03cc56d56e6b19250465a94a234dc4c6b28da9a");
536 EXPECT_EQ(support::encodeHex(ephemeralReaderKeyY),
537 "76e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923f54ff8240aaa86f640b8");
538 vector<uint8_t> ephemeralReaderKeyPublic =
539 support::ecKeyPairGetPublicKey(ephemeralReaderKey).value();
540
541 // We're given SessionEstablishment.
542 //
543 // SessionEstablishment = {
544 // "eReaderKey" : EReaderKeyBytes,
545 // "data" : bstr ; Encrypted mdoc request
546 // }
547 //
548 // Fish out EReaderKey from this.
549 //
550 // Note that the test vector below is incorrect insofar that it uses
551 // "eReaderKeyBytes" instead of just "eReaderKey". This will be corrected in
552 // the future.
553 //
554 optional<vector<uint8_t>> sessionEstablishmentEncoded = support::decodeHex(
555 "a26f655265616465724b65794279746573d818584ba40102200121582083a01a9378395bab9bcd6a0ad03c"
556 "c56d56e6b19250465a94a234dc4c6b28da9a22582076e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923"
557 "f54ff8240aaa86f640b864646174615902d945b31040c57491acb6d46a71f6c1f67a0b837df1bda9089fd0"
558 "3d0b1fdac3eeb2874a4ef6f90c97d03397186ba00a91102faae7e992e15f761d5662c3c37e3c6c2cfd2ebc"
559 "0bf59dbb8795e377bd7dd353230a41ba2d82294b45871a39b42ca531f26b52f46e356fbaf5075c8fd5b8b0"
560 "8a0df4a1d2e1bdd2e5d69169c1efbb51e393e608d833d325bebfbccb2e15ec08f94b264582fa7b93f7cebc"
561 "aa69f4f0cac2744d4fe35b04df26b2ae69273eed33024949080c1c95a6ef046beede959e9494297dd770af"
562 "4ac6fdd56783aa012555c213dc05cf0f41d1c95119720fcfe1621027f80e2ddd56ea3c1fc596f7b2579333"
563 "5a887ec788092b4a69d23b6219e27d0249b50b3fdcb95b5227007689362e0416b3bae3dae7cb56b4394666"
564 "4e3a3f60dce8d0b678fcd754bebf87bd2b0278dd782d952488a46f2874e34c2dd97bb74084a62b850e9719"
565 "252cd1dca7dbf1858193f6cf093cb3735312bbe1138cf29d8f350e285923f8ef07065299926720b42264e8"
566 "fd5d4b133e72f47c4e999ea689c353f8b41e50a59838e1a0d09eca4a557f77a9c389a0591ad1639119ce86"
567 "edc3320130480ee5101effae6066e8c85aac9ead2ae83e49c1e508aab02f753decbb522ea2200d62fd5d26"
568 "094bd35100bffaa1cdc6af9f7e9cfe7b63da6b5671cd5ac2cf5da450c72addc64cde441f3b7f7fdaf930ad"
569 "1e13388e8a7308d8ca4607e59e082db431a232e7e12cb692baeb4b2127e110ff24cea322ffdbc2e4d9c4c6"
570 "bed27753137d07897c8613627a799a560cf1a2d1edb3de029442862940a5ed7785eea8b6ace93aa6af0792"
571 "fd82877f62d07b757d0179ecbb7347004ecc9c0690d41f75f188cb17ffd2cec2ad8c9675466bb33b737a2a"
572 "e7592b2dcb8132aced2e572266f3f5413a5f9d6d4339a1e4662622af2e7e157a4ea3bfd5c4247e2ec91d8c"
573 "5c3c17427d5edfae673d0e0f782a8d40fa805fd8bc82ae3cb21a65cdad863e02309f6b01d1753fa884b778"
574 "f6e019a2004d8964deeb11f1fd478fcb");
575 ASSERT_TRUE(sessionEstablishmentEncoded);
576 auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
577 const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
578 ASSERT_NE(sessionEstablishment, nullptr);
579 const cppbor::Semantic* eReaderKeyBytes =
580 findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
581 ASSERT_NE(eReaderKeyBytes, nullptr);
582 ASSERT_EQ(eReaderKeyBytes->value(), 24);
583 const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
584 ASSERT_NE(eReaderKeyBstr, nullptr);
585 vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
586 // TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
587
588 // We're given DeviceEngagement.
589 //
590 vector<uint8_t> deviceEngagementEncoded =
591 support::decodeHex(
592 "a20063312e30018201d818584ba401022001215820cef66d6b2a3a993e591214d1ea223fb545ca"
593 "6c471c48306e4c36069404c5723f225820878662a229aaae906e123cdd9d3b4c10590ded29fe75"
594 "1eeeca34bbaa44af0773")
595 .value();
596
597 // Now calculate SessionTranscriptBytes. It is defined as
598 //
599 // SessionTranscript = [
600 // DeviceEngagementBytes,
601 // EReaderKeyBytes,
602 // Handover
603 // ]
604 //
605 // SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
606 //
607 cppbor::Array sessionTranscript;
608 sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
609 sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
610 sessionTranscript.add(cppbor::Null());
611 vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
612 vector<uint8_t> sessionTranscriptBytes =
613 cppbor::Semantic(24, sessionTranscriptEncoded).encode();
614
615 // The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
616 //
617 // Verify that support::calcEMacKey() gets the same result.
618 //
619 optional<vector<uint8_t>> eMacKey =
620 support::calcEMacKey(support::ecKeyPairGetPrivateKey(deviceKey).value(), // private key
621 ephemeralReaderKeyPublic, // public key
622 sessionTranscriptBytes); // sessionTranscriptBytes
623 ASSERT_TRUE(eMacKey);
624 ASSERT_EQ(support::encodeHex(eMacKey.value()),
625 "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
626
627 // Also do it the other way around
628 //
629 optional<vector<uint8_t>> eMacKey2 = support::calcEMacKey(
630 support::ecKeyPairGetPrivateKey(ephemeralReaderKey).value(), // private key
631 support::ecKeyPairGetPublicKey(deviceKey).value(), // public key
632 sessionTranscriptBytes); // sessionTranscriptBytes
633 ASSERT_TRUE(eMacKey2);
634 ASSERT_EQ(support::encodeHex(eMacKey2.value()),
635 "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
636
637 // We're given DeviceResponse
638 //
639 vector<uint8_t> deviceResponseEncoded =
640 support::decodeHex(
641 "a36776657273696f6e63312e3069646f63756d656e747381a367646f6354797065756f72672e69"
642 "736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d6553706163"
643 "6573a2716f72672e69736f2e31383031332e352e3181d8185863a4686469676573744944016672"
644 "616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e9"
645 "71656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456"
646 "616c756563446f656b636f6d2e6578616d706c6581d8185864a468646967657374494401667261"
647 "6e646f6d5820218ecf13521b53f4b96abaebe56417afec0e4c91fc8fb26086cd1e5cdc1a94ff71"
648 "656c656d656e744964656e7469666965726f616e6f746865725f656c656d656e746c656c656d65"
649 "6e7456616c75650a6a697373756572417574688443a10126a118215901d2308201ce30820174a0"
650 "0302010202141f7d44f4f107c5ee3f566049cf5d72de294b0d23300a06082a8648ce3d04030230"
651 "233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e17"
652 "0d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504"
653 "030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106"
654 "082a8648ce3d03010703420004301d9e502dc7e05da85da026a7ae9aa0fac9db7d52a95b3e3e3f"
655 "9aa0a1b45b8b6551b6f6b3061223e0d23c026b017d72298d9ae46887ca61d58db6aea17ee267a3"
656 "8187308184301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c"
657 "0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e04160414"
658 "7bef4db59a1ffb07592bfc57f4743b8a73aea792300e0603551d0f0101ff040403020780301506"
659 "03551d250101ff040b3009060728818c5d050102300a06082a8648ce3d04030203480030450220"
660 "21d52fb1fbda80e5bfda1e8dfb1bc7bf0acb7261d5c9ff54425af76eb21571c602210082bf301f"
661 "89e0a2cb9ca9c9050352de80b47956764f7a3e07bf6a8cd87528a3b55901d2d8185901cda66776"
662 "657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c75"
663 "6544696765737473a2716f72672e69736f2e31383031332e352e31a20058203b22af1126771f02"
664 "f0ea0d546d4ee3c5b51637381154f5211b79daf5f9facaa8015820f2cba0ce3cde5df901a3da75"
665 "13a4d7f7225fdfe5a306544529bf3dbcce655ca06b636f6d2e6578616d706c65a200582072636d"
666 "ddc282424a63499f4b3927aaa3b74da7b9c0134178bf735e949e4a761e01582006322d3cbe6603"
667 "876bdacc5b6679b51b0fc53d029c244fd5ea719d9028459c916d6465766963654b6579496e666f"
668 "a1696465766963654b6579a4010220012158203ed113b7883b4c590638379db0c21cda16742ed0"
669 "255048bf433391d374bc21d12258209099209accc4c8a224c843afa4f4c68a090d04da5e9889da"
670 "e2f8eefce82a374067646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c"
671 "76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a"
672 "30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c"
673 "6964556e74696cc074323032312d31302d30315431333a33303a30325a5840273ec1b59817d571"
674 "b5a2c5c0ab0ea213d42acb18547fd7097afcc888a22ecbb863c6461ce0e240880895b4aaa84308"
675 "784571c7be7aa3a2e7e3a2ea1a145ed1966c6465766963655369676e6564a26a6e616d65537061"
676 "636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f6582009"
677 "da7c964ac004ec36ec64edd0c1abf50c03433c215c3ddb144768abcdf20a60667374617475730"
678 "0")
679 .value();
680 auto [deviceResponseItem, _, _2] = cppbor::parse(deviceResponseEncoded);
681 const cppbor::Map* deviceResponse = deviceResponseItem->asMap();
682 ASSERT_NE(deviceResponse, nullptr);
683 const cppbor::Array* documents = findArrayValueForTstr(deviceResponse, "documents");
684 ASSERT_NE(documents, nullptr);
685 ASSERT_EQ(documents->size(), 1);
686 const cppbor::Map* document = ((*documents)[0])->asMap();
687 ASSERT_NE(document, nullptr);
688
689 // Get docType
690 string docType = findStringValueForTstr(document, "docType");
691 ASSERT_EQ(docType, "org.iso.18013.5.1.mDL");
692
693 // Drill down...
694 const cppbor::Map* deviceSigned = findMapValueForTstr(document, "deviceSigned");
695 ASSERT_NE(deviceSigned, nullptr);
696
697 // Dig out the encoded form of DeviceNameSpaces
698 //
699 const cppbor::Semantic* deviceNameSpacesBytes =
700 findSemanticValueForTstr(deviceSigned, "nameSpaces");
701 ASSERT_NE(deviceNameSpacesBytes, nullptr);
702 ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
703 const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
704 ASSERT_NE(deviceNameSpacesBstr, nullptr);
705 vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
706
707 // (For this version of 18013-5, DeviceNameSpaces is always supposed to be empty, check that.)
708 EXPECT_EQ(deviceNameSpacesEncoded, cppbor::Map().encode());
709
710 const cppbor::Map* deviceAuth = findMapValueForTstr(deviceSigned, "deviceAuth");
711 ASSERT_NE(deviceAuth, nullptr);
712 // deviceMac is is the COSE_Mac0.. dig out the encoded form to check that
713 // support::calcMac() gives exactly the same bytes.
714 //
715 const cppbor::Array* deviceMac = findArrayValueForTstr(deviceAuth, "deviceMac");
716 ASSERT_NE(deviceMac, nullptr);
717 vector<uint8_t> deviceMacEncoded = deviceMac->encode();
718
719 // Now we calculate what it should be..
720 optional<vector<uint8_t>> calculatedMac =
721 support::calcMac(sessionTranscriptEncoded, // SessionTranscript
722 docType, // DocType
723 deviceNameSpacesEncoded, // DeviceNamespaces
724 eMacKey.value()); // EMacKey
725 ASSERT_TRUE(calculatedMac);
726
727 // ... and hopefully it's the same!
728 ASSERT_EQ(calculatedMac.value().size(), deviceMacEncoded.size());
729 EXPECT_TRUE(memcmp(calculatedMac.value().data(), deviceMacEncoded.data(),
730 deviceMacEncoded.size()) == 0);
731}
732
David Zeuthenc75ac312019-10-28 13:16:45 -0400733} // namespace identity
734} // namespace hardware
735} // namespace android
736
737int main(int argc, char** argv) {
738 ::testing::InitGoogleTest(&argc, argv);
739 return RUN_ALL_TESTS();
740}