blob: bd72f5abeca9184ed2e0780a64d44d6836cded43 [file] [log] [blame]
Antonio de Angelis8908f472018-08-31 15:44:25 +01001/*
TTornblomfaf74f52020-03-04 17:56:27 +01002 * Copyright (c) 2018-2020, 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 Qin27e1dbc2020-08-28 10:47:26 +080012#include "tfm_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
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010020#ifndef TFM_PSA_API
21#include "tfm_secure_api.h"
22#endif
23
Raef Colesd2485af2019-10-30 10:15:33 +000024#ifdef CRYPTO_HW_ACCELERATOR
25#include "crypto_hw.h"
26#endif /* CRYPTO_HW_ACCLERATOR */
27
Antonio de Angelis4743e672019-04-11 11:38:48 +010028#ifdef TFM_PSA_API
Jamie Foxcc31d402019-01-28 17:13:52 +000029#include "psa/service.h"
Edison Aicc4c6162019-06-21 13:52:49 +080030#include "psa_manifest/tfm_crypto.h"
David Hu49a28eb2019-08-14 18:18:15 +080031#include "tfm_memory_utils.h"
Antonio de Angelis4743e672019-04-11 11:38:48 +010032
33/**
34 * \brief Table containing all the Uniform Signature API exposed
35 * by the TF-M Crypto partition
36 */
Edison Ai080b2e22019-04-17 16:27:21 +080037static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SID_MAX] = {
Antonio de Angelis25e2b2d2019-04-25 14:49:50 +010038#define X(api_name) api_name,
39LIST_TFM_CRYPTO_UNIFORM_SIGNATURE_API
40#undef X
Antonio de Angelis4743e672019-04-11 11:38:48 +010041};
42
43/**
44 * \brief Aligns a value x up to an alignment a.
45 */
46#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
47
48/**
49 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
50 * partition.
51 */
52#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
53
54/**
55 * \brief Default size of the internal scratch buffer used for IOVec allocations
56 * in bytes
57 */
58#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
Jamie Foxdaade492019-04-26 14:35:39 +010059#define TFM_CRYPTO_IOVEC_BUFFER_SIZE (5120)
Antonio de Angelis4743e672019-04-11 11:38:48 +010060#endif
61
62/**
63 * \brief Internal scratch used for IOVec allocations
64 *
65 */
66static struct tfm_crypto_scratch {
67 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
68 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
69 uint32_t alloc_index;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010070 int32_t owner;
Antonio de Angelis4743e672019-04-11 11:38:48 +010071} scratch = {.buf = {0}, .alloc_index = 0};
72
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010073static psa_status_t tfm_crypto_set_scratch_owner(int32_t id)
74{
75 scratch.owner = id;
76 return PSA_SUCCESS;
77}
78
79static psa_status_t tfm_crypto_get_scratch_owner(int32_t *id)
80{
81 *id = scratch.owner;
82 return PSA_SUCCESS;
83}
84
Antonio de Angelis4743e672019-04-11 11:38:48 +010085static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
86{
87 /* Ensure alloc_index remains aligned to the required iovec alignment */
88 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
89
90 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
91 return PSA_ERROR_INSUFFICIENT_MEMORY;
92 }
93
94 /* Compute the pointer to the allocated space */
95 *buf = (void *)&scratch.buf[scratch.alloc_index];
96
97 /* Increase the allocated size */
98 scratch.alloc_index += requested_size;
99
100 return PSA_SUCCESS;
101}
102
103static psa_status_t tfm_crypto_clear_scratch(void)
104{
105 scratch.alloc_index = 0;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100106 scratch.owner = 0;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100107 (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
108
109 return PSA_SUCCESS;
110}
111
112static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
113 struct tfm_crypto_pack_iovec *iov,
114 const uint32_t sfn_id)
115{
116 psa_status_t status = PSA_SUCCESS;
TTornblomfaf74f52020-03-04 17:56:27 +0100117 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100118 psa_invec in_vec[PSA_MAX_IOVEC] = { {0} };
119 psa_outvec out_vec[PSA_MAX_IOVEC] = { {0} };
120 void *alloc_buf_ptr = NULL;
121
122 /* Check the number of in_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100123 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
124 in_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100125 }
126
127 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
128 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100129 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100130 }
131 /* Initialise the first iovec with the IOV read when parsing */
132 in_vec[0].base = iov;
133 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
134
135 /* Alloc/read from the second element as the first is read when parsing */
136 for (i = 1; i < in_len; i++) {
137 /* Allocate necessary space in the internal scratch */
138 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
139 if (status != PSA_SUCCESS) {
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100140 (void)tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100141 return status;
142 }
143 /* Read from the IPC framework inputs into the scratch */
TTornblomfaf74f52020-03-04 17:56:27 +0100144 (void) psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
Antonio de Angelis4743e672019-04-11 11:38:48 +0100145 /* Populate the fields of the input to the secure function */
146 in_vec[i].base = alloc_buf_ptr;
147 in_vec[i].len = msg->in_size[i];
148 }
149
150 /* Check the number of out_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100151 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
152 out_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100153 }
154
155 for (i = 0; i < out_len; i++) {
156 /* Allocate necessary space for the output in the internal scratch */
157 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
158 if (status != PSA_SUCCESS) {
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100159 (void)tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100160 return status;
161 }
162 /* Populate the fields of the output to the secure function */
163 out_vec[i].base = alloc_buf_ptr;
164 out_vec[i].len = msg->out_size[i];
165 }
166
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100167 /* Set the owner of the data in the scratch */
168 (void)tfm_crypto_set_scratch_owner(msg->client_id);
169
Antonio de Angelis4743e672019-04-11 11:38:48 +0100170 /* Call the uniform signature API */
171 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
172
173 /* Write into the IPC framework outputs from the scratch */
174 for (i = 0; i < out_len; i++) {
175 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
176 }
177
178 /* Clear the allocated internal scratch before returning */
179 if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100180 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100181 }
182
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) {
233 case PSA_IPC_CONNECT:
234 case PSA_IPC_DISCONNECT:
235 psa_reply(msg.handle, PSA_SUCCESS);
236 break;
237 case PSA_IPC_CALL:
238 /* Parse the message */
239 status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
Edison Ai080b2e22019-04-17 16:27:21 +0800240 /* Call the dispatcher based on the SID passed as type */
241 if (sfn_id != TFM_CRYPTO_SID_INVALID) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100242 status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
243 } else {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100244 status = PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100245 }
246 psa_reply(msg.handle, status);
247 break;
248 default:
249 /* FIXME: Should be replaced by TF-M error handling */
250 while (1) {
251 ;
252 }
253 }
254 } else {
255 /* FIXME: Should be replaced by TF-M error handling */
256 while (1) {
257 ;
258 }
259 }
260 }
261
TTornblomfaf74f52020-03-04 17:56:27 +0100262 /* NOTREACHED */
Antonio de Angelis4743e672019-04-11 11:38:48 +0100263 return;
264}
265#endif /* TFM_PSA_API */
266
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100267/**
268 * \brief Default value for the size of the static buffer used by Mbed
269 * Crypto for its dynamic allocations
270 */
271#ifndef TFM_CRYPTO_ENGINE_BUF_SIZE
Ken Liu89443862020-08-25 13:06:45 +0800272#define TFM_CRYPTO_ENGINE_BUF_SIZE (0x2040) /* >8KB for EC signing in attest */
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100273#endif
274
275/**
276 * \brief Static buffer to be used by Mbed Crypto for memory allocations
277 *
278 */
279static uint8_t mbedtls_mem_buf[TFM_CRYPTO_ENGINE_BUF_SIZE] = {0};
280
281static psa_status_t tfm_crypto_engine_init(void)
282{
Soby Mathew803886d2020-08-10 12:18:03 +0100283 /* Log unsafe entropy source */
284#if defined (MBEDTLS_TEST_NULL_ENTROPY)
Summer Qin27e1dbc2020-08-28 10:47:26 +0800285 SPLOG_MSG("\033[1;34m[Crypto] MBEDTLS_TEST_NULL_ENTROPY is not suitable for production!\033[0m\r\n");
Soby Mathew803886d2020-08-10 12:18:03 +0100286#endif
287
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100288 /* Initialise the Mbed Crypto memory allocator to use static
289 * memory allocation from the provided buffer instead of using
290 * the heap
291 */
292 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
293 TFM_CRYPTO_ENGINE_BUF_SIZE);
294
Raef Colesd2485af2019-10-30 10:15:33 +0000295 /* Initialise the crypto accelerator if one is enabled */
296#ifdef CRYPTO_HW_ACCELERATOR
297 if (crypto_hw_accelerator_init() != 0) {
298 return PSA_ERROR_HARDWARE_FAILURE;
299 }
300#endif /* CRYPTO_HW_ACCELERATOR */
301
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100302 /* Previous function does not return any value, so just call the
303 * initialisation function of the Mbed Crypto layer
304 */
305 return psa_crypto_init();
306}
307
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000308static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100309{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100310 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000311 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100312}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100313
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100314psa_status_t tfm_crypto_get_caller_id(int32_t *id)
315{
316#ifdef TFM_PSA_API
317 return tfm_crypto_get_scratch_owner(id);
318#else
319 int32_t res;
320
321 res = tfm_core_get_caller_client_id(id);
322 if (res != TFM_SUCCESS) {
323 return PSA_ERROR_NOT_PERMITTED;
324 } else {
325 return PSA_SUCCESS;
326 }
327#endif
328}
329
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000330psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100331{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100332 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100333
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100334 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000335 status = tfm_crypto_module_init();
336 if (status != PSA_SUCCESS) {
337 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100338 }
339
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100340 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100341 status = tfm_crypto_engine_init();
342 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100343 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100344 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100345
Antonio de Angelis4743e672019-04-11 11:38:48 +0100346#ifdef TFM_PSA_API
347 /* Should not return in normal operations */
348 tfm_crypto_ipc_handler();
349#endif
350
351 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100352}