blob: c98a91ebc3fb783d2e96f28f444e7f6e1d905e44 [file] [log] [blame]
David Zeuthen630de2a2020-05-11 14:04:54 -04001/*
2 * Copyright 2020, 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#define LOG_TAG "EicOpsImpl"
18
19#include <optional>
20#include <tuple>
21#include <vector>
22
David Zeuthen1eb12b22021-09-11 13:59:43 -040023#ifndef _GNU_SOURCE
24#define _GNU_SOURCE
25#endif
26#include <string.h>
27
David Zeuthen630de2a2020-05-11 14:04:54 -040028#include <android-base/logging.h>
29#include <android-base/stringprintf.h>
David Zeuthen630de2a2020-05-11 14:04:54 -040030
31#include <android/hardware/identity/support/IdentityCredentialSupport.h>
32
33#include <openssl/sha.h>
34
35#include <openssl/aes.h>
36#include <openssl/bn.h>
37#include <openssl/crypto.h>
38#include <openssl/ec.h>
39#include <openssl/err.h>
40#include <openssl/evp.h>
41#include <openssl/hkdf.h>
42#include <openssl/hmac.h>
43#include <openssl/objects.h>
44#include <openssl/pem.h>
45#include <openssl/pkcs12.h>
46#include <openssl/rand.h>
47#include <openssl/x509.h>
48#include <openssl/x509_vfy.h>
49
50#include "EicOps.h"
51
David Zeuthen49f2d252020-10-16 11:27:24 -040052using ::std::map;
David Zeuthen630de2a2020-05-11 14:04:54 -040053using ::std::optional;
54using ::std::string;
55using ::std::tuple;
56using ::std::vector;
57
58void* eicMemSet(void* s, int c, size_t n) {
59 return memset(s, c, n);
60}
61
62void* eicMemCpy(void* dest, const void* src, size_t n) {
63 return memcpy(dest, src, n);
64}
65
66size_t eicStrLen(const char* s) {
67 return strlen(s);
68}
69
David Zeuthen1eb12b22021-09-11 13:59:43 -040070void* eicMemMem(const uint8_t* haystack, size_t haystackLen, const uint8_t* needle,
71 size_t needleLen) {
72 return memmem(haystack, haystackLen, needle, needleLen);
73}
74
David Zeuthen630de2a2020-05-11 14:04:54 -040075int eicCryptoMemCmp(const void* s1, const void* s2, size_t n) {
76 return CRYPTO_memcmp(s1, s2, n);
77}
78
79void eicOpsHmacSha256Init(EicHmacSha256Ctx* ctx, const uint8_t* key, size_t keySize) {
80 HMAC_CTX* realCtx = (HMAC_CTX*)ctx;
81 HMAC_CTX_init(realCtx);
82 if (HMAC_Init_ex(realCtx, key, keySize, EVP_sha256(), nullptr /* impl */) != 1) {
83 LOG(ERROR) << "Error initializing HMAC_CTX";
84 }
85}
86
87void eicOpsHmacSha256Update(EicHmacSha256Ctx* ctx, const uint8_t* data, size_t len) {
88 HMAC_CTX* realCtx = (HMAC_CTX*)ctx;
89 if (HMAC_Update(realCtx, data, len) != 1) {
90 LOG(ERROR) << "Error updating HMAC_CTX";
91 }
92}
93
94void eicOpsHmacSha256Final(EicHmacSha256Ctx* ctx, uint8_t digest[EIC_SHA256_DIGEST_SIZE]) {
95 HMAC_CTX* realCtx = (HMAC_CTX*)ctx;
96 unsigned int size = 0;
97 if (HMAC_Final(realCtx, digest, &size) != 1) {
98 LOG(ERROR) << "Error finalizing HMAC_CTX";
99 }
100 if (size != EIC_SHA256_DIGEST_SIZE) {
101 LOG(ERROR) << "Expected 32 bytes from HMAC_Final, got " << size;
102 }
103}
104
105void eicOpsSha256Init(EicSha256Ctx* ctx) {
106 SHA256_CTX* realCtx = (SHA256_CTX*)ctx;
107 SHA256_Init(realCtx);
108}
109
110void eicOpsSha256Update(EicSha256Ctx* ctx, const uint8_t* data, size_t len) {
111 SHA256_CTX* realCtx = (SHA256_CTX*)ctx;
112 SHA256_Update(realCtx, data, len);
113}
114
115void eicOpsSha256Final(EicSha256Ctx* ctx, uint8_t digest[EIC_SHA256_DIGEST_SIZE]) {
116 SHA256_CTX* realCtx = (SHA256_CTX*)ctx;
117 SHA256_Final(digest, realCtx);
118}
119
120bool eicOpsRandom(uint8_t* buf, size_t numBytes) {
121 optional<vector<uint8_t>> bytes = ::android::hardware::identity::support::getRandom(numBytes);
122 if (!bytes.has_value()) {
123 return false;
124 }
125 memcpy(buf, bytes.value().data(), numBytes);
126 return true;
127}
128
David Zeuthen1eb12b22021-09-11 13:59:43 -0400129bool eicNextId(uint32_t* id) {
130 uint32_t oldId = *id;
131 uint32_t newId = 0;
132
133 do {
134 union {
135 uint8_t value8;
136 uint32_t value32;
137 } value;
138 if (!eicOpsRandom(&value.value8, sizeof(value))) {
139 return false;
140 }
141 newId = value.value32;
142 } while (newId == oldId && newId == 0);
143
144 *id = newId;
145 return true;
146}
147
David Zeuthen630de2a2020-05-11 14:04:54 -0400148bool eicOpsEncryptAes128Gcm(
149 const uint8_t* key, // Must be 16 bytes
150 const uint8_t* nonce, // Must be 12 bytes
151 const uint8_t* data, // May be NULL if size is 0
152 size_t dataSize,
153 const uint8_t* additionalAuthenticationData, // May be NULL if size is 0
154 size_t additionalAuthenticationDataSize, uint8_t* encryptedData) {
155 vector<uint8_t> cppKey;
156 cppKey.resize(16);
157 memcpy(cppKey.data(), key, 16);
158
159 vector<uint8_t> cppData;
160 cppData.resize(dataSize);
161 if (dataSize > 0) {
162 memcpy(cppData.data(), data, dataSize);
163 }
164
165 vector<uint8_t> cppAAD;
166 cppAAD.resize(additionalAuthenticationDataSize);
167 if (additionalAuthenticationDataSize > 0) {
168 memcpy(cppAAD.data(), additionalAuthenticationData, additionalAuthenticationDataSize);
169 }
170
171 vector<uint8_t> cppNonce;
172 cppNonce.resize(12);
173 memcpy(cppNonce.data(), nonce, 12);
174
175 optional<vector<uint8_t>> cppEncryptedData =
176 android::hardware::identity::support::encryptAes128Gcm(cppKey, cppNonce, cppData,
177 cppAAD);
178 if (!cppEncryptedData.has_value()) {
179 return false;
180 }
181
182 memcpy(encryptedData, cppEncryptedData.value().data(), cppEncryptedData.value().size());
183 return true;
184}
185
186// Decrypts |encryptedData| using |key| and |additionalAuthenticatedData|,
187// returns resulting plaintext in |data| must be of size |encryptedDataSize| - 28.
188//
189// The format of |encryptedData| must be as specified in the
190// encryptAes128Gcm() function.
191bool eicOpsDecryptAes128Gcm(const uint8_t* key, // Must be 16 bytes
192 const uint8_t* encryptedData, size_t encryptedDataSize,
193 const uint8_t* additionalAuthenticationData,
194 size_t additionalAuthenticationDataSize, uint8_t* data) {
195 vector<uint8_t> keyVec;
196 keyVec.resize(16);
197 memcpy(keyVec.data(), key, 16);
198
199 vector<uint8_t> encryptedDataVec;
200 encryptedDataVec.resize(encryptedDataSize);
201 if (encryptedDataSize > 0) {
202 memcpy(encryptedDataVec.data(), encryptedData, encryptedDataSize);
203 }
204
205 vector<uint8_t> aadVec;
206 aadVec.resize(additionalAuthenticationDataSize);
207 if (additionalAuthenticationDataSize > 0) {
208 memcpy(aadVec.data(), additionalAuthenticationData, additionalAuthenticationDataSize);
209 }
210
211 optional<vector<uint8_t>> decryptedDataVec =
212 android::hardware::identity::support::decryptAes128Gcm(keyVec, encryptedDataVec,
213 aadVec);
214 if (!decryptedDataVec.has_value()) {
215 eicDebug("Error decrypting data");
216 return false;
217 }
218 if (decryptedDataVec.value().size() != encryptedDataSize - 28) {
219 eicDebug("Decrypted data is size %zd, expected %zd", decryptedDataVec.value().size(),
220 encryptedDataSize - 28);
221 return false;
222 }
223
224 if (decryptedDataVec.value().size() > 0) {
225 memcpy(data, decryptedDataVec.value().data(), decryptedDataVec.value().size());
226 }
227 return true;
228}
229
230bool eicOpsCreateEcKey(uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE],
231 uint8_t publicKey[EIC_P256_PUB_KEY_SIZE]) {
232 optional<vector<uint8_t>> keyPair = android::hardware::identity::support::createEcKeyPair();
233 if (!keyPair) {
234 eicDebug("Error creating EC keypair");
235 return false;
236 }
237 optional<vector<uint8_t>> privKey =
238 android::hardware::identity::support::ecKeyPairGetPrivateKey(keyPair.value());
239 if (!privKey) {
240 eicDebug("Error extracting private key");
241 return false;
242 }
243 if (privKey.value().size() != EIC_P256_PRIV_KEY_SIZE) {
David Zeuthen49f2d252020-10-16 11:27:24 -0400244 eicDebug("Private key is %zd bytes, expected %zd", privKey.value().size(),
245 (size_t)EIC_P256_PRIV_KEY_SIZE);
David Zeuthen630de2a2020-05-11 14:04:54 -0400246 return false;
247 }
248
249 optional<vector<uint8_t>> pubKey =
250 android::hardware::identity::support::ecKeyPairGetPublicKey(keyPair.value());
251 if (!pubKey) {
252 eicDebug("Error extracting public key");
253 return false;
254 }
255 // ecKeyPairGetPublicKey() returns 0x04 | x | y, we don't want the leading 0x04.
256 if (pubKey.value().size() != EIC_P256_PUB_KEY_SIZE + 1) {
David Zeuthen49f2d252020-10-16 11:27:24 -0400257 eicDebug("Public key is %zd bytes long, expected %zd", pubKey.value().size(),
David Zeuthen630de2a2020-05-11 14:04:54 -0400258 (size_t)EIC_P256_PRIV_KEY_SIZE + 1);
259 return false;
260 }
261
262 memcpy(privateKey, privKey.value().data(), EIC_P256_PRIV_KEY_SIZE);
263 memcpy(publicKey, pubKey.value().data() + 1, EIC_P256_PUB_KEY_SIZE);
264
265 return true;
266}
267
268bool eicOpsCreateCredentialKey(uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE], const uint8_t* challenge,
269 size_t challengeSize, const uint8_t* applicationId,
Seth Moorebe321132022-01-25 22:44:24 +0000270 size_t applicationIdSize, bool testCredential, uint8_t* cert,
271 size_t* certSize) {
272 vector<uint8_t> challengeVec(challengeSize);
273 memcpy(challengeVec.data(), challenge, challengeSize);
274
275 vector<uint8_t> applicationIdVec(applicationIdSize);
276 memcpy(applicationIdVec.data(), applicationId, applicationIdSize);
277
278 optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> ret =
279 android::hardware::identity::support::createEcKeyPairAndAttestation(
280 challengeVec, applicationIdVec, testCredential);
281 if (!ret) {
282 eicDebug("Error generating CredentialKey and attestation");
283 return false;
David Zeuthen630de2a2020-05-11 14:04:54 -0400284 }
285
Seth Moorebe321132022-01-25 22:44:24 +0000286 // Extract certificate chain.
287 vector<uint8_t> flatChain =
288 android::hardware::identity::support::certificateChainJoin(ret.value().second);
David Zeuthen630de2a2020-05-11 14:04:54 -0400289 if (*certSize < flatChain.size()) {
290 eicDebug("Buffer for certificate is only %zd bytes long, need %zd bytes", *certSize,
291 flatChain.size());
292 return false;
293 }
294 memcpy(cert, flatChain.data(), flatChain.size());
295 *certSize = flatChain.size();
296
297 // Extract private key.
298 optional<vector<uint8_t>> privKey =
Seth Moorebe321132022-01-25 22:44:24 +0000299 android::hardware::identity::support::ecKeyPairGetPrivateKey(ret.value().first);
David Zeuthen630de2a2020-05-11 14:04:54 -0400300 if (!privKey) {
301 eicDebug("Error extracting private key");
302 return false;
303 }
304 if (privKey.value().size() != EIC_P256_PRIV_KEY_SIZE) {
David Zeuthen49f2d252020-10-16 11:27:24 -0400305 eicDebug("Private key is %zd bytes, expected %zd", privKey.value().size(),
306 (size_t)EIC_P256_PRIV_KEY_SIZE);
David Zeuthen630de2a2020-05-11 14:04:54 -0400307 return false;
308 }
309
310 memcpy(privateKey, privKey.value().data(), EIC_P256_PRIV_KEY_SIZE);
311
312 return true;
313}
314
315bool eicOpsSignEcKey(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
316 const uint8_t signingKey[EIC_P256_PRIV_KEY_SIZE], unsigned int serial,
317 const char* issuerName, const char* subjectName, time_t validityNotBefore,
David Zeuthen49f2d252020-10-16 11:27:24 -0400318 time_t validityNotAfter, const uint8_t* proofOfBinding,
319 size_t proofOfBindingSize, uint8_t* cert, size_t* certSize) { // inout
David Zeuthen630de2a2020-05-11 14:04:54 -0400320 vector<uint8_t> signingKeyVec(EIC_P256_PRIV_KEY_SIZE);
321 memcpy(signingKeyVec.data(), signingKey, EIC_P256_PRIV_KEY_SIZE);
322
323 vector<uint8_t> pubKeyVec(EIC_P256_PUB_KEY_SIZE + 1);
324 pubKeyVec[0] = 0x04;
325 memcpy(pubKeyVec.data() + 1, publicKey, EIC_P256_PUB_KEY_SIZE);
326
David Zeuthen49f2d252020-10-16 11:27:24 -0400327 string serialDecimal = android::base::StringPrintf("%d", serial);
328
329 map<string, vector<uint8_t>> extensions;
330 if (proofOfBinding != nullptr) {
331 vector<uint8_t> proofOfBindingVec(proofOfBinding, proofOfBinding + proofOfBindingSize);
332 extensions["1.3.6.1.4.1.11129.2.1.26"] = proofOfBindingVec;
333 }
David Zeuthen630de2a2020-05-11 14:04:54 -0400334
335 optional<vector<uint8_t>> certVec =
336 android::hardware::identity::support::ecPublicKeyGenerateCertificate(
337 pubKeyVec, signingKeyVec, serialDecimal, issuerName, subjectName,
David Zeuthen49f2d252020-10-16 11:27:24 -0400338 validityNotBefore, validityNotAfter, extensions);
David Zeuthen630de2a2020-05-11 14:04:54 -0400339 if (!certVec) {
340 eicDebug("Error generating certificate");
341 return false;
342 }
343
344 if (*certSize < certVec.value().size()) {
345 eicDebug("Buffer for certificate is only %zd bytes long, need %zd bytes", *certSize,
346 certVec.value().size());
347 return false;
348 }
349 memcpy(cert, certVec.value().data(), certVec.value().size());
350 *certSize = certVec.value().size();
351
352 return true;
353}
354
355bool eicOpsEcDsa(const uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE],
356 const uint8_t digestOfData[EIC_SHA256_DIGEST_SIZE],
357 uint8_t signature[EIC_ECDSA_P256_SIGNATURE_SIZE]) {
358 vector<uint8_t> privKeyVec(EIC_P256_PRIV_KEY_SIZE);
359 memcpy(privKeyVec.data(), privateKey, EIC_P256_PRIV_KEY_SIZE);
360
361 vector<uint8_t> digestVec(EIC_SHA256_DIGEST_SIZE);
362 memcpy(digestVec.data(), digestOfData, EIC_SHA256_DIGEST_SIZE);
363
364 optional<vector<uint8_t>> derSignature =
365 android::hardware::identity::support::signEcDsaDigest(privKeyVec, digestVec);
366 if (!derSignature) {
367 eicDebug("Error signing data");
368 return false;
369 }
370
371 ECDSA_SIG* sig;
372 const unsigned char* p = derSignature.value().data();
373 sig = d2i_ECDSA_SIG(nullptr, &p, derSignature.value().size());
374 if (sig == nullptr) {
375 eicDebug("Error decoding DER signature");
376 return false;
377 }
378
379 if (BN_bn2binpad(sig->r, signature, 32) != 32) {
380 eicDebug("Error encoding r");
381 return false;
382 }
383 if (BN_bn2binpad(sig->s, signature + 32, 32) != 32) {
384 eicDebug("Error encoding s");
385 return false;
386 }
387
388 return true;
389}
390
391static const uint8_t hbkTest[16] = {0};
392static const uint8_t hbkReal[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
393
394const uint8_t* eicOpsGetHardwareBoundKey(bool testCredential) {
395 if (testCredential) {
396 return hbkTest;
397 }
398 return hbkReal;
399}
400
401bool eicOpsValidateAuthToken(uint64_t /* challenge */, uint64_t /* secureUserId */,
402 uint64_t /* authenticatorId */, int /* hardwareAuthenticatorType */,
403 uint64_t /* timeStamp */, const uint8_t* /* mac */,
404 size_t /* macSize */, uint64_t /* verificationTokenChallenge */,
405 uint64_t /* verificationTokenTimeStamp */,
406 int /* verificationTokenSecurityLevel */,
407 const uint8_t* /* verificationTokenMac */,
408 size_t /* verificationTokenMacSize */) {
409 // Here's where we would validate the passed-in |authToken| to assure ourselves
410 // that it comes from the e.g. biometric hardware and wasn't made up by an attacker.
411 //
412 // However this involves calculating the MAC which requires access to the to
413 // a pre-shared key which we don't have...
414 //
415 return true;
416}
417
418bool eicOpsX509GetPublicKey(const uint8_t* x509Cert, size_t x509CertSize, uint8_t* publicKey,
419 size_t* publicKeySize) {
420 vector<uint8_t> chain;
421 chain.resize(x509CertSize);
422 memcpy(chain.data(), x509Cert, x509CertSize);
423 optional<vector<uint8_t>> res =
424 android::hardware::identity::support::certificateChainGetTopMostKey(chain);
425 if (!res) {
426 return false;
427 }
428 if (res.value().size() > *publicKeySize) {
429 eicDebug("Public key size is %zd but buffer only has room for %zd bytes",
430 res.value().size(), *publicKeySize);
431 return false;
432 }
433 *publicKeySize = res.value().size();
434 memcpy(publicKey, res.value().data(), *publicKeySize);
435 eicDebug("Extracted %zd bytes public key from %zd bytes X.509 cert", *publicKeySize,
436 x509CertSize);
437 return true;
438}
439
440bool eicOpsX509CertSignedByPublicKey(const uint8_t* x509Cert, size_t x509CertSize,
441 const uint8_t* publicKey, size_t publicKeySize) {
442 vector<uint8_t> certVec(x509Cert, x509Cert + x509CertSize);
443 vector<uint8_t> publicKeyVec(publicKey, publicKey + publicKeySize);
444 return android::hardware::identity::support::certificateSignedByPublicKey(certVec,
445 publicKeyVec);
446}
447
448bool eicOpsEcDsaVerifyWithPublicKey(const uint8_t* digest, size_t digestSize,
449 const uint8_t* signature, size_t signatureSize,
450 const uint8_t* publicKey, size_t publicKeySize) {
451 vector<uint8_t> digestVec(digest, digest + digestSize);
452 vector<uint8_t> signatureVec(signature, signature + signatureSize);
453 vector<uint8_t> publicKeyVec(publicKey, publicKey + publicKeySize);
454
455 vector<uint8_t> derSignature;
456 if (!android::hardware::identity::support::ecdsaSignatureCoseToDer(signatureVec,
457 derSignature)) {
458 LOG(ERROR) << "Error convering signature to DER format";
459 return false;
460 }
461
462 if (!android::hardware::identity::support::checkEcDsaSignature(digestVec, derSignature,
463 publicKeyVec)) {
464 LOG(ERROR) << "Signature check failed";
465 return false;
466 }
467 return true;
468}
469
470bool eicOpsEcdh(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
471 const uint8_t privateKey[EIC_P256_PUB_KEY_SIZE],
472 uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE]) {
473 vector<uint8_t> pubKeyVec(EIC_P256_PUB_KEY_SIZE + 1);
474 pubKeyVec[0] = 0x04;
475 memcpy(pubKeyVec.data() + 1, publicKey, EIC_P256_PUB_KEY_SIZE);
476
477 vector<uint8_t> privKeyVec(EIC_P256_PRIV_KEY_SIZE);
478 memcpy(privKeyVec.data(), privateKey, EIC_P256_PRIV_KEY_SIZE);
479
480 optional<vector<uint8_t>> shared =
481 android::hardware::identity::support::ecdh(pubKeyVec, privKeyVec);
482 if (!shared) {
483 LOG(ERROR) << "Error performing ECDH";
484 return false;
485 }
486 if (shared.value().size() != EIC_P256_COORDINATE_SIZE) {
487 LOG(ERROR) << "Unexpected size of shared secret " << shared.value().size() << " expected "
488 << EIC_P256_COORDINATE_SIZE << " bytes";
489 return false;
490 }
491 memcpy(sharedSecret, shared.value().data(), EIC_P256_COORDINATE_SIZE);
492 return true;
493}
494
495bool eicOpsHkdf(const uint8_t* sharedSecret, size_t sharedSecretSize, const uint8_t* salt,
496 size_t saltSize, const uint8_t* info, size_t infoSize, uint8_t* output,
497 size_t outputSize) {
498 vector<uint8_t> sharedSecretVec(sharedSecretSize);
499 memcpy(sharedSecretVec.data(), sharedSecret, sharedSecretSize);
500 vector<uint8_t> saltVec(saltSize);
501 memcpy(saltVec.data(), salt, saltSize);
502 vector<uint8_t> infoVec(infoSize);
503 memcpy(infoVec.data(), info, infoSize);
504
505 optional<vector<uint8_t>> result = android::hardware::identity::support::hkdf(
506 sharedSecretVec, saltVec, infoVec, outputSize);
507 if (!result) {
508 LOG(ERROR) << "Error performing HKDF";
509 return false;
510 }
511 if (result.value().size() != outputSize) {
512 LOG(ERROR) << "Unexpected size of HKDF " << result.value().size() << " expected "
513 << outputSize;
514 return false;
515 }
516 memcpy(output, result.value().data(), outputSize);
517 return true;
518}
519
520#ifdef EIC_DEBUG
521
522void eicPrint(const char* format, ...) {
523 va_list args;
524 va_start(args, format);
Seth Moorebe321132022-01-25 22:44:24 +0000525 vfprintf(stderr, format, args);
David Zeuthen630de2a2020-05-11 14:04:54 -0400526 va_end(args);
David Zeuthen630de2a2020-05-11 14:04:54 -0400527}
528
529void eicHexdump(const char* message, const uint8_t* data, size_t dataSize) {
530 vector<uint8_t> dataVec(dataSize);
531 memcpy(dataVec.data(), data, dataSize);
532 android::hardware::identity::support::hexdump(message, dataVec);
533}
534
535void eicCborPrettyPrint(const uint8_t* cborData, size_t cborDataSize, size_t maxBStrSize) {
536 vector<uint8_t> cborDataVec(cborDataSize);
537 memcpy(cborDataVec.data(), cborData, cborDataSize);
538 string str =
539 android::hardware::identity::support::cborPrettyPrint(cborDataVec, maxBStrSize, {});
540 fprintf(stderr, "%s\n", str.c_str());
541}
542
543#endif // EIC_DEBUG