blob: 9b93ea819312d167bccb618141b717d9e9e1a219 [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 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
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
Soby Mathew7740b602020-10-07 12:08:28 +010059#error TFM_CRYPTO_IOVEC_BUFFER_SIZE is not defined
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
Summer Qin0a9e5372020-11-27 16:04:05 +0800103void tfm_crypto_clear_scratch(void)
Antonio de Angelis4743e672019-04-11 11:38:48 +0100104{
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100105 scratch.owner = 0;
Summer Qin0a9e5372020-11-27 16:04:05 +0800106 (void)tfm_memset(scratch.buf, 0, scratch.alloc_index);
107 scratch.alloc_index = 0;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100108}
109
110static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
111 struct tfm_crypto_pack_iovec *iov,
112 const uint32_t sfn_id)
113{
114 psa_status_t status = PSA_SUCCESS;
TTornblomfaf74f52020-03-04 17:56:27 +0100115 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
Soby Mathewd8abdfd2020-10-14 10:28:01 +0100116 psa_invec in_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
117 psa_outvec out_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
Antonio de Angelis4743e672019-04-11 11:38:48 +0100118 void *alloc_buf_ptr = NULL;
119
120 /* Check the number of in_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100121 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
122 in_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100123 }
124
125 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
126 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100127 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100128 }
129 /* Initialise the first iovec with the IOV read when parsing */
130 in_vec[0].base = iov;
131 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
132
133 /* Alloc/read from the second element as the first is read when parsing */
134 for (i = 1; i < in_len; i++) {
135 /* Allocate necessary space in the internal scratch */
136 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
137 if (status != PSA_SUCCESS) {
Summer Qin0a9e5372020-11-27 16:04:05 +0800138 tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100139 return status;
140 }
141 /* Read from the IPC framework inputs into the scratch */
TTornblomfaf74f52020-03-04 17:56:27 +0100142 (void) psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
Antonio de Angelis4743e672019-04-11 11:38:48 +0100143 /* Populate the fields of the input to the secure function */
144 in_vec[i].base = alloc_buf_ptr;
145 in_vec[i].len = msg->in_size[i];
146 }
147
148 /* Check the number of out_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100149 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
150 out_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100151 }
152
153 for (i = 0; i < out_len; i++) {
154 /* Allocate necessary space for the output in the internal scratch */
155 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
156 if (status != PSA_SUCCESS) {
Summer Qin0a9e5372020-11-27 16:04:05 +0800157 tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100158 return status;
159 }
160 /* Populate the fields of the output to the secure function */
161 out_vec[i].base = alloc_buf_ptr;
162 out_vec[i].len = msg->out_size[i];
163 }
164
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100165 /* Set the owner of the data in the scratch */
166 (void)tfm_crypto_set_scratch_owner(msg->client_id);
167
Antonio de Angelis4743e672019-04-11 11:38:48 +0100168 /* Call the uniform signature API */
169 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
170
171 /* Write into the IPC framework outputs from the scratch */
172 for (i = 0; i < out_len; i++) {
173 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
174 }
175
176 /* Clear the allocated internal scratch before returning */
Summer Qin0a9e5372020-11-27 16:04:05 +0800177 tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100178
179 return status;
180}
181
182static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
183 struct tfm_crypto_pack_iovec *iov,
184 uint32_t *sfn_id_p)
185{
186 size_t read_size;
187
188 /* Read the in_vec[0] which holds the IOVEC always */
189 read_size = psa_read(msg->handle,
190 0,
191 iov,
192 sizeof(struct tfm_crypto_pack_iovec));
193
194 if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100195 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100196 }
197
Edison Ai080b2e22019-04-17 16:27:21 +0800198 if (iov->sfn_id >= TFM_CRYPTO_SID_MAX) {
199 *sfn_id_p = TFM_CRYPTO_SID_INVALID;
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100200 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100201 }
202
203 *sfn_id_p = iov->sfn_id;
204
205 return PSA_SUCCESS;
206}
207
208static void tfm_crypto_ipc_handler(void)
209{
210 psa_signal_t signals = 0;
211 psa_msg_t msg;
212 psa_status_t status = PSA_SUCCESS;
Edison Ai080b2e22019-04-17 16:27:21 +0800213 uint32_t sfn_id = TFM_CRYPTO_SID_INVALID;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100214 struct tfm_crypto_pack_iovec iov = {0};
215
216 while (1) {
217 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
Edison Ai45b22552019-10-12 11:05:57 +0800218 if (signals & TFM_CRYPTO_SIGNAL) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100219 /* Extract the message */
Edison Ai45b22552019-10-12 11:05:57 +0800220 if (psa_get(TFM_CRYPTO_SIGNAL, &msg) != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100221 /* FIXME: Should be replaced by TF-M error handling */
222 while (1) {
223 ;
224 }
225 }
226
227 /* Process the message type */
228 switch (msg.type) {
229 case PSA_IPC_CONNECT:
230 case PSA_IPC_DISCONNECT:
231 psa_reply(msg.handle, PSA_SUCCESS);
232 break;
233 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{
Soby Mathew803886d2020-08-10 12:18:03 +0100279 /* Log unsafe entropy source */
280#if defined (MBEDTLS_TEST_NULL_ENTROPY)
Summer Qinc737ece2020-08-28 10:47:26 +0800281 LOG_INFFMT("\033[1;34m[Crypto] MBEDTLS_TEST_NULL_ENTROPY is not suitable for production!\033[0m\r\n");
Soby Mathew803886d2020-08-10 12:18:03 +0100282#endif
283
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100284 /* Initialise the Mbed Crypto memory allocator to use static
285 * memory allocation from the provided buffer instead of using
286 * the heap
287 */
288 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
289 TFM_CRYPTO_ENGINE_BUF_SIZE);
290
Raef Colesd2485af2019-10-30 10:15:33 +0000291 /* Initialise the crypto accelerator if one is enabled */
292#ifdef CRYPTO_HW_ACCELERATOR
293 if (crypto_hw_accelerator_init() != 0) {
294 return PSA_ERROR_HARDWARE_FAILURE;
295 }
296#endif /* CRYPTO_HW_ACCELERATOR */
297
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100298 /* Previous function does not return any value, so just call the
299 * initialisation function of the Mbed Crypto layer
300 */
301 return psa_crypto_init();
302}
303
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000304static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100305{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100306 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000307 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100308}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100309
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100310psa_status_t tfm_crypto_get_caller_id(int32_t *id)
311{
312#ifdef TFM_PSA_API
313 return tfm_crypto_get_scratch_owner(id);
314#else
315 int32_t res;
316
317 res = tfm_core_get_caller_client_id(id);
318 if (res != TFM_SUCCESS) {
319 return PSA_ERROR_NOT_PERMITTED;
320 } else {
321 return PSA_SUCCESS;
322 }
323#endif
324}
325
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000326psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100327{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100328 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100329
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100330 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000331 status = tfm_crypto_module_init();
332 if (status != PSA_SUCCESS) {
333 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100334 }
335
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100336 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100337 status = tfm_crypto_engine_init();
338 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100339 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100340 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100341
Antonio de Angelis4743e672019-04-11 11:38:48 +0100342#ifdef TFM_PSA_API
343 /* Should not return in normal operations */
344 tfm_crypto_ipc_handler();
345#endif
346
347 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100348}