blob: bdb99e4dfffcaa8fa8630a5c7677c78d9ef8991e [file] [log] [blame]
Antonio de Angelis8908f472018-08-31 15:44:25 +01001/*
Antonio de Angeliscf85ba22018-10-09 13:29:40 +01002 * Copyright (c) 2018-2019, 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"
12
13/*
14 * \brief This Mbed TLS include is needed to initialise the memory allocator
15 * inside the Mbed TLS layer of Mbed Crypto
16 */
17#include "mbedtls/memory_buffer_alloc.h"
Antonio de Angelis8908f472018-08-31 15:44:25 +010018
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010019#ifndef TFM_PSA_API
20#include "tfm_secure_api.h"
21#endif
22
Antonio de Angelis4743e672019-04-11 11:38:48 +010023#ifdef TFM_PSA_API
Jamie Foxcc31d402019-01-28 17:13:52 +000024#include "psa/service.h"
Edison Aicc4c6162019-06-21 13:52:49 +080025#include "psa_manifest/tfm_crypto.h"
David Hu49a28eb2019-08-14 18:18:15 +080026#include "tfm_memory_utils.h"
Antonio de Angelis4743e672019-04-11 11:38:48 +010027
28/**
29 * \brief Table containing all the Uniform Signature API exposed
30 * by the TF-M Crypto partition
31 */
Edison Ai080b2e22019-04-17 16:27:21 +080032static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SID_MAX] = {
Antonio de Angelis25e2b2d2019-04-25 14:49:50 +010033#define X(api_name) api_name,
34LIST_TFM_CRYPTO_UNIFORM_SIGNATURE_API
35#undef X
Antonio de Angelis4743e672019-04-11 11:38:48 +010036};
37
38/**
39 * \brief Aligns a value x up to an alignment a.
40 */
41#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
42
43/**
44 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
45 * partition.
46 */
47#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
48
49/**
50 * \brief Default size of the internal scratch buffer used for IOVec allocations
51 * in bytes
52 */
53#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
Jamie Foxdaade492019-04-26 14:35:39 +010054#define TFM_CRYPTO_IOVEC_BUFFER_SIZE (5120)
Antonio de Angelis4743e672019-04-11 11:38:48 +010055#endif
56
57/**
58 * \brief Internal scratch used for IOVec allocations
59 *
60 */
61static struct tfm_crypto_scratch {
62 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
63 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
64 uint32_t alloc_index;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010065 int32_t owner;
Antonio de Angelis4743e672019-04-11 11:38:48 +010066} scratch = {.buf = {0}, .alloc_index = 0};
67
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010068static psa_status_t tfm_crypto_set_scratch_owner(int32_t id)
69{
70 scratch.owner = id;
71 return PSA_SUCCESS;
72}
73
74static psa_status_t tfm_crypto_get_scratch_owner(int32_t *id)
75{
76 *id = scratch.owner;
77 return PSA_SUCCESS;
78}
79
Antonio de Angelis4743e672019-04-11 11:38:48 +010080static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
81{
82 /* Ensure alloc_index remains aligned to the required iovec alignment */
83 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
84
85 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
86 return PSA_ERROR_INSUFFICIENT_MEMORY;
87 }
88
89 /* Compute the pointer to the allocated space */
90 *buf = (void *)&scratch.buf[scratch.alloc_index];
91
92 /* Increase the allocated size */
93 scratch.alloc_index += requested_size;
94
95 return PSA_SUCCESS;
96}
97
98static psa_status_t tfm_crypto_clear_scratch(void)
99{
100 scratch.alloc_index = 0;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100101 scratch.owner = 0;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100102 (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
103
104 return PSA_SUCCESS;
105}
106
107static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
108 struct tfm_crypto_pack_iovec *iov,
109 const uint32_t sfn_id)
110{
111 psa_status_t status = PSA_SUCCESS;
Jamie Fox9a234e22019-04-30 11:12:05 +0100112 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i, read_size;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100113 psa_invec in_vec[PSA_MAX_IOVEC] = { {0} };
114 psa_outvec out_vec[PSA_MAX_IOVEC] = { {0} };
115 void *alloc_buf_ptr = NULL;
116
117 /* Check the number of in_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100118 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
119 in_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100120 }
121
122 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
123 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100124 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100125 }
126 /* Initialise the first iovec with the IOV read when parsing */
127 in_vec[0].base = iov;
128 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
129
130 /* Alloc/read from the second element as the first is read when parsing */
131 for (i = 1; i < in_len; i++) {
132 /* Allocate necessary space in the internal scratch */
133 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
134 if (status != PSA_SUCCESS) {
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100135 (void)tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100136 return status;
137 }
138 /* Read from the IPC framework inputs into the scratch */
139 read_size = psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
140 /* Populate the fields of the input to the secure function */
141 in_vec[i].base = alloc_buf_ptr;
142 in_vec[i].len = msg->in_size[i];
143 }
144
145 /* Check the number of out_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100146 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
147 out_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100148 }
149
150 for (i = 0; i < out_len; i++) {
151 /* Allocate necessary space for the output in the internal scratch */
152 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
153 if (status != PSA_SUCCESS) {
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100154 (void)tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100155 return status;
156 }
157 /* Populate the fields of the output to the secure function */
158 out_vec[i].base = alloc_buf_ptr;
159 out_vec[i].len = msg->out_size[i];
160 }
161
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100162 /* Set the owner of the data in the scratch */
163 (void)tfm_crypto_set_scratch_owner(msg->client_id);
164
Antonio de Angelis4743e672019-04-11 11:38:48 +0100165 /* Call the uniform signature API */
166 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
167
168 /* Write into the IPC framework outputs from the scratch */
169 for (i = 0; i < out_len; i++) {
170 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
171 }
172
173 /* Clear the allocated internal scratch before returning */
174 if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100175 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100176 }
177
178 return status;
179}
180
181static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
182 struct tfm_crypto_pack_iovec *iov,
183 uint32_t *sfn_id_p)
184{
185 size_t read_size;
186
187 /* Read the in_vec[0] which holds the IOVEC always */
188 read_size = psa_read(msg->handle,
189 0,
190 iov,
191 sizeof(struct tfm_crypto_pack_iovec));
192
193 if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100194 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100195 }
196
Edison Ai080b2e22019-04-17 16:27:21 +0800197 if (iov->sfn_id >= TFM_CRYPTO_SID_MAX) {
198 *sfn_id_p = TFM_CRYPTO_SID_INVALID;
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100199 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100200 }
201
202 *sfn_id_p = iov->sfn_id;
203
204 return PSA_SUCCESS;
205}
206
207static void tfm_crypto_ipc_handler(void)
208{
209 psa_signal_t signals = 0;
210 psa_msg_t msg;
211 psa_status_t status = PSA_SUCCESS;
Edison Ai080b2e22019-04-17 16:27:21 +0800212 uint32_t sfn_id = TFM_CRYPTO_SID_INVALID;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100213 struct tfm_crypto_pack_iovec iov = {0};
214
215 while (1) {
216 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
Edison Ai45b22552019-10-12 11:05:57 +0800217 if (signals & TFM_CRYPTO_SIGNAL) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100218 /* Extract the message */
Edison Ai45b22552019-10-12 11:05:57 +0800219 if (psa_get(TFM_CRYPTO_SIGNAL, &msg) != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100220 /* FIXME: Should be replaced by TF-M error handling */
221 while (1) {
222 ;
223 }
224 }
225
226 /* Process the message type */
227 switch (msg.type) {
228 case PSA_IPC_CONNECT:
229 case PSA_IPC_DISCONNECT:
230 psa_reply(msg.handle, PSA_SUCCESS);
231 break;
232 case PSA_IPC_CALL:
233 /* Parse the message */
234 status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
Edison Ai080b2e22019-04-17 16:27:21 +0800235 /* Call the dispatcher based on the SID passed as type */
236 if (sfn_id != TFM_CRYPTO_SID_INVALID) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100237 status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
238 } else {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100239 status = PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100240 }
241 psa_reply(msg.handle, status);
242 break;
243 default:
244 /* FIXME: Should be replaced by TF-M error handling */
245 while (1) {
246 ;
247 }
248 }
249 } else {
250 /* FIXME: Should be replaced by TF-M error handling */
251 while (1) {
252 ;
253 }
254 }
255 }
256
257 /* This is unreachable */
258 return;
259}
260#endif /* TFM_PSA_API */
261
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100262/**
263 * \brief Default value for the size of the static buffer used by Mbed
264 * Crypto for its dynamic allocations
265 */
266#ifndef TFM_CRYPTO_ENGINE_BUF_SIZE
Tamas Ban2a688992019-05-10 10:39:15 +0100267#define TFM_CRYPTO_ENGINE_BUF_SIZE (0x2000) /* 8KB for EC signing in attest */
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100268#endif
269
270/**
271 * \brief Static buffer to be used by Mbed Crypto for memory allocations
272 *
273 */
274static uint8_t mbedtls_mem_buf[TFM_CRYPTO_ENGINE_BUF_SIZE] = {0};
275
276static psa_status_t tfm_crypto_engine_init(void)
277{
278 /* Initialise the Mbed Crypto memory allocator to use static
279 * memory allocation from the provided buffer instead of using
280 * the heap
281 */
282 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
283 TFM_CRYPTO_ENGINE_BUF_SIZE);
284
285 /* Previous function does not return any value, so just call the
286 * initialisation function of the Mbed Crypto layer
287 */
288 return psa_crypto_init();
289}
290
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000291static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100292{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100293 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000294 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100295}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100296
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100297psa_status_t tfm_crypto_get_caller_id(int32_t *id)
298{
299#ifdef TFM_PSA_API
300 return tfm_crypto_get_scratch_owner(id);
301#else
302 int32_t res;
303
304 res = tfm_core_get_caller_client_id(id);
305 if (res != TFM_SUCCESS) {
306 return PSA_ERROR_NOT_PERMITTED;
307 } else {
308 return PSA_SUCCESS;
309 }
310#endif
311}
312
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000313psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100314{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100315 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100316
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100317 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000318 status = tfm_crypto_module_init();
319 if (status != PSA_SUCCESS) {
320 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100321 }
322
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100323 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100324 status = tfm_crypto_engine_init();
325 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100326 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100327 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100328
Antonio de Angelis4743e672019-04-11 11:38:48 +0100329#ifdef TFM_PSA_API
330 /* Should not return in normal operations */
331 tfm_crypto_ipc_handler();
332#endif
333
334 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100335}