blob: 6dd7bf28e0271022c8094a4193e3cc9aa848620c [file] [log] [blame]
Antonio de Angelis8908f472018-08-31 15:44:25 +01001/*
Summer Qina5448d62020-12-07 14:03:37 +08002 * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
Antonio de Angelis8908f472018-08-31 15:44:25 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
Jamie Fox0e54ebc2019-04-09 14:21:04 +01008#include "tfm_mbedcrypto_include.h"
9
Antonio de Angelis8908f472018-08-31 15:44:25 +010010#include "tfm_crypto_api.h"
Jamie Fox0e54ebc2019-04-09 14:21:04 +010011#include "tfm_crypto_defs.h"
Summer Qinc737ece2020-08-28 10:47:26 +080012#include "tfm_sp_log.h"
Jamie Fox0e54ebc2019-04-09 14:21:04 +010013
14/*
15 * \brief This Mbed TLS include is needed to initialise the memory allocator
16 * inside the Mbed TLS layer of Mbed Crypto
17 */
18#include "mbedtls/memory_buffer_alloc.h"
Antonio de Angelis8908f472018-08-31 15:44:25 +010019
Summer Qina5448d62020-12-07 14:03:37 +080020#ifdef PLATFORM_DUMMY_NV_SEED
21#include "tfm_plat_crypto_dummy_nv_seed.h"
22#endif
23
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010024#ifndef TFM_PSA_API
25#include "tfm_secure_api.h"
26#endif
27
Raef Colesd2485af2019-10-30 10:15:33 +000028#ifdef CRYPTO_HW_ACCELERATOR
29#include "crypto_hw.h"
30#endif /* CRYPTO_HW_ACCLERATOR */
31
Antonio de Angelis4743e672019-04-11 11:38:48 +010032#ifdef TFM_PSA_API
Jamie Foxcc31d402019-01-28 17:13:52 +000033#include "psa/service.h"
Edison Aicc4c6162019-06-21 13:52:49 +080034#include "psa_manifest/tfm_crypto.h"
David Hu49a28eb2019-08-14 18:18:15 +080035#include "tfm_memory_utils.h"
Antonio de Angelis4743e672019-04-11 11:38:48 +010036
37/**
38 * \brief Table containing all the Uniform Signature API exposed
39 * by the TF-M Crypto partition
40 */
Edison Ai080b2e22019-04-17 16:27:21 +080041static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SID_MAX] = {
Antonio de Angelis25e2b2d2019-04-25 14:49:50 +010042#define X(api_name) api_name,
43LIST_TFM_CRYPTO_UNIFORM_SIGNATURE_API
44#undef X
Antonio de Angelis4743e672019-04-11 11:38:48 +010045};
46
47/**
48 * \brief Aligns a value x up to an alignment a.
49 */
50#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
51
52/**
53 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
54 * partition.
55 */
56#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
57
58/**
59 * \brief Default size of the internal scratch buffer used for IOVec allocations
60 * in bytes
61 */
62#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
Soby Mathew7740b602020-10-07 12:08:28 +010063#error TFM_CRYPTO_IOVEC_BUFFER_SIZE is not defined
Antonio de Angelis4743e672019-04-11 11:38:48 +010064#endif
65
66/**
67 * \brief Internal scratch used for IOVec allocations
68 *
69 */
70static struct tfm_crypto_scratch {
71 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
72 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
73 uint32_t alloc_index;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010074 int32_t owner;
Antonio de Angelis4743e672019-04-11 11:38:48 +010075} scratch = {.buf = {0}, .alloc_index = 0};
76
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010077static psa_status_t tfm_crypto_set_scratch_owner(int32_t id)
78{
79 scratch.owner = id;
80 return PSA_SUCCESS;
81}
82
83static psa_status_t tfm_crypto_get_scratch_owner(int32_t *id)
84{
85 *id = scratch.owner;
86 return PSA_SUCCESS;
87}
88
Antonio de Angelis4743e672019-04-11 11:38:48 +010089static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
90{
91 /* Ensure alloc_index remains aligned to the required iovec alignment */
92 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
93
94 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
95 return PSA_ERROR_INSUFFICIENT_MEMORY;
96 }
97
98 /* Compute the pointer to the allocated space */
99 *buf = (void *)&scratch.buf[scratch.alloc_index];
100
101 /* Increase the allocated size */
102 scratch.alloc_index += requested_size;
103
104 return PSA_SUCCESS;
105}
106
Summer Qin0a9e5372020-11-27 16:04:05 +0800107void tfm_crypto_clear_scratch(void)
Antonio de Angelis4743e672019-04-11 11:38:48 +0100108{
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100109 scratch.owner = 0;
Summer Qin0a9e5372020-11-27 16:04:05 +0800110 (void)tfm_memset(scratch.buf, 0, scratch.alloc_index);
111 scratch.alloc_index = 0;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100112}
113
114static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
115 struct tfm_crypto_pack_iovec *iov,
116 const uint32_t sfn_id)
117{
118 psa_status_t status = PSA_SUCCESS;
TTornblomfaf74f52020-03-04 17:56:27 +0100119 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
Soby Mathewd8abdfd2020-10-14 10:28:01 +0100120 psa_invec in_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
121 psa_outvec out_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
Antonio de Angelis4743e672019-04-11 11:38:48 +0100122 void *alloc_buf_ptr = NULL;
123
124 /* Check the number of in_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100125 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
126 in_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100127 }
128
129 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
130 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100131 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100132 }
133 /* Initialise the first iovec with the IOV read when parsing */
134 in_vec[0].base = iov;
135 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
136
137 /* Alloc/read from the second element as the first is read when parsing */
138 for (i = 1; i < in_len; i++) {
139 /* Allocate necessary space in the internal scratch */
140 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
141 if (status != PSA_SUCCESS) {
Summer Qin0a9e5372020-11-27 16:04:05 +0800142 tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100143 return status;
144 }
145 /* Read from the IPC framework inputs into the scratch */
TTornblomfaf74f52020-03-04 17:56:27 +0100146 (void) psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
Antonio de Angelis4743e672019-04-11 11:38:48 +0100147 /* Populate the fields of the input to the secure function */
148 in_vec[i].base = alloc_buf_ptr;
149 in_vec[i].len = msg->in_size[i];
150 }
151
152 /* Check the number of out_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100153 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
154 out_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100155 }
156
157 for (i = 0; i < out_len; i++) {
158 /* Allocate necessary space for the output in the internal scratch */
159 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
160 if (status != PSA_SUCCESS) {
Summer Qin0a9e5372020-11-27 16:04:05 +0800161 tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100162 return status;
163 }
164 /* Populate the fields of the output to the secure function */
165 out_vec[i].base = alloc_buf_ptr;
166 out_vec[i].len = msg->out_size[i];
167 }
168
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100169 /* Set the owner of the data in the scratch */
170 (void)tfm_crypto_set_scratch_owner(msg->client_id);
171
Antonio de Angelis4743e672019-04-11 11:38:48 +0100172 /* Call the uniform signature API */
173 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
174
175 /* Write into the IPC framework outputs from the scratch */
176 for (i = 0; i < out_len; i++) {
177 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
178 }
179
180 /* Clear the allocated internal scratch before returning */
Summer Qin0a9e5372020-11-27 16:04:05 +0800181 tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100182
183 return status;
184}
185
186static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
187 struct tfm_crypto_pack_iovec *iov,
188 uint32_t *sfn_id_p)
189{
190 size_t read_size;
191
192 /* Read the in_vec[0] which holds the IOVEC always */
193 read_size = psa_read(msg->handle,
194 0,
195 iov,
196 sizeof(struct tfm_crypto_pack_iovec));
197
198 if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100199 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100200 }
201
Edison Ai080b2e22019-04-17 16:27:21 +0800202 if (iov->sfn_id >= TFM_CRYPTO_SID_MAX) {
203 *sfn_id_p = TFM_CRYPTO_SID_INVALID;
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100204 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100205 }
206
207 *sfn_id_p = iov->sfn_id;
208
209 return PSA_SUCCESS;
210}
211
212static void tfm_crypto_ipc_handler(void)
213{
214 psa_signal_t signals = 0;
215 psa_msg_t msg;
216 psa_status_t status = PSA_SUCCESS;
Edison Ai080b2e22019-04-17 16:27:21 +0800217 uint32_t sfn_id = TFM_CRYPTO_SID_INVALID;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100218 struct tfm_crypto_pack_iovec iov = {0};
219
220 while (1) {
221 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
Edison Ai45b22552019-10-12 11:05:57 +0800222 if (signals & TFM_CRYPTO_SIGNAL) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100223 /* Extract the message */
Edison Ai45b22552019-10-12 11:05:57 +0800224 if (psa_get(TFM_CRYPTO_SIGNAL, &msg) != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100225 /* FIXME: Should be replaced by TF-M error handling */
226 while (1) {
227 ;
228 }
229 }
230
231 /* Process the message type */
232 switch (msg.type) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100233 case PSA_IPC_CALL:
234 /* Parse the message */
235 status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
Edison Ai080b2e22019-04-17 16:27:21 +0800236 /* Call the dispatcher based on the SID passed as type */
237 if (sfn_id != TFM_CRYPTO_SID_INVALID) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100238 status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
239 } else {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100240 status = PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100241 }
242 psa_reply(msg.handle, status);
243 break;
244 default:
245 /* FIXME: Should be replaced by TF-M error handling */
246 while (1) {
247 ;
248 }
249 }
250 } else {
251 /* FIXME: Should be replaced by TF-M error handling */
252 while (1) {
253 ;
254 }
255 }
256 }
257
TTornblomfaf74f52020-03-04 17:56:27 +0100258 /* NOTREACHED */
Antonio de Angelis4743e672019-04-11 11:38:48 +0100259 return;
260}
261#endif /* TFM_PSA_API */
262
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100263/**
264 * \brief Default value for the size of the static buffer used by Mbed
265 * Crypto for its dynamic allocations
266 */
267#ifndef TFM_CRYPTO_ENGINE_BUF_SIZE
Soby Mathew7740b602020-10-07 12:08:28 +0100268#error TFM_CRYPTO_ENGINE_BUF_SIZE is not defined
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100269#endif
270
271/**
272 * \brief Static buffer to be used by Mbed Crypto for memory allocations
273 *
274 */
275static uint8_t mbedtls_mem_buf[TFM_CRYPTO_ENGINE_BUF_SIZE] = {0};
276
277static psa_status_t tfm_crypto_engine_init(void)
278{
Summer Qina5448d62020-12-07 14:03:37 +0800279#ifdef PLATFORM_DUMMY_NV_SEED
Summer Qin9347dc72021-07-12 18:57:57 +0800280 LOG_INFFMT("\033[1;34m[Crypto] Dummy Entropy NV Seed is not suitable for production!\033[0m\r\n");
Summer Qina5448d62020-12-07 14:03:37 +0800281 if (tfm_plat_crypto_create_entropy_seed() != TFM_CRYPTO_NV_SEED_SUCCESS) {
282 return PSA_ERROR_GENERIC_ERROR;
283 }
284#endif
285
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100286 /* Initialise the Mbed Crypto memory allocator to use static
287 * memory allocation from the provided buffer instead of using
288 * the heap
289 */
290 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
291 TFM_CRYPTO_ENGINE_BUF_SIZE);
292
Raef Colesd2485af2019-10-30 10:15:33 +0000293 /* Initialise the crypto accelerator if one is enabled */
294#ifdef CRYPTO_HW_ACCELERATOR
295 if (crypto_hw_accelerator_init() != 0) {
296 return PSA_ERROR_HARDWARE_FAILURE;
297 }
298#endif /* CRYPTO_HW_ACCELERATOR */
299
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100300 /* Previous function does not return any value, so just call the
301 * initialisation function of the Mbed Crypto layer
302 */
303 return psa_crypto_init();
304}
305
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000306static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100307{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100308 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000309 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100310}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100311
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100312psa_status_t tfm_crypto_get_caller_id(int32_t *id)
313{
314#ifdef TFM_PSA_API
315 return tfm_crypto_get_scratch_owner(id);
316#else
317 int32_t res;
318
319 res = tfm_core_get_caller_client_id(id);
320 if (res != TFM_SUCCESS) {
321 return PSA_ERROR_NOT_PERMITTED;
322 } else {
323 return PSA_SUCCESS;
324 }
325#endif
326}
327
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000328psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100329{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100330 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100331
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100332 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000333 status = tfm_crypto_module_init();
334 if (status != PSA_SUCCESS) {
335 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100336 }
337
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100338 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100339 status = tfm_crypto_engine_init();
340 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100341 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100342 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100343
Antonio de Angelis4743e672019-04-11 11:38:48 +0100344#ifdef TFM_PSA_API
345 /* Should not return in normal operations */
346 tfm_crypto_ipc_handler();
347#endif
348
349 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100350}