• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params);
134 	if (rc != 0) {
135 		rc = CRYPTO_ERR_SIGNATURE;
136 		goto end;
137 	}
138 
139 	rc = mbedtls_x509_get_sig_alg(&sig_alg_oid, &params, &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, &params);
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