1 /*
2  * Copyright (c) 2024, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 /**
8  * \note This source file is derivative work of psa_crypto.c from the Mbed TLS project
9  */
10 #include <assert.h>
11 #include <string.h>
12 #include <stdbool.h>
13 
14 #include "common.h"
15 #include "psa/crypto.h"
16 #include "psa_crypto_driver_wrappers.h"
17 #include "psa_crypto_driver_wrappers_no_static.h"
18 #ifdef MCUBOOT_BUILTIN_KEY
19 #include "tfm_plat_crypto_keys.h"
20 #include "tfm_plat_otp.h"
21 #endif /* MCUBOOT_BUILTIN_KEY */
22 
23 /* For mbedtls_psa_ecdsa_verify_hash() */
24 #include "psa_crypto_ecp.h"
25 
26 /* A few Mbed TLS definitions */
27 #include "mbedtls/entropy.h"
28 #include "mbedtls/ecp.h"
29 
30 /* Definitions required for the MCUBOOT_BUILTIN_KEY case */
31 #if defined(MCUBOOT_BUILTIN_KEY)
32 #define MCUBOOT_BUILTIN_KEY_ID_MIN   (0x1)
33 #define MCUBOOT_BUILTIN_KEY_ID_MAX   (MCUBOOT_IMAGE_NUMBER)
34 #if defined(MCUBOOT_SIGN_EC256)
35 #define PUBKEY_DATA_SIZE             (65)
36 #define PUBKEY_BUF_SIZE              (68) /* Must be aligned to 4 Bytes */
37 #elif defined(MCUBOOT_SIGN_EC384)
38 #define PUBKEY_DATA_SIZE             (97)
39 #define PUBKEY_BUF_SIZE              (100) /* Must be aligned to 4 Bytes */
40 #endif /* MCUBOOT_SIGN_EC256 */
41 #endif /* MCUBOOT_BUILTIN_KEY */
42 
43 /**
44  * @note MCUboot uses the keys by importing them after parsing and then using
45  *       them right away in the following call, so it makes sense to avoid a copy
46  *       of data and just directly use the pointer to key material from the
47  *       caller. The psa_import_key() call does not cross any security boundary.
48  */
49 
50 /**
51  * @brief A structure describing the contents of a thin key slot, which
52  *        holds key material and metadata following a psa_import_key() call
53  */
54 struct thin_key_slot_s {
55     const uint8_t *buf;        /*!< Pointer to the buffer holding the key material */
56     size_t len;                /*!< Size in bytes of the \a buf buffer */
57     psa_key_attributes_t attr; /*!< Attributes of the key */
58     psa_key_id_t key_id;       /*!< Key ID assigned to the key */
59     bool is_valid;             /*!< Boolean value, true if the key material is valid */
60 };
61 
62 #if defined(MCUBOOT_BUILTIN_KEY)
63 /**
64  * @brief Static local buffer that holds enough data for the key material
65  *        provisioned bundle to be retrieved from the platform
66  */
67 static uint8_t g_pubkey_data[PUBKEY_BUF_SIZE];
68 #endif /* MCUBOOT_BUILTIN_KEY */
69 
70 /**
71  * @brief This static global variable holds the key slot. The thin PSA Crypto core
72  *        supports only a single key to be imported at any given time. Importing a
73  *        new key will just cause the existing key to be forgotten
74  */
75 static struct thin_key_slot_s g_key_slot =  {
76 #if !defined(MCUBOOT_BUILTIN_KEY)
77     .buf = NULL,
78     .len = 0,
79     .attr = PSA_KEY_ATTRIBUTES_INIT,
80     .key_id = PSA_KEY_ID_NULL,
81     .is_valid = false,
82 #else
83     .buf  = g_pubkey_data,
84     .len  = sizeof(g_pubkey_data),
85     .attr = PSA_KEY_ATTRIBUTES_INIT,
86     /* .key_id   - not used
87      * .is_valid - not used
88      */
89 #endif /* !MCUBOOT_BUILTIN_KEY */
90 };
91 
92 /**
93  * @brief Context required by the RNG function, mocked
94  *
95  */
96 static mbedtls_psa_external_random_context_t *g_ctx = NULL;
97 
98 #if defined(MCUBOOT_BUILTIN_KEY)
get_builtin_public_key(psa_key_id_t key_id,psa_algorithm_t alg)99 static psa_status_t get_builtin_public_key(psa_key_id_t key_id,
100                                            psa_algorithm_t alg)
101 {
102     enum tfm_plat_err_t plat_err;
103 
104     /* Decrease key ID by MCUBOOT_BUILTIN_KEY_ID_MIN as zero (PSA_KEY_ID_NULL)
105      * is reserved and considered invalid.
106      */
107     plat_err = tfm_plat_otp_read(
108             (PLAT_OTP_ID_BL2_ROTPK_0 + (key_id - MCUBOOT_BUILTIN_KEY_ID_MIN)),
109             PUBKEY_BUF_SIZE,
110             g_pubkey_data);
111     if (plat_err == TFM_PLAT_ERR_SUCCESS) {
112         g_key_slot.len = PUBKEY_DATA_SIZE;
113     } else {
114         return PSA_ERROR_GENERIC_ERROR;
115     }
116 
117     psa_set_key_usage_flags(&g_key_slot.attr, PSA_KEY_USAGE_VERIFY_HASH);
118     psa_set_key_algorithm(&g_key_slot.attr, alg);
119     psa_set_key_type(&g_key_slot.attr,
120                      PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
121     psa_set_key_bits(&g_key_slot.attr,
122                      PSA_BYTES_TO_BITS((g_key_slot.len - 1)/2));
123 
124     return PSA_SUCCESS;
125 }
126 #endif /* MCUBOOT_BUILTIN_KEY */
127 
psa_crypto_init(void)128 psa_status_t psa_crypto_init(void)
129 {
130     psa_status_t status = psa_driver_wrapper_init();
131 
132     /* This will have to perform RNG/DRBG init in case that will be ever required by
133      * any API
134      */
135     return status;
136 }
137 
psa_hash_abort(psa_hash_operation_t * operation)138 psa_status_t psa_hash_abort(psa_hash_operation_t *operation)
139 {
140     /* Aborting a non-active operation is allowed */
141     if (operation->id == 0) {
142         return PSA_SUCCESS;
143     }
144 
145     psa_status_t status = psa_driver_wrapper_hash_abort(operation);
146 
147     operation->id = 0;
148 
149     return status;
150 }
151 
psa_hash_setup(psa_hash_operation_t * operation,psa_algorithm_t alg)152 psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
153                             psa_algorithm_t alg)
154 {
155     psa_status_t status;
156 
157     /* A context must be freshly initialized before it can be set up. */
158     assert(operation->id == 0);
159     assert(PSA_ALG_IS_HASH(alg));
160 
161     /* Ensure all of the context is zeroized, since PSA_HASH_OPERATION_INIT only
162      * directly zeroes the int-sized dummy member of the context union.
163      */
164     memset(&operation->ctx, 0, sizeof(operation->ctx));
165 
166     status = psa_driver_wrapper_hash_setup(operation, alg);
167 
168     assert(status == PSA_SUCCESS);
169 
170     return status;
171 }
172 
psa_hash_update(psa_hash_operation_t * operation,const uint8_t * input,size_t input_length)173 psa_status_t psa_hash_update(psa_hash_operation_t *operation,
174                              const uint8_t *input,
175                              size_t input_length)
176 {
177     psa_status_t status;
178 
179     assert(operation->id != 0);
180 
181     /* Don't require hash implementations to behave correctly on a
182      * zero-length input, which may have an invalid pointer.
183      */
184     if (input_length == 0) {
185         return PSA_SUCCESS;
186     }
187 
188     status = psa_driver_wrapper_hash_update(operation, input, input_length);
189 
190     assert(status == PSA_SUCCESS);
191 
192     return status;
193 }
194 
psa_hash_finish(psa_hash_operation_t * operation,uint8_t * hash,size_t hash_size,size_t * hash_length)195 psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
196                              uint8_t *hash,
197                              size_t hash_size,
198                              size_t *hash_length)
199 {
200     *hash_length = 0;
201     assert(operation->id != 0);
202 
203     psa_status_t status = psa_driver_wrapper_hash_finish(
204         operation, hash, hash_size, hash_length);
205     psa_hash_abort(operation);
206     return status;
207 }
208 
209 #if !defined(MCUBOOT_BUILTIN_KEY)
210 /**
211  * The key management subsystem is simplified to support only the BL2 required
212  * use case for signature verification either with RSA or ECDSA. MCUboot key
213  * bundles can be encoded in the SubjectPublicKeyInfo format (RFC 5480):
214  *
215  * SubjectPublicKeyInfo  ::= SEQUENCE  {
216  *     algorithm            AlgorithmIdentifier,
217  *     subjectPublicKey     BIT STRING
218  * }
219  *
220  * where, for RSA, the subjectPublicKey is either specified in RFC 3447 (PKCS#1v2.1)
221  * or the newest RFC 8017 (PKCS#1v2.2) using RSAPublicKey:
222  *
223  * RSAPublicKey ::= SEQUENCE {
224  *     modulus           INTEGER,  -- n
225  *     publicExponent    INTEGER   -- e
226  * }
227  *
228  * or for ECDSA is specified in RFC 5480 itself as ECPoint ::= OCTET STRING
229  *
230  * For ECDSA, MCUboot passes the uncompressed format (i.e. 0x04 X Y), i.e. the
231  * key encoding is parsed by MCUboot itself before being imported. For RSA, the
232  * AlgorithmIdentifier is instead specified in RFC 3279 as the value of the OID
233  * rsaEncryption: 1.2.840.113549.1.1.1, but MCUboot chooses in this case to
234  * pass already the RSAPublicKey structure to the APIs, hence the code below just
235  * understands the length of n by inspecting the fields of the ASN.1 encoding
236  *
237  */
psa_import_key(const psa_key_attributes_t * attributes,const uint8_t * data,size_t data_length,psa_key_id_t * key)238 psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
239                             const uint8_t *data,
240                             size_t data_length,
241                             psa_key_id_t *key)
242 {
243 #if defined(MCUBOOT_SIGN_RSA)
244     /* This is either a 2048, 3072 or 4096 bit RSA key, hence the TLV must place
245      * the length at index (6,7) with a leading 0x00. The leading 0x00 is due to
246      * the fact that the MSB will always be set for RSA keys where the length is
247      * a multiple of 8 bits.
248      */
249     const size_t bits =
250         PSA_BYTES_TO_BITS((((uint16_t)data[6]) << 8) | (uint16_t)data[7]) - 8;
251 
252 #elif defined(MCUBOOT_SIGN_EC256) || defined(MCUBOOT_SIGN_EC384)
253     /* The public key is expected in uncompressed format, i.e. 0x04 X Y
254      * for 256 or 384 bit lengths, and the driver wrappers expect to receive
255      * it in that format
256      */
257     assert(data[0] == 0x04);
258     const size_t bits = PSA_BYTES_TO_BITS((data_length - 1)/2);
259 #endif
260 
261     g_key_slot.buf = data;
262     g_key_slot.len = data_length;
263 
264     memcpy(&g_key_slot.attr, attributes, sizeof(psa_key_attributes_t));
265     g_key_slot.attr.bits = (psa_key_bits_t)bits;
266 
267     /* This signals that a new key has been imported */
268     *key = (++g_key_slot.key_id);
269 
270     g_key_slot.is_valid = true;
271 
272     return PSA_SUCCESS;
273 }
274 
psa_get_key_attributes(psa_key_id_t key,psa_key_attributes_t * attributes)275 psa_status_t psa_get_key_attributes(psa_key_id_t key,
276                                     psa_key_attributes_t *attributes)
277 {
278     assert(g_key_slot.is_valid && (g_key_slot.key_id == key));
279     memcpy(attributes, &g_key_slot.attr, sizeof(psa_key_attributes_t));
280     return PSA_SUCCESS;
281 }
282 #endif /* !MCUBOOT_BUILTIN_KEY */
283 
psa_destroy_key(psa_key_id_t key)284 psa_status_t psa_destroy_key(psa_key_id_t key)
285 {
286 #if !defined(MCUBOOT_BUILTIN_KEY)
287     assert(g_key_slot.is_valid && (g_key_slot.key_id == key));
288 
289     g_key_slot.buf = NULL;
290     g_key_slot.len = 0;
291     g_key_slot.attr = psa_key_attributes_init();
292     g_key_slot.is_valid = false;
293 
294     /* This will keep the value of the key_id so that a new import will
295      * just use the next key_id. This allows to keep track of potential
296      * clients trying to reuse a deleted key ID
297      */
298 #else /* !MCUBOOT_BUILTIN_KEY */
299     memset(g_pubkey_data, 0, sizeof(g_pubkey_data));
300     g_key_slot.len = 0;
301     g_key_slot.attr = psa_key_attributes_init();
302 #endif /* !MCUBOOT_BUILTIN_KEY */
303 
304     return PSA_SUCCESS;
305 }
306 
307 /* Signature verification supports only RSA or ECDSA with P256 or P384 */
psa_verify_hash(psa_key_id_t key,psa_algorithm_t alg,const uint8_t * hash,size_t hash_length,const uint8_t * signature,size_t signature_length)308 psa_status_t psa_verify_hash(psa_key_id_t key,
309                              psa_algorithm_t alg,
310                              const uint8_t *hash,
311                              size_t hash_length,
312                              const uint8_t *signature,
313                              size_t signature_length)
314 {
315     psa_status_t status;
316 
317 #if !defined(MCUBOOT_BUILTIN_KEY)
318     assert(g_key_slot.is_valid && (g_key_slot.key_id == key));
319 #else
320     assert((key >= MCUBOOT_BUILTIN_KEY_ID_MIN) &&
321            (key <= MCUBOOT_BUILTIN_KEY_ID_MAX));
322 
323     status = get_builtin_public_key(key, alg);
324     if (status != PSA_SUCCESS) {
325         return status;
326     }
327 #endif /* !MCUBOOT_BUILTIN_KEY */
328 
329     status = psa_driver_wrapper_verify_hash(
330                 &g_key_slot.attr,
331                 g_key_slot.buf, g_key_slot.len,
332                 alg, hash, hash_length,
333                 signature, signature_length);
334 
335     return status;
336 }
337 
mbedtls_to_psa_error(int ret)338 psa_status_t mbedtls_to_psa_error(int ret)
339 {
340     /* We don't require precise error translation */
341     if (!ret) {
342         return PSA_SUCCESS;
343     } else {
344         return PSA_ERROR_GENERIC_ERROR;
345     }
346 }
347 
psa_generate_random(uint8_t * output,size_t output_size)348 psa_status_t psa_generate_random(uint8_t *output,
349                                  size_t output_size)
350 {
351 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
352 
353     size_t output_length = 0;
354     psa_status_t status = mbedtls_psa_external_get_random(g_ctx,
355                                                           output, output_size,
356                                                           &output_length);
357     if (status != PSA_SUCCESS) {
358         return status;
359     }
360     /* Breaking up a request into smaller chunks is currently not supported
361      * for the external RNG interface.
362      */
363     if (output_length != output_size) {
364         return PSA_ERROR_INSUFFICIENT_ENTROPY;
365     }
366     return PSA_SUCCESS;
367 
368 #endif
369     return PSA_ERROR_NOT_SUPPORTED;
370 }
371 
372 /* This gets linked by the driver wrapper if no driver is present */
psa_verify_hash_builtin(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * hash,size_t hash_length,const uint8_t * signature,size_t signature_length)373 psa_status_t psa_verify_hash_builtin(
374     const psa_key_attributes_t *attributes,
375     const uint8_t *key_buffer, size_t key_buffer_size,
376     psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
377     const uint8_t *signature, size_t signature_length)
378 {
379 #if defined(MCUBOOT_SIGN_RSA)
380     if (PSA_KEY_TYPE_IS_RSA(psa_get_key_type(attributes))) {
381         if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||
382             PSA_ALG_IS_RSA_PSS(alg)) {
383 #if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS)
384             return mbedtls_psa_rsa_verify_hash(
385                 attributes,
386                 key_buffer, key_buffer_size,
387                 alg, hash, hash_length,
388                 signature, signature_length);
389 #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PSS) */
390         } else {
391             return PSA_ERROR_INVALID_ARGUMENT;
392         }
393     }
394 #elif defined(MCUBOOT_SIGN_EC256) || defined(MCUBOOT_SIGN_EC384)
395     if (PSA_KEY_TYPE_IS_ECC(psa_get_key_type(attributes))) {
396         if (PSA_ALG_IS_ECDSA(alg)) {
397 #if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
398             defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
399             return mbedtls_psa_ecdsa_verify_hash(
400                 attributes,
401                 key_buffer, key_buffer_size,
402                 alg, hash, hash_length,
403                 signature, signature_length);
404 #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
405         * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
406         */
407         } else {
408             return PSA_ERROR_INVALID_ARGUMENT;
409         }
410     }
411 #endif
412 
413     (void) key_buffer;
414     (void) key_buffer_size;
415     (void) hash;
416     (void) hash_length;
417     (void) signature;
418     (void) signature_length;
419 
420     return PSA_ERROR_NOT_SUPPORTED;
421 }
422 
423 /* We don't need the full driver wrapper, we know the key is already a public key */
psa_driver_wrapper_export_public_key(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,uint8_t * data,size_t data_size,size_t * data_length)424 psa_status_t psa_driver_wrapper_export_public_key(
425     const psa_key_attributes_t *attributes,
426     const uint8_t *key_buffer, size_t key_buffer_size,
427     uint8_t *data, size_t data_size, size_t *data_length)
428 {
429     assert(PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(attributes)));
430     assert(key_buffer_size <= data_size);
431 
432     memcpy(data, key_buffer, key_buffer_size);
433     *data_length = key_buffer_size;
434 
435     return PSA_SUCCESS;
436 }
437