1 /*
2 * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <stddef.h>
9 #include <string.h>
10
11 /* mbed TLS headers */
12 #include <mbedtls/md.h>
13 #include <mbedtls/memory_buffer_alloc.h>
14 #include <mbedtls/oid.h>
15 #include <mbedtls/platform.h>
16 #include <mbedtls/psa_util.h>
17 #include <mbedtls/x509.h>
18 #include <psa/crypto.h>
19 #include <psa/crypto_platform.h>
20 #include <psa/crypto_types.h>
21 #include <psa/crypto_values.h>
22
23 #include <common/debug.h>
24 #include <drivers/auth/crypto_mod.h>
25 #include <drivers/auth/mbedtls/mbedtls_common.h>
26 #include <plat/common/platform.h>
27
28 #define LIB_NAME "mbed TLS PSA"
29
30 /* Minimum required size for a buffer containing a raw EC signature when using
31 * a maximum curve size of 384 bits.
32 * This is calculated as 2 * (384 / 8). */
33 #define ECDSA_SIG_BUFFER_SIZE 96U
34
35 /* Size of ASN.1 length and tag in bytes*/
36 #define SIZE_OF_ASN1_LEN 1U
37 #define SIZE_OF_ASN1_TAG 1U
38
39 #if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
40 CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
41 /*
42 * CRYPTO_MD_MAX_SIZE value is as per current stronger algorithm available
43 * so make sure that mbed TLS MD maximum size must be lesser than this.
44 */
45 CASSERT(CRYPTO_MD_MAX_SIZE >= MBEDTLS_MD_MAX_SIZE,
46 assert_mbedtls_md_size_overflow);
47
48 #endif /*
49 * CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
50 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
51 */
52
53 /*
54 * AlgorithmIdentifier ::= SEQUENCE {
55 * algorithm OBJECT IDENTIFIER,
56 * parameters ANY DEFINED BY algorithm OPTIONAL
57 * }
58 *
59 * SubjectPublicKeyInfo ::= SEQUENCE {
60 * algorithm AlgorithmIdentifier,
61 * subjectPublicKey BIT STRING
62 * }
63 *
64 * DigestInfo ::= SEQUENCE {
65 * digestAlgorithm AlgorithmIdentifier,
66 * digest OCTET STRING
67 * }
68 */
69
70 /*
71 * We pretend using an external RNG (through MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
72 * mbedTLS config option) so we need to provide an implementation of
73 * mbedtls_psa_external_get_random(). Provide a fake one, since we do not
74 * actually have any external RNG and TF-A itself doesn't engage in
75 * cryptographic operations that demands randomness.
76 */
mbedtls_psa_external_get_random(mbedtls_psa_external_random_context_t * context,uint8_t * output,size_t output_size,size_t * output_length)77 psa_status_t mbedtls_psa_external_get_random(
78 mbedtls_psa_external_random_context_t *context,
79 uint8_t *output, size_t output_size,
80 size_t *output_length)
81 {
82 return PSA_ERROR_INSUFFICIENT_ENTROPY;
83 }
84
85 /*
86 * Initialize the library and export the descriptor
87 */
init(void)88 static void init(void)
89 {
90 /* Initialize mbed TLS */
91 mbedtls_init();
92
93 /* Initialise PSA mbedTLS */
94 psa_status_t status = psa_crypto_init();
95
96 if (status != PSA_SUCCESS) {
97 ERROR("Failed to initialize %s crypto (%d).\n", LIB_NAME, status);
98 panic();
99 }
100
101 INFO("PSA crypto initialized successfully!\n");
102 }
103
104 #if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
105 CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
106
107 /*
108 * NOTE: This has been made internal in mbedtls 3.6.0 and the mbedtls team has
109 * advised that it's better to copy out the declaration than it would be to
110 * update to 3.5.2, where this function is exposed.
111 */
112 int mbedtls_x509_get_sig_alg(const mbedtls_x509_buf *sig_oid,
113 const mbedtls_x509_buf *sig_params,
114 mbedtls_md_type_t *md_alg,
115 mbedtls_pk_type_t *pk_alg,
116 void **sig_opts);
117
118 /*
119 * This is a helper function which parses a SignatureAlgorithm OID.
120 * It extracts the pk algorithm and constructs a psa_algorithm_t object
121 * to be used by PSA calls.
122 */
construct_psa_alg(void * sig_alg,unsigned int sig_alg_len,mbedtls_pk_type_t * pk_alg,psa_algorithm_t * psa_alg)123 static int construct_psa_alg(void *sig_alg, unsigned int sig_alg_len,
124 mbedtls_pk_type_t *pk_alg, psa_algorithm_t *psa_alg)
125 {
126 int rc;
127 mbedtls_md_type_t md_alg;
128 void *sig_opts = NULL;
129 mbedtls_asn1_buf sig_alg_oid, params;
130 unsigned char *p = (unsigned char *) sig_alg;
131 unsigned char *end = (unsigned char *) sig_alg + sig_alg_len;
132
133 rc = mbedtls_asn1_get_alg(&p, end, &sig_alg_oid, ¶ms);
134 if (rc != 0) {
135 rc = CRYPTO_ERR_SIGNATURE;
136 goto end;
137 }
138
139 rc = mbedtls_x509_get_sig_alg(&sig_alg_oid, ¶ms, &md_alg, pk_alg, &sig_opts);
140 if (rc != 0) {
141 rc = CRYPTO_ERR_SIGNATURE;
142 goto end;
143 }
144
145 psa_algorithm_t psa_md_alg = mbedtls_md_psa_alg_from_type(md_alg);
146
147 switch (*pk_alg) {
148 case MBEDTLS_PK_RSASSA_PSS:
149 *psa_alg = PSA_ALG_RSA_PSS(psa_md_alg);
150 rc = CRYPTO_SUCCESS;
151 break;
152 case MBEDTLS_PK_ECDSA:
153 *psa_alg = PSA_ALG_ECDSA(psa_md_alg);
154 rc = CRYPTO_SUCCESS;
155 break;
156 default:
157 *psa_alg = PSA_ALG_NONE;
158 rc = CRYPTO_ERR_SIGNATURE;
159 break;
160 }
161
162 end:
163 mbedtls_free(sig_opts);
164 return rc;
165 }
166
167 /*
168 * Helper functions for mbedtls PK contexts.
169 */
initialize_pk_context(mbedtls_pk_context * pk,bool * pk_initialized)170 static void initialize_pk_context(mbedtls_pk_context *pk, bool *pk_initialized)
171 {
172 mbedtls_pk_init(pk);
173 *pk_initialized = true;
174 }
175
cleanup_pk_context(mbedtls_pk_context * pk,bool * pk_initialized)176 static void cleanup_pk_context(mbedtls_pk_context *pk, bool *pk_initialized)
177 {
178 if (*pk_initialized) {
179 mbedtls_pk_free(pk);
180 *pk_initialized = false;
181 }
182 }
183
184 /*
185 * Verify a signature.
186 *
187 * Parameters are passed using the DER encoding format following the ASN.1
188 * structures detailed above.
189 */
verify_signature(void * data_ptr,unsigned int data_len,void * sig_ptr,unsigned int sig_len,void * sig_alg,unsigned int sig_alg_len,void * pk_ptr,unsigned int pk_len)190 static int verify_signature(void *data_ptr, unsigned int data_len,
191 void *sig_ptr, unsigned int sig_len,
192 void *sig_alg, unsigned int sig_alg_len,
193 void *pk_ptr, unsigned int pk_len)
194 {
195 unsigned char *p, *end;
196 mbedtls_pk_context pk;
197 bool pk_initialized = false;
198 int rc = CRYPTO_ERR_SIGNATURE;
199 psa_status_t psa_status = PSA_ERROR_CORRUPTION_DETECTED;
200 psa_key_attributes_t psa_key_attr = PSA_KEY_ATTRIBUTES_INIT;
201 psa_key_id_t psa_key_id;
202 mbedtls_pk_type_t pk_alg;
203 psa_algorithm_t psa_alg;
204 __unused unsigned char reformatted_sig[ECDSA_SIG_BUFFER_SIZE] = {0};
205 unsigned char *local_sig_ptr;
206 size_t local_sig_len;
207
208 /* Load the key into the PSA key store. */
209 initialize_pk_context(&pk, &pk_initialized);
210
211 p = (unsigned char *) pk_ptr;
212 end = p + pk_len;
213 rc = mbedtls_pk_parse_subpubkey(&p, end, &pk);
214 if (rc != 0) {
215 rc = CRYPTO_ERR_SIGNATURE;
216 goto end2;
217 }
218
219 rc = mbedtls_pk_get_psa_attributes(&pk, PSA_KEY_USAGE_VERIFY_MESSAGE, &psa_key_attr);
220 if (rc != 0) {
221 rc = CRYPTO_ERR_SIGNATURE;
222 goto end2;
223 }
224
225 rc = construct_psa_alg(sig_alg, sig_alg_len, &pk_alg, &psa_alg);
226 if (rc != CRYPTO_SUCCESS) {
227 goto end2;
228 }
229 psa_set_key_algorithm(&psa_key_attr, psa_alg);
230
231 rc = mbedtls_pk_import_into_psa(&pk, &psa_key_attr, &psa_key_id);
232 if (rc != 0) {
233 rc = CRYPTO_ERR_SIGNATURE;
234 goto end2;
235 }
236
237 /* Optimize mbedtls heap usage by freeing the pk context now. */
238 cleanup_pk_context(&pk, &pk_initialized);
239
240 /* Extract the signature from sig_ptr. */
241 p = (unsigned char *) sig_ptr;
242 end = p + sig_len;
243 rc = mbedtls_asn1_get_bitstring_null(&p, end, &local_sig_len);
244 if (rc != 0) {
245 rc = CRYPTO_ERR_SIGNATURE;
246 goto end1;
247 }
248 local_sig_ptr = p;
249
250 #if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
251 TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
252 if (pk_alg == MBEDTLS_PK_ECDSA) {
253 /* Convert the DER ASN.1 signature to raw format. */
254 size_t key_bits = psa_get_key_bits(&psa_key_attr);
255
256 rc = mbedtls_ecdsa_der_to_raw(key_bits, p, local_sig_len,
257 reformatted_sig, ECDSA_SIG_BUFFER_SIZE,
258 &local_sig_len);
259 if (rc != 0) {
260 rc = CRYPTO_ERR_SIGNATURE;
261 goto end1;
262 }
263 local_sig_ptr = reformatted_sig;
264 }
265 #endif /*
266 * TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
267 * TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
268 **/
269
270 /* Verify the signature. */
271 psa_status = psa_verify_message(psa_key_id, psa_alg,
272 data_ptr, data_len,
273 local_sig_ptr, local_sig_len);
274 if (psa_status == PSA_SUCCESS) {
275 /* The signature has been successfully verified. */
276 rc = CRYPTO_SUCCESS;
277 } else {
278 rc = CRYPTO_ERR_SIGNATURE;
279 }
280
281 end1:
282 /* Destroy the key from the PSA subsystem. */
283 psa_destroy_key(psa_key_id);
284 end2:
285 /* Free the pk context, if it is initialized. */
286 cleanup_pk_context(&pk, &pk_initialized);
287
288 return rc;
289 }
290
291 /*
292 * Match a hash
293 *
294 * Digest info is passed in DER format following the ASN.1 structure detailed
295 * above.
296 */
verify_hash(void * data_ptr,unsigned int data_len,void * digest_info_ptr,unsigned int digest_info_len)297 static int verify_hash(void *data_ptr, unsigned int data_len,
298 void *digest_info_ptr, unsigned int digest_info_len)
299 {
300 mbedtls_asn1_buf hash_oid, params;
301 mbedtls_md_type_t md_alg;
302 unsigned char *p, *end, *hash;
303 size_t len;
304 int rc;
305 psa_status_t status;
306 psa_algorithm_t psa_md_alg;
307
308 /*
309 * Digest info should be an MBEDTLS_ASN1_SEQUENCE, but padding after
310 * it is allowed. This is necessary to support multiple hash
311 * algorithms.
312 */
313 p = (unsigned char *)digest_info_ptr;
314 end = p + digest_info_len;
315 rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
316 MBEDTLS_ASN1_SEQUENCE);
317 if (rc != 0) {
318 return CRYPTO_ERR_HASH;
319 }
320
321 end = p + len;
322
323 /* Get the hash algorithm */
324 rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, ¶ms);
325 if (rc != 0) {
326 return CRYPTO_ERR_HASH;
327 }
328
329 /* Hash should be octet string type and consume all bytes */
330 rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
331 if ((rc != 0) || ((size_t)(end - p) != len)) {
332 return CRYPTO_ERR_HASH;
333 }
334 hash = p;
335
336 rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
337 if (rc != 0) {
338 return CRYPTO_ERR_HASH;
339 }
340
341 /* convert the md_alg to psa_algo */
342 psa_md_alg = mbedtls_md_psa_alg_from_type(md_alg);
343
344 /* Length of hash must match the algorithm's size */
345 if (len != PSA_HASH_LENGTH(psa_md_alg)) {
346 return CRYPTO_ERR_HASH;
347 }
348
349 /*
350 * Calculate Hash and compare it against the retrieved hash from
351 * the certificate (one shot API).
352 */
353 status = psa_hash_compare(psa_md_alg,
354 data_ptr, (size_t)data_len,
355 (const uint8_t *)hash, len);
356
357 if (status != PSA_SUCCESS) {
358 return CRYPTO_ERR_HASH;
359 }
360
361 return CRYPTO_SUCCESS;
362 }
363 #endif /*
364 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
365 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
366 */
367
368 #if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
369 CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
370 /*
371 * Map a generic crypto message digest algorithm to the corresponding macro used
372 * by Mbed TLS.
373 */
md_type(enum crypto_md_algo algo)374 static inline mbedtls_md_type_t md_type(enum crypto_md_algo algo)
375 {
376 switch (algo) {
377 case CRYPTO_MD_SHA512:
378 return MBEDTLS_MD_SHA512;
379 case CRYPTO_MD_SHA384:
380 return MBEDTLS_MD_SHA384;
381 case CRYPTO_MD_SHA256:
382 return MBEDTLS_MD_SHA256;
383 default:
384 /* Invalid hash algorithm. */
385 return MBEDTLS_MD_NONE;
386 }
387 }
388
389 /*
390 * Calculate a hash
391 *
392 * output points to the computed hash
393 */
calc_hash(enum crypto_md_algo md_algo,void * data_ptr,unsigned int data_len,unsigned char output[CRYPTO_MD_MAX_SIZE])394 static int calc_hash(enum crypto_md_algo md_algo, void *data_ptr,
395 unsigned int data_len,
396 unsigned char output[CRYPTO_MD_MAX_SIZE])
397 {
398 size_t hash_length;
399 psa_status_t status;
400 psa_algorithm_t psa_md_alg;
401
402 /* convert the md_alg to psa_algo */
403 psa_md_alg = mbedtls_md_psa_alg_from_type(md_type(md_algo));
404
405 /*
406 * Calculate the hash of the data, it is safe to pass the
407 * 'output' hash buffer pointer considering its size is always
408 * bigger than or equal to MBEDTLS_MD_MAX_SIZE.
409 */
410 status = psa_hash_compute(psa_md_alg, data_ptr, (size_t)data_len,
411 (uint8_t *)output, CRYPTO_MD_MAX_SIZE,
412 &hash_length);
413 if (status != PSA_SUCCESS) {
414 return CRYPTO_ERR_HASH;
415 }
416
417 return CRYPTO_SUCCESS;
418 }
419 #endif /*
420 * CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
421 * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
422 */
423
424 #if TF_MBEDTLS_USE_AES_GCM
425 /*
426 * Stack based buffer allocation for decryption operation. It could
427 * be configured to balance stack usage vs execution speed.
428 */
429 #define DEC_OP_BUF_SIZE 128
430
aes_gcm_decrypt(void * data_ptr,size_t len,const void * key,unsigned int key_len,const void * iv,unsigned int iv_len,const void * tag,unsigned int tag_len)431 static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
432 unsigned int key_len, const void *iv,
433 unsigned int iv_len, const void *tag,
434 unsigned int tag_len)
435 {
436 mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
437 psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
438 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
439 psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
440 unsigned char buf[DEC_OP_BUF_SIZE];
441 unsigned char *pt = data_ptr;
442 size_t dec_len;
443 size_t output_length;
444
445 /* Load the key into the PSA key store. */
446 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
447 psa_set_key_algorithm(&attributes, PSA_ALG_GCM);
448 psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
449
450 psa_status = psa_import_key(&attributes, key, key_len, &key_id);
451 if (psa_status != PSA_SUCCESS) {
452 return CRYPTO_ERR_DECRYPTION;
453 }
454
455 /* Perform the decryption. */
456 psa_status = psa_aead_decrypt_setup(&operation, key_id, PSA_ALG_GCM);
457 if (psa_status != PSA_SUCCESS) {
458 goto err;
459 }
460
461 psa_status = psa_aead_set_nonce(&operation, iv, iv_len);
462 if (psa_status != PSA_SUCCESS) {
463 goto err;
464 }
465
466 while (len > 0) {
467 dec_len = MIN(sizeof(buf), len);
468
469 psa_status = psa_aead_update(&operation, pt, dec_len, buf,
470 sizeof(buf), &output_length);
471 if (psa_status != PSA_SUCCESS) {
472 goto err;
473 }
474
475 memcpy(pt, buf, output_length);
476 pt += output_length;
477 len -= dec_len;
478 }
479
480 /* Verify the tag. */
481 psa_status = psa_aead_verify(&operation, NULL, 0, &output_length, tag, tag_len);
482 if (psa_status == PSA_SUCCESS) {
483 psa_destroy_key(key_id);
484 return CRYPTO_SUCCESS;
485 }
486
487 err:
488 psa_aead_abort(&operation);
489 psa_destroy_key(key_id);
490 return CRYPTO_ERR_DECRYPTION;
491 }
492
493 /*
494 * Authenticated decryption of an image
495 */
auth_decrypt(enum crypto_dec_algo dec_algo,void * data_ptr,size_t len,const void * key,unsigned int key_len,unsigned int key_flags,const void * iv,unsigned int iv_len,const void * tag,unsigned int tag_len)496 static int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
497 size_t len, const void *key, unsigned int key_len,
498 unsigned int key_flags, const void *iv,
499 unsigned int iv_len, const void *tag,
500 unsigned int tag_len)
501 {
502 int rc;
503
504 assert((key_flags & ENC_KEY_IS_IDENTIFIER) == 0);
505
506 switch (dec_algo) {
507 case CRYPTO_GCM_DECRYPT:
508 rc = aes_gcm_decrypt(data_ptr, len, key, key_len, iv, iv_len,
509 tag, tag_len);
510 if (rc != 0)
511 return rc;
512 break;
513 default:
514 return CRYPTO_ERR_DECRYPTION;
515 }
516
517 return CRYPTO_SUCCESS;
518 }
519 #endif /* TF_MBEDTLS_USE_AES_GCM */
520
521 /*
522 * Register crypto library descriptor
523 */
524 #if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
525 #if TF_MBEDTLS_USE_AES_GCM
526 REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
527 auth_decrypt, NULL);
528 #else
529 REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
530 NULL, NULL);
531 #endif
532 #elif CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY
533 #if TF_MBEDTLS_USE_AES_GCM
534 REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
535 auth_decrypt, NULL);
536 #else
537 REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
538 NULL, NULL);
539 #endif
540 #elif CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY
541 REGISTER_CRYPTO_LIB(LIB_NAME, init, NULL, NULL, calc_hash, NULL, NULL);
542 #endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
543