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