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 #pragma once
18 
19 #include <stddef.h>
20 #include <optional>
21 #include <span>
22 #include <vector>
23 
24 // From https://tools.ietf.org/html/rfc8152
25 constexpr int COSE_LABEL_ALG = 1;
26 constexpr int COSE_LABEL_KID = 4;
27 constexpr int COSE_LABEL_IV = 5;
28 constexpr int COSE_LABEL_KEY_KTY = 1;
29 constexpr int COSE_LABEL_KEY_ALG = 3;
30 constexpr int COSE_LABEL_KEY_SYMMETRIC_KEY = -1;
31 constexpr int COSE_TAG_ENCRYPT = 96;
32 constexpr int COSE_TAG_SIGN1 = 18;
33 constexpr int COSE_KEY_TYPE_SYMMETRIC = 4;
34 
35 constexpr char COSE_CONTEXT_ENCRYPT[] = "Encrypt";
36 constexpr char COSE_CONTEXT_ENC_RECIPIENT[] = "Enc_Recipient";
37 
38 // From "COSE Algorithms" registry
39 // See: RFC9053 or https://www.iana.org/assignments/cose/cose.txt
40 constexpr int COSE_ALG_A128GCM = 1;
41 constexpr int COSE_ALG_A256GCM = 2;
42 constexpr int COSE_ALG_ECDSA_256 = -7;
43 constexpr int COSE_ALG_ECDSA_384 = -35;
44 
45 // Trusty-specific COSE constants
46 constexpr int COSE_LABEL_TRUSTY = -65537;
47 
48 #ifdef APPLOADER_PACKAGE_CIPHER_A256
49 constexpr int COSE_VAL_CIPHER_ALG = COSE_ALG_A256GCM;
50 #else
51 constexpr int COSE_VAL_CIPHER_ALG = COSE_ALG_A128GCM;
52 #endif
53 
54 #ifdef APPLOADER_PACKAGE_SIGN_P384
55 constexpr int COSE_VAL_SIGN_ALG = COSE_ALG_ECDSA_384;
56 #else
57 constexpr int COSE_VAL_SIGN_ALG = COSE_ALG_ECDSA_256;
58 #endif
59 
60 constexpr size_t kAesGcmIvSize = 12;
61 constexpr size_t kAesGcmTagSize = 16;
62 #ifdef APPLOADER_PACKAGE_CIPHER_A256
63 constexpr size_t kAesGcmKeySize = 32;
64 #else
65 constexpr size_t kAesGcmKeySize = 16;
66 #endif
67 constexpr size_t kCoseEncryptArrayElements = 4;
68 
69 using CoseByteView = std::span<const uint8_t>;
70 
71 using GetKeyFn =
72         std::function<std::tuple<std::unique_ptr<uint8_t[]>, size_t>(uint8_t)>;
73 using DecryptFn = std::function<bool(CoseByteView key,
74                                      CoseByteView nonce,
75                                      uint8_t* encryptedData,
76                                      size_t encryptedDataSize,
77                                      CoseByteView additionalAuthenticatedData,
78                                      size_t* outPlaintextSize)>;
79 
80 /**
81  * coseSetSilenceErrors() - Enable or disable the silencing of errors;
82  * @value: New value of the flag, %true if errors should be silenced.
83  *
84  * Return: the old value of the flag.
85  */
86 bool coseSetSilenceErrors(bool value);
87 
88 /**
89  * coseSignEcDsa() - Sign the given data using ECDSA and emit a COSE CBOR blob.
90  * @key:
91  *      DER-encoded private key.
92  * @keyId:
93  *      Key identifier, an unsigned 1-byte integer.
94  * @data:
95  *      Block of data to sign and optionally encode inside the COSE signature
96  *      structure.
97  * @protectedHeaders:
98  *      Protected headers for the COSE structure. The function may add its own
99  *      additional entries.
100  * @unprotectedHeaders:
101  *      Unprotected headers for the COSE structure. The function may add its
102  *      own additional entries.
103  * @detachContent:
104  *      Whether to detach the data, i.e., not include @data in the returned
105  *      ```COSE_Sign1``` structure.
106  * @tagged:
107  *      Whether to return the tagged ```COSE_Sign1_Tagged``` or the untagged
108  *      ```COSE_Sign1``` structure.
109  *
110  * This function signs a given block of data with ECDSA-SHA256 and encodes both
111  * the data and the signature using the COSE encoding from RFC 8152. The caller
112  * may specify whether the data is included or detached from the returned
113  * structure using the @detachContent parameter, as well as additional
114  * context-specific header values with the @protectedHeaders and
115  * @unprotectedHeaders parameters.
116  *
117  * Return: A vector containing the encoded ```COSE_Sign1``` structure if the
118  *         signing algorithm succeeds, or a nullopt otherwise.
119  */
120 std::optional<std::vector<uint8_t>> coseSignEcDsa(
121         const std::vector<uint8_t>& key,
122         uint8_t keyId,
123         const std::vector<uint8_t>& data,
124         const std::span<const uint8_t>& encodedProtectedHeaders,
125         std::span<const uint8_t>&,
126         bool detachContent,
127         bool tagged);
128 
129 /**
130  * coseIsSigned() - Check if a block of bytes is a COSE signature emitted
131  *                  by coseSignEcDsa().
132  * @data:            Input data.
133  * @signatureLength: If not NULL, output argument where the total length
134  *                   of the signature structure will be stored.
135  *
136  * This function checks if the given data is a COSE signature structure
137  * emitted by coseSignEcDsa(), and returns the size of the signature if needed.
138  *
139  * Return: %true if the signature structure is valid, %false otherwise.
140  */
141 bool coseIsSigned(CoseByteView data, size_t* signatureLength);
142 
143 /**
144  * coseCheckEcDsaSignature() - Check if a given COSE signature structure is
145  *                             valid.
146  * @signatureCoseSign1: Input COSE signature structure.
147  * @detachedContent:    Additional data to include in the signature.
148  *                      Corresponds to the @detachedContent parameter passed to
149  *                      coseSignEcDsa().
150  * @publicKey:          Public key in DER encoding.
151  *
152  * Returns: %true if the signature verification passes, %false otherwise.
153  */
154 bool coseCheckEcDsaSignature(const std::vector<uint8_t>& signatureCoseSign1,
155                              const std::vector<uint8_t>& detachedContent,
156                              const std::vector<uint8_t>& publicKey);
157 
158 /**
159  * strictCheckEcDsaSignature() - Check a given COSE signature in strict mode.
160  * @packageStart:       Pointer to the start of the signed input package.
161  * @packageSize:        Size of the signed input package.
162  * @keyFn:              Function to call with a key id that returns the public
163  *                      key for that id.
164  * @outPackageStart:    If not NULL, output argument where the start of the
165  *                      payload will be stored.
166  * @outPackageSize:     If not NULL, output argument where the size of the
167  *                      payload will be stored.
168  *
169  * This function performs a strict verification of the COSE signature of a
170  * package. Instead of parsing the COSE structure, the function compares the
171  * raw bytes against a set of exact patterns, and fails if the bytes do not
172  * match. The actual signature and payload are also assumed to start at fixed
173  * offsets from @packageStart.
174  *
175  * Returns: %true if the signature verification passes, %false otherwise.
176  */
177 bool strictCheckEcDsaSignature(const uint8_t* packageStart,
178                                size_t packageSize,
179                                GetKeyFn keyFn,
180                                const uint8_t** outPackageStart,
181                                size_t* outPackageSize);
182 
183 /**
184  * coseEncryptAes128GcmKeyWrap() - Encrypt a block of data using AES-GCM
185  *                                 and a randomly-generated wrapped CEK.
186  * @key:
187  *      Key encryption key (KEK), 16 or 32 bytes in size.
188  * @keyId:
189  *      Key identifier for the KEK, an unsigned 1-byte integer.
190  * @data:
191  *      Input data to encrypt.
192  * @externalAad:
193  *      Additional authentication data to pass to AES-GCM.
194  * @protectedHeaders:
195  *      Protected headers for the COSE structure. The function may add its own
196  *      additional entries.
197  * @unprotectedHeaders:
198  *      Unprotected headers for the COSE structure. The function may add its
199  *      own additional entries.
200  * @tagged:
201  *      Whether to return the tagged ```COSE_Encrypt_Tagged``` or the untagged
202  *      ```COSE_Encrypt``` structure.
203  *
204  * This function generates a random key content encryption key (CEK) and wraps
205  * it using AES-GCM, then encrypts a given block of data with AES-GCM
206  * with the wrapped CEK and encodes both the data and CEK using the COSE
207  * encoding from RFC 8152.
208  *
209  * The key length must be 128 or 256 depending on build-time configuration.
210  * The IV and Tag lengths are fixed (128-bit and 96-bits respectively, see
211  * ```kAesGcmIvSize``` and ```kAesGcmTagSize```).
212  *
213  * The caller may specify additional context-specific header values with the
214  * @protectedHeaders and @unprotectedHeaders parameters.
215  *
216  * Return: A vector of bytes containing the encoded ```COSE_Encrypt``` structure
217  *         if the encryption succeeds, or a nullopt otherwise.
218  */
219 std::optional<std::vector<uint8_t>> coseEncryptAesGcmKeyWrap(
220         const std::vector<uint8_t>& key,
221         uint8_t keyId,
222         const CoseByteView& data,
223         const std::vector<uint8_t>& externalAad,
224         const std::vector<uint8_t>& encodedProtectedHeaders,
225         const CoseByteView& unprotectedHeaders,
226         bool tagged);
227 
228 /**
229  * coseDecryptAesGcmKeyWrapInPlace() - Decrypt a block of data containing a
230  *                                     wrapped key using AES-GCM.
231  * @item:               CBOR item containing a ```COSE_Encrypt``` structure.
232  * @keyFn:              Function to call with a key id that returns the key
233  *                      encryption key (KEK) for that id.
234  * @externalAad:        Additional authentication data to pass to AES-GCM.
235  * @checkTag:           Whether to check the CBOR semantic tag of @item.
236  * @outPackageStart:    The output argument where the start of the
237  *                      payload will be stored. Must not be %NULL.
238  * @outPackageSize:     The output argument where the size of the
239  *                      payload will be stored. Must not be %NULL.
240  *
241  * This function decrypts a ciphertext encrypted with AES-GCM and encoded
242  * in a ```COSE_Encrypt0_Tagged``` structure. The function performs in-place
243  * decryption and overwrites the ciphertext with the plaintext, and returns
244  * the pointer and size of the plaintext in @outPackageStart and
245  * @outPackageSize, respectively.
246  * The key length is 128 or 256 depending on build-time configuration.  The IV
247  * and Tag lengths are fixed (128-bit and 96-bits respectively).
248  *
249  * Returns: %true if the decryption succeeds, %false otherwise.
250  */
251 bool coseDecryptAesGcmKeyWrapInPlace(const CoseByteView& item,
252                                      GetKeyFn keyFn,
253                                      const std::vector<uint8_t>& externalAad,
254                                      bool checkTag,
255                                      const uint8_t** outPackageStart,
256                                      size_t* outPackageSize,
257                                      DecryptFn decryptFn = DecryptFn());
258 
259 /**
260  * coseGetCipherAlg - Get the name of the cipher for package encryption.
261  * Returns: A pointer to a static string describing the cipher.
262  */
263 const char* coseGetCipherAlg(void);
264 
265 /**
266  * coseGetSigningDsa() - Get the name of the signing Digital Signature Algo.
267  * Returns: A pointer to a static string describing the signing method.
268  */
269 const char* coseGetSigningDsa(void);
270