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 
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 
29 using std::optional;
30 using std::string;
31 using std::vector;
32 
33 namespace android {
34 namespace hardware {
35 namespace identity {
36 
TEST(IdentityCredentialSupport,encodeHex)37 TEST(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 
TEST(IdentityCredentialSupport,decodeHex)46 TEST(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 
TEST(IdentityCredentialSupport,CborPrettyPrint)58 TEST(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 
TEST(IdentityCredentialSupport,CborPrettyPrintCompound)84 TEST(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 
TEST(IdentityCredentialSupport,Signatures)151 TEST(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 
replaceLine(const string & str,ssize_t lineNumber,const string & replacement)177 string 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 
TEST(IdentityCredentialSupport,CoseSignatures)203 TEST(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 
TEST(IdentityCredentialSupport,CoseSignaturesAdditionalData)234 TEST(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 
generateCertChain(size_t numCerts)265 vector<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 
TEST(IdentityCredentialSupport,CoseSignaturesX5ChainWithSingleCert)280 TEST(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 
TEST(IdentityCredentialSupport,CoseSignaturesX5ChainWithMultipleCerts)306 TEST(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 
TEST(IdentityCredentialSupport,CertificateChain)332 TEST(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 
strToVec(const string & str)373 vector<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
TEST(IdentityCredentialSupport,hmacSha256)382 TEST(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/
TEST(IdentityCredentialSupport,CoseMac0)396 TEST(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 
TEST(IdentityCredentialSupport,CoseMac0DetachedContent)417 TEST(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 
439 }  // namespace identity
440 }  // namespace hardware
441 }  // namespace android
442 
main(int argc,char ** argv)443 int main(int argc, char** argv) {
444     ::testing::InitGoogleTest(&argc, argv);
445     return RUN_ALL_TESTS();
446 }
447