1 /*
2  * Copyright (C) 2021 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 TLOG_TAG "apploader-cose"
18 
19 #include <apploader/cbor.h>
20 #include <apploader/cose.h>
21 #include <assert.h>
22 #include <inttypes.h>
23 #include <openssl/bn.h>
24 #include <openssl/crypto.h>
25 #include <openssl/ec.h>
26 #include <openssl/err.h>
27 #include <openssl/evp.h>
28 #include <openssl/rand.h>
29 #include <openssl/x509.h>
30 #include <stddef.h>
31 #include <trusty_log.h>
32 #include <array>
33 #include <optional>
34 #include <vector>
35 
36 #ifdef __COSE_HOST__
37 #define COSE_PRINT_ERROR(...)         \
38     if (!gSilenceErrors) {            \
39         fprintf(stderr, __VA_ARGS__); \
40     }
41 #else
42 #define COSE_PRINT_ERROR(...) \
43     if (!gSilenceErrors) {    \
44         TLOGE(__VA_ARGS__);   \
45     }
46 #endif
47 
48 #ifdef APPLOADER_PACKAGE_SIGN_P384
49 #define APPLOADER_DSA_LENGTH SHA384_DIGEST_LENGTH
50 #define APPLOADER_DSA_NID NID_secp384r1
51 #else
52 #define APPLOADER_DSA_LENGTH SHA256_DIGEST_LENGTH
53 #define APPLOADER_DSA_NID NID_X9_62_prime256v1
54 #endif
55 
56 #ifdef APPLOADER_PACKAGE_CIPHER_A256
57 #define EVP_aes_trusty_gcm() EVP_aes_256_gcm()
58 #else
59 #define EVP_aes_trusty_gcm() EVP_aes_128_gcm()
60 #endif
61 
62 static bool gSilenceErrors = false;
63 
64 constexpr size_t kEcdsaValueSize = APPLOADER_DSA_LENGTH;
65 constexpr size_t kEcdsaSignatureSize = 2 * kEcdsaValueSize;
66 
coseSetSilenceErrors(bool value)67 bool coseSetSilenceErrors(bool value) {
68     bool old = gSilenceErrors;
69     gSilenceErrors = value;
70     return old;
71 }
72 
73 using BIGNUM_Ptr = std::unique_ptr<BIGNUM, std::function<void(BIGNUM*)>>;
74 using EC_KEY_Ptr = std::unique_ptr<EC_KEY, std::function<void(EC_KEY*)>>;
75 using ECDSA_SIG_Ptr =
76         std::unique_ptr<ECDSA_SIG, std::function<void(ECDSA_SIG*)>>;
77 using EVP_CIPHER_CTX_Ptr =
78         std::unique_ptr<EVP_CIPHER_CTX, std::function<void(EVP_CIPHER_CTX*)>>;
79 
80 using SHADigest = std::array<uint8_t, kEcdsaValueSize>;
81 
coseBuildToBeSigned(const std::span<const uint8_t> & encodedProtectedHeaders,const std::vector<uint8_t> & data)82 static std::vector<uint8_t> coseBuildToBeSigned(
83         const std::span<const uint8_t>& encodedProtectedHeaders,
84         const std::vector<uint8_t>& data) {
85     cbor::VectorCborEncoder enc;
86     enc.encodeArray([&](auto& enc) {
87         enc.encodeTstr("Signature1");
88         enc.encodeBstr(encodedProtectedHeaders);
89         // We currently don't support Externally Supplied Data (RFC 8152
90         // section 4.3) so external_aad is the empty bstr
91         enc.encodeEmptyBstr();
92         enc.encodeBstr(data);
93     });
94 
95     return enc.intoVec();
96 }
97 
getRandom(size_t numBytes)98 static std::optional<std::vector<uint8_t>> getRandom(size_t numBytes) {
99     std::vector<uint8_t> output;
100     output.resize(numBytes);
101     if (RAND_bytes(output.data(), numBytes) != 1) {
102         COSE_PRINT_ERROR("RAND_bytes: failed getting %zu random\n", numBytes);
103         return {};
104     }
105     return output;
106 }
107 
108 #ifdef APPLOADER_PACKAGE_SIGN_P384
sha(const std::vector<std::tuple<const void *,size_t>> & data_list)109 static SHADigest sha(
110         const std::vector<std::tuple<const void*, size_t>>& data_list) {
111     SHADigest ret;
112     SHA512_CTX ctx;  // Note that SHA384 functions use a SHA512 context
113 
114     SHA384_Init(&ctx);
115 
116     for (auto data : data_list) {
117         SHA384_Update(&ctx, std::get<0>(data), std::get<1>(data));
118     }
119 
120     SHA384_Final((unsigned char*)ret.data(), &ctx);
121 
122     return ret;
123 }
124 #else
sha(const std::vector<std::tuple<const void *,size_t>> & data_list)125 static SHADigest sha(
126         const std::vector<std::tuple<const void*, size_t>>& data_list) {
127     SHADigest ret;
128     SHA256_CTX ctx;
129 
130     SHA256_Init(&ctx);
131 
132     for (auto data : data_list) {
133         SHA256_Update(&ctx, std::get<0>(data), std::get<1>(data));
134     }
135 
136     SHA256_Final((unsigned char*)ret.data(), &ctx);
137 
138     return ret;
139 }
140 #endif
141 
sha(const std::vector<uint8_t> & data)142 static SHADigest sha(const std::vector<uint8_t>& data) {
143     return sha({{data.data(), data.size()}});
144 }
145 
signEcDsaDigest(const std::vector<uint8_t> & key,const SHADigest & dataDigest)146 static std::optional<std::vector<uint8_t>> signEcDsaDigest(
147         const std::vector<uint8_t>& key,
148         const SHADigest& dataDigest) {
149     const unsigned char* k = key.data();
150     auto ecKey =
151             EC_KEY_Ptr(d2i_ECPrivateKey(nullptr, &k, key.size()), EC_KEY_free);
152     if (!ecKey) {
153         COSE_PRINT_ERROR("Error parsing EC private key\n");
154         return {};
155     }
156 
157     if (EC_KEY_check_key(ecKey.get()) == 0) {
158         COSE_PRINT_ERROR("Error checking EC private key\n");
159         return {};
160     }
161 
162     const EC_GROUP* ecGroup = EC_KEY_get0_group(ecKey.get());
163     if (EC_GROUP_get_curve_name(ecGroup) != APPLOADER_DSA_NID) {
164         COSE_PRINT_ERROR("Error checking EC group (not secp384r1)\n");
165         return {};
166     }
167 
168     auto sig = ECDSA_SIG_Ptr(
169             ECDSA_do_sign(dataDigest.data(), dataDigest.size(), ecKey.get()),
170             ECDSA_SIG_free);
171     if (!sig) {
172         COSE_PRINT_ERROR("Error signing digest:\n");
173         return {};
174     }
175     size_t len = i2d_ECDSA_SIG(sig.get(), nullptr);
176     std::vector<uint8_t> signature;
177     signature.resize(len);
178     unsigned char* p = (unsigned char*)signature.data();
179     i2d_ECDSA_SIG(sig.get(), &p);
180     return signature;
181 }
182 
signEcDsa(const std::vector<uint8_t> & key,const std::vector<uint8_t> & data)183 static std::optional<std::vector<uint8_t>> signEcDsa(
184         const std::vector<uint8_t>& key,
185         const std::vector<uint8_t>& data) {
186     return signEcDsaDigest(key, sha(data));
187 }
188 
ecdsaSignatureDerToCose(const std::vector<uint8_t> & ecdsaDerSignature,std::vector<uint8_t> & ecdsaCoseSignature)189 static bool ecdsaSignatureDerToCose(
190         const std::vector<uint8_t>& ecdsaDerSignature,
191         std::vector<uint8_t>& ecdsaCoseSignature) {
192     const unsigned char* p = ecdsaDerSignature.data();
193     auto sig =
194             ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, ecdsaDerSignature.size()),
195                           ECDSA_SIG_free);
196     if (!sig) {
197         COSE_PRINT_ERROR("Error decoding DER signature\n");
198         return false;
199     }
200 
201     const BIGNUM* rBn;
202     const BIGNUM* sBn;
203     ECDSA_SIG_get0(sig.get(), &rBn, &sBn);
204 
205     /*
206      * Older versions of OpenSSL also do not have BN_bn2binpad,
207      * so we need to use BN_bn2bin with the correct offsets.
208      * Each of the output values is a 32-byte big-endian number,
209      * while the inputs are BIGNUMs stored in host format.
210      * We can insert the padding ourselves by zeroing the output array,
211      * then placing the output of BN_bn2bin so its end aligns
212      * with the end of the 32-byte big-endian number.
213      */
214     auto rBnSize = BN_num_bytes(rBn);
215     if (rBnSize < 0 || static_cast<size_t>(rBnSize) > kEcdsaValueSize) {
216         COSE_PRINT_ERROR("Invalid ECDSA r value size (%d)\n", rBnSize);
217         return false;
218     }
219     auto sBnSize = BN_num_bytes(sBn);
220     if (sBnSize < 0 || static_cast<size_t>(sBnSize) > kEcdsaValueSize) {
221         COSE_PRINT_ERROR("Invalid ECDSA s value size (%d)\n", sBnSize);
222         return false;
223     }
224 
225     ecdsaCoseSignature.clear();
226     ecdsaCoseSignature.resize(kEcdsaSignatureSize, 0);
227     if (BN_bn2bin(rBn, ecdsaCoseSignature.data() + kEcdsaValueSize - rBnSize) !=
228         rBnSize) {
229         COSE_PRINT_ERROR("Error encoding r\n");
230         return false;
231     }
232     if (BN_bn2bin(sBn, ecdsaCoseSignature.data() + kEcdsaSignatureSize -
233                                sBnSize) != sBnSize) {
234         COSE_PRINT_ERROR("Error encoding s\n");
235         return false;
236     }
237     return true;
238 }
239 
coseSignEcDsa(const std::vector<uint8_t> & key,uint8_t keyId,const std::vector<uint8_t> & data,const std::span<const uint8_t> & encodedProtectedHeaders,std::span<const uint8_t> & unprotectedHeaders,bool detachContent,bool tagged)240 std::optional<std::vector<uint8_t>> coseSignEcDsa(
241         const std::vector<uint8_t>& key,
242         uint8_t keyId,
243         const std::vector<uint8_t>& data,
244         const std::span<const uint8_t>& encodedProtectedHeaders,
245         std::span<const uint8_t>& unprotectedHeaders,
246         bool detachContent,
247         bool tagged) {
248     cbor::VectorCborEncoder addnHeadersEnc;
249     addnHeadersEnc.encodeMap([&](auto& enc) {
250         enc.encodeKeyValue(COSE_LABEL_KID, [&](auto& enc) {
251             enc.encodeBstr(std::span(&keyId, 1));
252         });
253     });
254     auto updatedUnprotectedHeaders =
255             cbor::mergeMaps(unprotectedHeaders, addnHeadersEnc.view());
256     if (!updatedUnprotectedHeaders.has_value()) {
257         COSE_PRINT_ERROR("Error updating unprotected headers\n");
258         return {};
259     }
260 
261     std::vector<uint8_t> toBeSigned =
262             coseBuildToBeSigned(encodedProtectedHeaders, data);
263 
264     std::optional<std::vector<uint8_t>> derSignature =
265             signEcDsa(key, toBeSigned);
266     if (!derSignature) {
267         COSE_PRINT_ERROR("Error signing toBeSigned data\n");
268         return {};
269     }
270     std::vector<uint8_t> coseSignature;
271     if (!ecdsaSignatureDerToCose(derSignature.value(), coseSignature)) {
272         COSE_PRINT_ERROR(
273                 "Error converting ECDSA signature from DER to COSE format\n");
274         return {};
275     }
276 
277     auto arrayEncodingFn = [&](auto& enc) {
278         enc.encodeArray([&](auto& enc) {
279             /* 1: protected:empty_or_serialized_map */
280             enc.encodeBstr(encodedProtectedHeaders);
281 
282             /* 2: unprotected:map */
283             enc.copyBytes(updatedUnprotectedHeaders.value());
284 
285             /* 3: payload:bstr_or_nil */
286             if (detachContent) {
287                 enc.encodeNull();
288             } else {
289                 enc.encodeBstr(data);
290             }
291 
292             /* 4: signature:bstr */
293             enc.encodeBstr(coseSignature);
294         });
295     };
296 
297     cbor::VectorCborEncoder enc;
298     if (tagged) {
299         enc.encodeTag(COSE_TAG_SIGN1, arrayEncodingFn);
300     } else {
301         arrayEncodingFn(enc);
302     }
303 
304     return enc.intoVec();
305 }
306 
coseIsSigned(CoseByteView data,size_t * signatureLength)307 bool coseIsSigned(CoseByteView data, size_t* signatureLength) {
308     struct CborIn in;
309     uint64_t tag;
310 
311     CborInInit(data.data(), data.size(), &in);
312     while (!CborInAtEnd(&in)) {
313         if (CborReadTag(&in, &tag) == CBOR_READ_RESULT_OK) {
314             if (tag == COSE_TAG_SIGN1) {
315                 if (signatureLength) {
316                     /* read tag item to get its size */
317                     CborReadSkip(&in);
318                     *signatureLength = CborInOffset(&in);
319                 }
320                 return true;
321             }
322         } else if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
323             /*
324              * CborReadSkip uses a stack to track nested content so parsing can
325              * fail if nesting of CBOR items causes stack exhaustion. The COSE
326              * format does not cause stack exhaustion so the input must be bad.
327              */
328             return false;
329         }
330     }
331 
332     return false;
333 }
334 
checkEcDsaSignature(const SHADigest & digest,const uint8_t * signature,const uint8_t * publicKey,size_t publicKeySize)335 static bool checkEcDsaSignature(const SHADigest& digest,
336                                 const uint8_t* signature,
337                                 const uint8_t* publicKey,
338                                 size_t publicKeySize) {
339     auto rBn =
340             BIGNUM_Ptr(BN_bin2bn(signature, kEcdsaValueSize, nullptr), BN_free);
341     if (rBn.get() == nullptr) {
342         COSE_PRINT_ERROR("Error creating BIGNUM for r\n");
343         return false;
344     }
345 
346     auto sBn = BIGNUM_Ptr(
347             BN_bin2bn(signature + kEcdsaValueSize, kEcdsaValueSize, nullptr),
348             BN_free);
349     if (sBn.get() == nullptr) {
350         COSE_PRINT_ERROR("Error creating BIGNUM for s\n");
351         return false;
352     }
353 
354     auto sig = ECDSA_SIG_Ptr(ECDSA_SIG_new(), ECDSA_SIG_free);
355     if (!sig) {
356         COSE_PRINT_ERROR("Error allocating ECDSA_SIG\n");
357         return false;
358     }
359 
360     ECDSA_SIG_set0(sig.get(), rBn.release(), sBn.release());
361 
362     const unsigned char* k = publicKey;
363     auto ecKey =
364             EC_KEY_Ptr(d2i_EC_PUBKEY(nullptr, &k, publicKeySize), EC_KEY_free);
365     if (!ecKey) {
366         COSE_PRINT_ERROR("Error parsing EC public key\n");
367         return false;
368     }
369 
370     int rc = ECDSA_do_verify(digest.data(), digest.size(), sig.get(),
371                              ecKey.get());
372     if (rc != 1) {
373         COSE_PRINT_ERROR("Error verifying signature (rc=%d)\n", rc);
374         return false;
375     }
376 
377     return true;
378 }
379 
coseCheckEcDsaSignature(const std::vector<uint8_t> & signatureCoseSign1,const std::vector<uint8_t> & detachedContent,const std::vector<uint8_t> & publicKey)380 bool coseCheckEcDsaSignature(const std::vector<uint8_t>& signatureCoseSign1,
381                              const std::vector<uint8_t>& detachedContent,
382                              const std::vector<uint8_t>& publicKey) {
383     struct CborIn in;
384     CborInInit(signatureCoseSign1.data(), signatureCoseSign1.size(), &in);
385 
386     uint64_t tag;
387     /* COSE message tag is optional */
388     if (CborReadTag(&in, &tag) == CBOR_READ_RESULT_OK) {
389         if (tag != COSE_TAG_SIGN1) {
390             COSE_PRINT_ERROR("Passed-in COSE_Sign1 contained invalid tag\n");
391             return false;
392         }
393     }
394 
395     size_t arraySize;
396     if (CborReadArray(&in, &arraySize) != CBOR_READ_RESULT_OK) {
397         COSE_PRINT_ERROR("Value for COSE_Sign1 is not an array\n");
398         return false;
399     }
400 
401     if (arraySize != 4) {
402         COSE_PRINT_ERROR("Value for COSE_Sign1 is not an array of size 4\n");
403         return false;
404     }
405 
406     const uint8_t* encodedProtectedHeadersPtr;
407     size_t encodedProtectedHeadersSize;
408     if (CborReadBstr(&in, &encodedProtectedHeadersSize,
409                      &encodedProtectedHeadersPtr) != CBOR_READ_RESULT_OK) {
410         COSE_PRINT_ERROR("Value for encodedProtectedHeaders is not a bstr\n");
411         return false;
412     }
413     std::span encodedProtectedHeaders(encodedProtectedHeadersPtr,
414                                       encodedProtectedHeadersSize);
415 
416     size_t unprotectedHeadersSize;
417     if (CborReadMap(&in, &unprotectedHeadersSize) != CBOR_READ_RESULT_OK) {
418         COSE_PRINT_ERROR("Value for unprotectedHeaders is not a map\n");
419         return false;
420     }
421 
422     /* skip past unprotected headers by reading two items per map entry */
423     for (size_t item = 0; item < 2 * unprotectedHeadersSize; item++) {
424         if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
425             COSE_PRINT_ERROR("Passed-in COSE_Sign1 is not valid CBOR\n");
426             return false;
427         }
428     }
429 
430     const uint8_t* dataPtr;
431     size_t dataSize = 0;
432     if (CborReadBstr(&in, &dataSize, &dataPtr) != CBOR_READ_RESULT_OK) {
433         if (CborReadNull(&in) != CBOR_READ_RESULT_OK) {
434             COSE_PRINT_ERROR("Value for payload is not null or a bstr\n");
435             return false;
436         }
437     }
438     std::vector<uint8_t> data(dataPtr, dataPtr + dataSize);
439 
440     if (data.size() > 0 && detachedContent.size() > 0) {
441         COSE_PRINT_ERROR("data and detachedContent cannot both be non-empty\n");
442         return false;
443     }
444 
445     const uint8_t* coseSignatureData;
446     size_t coseSignatureSize;
447     if (CborReadBstr(&in, &coseSignatureSize, &coseSignatureData) !=
448         CBOR_READ_RESULT_OK) {
449         COSE_PRINT_ERROR("Value for signature is not a bstr\n");
450         return false;
451     }
452 
453     if (coseSignatureSize != kEcdsaSignatureSize) {
454         COSE_PRINT_ERROR("COSE signature length is %zu, expected %zu\n",
455                          coseSignatureSize, kEcdsaSignatureSize);
456         return false;
457     }
458 
459     // The last field is the payload, independently of how it's transported (RFC
460     // 8152 section 4.4). Since our API specifies only one of |data| and
461     // |detachedContent| can be non-empty, it's simply just the non-empty one.
462     auto& signaturePayload = data.size() > 0 ? data : detachedContent;
463 
464     std::vector<uint8_t> toBeSigned =
465             coseBuildToBeSigned(encodedProtectedHeaders, signaturePayload);
466     if (!checkEcDsaSignature(sha(toBeSigned), coseSignatureData,
467                              publicKey.data(), publicKey.size())) {
468         COSE_PRINT_ERROR("Signature check failed\n");
469         return false;
470     }
471 
472     return true;
473 }
474 
475 /*
476  * Strict signature verification code
477  */
478 static const uint8_t kSignatureHeader[] = {
479         /* clang-format off */
480     0xD2,       // 0xc0 = Tagged item | tag = 18 = COSE_TAG_SIGN1
481     0x84,       // 0x80 = Array       | len = 4
482 
483     // Array item 1
484 #ifdef APPLOADER_PACKAGE_SIGN_P384
485     0x55,       // 0x20 = Byte string | len = 21
486 #else
487     0x54,       // 0x20 = Byte string | len = 20
488 #endif
489 
490         0xA2,       // 0xa0 = Map         | items = 2
491 
492         // Map entry 1: key, value
493         0x01,       // 0x0 = unsigned int | val = 1 = COSE_LABEL_ALG
494 #ifdef APPLOADER_PACKAGE_SIGN_P384
495         0x38,       // 0x2 = Negative int | additional = 24 (1 byte val)
496         0x22,       // Value = 34
497                     // == -1 - 34 = -35 = COSE_ALG_ECDSA_384
498 #else
499         0x26,       // 0x2 = Negative int | value = 6
500                     // == -1 - 6 = -7 = COSE_ALG_ECDSA_256
501 #endif
502         // Map entry 2: key, value
503         0x3A,       // 0x3 = Negative int | additional = 26 = next 4 bytes
504         0x00,       // 0x00010000 = 65536
505         0x01,       //              -1 - 65536 = -65535 = COSE_LABEL_TRUSTY
506         0x00,
507         0x00,
508 
509         0x82,       // 0x80 = Array       | len = 2
510             0x69,       // 0x30 = Text string | len = 9
511             0x54,       // T
512             0x72,       // r
513             0x75,       // u
514             0x73,       // s
515             0x74,       // t
516             0x79,       // y
517             0x41,       // A
518             0x70,       // p
519             0x70,       // p
520             // Version
521             0x01,       // 0x00 = Small value | value = 1 = APPLOADER_SIGNATURE_FORMAT_VERSION_CURRENT
522 
523     // Array Item 2
524     0xA1,       // 0xa = Map          | items = 1
525     0x04,       // 0x0 = unsigned int | value = 4 = COSE_LABEL_KID
526     0x41,       // 0x4 = byte string  | len = 1
527     /* Next octet is the key Id */
528 
529         /* clang-format on */
530 };
531 
532 static const uint8_t kSignatureHeaderPart2[] = {
533         /* clang-format off */
534     0xF6,       // 0x7 = simple value | value = 22 = null
535     0x58,       // 0x2 = bytes string | additional = 24 = next 1 byte
536 #ifdef APPLOADER_PACKAGE_SIGN_P384
537     0x60        // length = 96
538 #else
539     0x40        // length = 64
540 #endif
541         /* clang-format on */
542 };
543 
544 static const uint8_t kSignature1Header[] = {
545         /* clang-format off */
546     0x84,       // 0x8 = array       | length = 4
547 
548     // Array item 1
549     0x6A,       // 0x6 = text string | length = 10
550         0x53,       // S
551         0x69,       // i
552         0x67,       // g
553         0x6E,       // n
554         0x61,       // a
555         0x74,       // t
556         0x75,       // u
557         0x72,       // r
558         0x65,       // e
559         0x31,       // 1
560 
561     // Array item 2
562 #ifdef APPLOADER_PACKAGE_SIGN_P384
563     0x55,       // 0x20 = Byte string | len = 21
564 #else
565     0x54,       // 0x20 = Byte string | len = 20
566 #endif
567         0xA2,       // 0xa0 = Map         | items = 2
568 
569         // Map entry 1: key, value
570         0x01,       // 0x0 = unsigned int | val = 1 = COSE_LABEL_ALG
571 #ifdef APPLOADER_PACKAGE_SIGN_P384
572         0x38,       // 0x2 = Negative int | additional = 24 (1 byte val)
573         0x22,       // Value = 34
574                     // == -1 - 34 = -35 = COSE_ALG_ECDSA_384
575 #else
576         0x26,       // 0x2 = Negative int | value = 6
577                     // == -1 - 6 = -7 = COSE_ALG_ECDSA_256
578 #endif
579         // Map entry 2: key, value
580         0x3A,       // 0x3 = Negative int | additional = 26 = next 4 bytes
581         0x00,       // 0x00010000 = 65536
582         0x01,       //              -1 - 65536 = -65535 = COSE_LABEL_TRUSTY
583         0x00,
584         0x00,
585 
586         0x82,       // 0x8 = Array       | len = 2
587                 0x69,       // 0x30 = Text string | len = 9
588                 0x54,       // T
589                 0x72,       // r
590                 0x75,       // u
591                 0x73,       // s
592                 0x74,       // t
593                 0x79,       // y
594                 0x41,       // A
595                 0x70,       // p
596                 0x70,       // p
597                 // Version
598                 0x01,       // 0x00 = Small value | value = 1
599                             //    = APPLOADER_SIGNATURE_FORMAT_VERSION_CURRENT
600 
601     // Array item 3
602     0x40,       // 0x4 = byte string    | len = 0
603 
604         /* clang-format on */
605 };
606 
607 /*
608  * Fixed offset constants
609  */
610 constexpr size_t kSignatureKeyIdOffset = sizeof(kSignatureHeader);
611 constexpr size_t kSignatureHeaderPart2Offset = kSignatureKeyIdOffset + 1;
612 constexpr size_t kSignatureOffset =
613         kSignatureHeaderPart2Offset + sizeof(kSignatureHeaderPart2);
614 constexpr size_t kPayloadOffset = kSignatureOffset + kEcdsaSignatureSize;
615 
strictCheckEcDsaSignature(const uint8_t * packageStart,size_t packageSize,GetKeyFn keyFn,const uint8_t ** outPackageStart,size_t * outPackageSize)616 bool strictCheckEcDsaSignature(const uint8_t* packageStart,
617                                size_t packageSize,
618                                GetKeyFn keyFn,
619                                const uint8_t** outPackageStart,
620                                size_t* outPackageSize) {
621     if (packageSize < kPayloadOffset) {
622         COSE_PRINT_ERROR("Passed-in COSE_Sign1 is not large enough\n");
623         return false;
624     }
625 
626     if (CRYPTO_memcmp(packageStart, kSignatureHeader,
627                       sizeof(kSignatureHeader))) {
628         COSE_PRINT_ERROR("Passed-in COSE_Sign1 is not valid CBOR\n");
629         return false;
630     }
631 
632     uint8_t kid = packageStart[kSignatureKeyIdOffset];
633     auto [publicKey, publicKeySize] = keyFn(kid);
634     if (!publicKey) {
635         COSE_PRINT_ERROR("Failed to retrieve public key\n");
636         return false;
637     }
638 
639     if (CRYPTO_memcmp(packageStart + kSignatureHeaderPart2Offset,
640                       kSignatureHeaderPart2, sizeof(kSignatureHeaderPart2))) {
641         COSE_PRINT_ERROR("Passed-in COSE_Sign1 is not valid CBOR\n");
642         return false;
643     }
644 
645     // The Signature1 structure encodes the payload as a bstr wrapping the
646     // actual contents (even if they already are CBOR), so we need to manually
647     // prepend a CBOR bstr header to the payload
648     constexpr size_t kMaxPayloadSizeHeaderSize = 9;
649     size_t payloadSize = packageSize - kPayloadOffset;
650     size_t payloadSizeHeaderSize = cbor::encodedSizeOf(payloadSize);
651     assert(payloadSizeHeaderSize <= kMaxPayloadSizeHeaderSize);
652 
653     uint8_t payloadSizeHeader[kMaxPayloadSizeHeaderSize];
654 
655     cbor::encodeBstrHeader(payloadSize, kMaxPayloadSizeHeaderSize,
656                            payloadSizeHeader);
657 
658     SHADigest digest = sha({{kSignature1Header, sizeof(kSignature1Header)},
659                             {payloadSizeHeader, payloadSizeHeaderSize},
660                             {packageStart + kPayloadOffset, payloadSize}});
661 
662     if (!checkEcDsaSignature(digest, packageStart + kSignatureOffset,
663                              publicKey.get(), publicKeySize)) {
664         COSE_PRINT_ERROR("Signature check failed\n");
665         return false;
666     }
667 
668     if (outPackageStart != nullptr) {
669         *outPackageStart = packageStart + kPayloadOffset;
670     }
671     if (outPackageSize != nullptr) {
672         *outPackageSize = payloadSize;
673     }
674     return true;
675 }
676 
coseBuildGcmAad(const std::string_view context,const std::span<const uint8_t> encodedProtectedHeaders,const std::span<const uint8_t> externalAad)677 static std::tuple<std::unique_ptr<uint8_t[]>, size_t> coseBuildGcmAad(
678         const std::string_view context,
679         const std::span<const uint8_t> encodedProtectedHeaders,
680         const std::span<const uint8_t> externalAad) {
681     cbor::ArrayCborEncoder enc;
682     enc.encodeArray([&](auto& enc) {
683         enc.encodeTstr(context);
684         enc.encodeBstr(encodedProtectedHeaders);
685         enc.encodeBstr(externalAad);
686     });
687 
688     return {enc.intoVec().arr(), enc.size()};
689 }
690 
encryptAesGcm(const std::vector<uint8_t> & key,const std::vector<uint8_t> & nonce,const CoseByteView & data,std::span<const uint8_t> additionalAuthenticatedData)691 static std::optional<std::vector<uint8_t>> encryptAesGcm(
692         const std::vector<uint8_t>& key,
693         const std::vector<uint8_t>& nonce,
694         const CoseByteView& data,
695         std::span<const uint8_t> additionalAuthenticatedData) {
696     if (key.size() != kAesGcmKeySize) {
697         COSE_PRINT_ERROR("key is not kAesGcmKeySize (%zu) bytes, got %zu\n",
698                          kAesGcmKeySize, key.size());
699         return {};
700     }
701     if (nonce.size() != kAesGcmIvSize) {
702         COSE_PRINT_ERROR("nonce is not kAesGcmIvSize bytes, got %zu\n",
703                          nonce.size());
704         return {};
705     }
706 
707     // The result is the ciphertext followed by the tag (kAesGcmTagSize bytes).
708     std::vector<uint8_t> encryptedData;
709     encryptedData.resize(data.size() + kAesGcmTagSize);
710     unsigned char* ciphertext = (unsigned char*)encryptedData.data();
711     unsigned char* tag = ciphertext + data.size();
712 
713     auto ctx = EVP_CIPHER_CTX_Ptr(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
714     if (ctx.get() == nullptr) {
715         COSE_PRINT_ERROR("EVP_CIPHER_CTX_new: failed, error 0x%lx\n",
716                          static_cast<unsigned long>(ERR_get_error()));
717         return {};
718     }
719 
720     if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_trusty_gcm(), NULL, NULL, NULL) !=
721         1) {
722         COSE_PRINT_ERROR("EVP_EncryptInit_ex: failed, error 0x%lx\n",
723                          static_cast<unsigned long>(ERR_get_error()));
724         return {};
725     }
726 
727     if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, kAesGcmIvSize,
728                             NULL) != 1) {
729         COSE_PRINT_ERROR(
730                 "EVP_CIPHER_CTX_ctrl: failed setting nonce length, "
731                 "error 0x%lx\n",
732                 static_cast<unsigned long>(ERR_get_error()));
733         return {};
734     }
735 
736     if (EVP_EncryptInit_ex(ctx.get(), NULL, NULL, key.data(), nonce.data()) !=
737         1) {
738         COSE_PRINT_ERROR("EVP_EncryptInit_ex: failed, error 0x%lx\n",
739                          static_cast<unsigned long>(ERR_get_error()));
740         return {};
741     }
742 
743     int numWritten;
744     if (additionalAuthenticatedData.size() > 0) {
745         if (EVP_EncryptUpdate(ctx.get(), NULL, &numWritten,
746                               additionalAuthenticatedData.data(),
747                               additionalAuthenticatedData.size()) != 1) {
748             fprintf(stderr,
749                     "EVP_EncryptUpdate: failed for "
750                     "additionalAuthenticatedData, error 0x%lx\n",
751                     static_cast<unsigned long>(ERR_get_error()));
752             return {};
753         }
754         /*
755          * std::span::size() should return an size_type==size_t
756          * value but older versions of libcxx return an index_type
757          * which is an alias of ptrdiff_t (a signed type).
758          * We cast the size explicitly to a size_t to cover both cases.
759          */
760         if (static_cast<size_t>(numWritten) !=
761             static_cast<size_t>(additionalAuthenticatedData.size())) {
762             fprintf(stderr,
763                     "EVP_EncryptUpdate: Unexpected outl=%d (expected %zu) "
764                     "for additionalAuthenticatedData\n",
765                     numWritten, additionalAuthenticatedData.size());
766             return {};
767         }
768     }
769 
770     if (data.size() > 0) {
771         if (EVP_EncryptUpdate(ctx.get(), ciphertext, &numWritten, data.data(),
772                               data.size()) != 1) {
773             COSE_PRINT_ERROR("EVP_EncryptUpdate: failed, error 0x%lx\n",
774                              static_cast<unsigned long>(ERR_get_error()));
775             return {};
776         }
777         if (static_cast<size_t>(numWritten) !=
778             static_cast<size_t>(data.size())) {
779             fprintf(stderr,
780                     "EVP_EncryptUpdate: Unexpected outl=%d (expected %zu)\n",
781                     numWritten, data.size());
782             ;
783             return {};
784         }
785     }
786 
787     if (EVP_EncryptFinal_ex(ctx.get(), ciphertext + numWritten, &numWritten) !=
788         1) {
789         COSE_PRINT_ERROR("EVP_EncryptFinal_ex: failed, error 0x%lx\n",
790                          static_cast<unsigned long>(ERR_get_error()));
791         return {};
792     }
793     if (numWritten != 0) {
794         COSE_PRINT_ERROR("EVP_EncryptFinal_ex: Unexpected non-zero outl=%d\n",
795                          numWritten);
796         return {};
797     }
798 
799     if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
800                             tag) != 1) {
801         COSE_PRINT_ERROR(
802                 "EVP_CIPHER_CTX_ctrl: failed getting tag, "
803                 "error 0x%lx\n",
804                 static_cast<unsigned long>(ERR_get_error()));
805         return {};
806     }
807 
808     return encryptedData;
809 }
810 
coseEncryptAesGcm(const std::string_view context,const std::vector<uint8_t> & key,const CoseByteView & data,const std::vector<uint8_t> & externalAad,const std::vector<uint8_t> & encodedProtectedHeaders,const CoseByteView & unprotectedHeaders,std::optional<std::vector<uint8_t>> recipients)811 static std::optional<std::vector<uint8_t>> coseEncryptAesGcm(
812         const std::string_view context,
813         const std::vector<uint8_t>& key,
814         const CoseByteView& data,
815         const std::vector<uint8_t>& externalAad,
816         const std::vector<uint8_t>& encodedProtectedHeaders,
817         const CoseByteView& unprotectedHeaders,
818         std::optional<std::vector<uint8_t>> recipients) {
819     std::optional<std::vector<uint8_t>> iv = getRandom(kAesGcmIvSize);
820     if (!iv) {
821         COSE_PRINT_ERROR("Error generating encryption IV\n");
822         return {};
823     }
824 
825     cbor::VectorCborEncoder ivEnc;
826     ivEnc.encodeMap([&](auto& enc) {
827         enc.encodeKeyValue(COSE_LABEL_IV,
828                            [&](auto& enc) { enc.encodeBstr(iv.value()); });
829     });
830 
831     auto finalUnprotectedHeaders =
832             cbor::mergeMaps(unprotectedHeaders, ivEnc.view());
833     if (!finalUnprotectedHeaders) {
834         COSE_PRINT_ERROR("Error updating unprotected headers with IV\n");
835         return {};
836     }
837 
838     std::span encodedProtectedHeadersView(encodedProtectedHeaders.data(),
839                                           encodedProtectedHeaders.size());
840     std::span externalAadView = externalAad;
841     auto [gcmAad, gcmAadSize] = coseBuildGcmAad(
842             context, encodedProtectedHeadersView, externalAadView);
843     std::span gcmAadView(gcmAad.get(), gcmAadSize);
844 
845     std::optional<std::vector<uint8_t>> ciphertext =
846             encryptAesGcm(key, iv.value(), data, gcmAadView);
847     if (!ciphertext) {
848         COSE_PRINT_ERROR("Error encrypting data\n");
849         return {};
850     }
851 
852     cbor::VectorCborEncoder enc;
853     enc.encodeArray([&](auto& enc) {
854         enc.encodeBstr(encodedProtectedHeaders);
855         enc.copyBytes(finalUnprotectedHeaders.value());
856         enc.encodeBstr(ciphertext.value());
857         if (recipients) {
858             enc.copyBytes(recipients.value());
859         }
860     });
861 
862     return enc.intoVec();
863 }
864 
coseEncryptAesGcmKeyWrap(const std::vector<uint8_t> & key,uint8_t keyId,const CoseByteView & data,const std::vector<uint8_t> & externalAad,const std::vector<uint8_t> & encodedProtectedHeaders,const CoseByteView & unprotectedHeaders,bool tagged)865 std::optional<std::vector<uint8_t>> coseEncryptAesGcmKeyWrap(
866         const std::vector<uint8_t>& key,
867         uint8_t keyId,
868         const CoseByteView& data,
869         const std::vector<uint8_t>& externalAad,
870         const std::vector<uint8_t>& encodedProtectedHeaders,
871         const CoseByteView& unprotectedHeaders,
872         bool tagged) {
873     /* Generate and encrypt the CEK */
874     std::optional<std::vector<uint8_t>> contentEncryptionKey =
875             getRandom(kAesGcmKeySize);
876     if (!contentEncryptionKey) {
877         COSE_PRINT_ERROR("Error generating encryption key\n");
878         return {};
879     }
880 
881     cbor::VectorCborEncoder coseKeyEnc;
882     coseKeyEnc.encodeMap([&](auto& enc) {
883         enc.encodeKeyValue(COSE_LABEL_KEY_KTY, COSE_KEY_TYPE_SYMMETRIC);
884         enc.encodeKeyValue(COSE_LABEL_KEY_ALG, COSE_VAL_CIPHER_ALG);
885         enc.encodeKeyValue(COSE_LABEL_KEY_SYMMETRIC_KEY, [&](auto& enc) {
886             enc.encodeBstr(contentEncryptionKey.value());
887         });
888     });
889     CoseByteView coseKeyByteView = coseKeyEnc.view();
890 
891     cbor::VectorCborEncoder keyUnprotectedHeadersEnc;
892     keyUnprotectedHeadersEnc.encodeMap([&](auto& enc) {
893         enc.encodeKeyValue(COSE_LABEL_KID, [&](auto& enc) {
894             enc.encodeBstr(std::span<const uint8_t>(&keyId, 1));
895         });
896     });
897     auto keyUnprotectedHeaders = keyUnprotectedHeadersEnc.view();
898 
899     cbor::VectorCborEncoder encodedProtectedHeadersForEncKey;
900     encodedProtectedHeadersForEncKey.encodeMap([&](auto& enc) {
901         enc.encodeKeyValue(COSE_LABEL_ALG, COSE_VAL_CIPHER_ALG);
902     });
903 
904     auto encContentEncryptionKey =
905             coseEncryptAesGcm(COSE_CONTEXT_ENC_RECIPIENT, key, coseKeyByteView,
906                               {}, encodedProtectedHeadersForEncKey.intoVec(),
907                               keyUnprotectedHeaders, {});
908     if (!encContentEncryptionKey.has_value()) {
909         COSE_PRINT_ERROR("Error wrapping encryption key\n");
910         return {};
911     }
912 
913     cbor::VectorCborEncoder recipientsEnc;
914     recipientsEnc.encodeArray(
915             [&](auto& enc) { enc.copyBytes(encContentEncryptionKey.value()); });
916     auto recipients = recipientsEnc.intoVec();
917 
918     auto coseEncrypt = coseEncryptAesGcm(
919             COSE_CONTEXT_ENCRYPT, std::move(contentEncryptionKey.value()), data,
920             externalAad, encodedProtectedHeaders, unprotectedHeaders,
921             std::move(recipients));
922     if (!coseEncrypt.has_value()) {
923         COSE_PRINT_ERROR("Error encrypting application package\n");
924         return {};
925     }
926 
927     if (tagged) {
928         cbor::VectorCborEncoder enc;
929         enc.encodeTag(COSE_TAG_ENCRYPT,
930                       [&](auto& enc) { enc.copyBytes(coseEncrypt.value()); });
931         return enc.intoVec();
932     } else {
933         return coseEncrypt;
934     }
935 }
936 
decryptAesGcmInPlace(std::span<const uint8_t> key,std::span<const uint8_t> nonce,uint8_t * encryptedData,size_t encryptedDataSize,std::span<const uint8_t> additionalAuthenticatedData,size_t * outPlaintextSize)937 static bool decryptAesGcmInPlace(
938         std::span<const uint8_t> key,
939         std::span<const uint8_t> nonce,
940         uint8_t* encryptedData,
941         size_t encryptedDataSize,
942         std::span<const uint8_t> additionalAuthenticatedData,
943         size_t* outPlaintextSize) {
944     assert(outPlaintextSize != nullptr);
945 
946     int ciphertextSize = int(encryptedDataSize) - kAesGcmTagSize;
947     if (ciphertextSize < 0) {
948         COSE_PRINT_ERROR("encryptedData too small\n");
949         return false;
950     }
951     if (key.size() != kAesGcmKeySize) {
952         COSE_PRINT_ERROR("key is not kAesGcmKeySize (%zu) bytes, got %zu\n",
953                          kAesGcmKeySize, key.size());
954         return {};
955     }
956     if (nonce.size() != kAesGcmIvSize) {
957         COSE_PRINT_ERROR("nonce is not kAesGcmIvSize bytes, got %zu\n",
958                          nonce.size());
959         return false;
960     }
961     unsigned char* ciphertext = encryptedData;
962     unsigned char* tag = ciphertext + ciphertextSize;
963 
964     /*
965      * Decrypt the data in place. OpenSSL and BoringSSL support this as long as
966      * the plaintext buffer completely overlaps the ciphertext.
967      */
968     unsigned char* plaintext = encryptedData;
969 
970     auto ctx = EVP_CIPHER_CTX_Ptr(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
971     if (ctx.get() == nullptr) {
972         COSE_PRINT_ERROR("EVP_CIPHER_CTX_new: failed, error 0x%lx\n",
973                          static_cast<unsigned long>(ERR_get_error()));
974         return false;
975     }
976 
977     if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_trusty_gcm(), NULL, NULL, NULL) !=
978         1) {
979         COSE_PRINT_ERROR("EVP_DecryptInit_ex: failed, error 0x%lx\n",
980                          static_cast<unsigned long>(ERR_get_error()));
981         return false;
982     }
983 
984     if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, kAesGcmIvSize,
985                             NULL) != 1) {
986         COSE_PRINT_ERROR(
987                 "EVP_CIPHER_CTX_ctrl: failed setting nonce length, "
988                 "error 0x%lx\n",
989                 static_cast<unsigned long>(ERR_get_error()));
990         return false;
991     }
992 
993     if (EVP_DecryptInit_ex(ctx.get(), NULL, NULL, key.data(), nonce.data()) !=
994         1) {
995         COSE_PRINT_ERROR("EVP_DecryptInit_ex: failed, error 0x%lx\n",
996                          static_cast<unsigned long>(ERR_get_error()));
997         return false;
998     }
999 
1000     int numWritten;
1001     if (additionalAuthenticatedData.size() > 0) {
1002         if (EVP_DecryptUpdate(ctx.get(), NULL, &numWritten,
1003                               additionalAuthenticatedData.data(),
1004                               additionalAuthenticatedData.size()) != 1) {
1005             COSE_PRINT_ERROR(
1006                     "EVP_DecryptUpdate: failed for "
1007                     "additionalAuthenticatedData, error 0x%lx\n",
1008                     static_cast<unsigned long>(ERR_get_error()));
1009             return false;
1010         }
1011         if (static_cast<size_t>(numWritten) !=
1012             static_cast<size_t>(additionalAuthenticatedData.size())) {
1013             COSE_PRINT_ERROR(
1014                     "EVP_DecryptUpdate: Unexpected outl=%d "
1015                     "(expected %zd) for additionalAuthenticatedData\n",
1016                     numWritten, additionalAuthenticatedData.size());
1017             return false;
1018         }
1019     }
1020 
1021     if (EVP_DecryptUpdate(ctx.get(), plaintext, &numWritten, ciphertext,
1022                           ciphertextSize) != 1) {
1023         COSE_PRINT_ERROR("EVP_DecryptUpdate: failed, error 0x%lx\n",
1024                          static_cast<unsigned long>(ERR_get_error()));
1025         return false;
1026     }
1027     if (numWritten != ciphertextSize) {
1028         COSE_PRINT_ERROR(
1029                 "EVP_DecryptUpdate: Unexpected outl=%d "
1030                 "(expected %d)\n",
1031                 numWritten, ciphertextSize);
1032         return false;
1033     }
1034 
1035     if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize,
1036                              tag)) {
1037         COSE_PRINT_ERROR(
1038                 "EVP_CIPHER_CTX_ctrl: failed setting expected tag, "
1039                 "error 0x%lx\n",
1040                 static_cast<unsigned long>(ERR_get_error()));
1041         return false;
1042     }
1043 
1044     int ret =
1045             EVP_DecryptFinal_ex(ctx.get(), plaintext + numWritten, &numWritten);
1046     if (ret != 1) {
1047         COSE_PRINT_ERROR("EVP_DecryptFinal_ex: failed, error 0x%lx\n",
1048                          static_cast<unsigned long>(ERR_get_error()));
1049         return false;
1050     }
1051     if (numWritten != 0) {
1052         COSE_PRINT_ERROR("EVP_DecryptFinal_ex: Unexpected non-zero outl=%d\n",
1053                          numWritten);
1054         return false;
1055     }
1056 
1057     *outPlaintextSize = ciphertextSize;
1058     return true;
1059 }
1060 
coseDecryptAesGcmInPlace(const std::string_view context,const CoseByteView & item,const std::span<const uint8_t> key,const std::vector<uint8_t> & externalAad,const uint8_t ** outPlaintextStart,size_t * outPlaintextSize,DecryptFn keyDecryptFn)1061 static bool coseDecryptAesGcmInPlace(const std::string_view context,
1062                                      const CoseByteView& item,
1063                                      const std::span<const uint8_t> key,
1064                                      const std::vector<uint8_t>& externalAad,
1065                                      const uint8_t** outPlaintextStart,
1066                                      size_t* outPlaintextSize,
1067                                      DecryptFn keyDecryptFn) {
1068     assert(outPlaintextStart != nullptr);
1069     assert(outPlaintextSize != nullptr);
1070 
1071     struct CborIn in;
1072     CborInInit(item.data(), item.size(), &in);
1073 
1074     size_t num_elements;
1075     if (CborReadArray(&in, &num_elements) != CBOR_READ_RESULT_OK) {
1076         COSE_PRINT_ERROR("Encrypted data is not a CBOR array\n");
1077         return false;
1078     }
1079 
1080     if (num_elements < 3 || num_elements > 4) {
1081         COSE_PRINT_ERROR("Invalid COSE encryption array size, got %zu\n",
1082                          num_elements);
1083         return false;
1084     }
1085 
1086     const uint8_t* enc_protected_headers_data;
1087     size_t enc_protected_headers_size;
1088     if (CborReadBstr(&in, &enc_protected_headers_size,
1089                      &enc_protected_headers_data) != CBOR_READ_RESULT_OK) {
1090         COSE_PRINT_ERROR(
1091                 "Failed to retrieve protected headers "
1092                 "from COSE encryption structure\n");
1093         return false;
1094     }
1095 
1096     struct CborIn protHdrIn;
1097     CborInInit(enc_protected_headers_data, enc_protected_headers_size,
1098                &protHdrIn);
1099 
1100     size_t numPairs;
1101     if (CborReadMap(&protHdrIn, &numPairs) != CBOR_READ_RESULT_OK) {
1102         COSE_PRINT_ERROR("Invalid protected headers CBOR type\n");
1103         return false;
1104     }
1105 
1106     int64_t label;
1107     std::optional<uint64_t> alg;
1108     for (size_t i = 0; i < numPairs; i++) {
1109         // Read key
1110         if (CborReadInt(&protHdrIn, &label) != CBOR_READ_RESULT_OK) {
1111             COSE_PRINT_ERROR(
1112                     "Failed to read protected headers "
1113                     "in COSE encryption structure\n");
1114             return false;
1115         }
1116 
1117         // Read value
1118         if (label == COSE_LABEL_ALG) {
1119             uint64_t algVal;
1120             if (CborReadUint(&protHdrIn, &algVal) != CBOR_READ_RESULT_OK) {
1121                 COSE_PRINT_ERROR(
1122                         "Wrong CBOR type for alg value in unprotected headers\n");
1123                 return false;
1124             }
1125 
1126             if (algVal != COSE_VAL_CIPHER_ALG) {
1127                 COSE_PRINT_ERROR("Invalid COSE algorithm, got %" PRId64 "\n",
1128                                  algVal);
1129                 return false;
1130             }
1131 
1132             alg = algVal;
1133         } else if (CborReadSkip(&protHdrIn) != CBOR_READ_RESULT_OK) {
1134             COSE_PRINT_ERROR(
1135                     "Failed to read protected headers "
1136                     "in COSE encryption structure\n");
1137             return false;
1138         }
1139     }
1140 
1141     if (CborReadMap(&in, &numPairs) != CBOR_READ_RESULT_OK) {
1142         COSE_PRINT_ERROR(
1143                 "Failed to retrieve unprotected headers "
1144                 "from COSE encryption structure\n");
1145         return false;
1146     }
1147 
1148     const uint8_t* ivData = nullptr;
1149     size_t ivSize;
1150     for (size_t i = 0; i < numPairs; i++) {
1151         // Read key
1152         if (CborReadInt(&in, &label) != CBOR_READ_RESULT_OK) {
1153             COSE_PRINT_ERROR(
1154                     "Failed to read unprotected headers "
1155                     "in COSE encryption structure\n");
1156             return false;
1157         }
1158 
1159         // Read value
1160         if (label == COSE_LABEL_IV) {
1161             if (CborReadBstr(&in, &ivSize, &ivData) != CBOR_READ_RESULT_OK) {
1162                 COSE_PRINT_ERROR(
1163                         "Wrong CBOR type for IV value in unprotected headers\n");
1164                 return false;
1165             }
1166         } else if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
1167             COSE_PRINT_ERROR(
1168                     "Failed to read unprotected headers "
1169                     "in COSE encryption structure\n");
1170             return false;
1171         }
1172     }
1173 
1174     if (ivData == nullptr) {
1175         COSE_PRINT_ERROR("Missing IV field in COSE encryption structure\n");
1176         return false;
1177     }
1178 
1179     const uint8_t* ciphertextData;
1180     size_t ciphertextSize;
1181     if (CborReadBstr(&in, &ciphertextSize, &ciphertextData) !=
1182         CBOR_READ_RESULT_OK) {
1183         COSE_PRINT_ERROR(
1184                 "Failed to retrieve ciphertext "
1185                 "from COSE encryption structure\n");
1186         return false;
1187     }
1188 
1189     std::span externalAadView = externalAad;
1190     std::span encodedProtectedHeaders(enc_protected_headers_data,
1191                                       enc_protected_headers_size);
1192     auto [gcmAad, gcmAadSize] =
1193             coseBuildGcmAad(context, encodedProtectedHeaders, externalAadView);
1194 
1195     std::span gcmAadView(gcmAad.get(), gcmAadSize);
1196     std::span ivView(ivData, ivSize);
1197     if (!keyDecryptFn(key, ivView, const_cast<uint8_t*>(ciphertextData),
1198                       ciphertextSize, gcmAadView, outPlaintextSize)) {
1199         return false;
1200     }
1201 
1202     *outPlaintextStart = ciphertextData;
1203 
1204     return true;
1205 }
1206 
coseDecryptAesGcmKeyWrapInPlace(const CoseByteView & cose_encrypt,GetKeyFn keyFn,const std::vector<uint8_t> & externalAad,bool checkTag,const uint8_t ** outPackageStart,size_t * outPackageSize,DecryptFn keyDecryptFn)1207 bool coseDecryptAesGcmKeyWrapInPlace(const CoseByteView& cose_encrypt,
1208                                      GetKeyFn keyFn,
1209                                      const std::vector<uint8_t>& externalAad,
1210                                      bool checkTag,
1211                                      const uint8_t** outPackageStart,
1212                                      size_t* outPackageSize,
1213                                      DecryptFn keyDecryptFn) {
1214     assert(outPackageStart != nullptr);
1215     assert(outPackageSize != nullptr);
1216 
1217     if (!keyDecryptFn) {
1218         keyDecryptFn = &decryptAesGcmInPlace;
1219     }
1220 
1221     struct CborIn in;
1222     CborInInit(cose_encrypt.data(), cose_encrypt.size(), &in);
1223 
1224     uint64_t tag;
1225     if (CborReadTag(&in, &tag) == CBOR_READ_RESULT_OK) {
1226         if (checkTag && tag != COSE_TAG_ENCRYPT) {
1227             TLOGE("Invalid COSE_Encrypt semantic tag: %" PRIu64 "\n", tag);
1228             return false;
1229         }
1230     } else if (checkTag) {
1231         TLOGE("Expected COSE_Encrypt semantic tag\n");
1232         return false;
1233     }
1234 
1235     size_t num_elements;
1236     if (CborReadArray(&in, &num_elements) != CBOR_READ_RESULT_OK) {
1237         COSE_PRINT_ERROR("Encrypted data is not a CBOR array\n");
1238         return false;
1239     }
1240 
1241     if (num_elements != kCoseEncryptArrayElements) {
1242         COSE_PRINT_ERROR("Invalid COSE_Encrypt array size, got %zu\n",
1243                          num_elements);
1244         return false;
1245     }
1246 
1247     // Skip past the first three array elemements
1248     while (num_elements-- > 1) {
1249         if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
1250             COSE_PRINT_ERROR(
1251                     "Failed to retrieve recipients "
1252                     "from COSE_Encrypt structure\n");
1253             return false;
1254         }
1255     }
1256 
1257     // Read recipients array
1258     if (CborReadArray(&in, &num_elements) != CBOR_READ_RESULT_OK) {
1259         COSE_PRINT_ERROR(
1260                 "Failed to retrieve recipients "
1261                 "from COSE_Encrypt structure\n");
1262         return false;
1263     }
1264 
1265     if (num_elements != 1) {
1266         COSE_PRINT_ERROR("Invalid recipients array size, got %zu\n",
1267                          num_elements);
1268         return false;
1269     }
1270 
1271     const size_t recipientOffset = CborInOffset(&in);
1272     // Read singleton recipient
1273     if (CborReadArray(&in, &num_elements) != CBOR_READ_RESULT_OK) {
1274         COSE_PRINT_ERROR("COSE_Recipient is not a CBOR array\n");
1275         return false;
1276     }
1277 
1278     if (num_elements != 3) {
1279         COSE_PRINT_ERROR(
1280                 "Invalid COSE_Recipient structure array size, "
1281                 "got %zu\n",
1282                 num_elements);
1283         return false;
1284     }
1285 
1286     // Skip to unprotected headers array element
1287     if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
1288         COSE_PRINT_ERROR("Failed to read COSE_Recipient structure\n");
1289         return false;
1290     }
1291 
1292     size_t numPairs;
1293     if (CborReadMap(&in, &numPairs) != CBOR_READ_RESULT_OK) {
1294         COSE_PRINT_ERROR(
1295                 "Failed to retrieve unprotected headers "
1296                 "from COSE_Recipient structure\n");
1297         return false;
1298     }
1299 
1300     uint64_t label;
1301     const uint8_t* keyIdBytes = nullptr;
1302     size_t keyIdSize;
1303     for (size_t i = 0; i < numPairs; i++) {
1304         // Read key
1305         if (CborReadUint(&in, &label) != CBOR_READ_RESULT_OK) {
1306             COSE_PRINT_ERROR(
1307                     "Failed to read unprotected headers "
1308                     "in COSE_Recipient structure\n");
1309             return false;
1310         }
1311 
1312         // Read value
1313         if (label == COSE_LABEL_KID) {
1314             if (CborReadBstr(&in, &keyIdSize, &keyIdBytes) !=
1315                 CBOR_READ_RESULT_OK) {
1316                 COSE_PRINT_ERROR(
1317                         "Failed to extract key id from unprotected headers "
1318                         "in COSE_Recipient structure\n");
1319                 return false;
1320             }
1321         } else if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
1322             COSE_PRINT_ERROR(
1323                     "Failed to read unprotected headers "
1324                     "in COSE_Recipient structure\n");
1325             return false;
1326         }
1327     }
1328 
1329     // Skip over ciphertext
1330     if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
1331         COSE_PRINT_ERROR("Failed to read COSE_Recipient structure\n");
1332         return false;
1333     }
1334 
1335     if (!CborInAtEnd(&in)) {
1336         COSE_PRINT_ERROR("Failed to read COSE_Recipient structure\n");
1337         return false;
1338     }
1339 
1340     CoseByteView recipient(cose_encrypt.data() + recipientOffset,
1341                            CborInOffset(&in) - recipientOffset);
1342 
1343     if (keyIdBytes == nullptr) {
1344         COSE_PRINT_ERROR("Missing key id field in COSE_Recipient\n");
1345         return false;
1346     }
1347 
1348     if (keyIdSize != 1) {
1349         COSE_PRINT_ERROR("Invalid key id field length, got %zu\n", keyIdSize);
1350         return false;
1351     }
1352 
1353     auto [keyEncryptionKeyStart, keyEncryptionKeySize] = keyFn(keyIdBytes[0]);
1354     if (!keyEncryptionKeyStart) {
1355         COSE_PRINT_ERROR("Failed to retrieve decryption key\n");
1356         return false;
1357     }
1358 
1359     std::span keyEncryptionKey(keyEncryptionKeyStart.get(),
1360                                keyEncryptionKeySize);
1361 
1362     const uint8_t* coseKeyStart;
1363     size_t coseKeySize;
1364     if (!coseDecryptAesGcmInPlace(COSE_CONTEXT_ENC_RECIPIENT, recipient,
1365                                   keyEncryptionKey, {}, &coseKeyStart,
1366                                   &coseKeySize, keyDecryptFn)) {
1367         COSE_PRINT_ERROR("Failed to decrypt COSE_Key structure\n");
1368         return false;
1369     }
1370 
1371     CborInInit(coseKeyStart, coseKeySize, &in);
1372     if (CborReadMap(&in, &numPairs) != CBOR_READ_RESULT_OK) {
1373         COSE_PRINT_ERROR("COSE_Key structure is not a map\n");
1374         return false;
1375     }
1376 
1377     int64_t keyLabel;
1378     int64_t value;
1379     bool ktyValidated = false;
1380     bool algValidated = false;
1381     const uint8_t* contentEncryptionKeyStart = nullptr;
1382     size_t contentEncryptionKeySize = 0;
1383     for (size_t i = 0; i < numPairs; i++) {
1384         if (CborReadInt(&in, &keyLabel) != CBOR_READ_RESULT_OK) {
1385             COSE_PRINT_ERROR("Failed to parse key in COSE_Key structure\n");
1386             return false;
1387         }
1388 
1389         switch (keyLabel) {
1390         case COSE_LABEL_KEY_KTY:
1391             if (CborReadInt(&in, &value) != CBOR_READ_RESULT_OK) {
1392                 COSE_PRINT_ERROR("Wrong CBOR type for kty field of COSE_Key\n");
1393                 return false;
1394             }
1395             if (value != COSE_KEY_TYPE_SYMMETRIC) {
1396                 COSE_PRINT_ERROR("Invalid COSE_Key key type: %" PRId64 "\n",
1397                                  value);
1398                 return false;
1399             }
1400             ktyValidated = true;
1401             break;
1402         case COSE_LABEL_KEY_ALG:
1403             if (CborReadInt(&in, &value) != CBOR_READ_RESULT_OK) {
1404                 COSE_PRINT_ERROR("Wrong CBOR type for kty field of COSE_Key\n");
1405                 return false;
1406             }
1407             if (value != COSE_VAL_CIPHER_ALG) {
1408                 COSE_PRINT_ERROR("Invalid COSE_Key algorithm value: %" PRId64
1409                                  "\n",
1410                                  value);
1411                 return false;
1412             }
1413             algValidated = true;
1414             break;
1415         case COSE_LABEL_KEY_SYMMETRIC_KEY:
1416             if (CborReadBstr(&in, &contentEncryptionKeySize,
1417                              &contentEncryptionKeyStart)) {
1418                 COSE_PRINT_ERROR("Wrong CBOR type for key field of COSE_Key\n");
1419                 return false;
1420             }
1421             if (contentEncryptionKeySize != kAesGcmKeySize) {
1422                 COSE_PRINT_ERROR(
1423                         "Invalid content encryption key size, got %zu\n",
1424                         contentEncryptionKeySize);
1425                 return false;
1426             }
1427             break;
1428         default:
1429             COSE_PRINT_ERROR("Invalid key field in COSE_Key: %" PRId64 "\n",
1430                              label);
1431             return false;
1432             break;
1433         }
1434     }
1435 
1436     if (!ktyValidated) {
1437         COSE_PRINT_ERROR("Missing kty field of COSE_Key\n");
1438         return false;
1439     } else if (!algValidated) {
1440         COSE_PRINT_ERROR("Missing alg field of COSE_Key\n");
1441         return false;
1442     } else if (!contentEncryptionKeyStart) {
1443         COSE_PRINT_ERROR("Missing key field in COSE_Key\n");
1444         return false;
1445     }
1446 
1447     const CoseByteView contentEncryptionKey(contentEncryptionKeyStart,
1448                                             contentEncryptionKeySize);
1449     if (!coseDecryptAesGcmInPlace(COSE_CONTEXT_ENCRYPT, cose_encrypt,
1450                                   contentEncryptionKey, externalAad,
1451                                   outPackageStart, outPackageSize,
1452                                   decryptAesGcmInPlace)) {
1453         COSE_PRINT_ERROR("Failed to decrypt payload\n");
1454         return false;
1455     }
1456 
1457     return true;
1458 }
1459 
coseGetCipherAlg(void)1460 const char* coseGetCipherAlg(void) {
1461 #ifdef APPLOADER_PACKAGE_CIPHER_A256
1462     return "AES-GCM with 256-bit key, 128-bit tag";
1463 #else
1464     return "AES-GCM with 128-bit key, 128-bit tag";
1465 #endif
1466 }
1467 
coseGetSigningDsa(void)1468 const char* coseGetSigningDsa(void) {
1469 #ifdef APPLOADER_PACKAGE_SIGN_P384
1470     return "ECDA P-384 + SHA-384 signatures";
1471 #else
1472     return "ECDA P-256 + SHA-256 signatures";
1473 #endif
1474 }
1475