blob: a241f8ac46ae458872e1ed03334497e73234707c [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 Angelis4743e672019-04-11 11:38:48 +010019#ifdef TFM_PSA_API
20#include "psa_service.h"
21#include "tfm_crypto_signal.h"
22#include "secure_fw/core/tfm_memory_utils.h"
23
24/**
25 * \brief Table containing all the Uniform Signature API exposed
26 * by the TF-M Crypto partition
27 */
28static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SFID_MAX] = {
Antonio de Angelis25e2b2d2019-04-25 14:49:50 +010029#define X(api_name) api_name,
30LIST_TFM_CRYPTO_UNIFORM_SIGNATURE_API
31#undef X
Antonio de Angelis4743e672019-04-11 11:38:48 +010032};
33
34/**
35 * \brief Aligns a value x up to an alignment a.
36 */
37#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
38
39/**
40 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
41 * partition.
42 */
43#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
44
45/**
46 * \brief Default size of the internal scratch buffer used for IOVec allocations
47 * in bytes
48 */
49#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
50#define TFM_CRYPTO_IOVEC_BUFFER_SIZE (1024)
51#endif
52
53/**
54 * \brief Internal scratch used for IOVec allocations
55 *
56 */
57static struct tfm_crypto_scratch {
58 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
59 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
60 uint32_t alloc_index;
61} scratch = {.buf = {0}, .alloc_index = 0};
62
63static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
64{
65 /* Ensure alloc_index remains aligned to the required iovec alignment */
66 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
67
68 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
69 return PSA_ERROR_INSUFFICIENT_MEMORY;
70 }
71
72 /* Compute the pointer to the allocated space */
73 *buf = (void *)&scratch.buf[scratch.alloc_index];
74
75 /* Increase the allocated size */
76 scratch.alloc_index += requested_size;
77
78 return PSA_SUCCESS;
79}
80
81static psa_status_t tfm_crypto_clear_scratch(void)
82{
83 scratch.alloc_index = 0;
84 (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
85
86 return PSA_SUCCESS;
87}
88
89static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
90 struct tfm_crypto_pack_iovec *iov,
91 const uint32_t sfn_id)
92{
93 psa_status_t status = PSA_SUCCESS;
94 size_t in_len = 0, out_len = 0, i, read_size;
95 psa_invec in_vec[PSA_MAX_IOVEC] = { {0} };
96 psa_outvec out_vec[PSA_MAX_IOVEC] = { {0} };
97 void *alloc_buf_ptr = NULL;
98
99 /* Check the number of in_vec filled */
100 while ((in_len < PSA_MAX_IOVEC) && (msg->in_size[in_len] != 0)) {
101 in_len++;
102 }
103
104 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
105 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100106 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100107 }
108 /* Initialise the first iovec with the IOV read when parsing */
109 in_vec[0].base = iov;
110 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
111
112 /* Alloc/read from the second element as the first is read when parsing */
113 for (i = 1; i < in_len; i++) {
114 /* Allocate necessary space in the internal scratch */
115 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
116 if (status != PSA_SUCCESS) {
117 return status;
118 }
119 /* Read from the IPC framework inputs into the scratch */
120 read_size = psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
121 /* Populate the fields of the input to the secure function */
122 in_vec[i].base = alloc_buf_ptr;
123 in_vec[i].len = msg->in_size[i];
124 }
125
126 /* Check the number of out_vec filled */
127 while ((out_len < PSA_MAX_IOVEC) && (msg->out_size[out_len] != 0)) {
128 out_len++;
129 }
130
131 for (i = 0; i < out_len; i++) {
132 /* Allocate necessary space for the output in the internal scratch */
133 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
134 if (status != PSA_SUCCESS) {
135 return status;
136 }
137 /* Populate the fields of the output to the secure function */
138 out_vec[i].base = alloc_buf_ptr;
139 out_vec[i].len = msg->out_size[i];
140 }
141
142 /* Call the uniform signature API */
143 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
144
145 /* Write into the IPC framework outputs from the scratch */
146 for (i = 0; i < out_len; i++) {
147 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
148 }
149
150 /* Clear the allocated internal scratch before returning */
151 if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100152 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100153 }
154
155 return status;
156}
157
158static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
159 struct tfm_crypto_pack_iovec *iov,
160 uint32_t *sfn_id_p)
161{
162 size_t read_size;
163
164 /* Read the in_vec[0] which holds the IOVEC always */
165 read_size = psa_read(msg->handle,
166 0,
167 iov,
168 sizeof(struct tfm_crypto_pack_iovec));
169
170 if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100171 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100172 }
173
174 if (iov->sfn_id >= TFM_CRYPTO_SFID_MAX) {
175 *sfn_id_p = TFM_CRYPTO_SFID_INVALID;
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100176 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100177 }
178
179 *sfn_id_p = iov->sfn_id;
180
181 return PSA_SUCCESS;
182}
183
184static void tfm_crypto_ipc_handler(void)
185{
186 psa_signal_t signals = 0;
187 psa_msg_t msg;
188 psa_status_t status = PSA_SUCCESS;
189 uint32_t sfn_id = TFM_CRYPTO_SFID_INVALID;
190 struct tfm_crypto_pack_iovec iov = {0};
191
192 while (1) {
193 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
194 if (signals & TFM_CRYPTO_SIG) {
195 /* Extract the message */
196 if (psa_get(TFM_CRYPTO_SIG, &msg) != PSA_SUCCESS) {
197 /* FIXME: Should be replaced by TF-M error handling */
198 while (1) {
199 ;
200 }
201 }
202
203 /* Process the message type */
204 switch (msg.type) {
205 case PSA_IPC_CONNECT:
206 case PSA_IPC_DISCONNECT:
207 psa_reply(msg.handle, PSA_SUCCESS);
208 break;
209 case PSA_IPC_CALL:
210 /* Parse the message */
211 status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
212 /* Call the dispatcher based on the SFID passed as type */
213 if (sfn_id != TFM_CRYPTO_SFID_INVALID) {
214 status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
215 } else {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100216 status = PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100217 }
218 psa_reply(msg.handle, status);
219 break;
220 default:
221 /* FIXME: Should be replaced by TF-M error handling */
222 while (1) {
223 ;
224 }
225 }
226 } else {
227 /* FIXME: Should be replaced by TF-M error handling */
228 while (1) {
229 ;
230 }
231 }
232 }
233
234 /* This is unreachable */
235 return;
236}
237#endif /* TFM_PSA_API */
238
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100239/**
240 * \brief Default value for the size of the static buffer used by Mbed
241 * Crypto for its dynamic allocations
242 */
243#ifndef TFM_CRYPTO_ENGINE_BUF_SIZE
244#define TFM_CRYPTO_ENGINE_BUF_SIZE (1024)
245#endif
246
247/**
248 * \brief Static buffer to be used by Mbed Crypto for memory allocations
249 *
250 */
251static uint8_t mbedtls_mem_buf[TFM_CRYPTO_ENGINE_BUF_SIZE] = {0};
252
253static psa_status_t tfm_crypto_engine_init(void)
254{
255 /* Initialise the Mbed Crypto memory allocator to use static
256 * memory allocation from the provided buffer instead of using
257 * the heap
258 */
259 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
260 TFM_CRYPTO_ENGINE_BUF_SIZE);
261
262 /* Previous function does not return any value, so just call the
263 * initialisation function of the Mbed Crypto layer
264 */
265 return psa_crypto_init();
266}
267
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000268static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100269{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100270 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000271 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100272}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100273
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000274psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100275{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100276 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100277
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100278 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000279 status = tfm_crypto_module_init();
280 if (status != PSA_SUCCESS) {
281 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100282 }
283
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100284 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100285 status = tfm_crypto_engine_init();
286 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100287 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100288 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100289
Antonio de Angelis4743e672019-04-11 11:38:48 +0100290#ifdef TFM_PSA_API
291 /* Should not return in normal operations */
292 tfm_crypto_ipc_handler();
293#endif
294
295 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100296}