blob: b3acd556f37dcb5607bd43087952bf9f098246a6 [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
Raef Colesd2485af2019-10-30 10:15:33 +000023#ifdef CRYPTO_HW_ACCELERATOR
24#include "crypto_hw.h"
25#endif /* CRYPTO_HW_ACCLERATOR */
26
Antonio de Angelis4743e672019-04-11 11:38:48 +010027#ifdef TFM_PSA_API
Jamie Foxcc31d402019-01-28 17:13:52 +000028#include "psa/service.h"
Edison Aicc4c6162019-06-21 13:52:49 +080029#include "psa_manifest/tfm_crypto.h"
David Hu49a28eb2019-08-14 18:18:15 +080030#include "tfm_memory_utils.h"
Antonio de Angelis4743e672019-04-11 11:38:48 +010031
32/**
33 * \brief Table containing all the Uniform Signature API exposed
34 * by the TF-M Crypto partition
35 */
Edison Ai080b2e22019-04-17 16:27:21 +080036static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SID_MAX] = {
Antonio de Angelis25e2b2d2019-04-25 14:49:50 +010037#define X(api_name) api_name,
38LIST_TFM_CRYPTO_UNIFORM_SIGNATURE_API
39#undef X
Antonio de Angelis4743e672019-04-11 11:38:48 +010040};
41
42/**
43 * \brief Aligns a value x up to an alignment a.
44 */
45#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
46
47/**
48 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
49 * partition.
50 */
51#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
52
53/**
54 * \brief Default size of the internal scratch buffer used for IOVec allocations
55 * in bytes
56 */
57#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
Jamie Foxdaade492019-04-26 14:35:39 +010058#define TFM_CRYPTO_IOVEC_BUFFER_SIZE (5120)
Antonio de Angelis4743e672019-04-11 11:38:48 +010059#endif
60
61/**
62 * \brief Internal scratch used for IOVec allocations
63 *
64 */
65static struct tfm_crypto_scratch {
66 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
67 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
68 uint32_t alloc_index;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010069 int32_t owner;
Antonio de Angelis4743e672019-04-11 11:38:48 +010070} scratch = {.buf = {0}, .alloc_index = 0};
71
Antonio de Angelis60a6fe62019-06-18 15:27:34 +010072static psa_status_t tfm_crypto_set_scratch_owner(int32_t id)
73{
74 scratch.owner = id;
75 return PSA_SUCCESS;
76}
77
78static psa_status_t tfm_crypto_get_scratch_owner(int32_t *id)
79{
80 *id = scratch.owner;
81 return PSA_SUCCESS;
82}
83
Antonio de Angelis4743e672019-04-11 11:38:48 +010084static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
85{
86 /* Ensure alloc_index remains aligned to the required iovec alignment */
87 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
88
89 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
90 return PSA_ERROR_INSUFFICIENT_MEMORY;
91 }
92
93 /* Compute the pointer to the allocated space */
94 *buf = (void *)&scratch.buf[scratch.alloc_index];
95
96 /* Increase the allocated size */
97 scratch.alloc_index += requested_size;
98
99 return PSA_SUCCESS;
100}
101
102static psa_status_t tfm_crypto_clear_scratch(void)
103{
104 scratch.alloc_index = 0;
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100105 scratch.owner = 0;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100106 (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
107
108 return PSA_SUCCESS;
109}
110
111static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
112 struct tfm_crypto_pack_iovec *iov,
113 const uint32_t sfn_id)
114{
115 psa_status_t status = PSA_SUCCESS;
Jamie Fox9a234e22019-04-30 11:12:05 +0100116 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i, read_size;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100117 psa_invec in_vec[PSA_MAX_IOVEC] = { {0} };
118 psa_outvec out_vec[PSA_MAX_IOVEC] = { {0} };
119 void *alloc_buf_ptr = NULL;
120
121 /* Check the number of in_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100122 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
123 in_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100124 }
125
126 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
127 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100128 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100129 }
130 /* Initialise the first iovec with the IOV read when parsing */
131 in_vec[0].base = iov;
132 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
133
134 /* Alloc/read from the second element as the first is read when parsing */
135 for (i = 1; i < in_len; i++) {
136 /* Allocate necessary space in the internal scratch */
137 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
138 if (status != PSA_SUCCESS) {
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100139 (void)tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100140 return status;
141 }
142 /* Read from the IPC framework inputs into the scratch */
143 read_size = psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
144 /* Populate the fields of the input to the secure function */
145 in_vec[i].base = alloc_buf_ptr;
146 in_vec[i].len = msg->in_size[i];
147 }
148
149 /* Check the number of out_vec filled */
Jamie Fox9a234e22019-04-30 11:12:05 +0100150 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
151 out_len--;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100152 }
153
154 for (i = 0; i < out_len; i++) {
155 /* Allocate necessary space for the output in the internal scratch */
156 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
157 if (status != PSA_SUCCESS) {
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100158 (void)tfm_crypto_clear_scratch();
Antonio de Angelis4743e672019-04-11 11:38:48 +0100159 return status;
160 }
161 /* Populate the fields of the output to the secure function */
162 out_vec[i].base = alloc_buf_ptr;
163 out_vec[i].len = msg->out_size[i];
164 }
165
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100166 /* Set the owner of the data in the scratch */
167 (void)tfm_crypto_set_scratch_owner(msg->client_id);
168
Antonio de Angelis4743e672019-04-11 11:38:48 +0100169 /* Call the uniform signature API */
170 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
171
172 /* Write into the IPC framework outputs from the scratch */
173 for (i = 0; i < out_len; i++) {
174 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
175 }
176
177 /* Clear the allocated internal scratch before returning */
178 if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100179 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100180 }
181
182 return status;
183}
184
185static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
186 struct tfm_crypto_pack_iovec *iov,
187 uint32_t *sfn_id_p)
188{
189 size_t read_size;
190
191 /* Read the in_vec[0] which holds the IOVEC always */
192 read_size = psa_read(msg->handle,
193 0,
194 iov,
195 sizeof(struct tfm_crypto_pack_iovec));
196
197 if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100198 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100199 }
200
Edison Ai080b2e22019-04-17 16:27:21 +0800201 if (iov->sfn_id >= TFM_CRYPTO_SID_MAX) {
202 *sfn_id_p = TFM_CRYPTO_SID_INVALID;
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100203 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100204 }
205
206 *sfn_id_p = iov->sfn_id;
207
208 return PSA_SUCCESS;
209}
210
211static void tfm_crypto_ipc_handler(void)
212{
213 psa_signal_t signals = 0;
214 psa_msg_t msg;
215 psa_status_t status = PSA_SUCCESS;
Edison Ai080b2e22019-04-17 16:27:21 +0800216 uint32_t sfn_id = TFM_CRYPTO_SID_INVALID;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100217 struct tfm_crypto_pack_iovec iov = {0};
218
219 while (1) {
220 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
Edison Ai45b22552019-10-12 11:05:57 +0800221 if (signals & TFM_CRYPTO_SIGNAL) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100222 /* Extract the message */
Edison Ai45b22552019-10-12 11:05:57 +0800223 if (psa_get(TFM_CRYPTO_SIGNAL, &msg) != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100224 /* FIXME: Should be replaced by TF-M error handling */
225 while (1) {
226 ;
227 }
228 }
229
230 /* Process the message type */
231 switch (msg.type) {
232 case PSA_IPC_CONNECT:
233 case PSA_IPC_DISCONNECT:
234 psa_reply(msg.handle, PSA_SUCCESS);
235 break;
236 case PSA_IPC_CALL:
237 /* Parse the message */
238 status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
Edison Ai080b2e22019-04-17 16:27:21 +0800239 /* Call the dispatcher based on the SID passed as type */
240 if (sfn_id != TFM_CRYPTO_SID_INVALID) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100241 status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
242 } else {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100243 status = PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100244 }
245 psa_reply(msg.handle, status);
246 break;
247 default:
248 /* FIXME: Should be replaced by TF-M error handling */
249 while (1) {
250 ;
251 }
252 }
253 } else {
254 /* FIXME: Should be replaced by TF-M error handling */
255 while (1) {
256 ;
257 }
258 }
259 }
260
261 /* This is unreachable */
262 return;
263}
264#endif /* TFM_PSA_API */
265
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100266/**
267 * \brief Default value for the size of the static buffer used by Mbed
268 * Crypto for its dynamic allocations
269 */
270#ifndef TFM_CRYPTO_ENGINE_BUF_SIZE
Tamas Ban2a688992019-05-10 10:39:15 +0100271#define TFM_CRYPTO_ENGINE_BUF_SIZE (0x2000) /* 8KB for EC signing in attest */
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100272#endif
273
274/**
275 * \brief Static buffer to be used by Mbed Crypto for memory allocations
276 *
277 */
278static uint8_t mbedtls_mem_buf[TFM_CRYPTO_ENGINE_BUF_SIZE] = {0};
279
280static psa_status_t tfm_crypto_engine_init(void)
281{
282 /* Initialise the Mbed Crypto memory allocator to use static
283 * memory allocation from the provided buffer instead of using
284 * the heap
285 */
286 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
287 TFM_CRYPTO_ENGINE_BUF_SIZE);
288
Raef Colesd2485af2019-10-30 10:15:33 +0000289 /* Initialise the crypto accelerator if one is enabled */
290#ifdef CRYPTO_HW_ACCELERATOR
291 if (crypto_hw_accelerator_init() != 0) {
292 return PSA_ERROR_HARDWARE_FAILURE;
293 }
294#endif /* CRYPTO_HW_ACCELERATOR */
295
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100296 /* Previous function does not return any value, so just call the
297 * initialisation function of the Mbed Crypto layer
298 */
299 return psa_crypto_init();
300}
301
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000302static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100303{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100304 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000305 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100306}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100307
Antonio de Angelis60a6fe62019-06-18 15:27:34 +0100308psa_status_t tfm_crypto_get_caller_id(int32_t *id)
309{
310#ifdef TFM_PSA_API
311 return tfm_crypto_get_scratch_owner(id);
312#else
313 int32_t res;
314
315 res = tfm_core_get_caller_client_id(id);
316 if (res != TFM_SUCCESS) {
317 return PSA_ERROR_NOT_PERMITTED;
318 } else {
319 return PSA_SUCCESS;
320 }
321#endif
322}
323
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000324psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100325{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100326 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100327
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100328 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000329 status = tfm_crypto_module_init();
330 if (status != PSA_SUCCESS) {
331 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100332 }
333
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100334 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100335 status = tfm_crypto_engine_init();
336 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100337 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100338 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100339
Antonio de Angelis4743e672019-04-11 11:38:48 +0100340#ifdef TFM_PSA_API
341 /* Should not return in normal operations */
342 tfm_crypto_ipc_handler();
343#endif
344
345 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100346}