David Zeuthen | c75ac31 | 2019-10-28 13:16:45 -0400 | [diff] [blame^] | 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 |
| 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/ |
| 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 | |
| 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 | |
| 443 | int main(int argc, char** argv) { |
| 444 | ::testing::InitGoogleTest(&argc, argv); |
| 445 | return RUN_ALL_TESTS(); |
| 446 | } |