blob: 0144f023d7b8269bdac43531cd41d7e8f3012fc1 [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] = {
Jamie Fox0e54ebc2019-04-09 14:21:04 +010029 tfm_crypto_allocate_key,
Antonio de Angelis4743e672019-04-11 11:38:48 +010030 tfm_crypto_import_key,
31 tfm_crypto_destroy_key,
32 tfm_crypto_get_key_information,
33 tfm_crypto_export_key,
Antonio de Angelis4743e672019-04-11 11:38:48 +010034 tfm_crypto_set_key_policy,
35 tfm_crypto_get_key_policy,
Antonio de Angelis4743e672019-04-11 11:38:48 +010036 tfm_crypto_get_key_lifetime,
37 tfm_crypto_cipher_set_iv,
38 tfm_crypto_cipher_encrypt_setup,
39 tfm_crypto_cipher_decrypt_setup,
40 tfm_crypto_cipher_update,
41 tfm_crypto_cipher_abort,
42 tfm_crypto_cipher_finish,
43 tfm_crypto_hash_setup,
44 tfm_crypto_hash_update,
45 tfm_crypto_hash_finish,
46 tfm_crypto_hash_verify,
47 tfm_crypto_hash_abort,
48 tfm_crypto_mac_sign_setup,
49 tfm_crypto_mac_verify_setup,
50 tfm_crypto_mac_update,
51 tfm_crypto_mac_sign_finish,
52 tfm_crypto_mac_verify_finish,
53 tfm_crypto_mac_abort,
54 tfm_crypto_aead_encrypt,
55 tfm_crypto_aead_decrypt
56};
57
58/**
59 * \brief Aligns a value x up to an alignment a.
60 */
61#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
62
63/**
64 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
65 * partition.
66 */
67#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
68
69/**
70 * \brief Default size of the internal scratch buffer used for IOVec allocations
71 * in bytes
72 */
73#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
74#define TFM_CRYPTO_IOVEC_BUFFER_SIZE (1024)
75#endif
76
77/**
78 * \brief Internal scratch used for IOVec allocations
79 *
80 */
81static struct tfm_crypto_scratch {
82 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
83 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
84 uint32_t alloc_index;
85} scratch = {.buf = {0}, .alloc_index = 0};
86
87static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
88{
89 /* Ensure alloc_index remains aligned to the required iovec alignment */
90 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
91
92 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
93 return PSA_ERROR_INSUFFICIENT_MEMORY;
94 }
95
96 /* Compute the pointer to the allocated space */
97 *buf = (void *)&scratch.buf[scratch.alloc_index];
98
99 /* Increase the allocated size */
100 scratch.alloc_index += requested_size;
101
102 return PSA_SUCCESS;
103}
104
105static psa_status_t tfm_crypto_clear_scratch(void)
106{
107 scratch.alloc_index = 0;
108 (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
109
110 return PSA_SUCCESS;
111}
112
113static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
114 struct tfm_crypto_pack_iovec *iov,
115 const uint32_t sfn_id)
116{
117 psa_status_t status = PSA_SUCCESS;
118 size_t in_len = 0, out_len = 0, i, read_size;
119 psa_invec in_vec[PSA_MAX_IOVEC] = { {0} };
120 psa_outvec out_vec[PSA_MAX_IOVEC] = { {0} };
121 void *alloc_buf_ptr = NULL;
122
123 /* Check the number of in_vec filled */
124 while ((in_len < PSA_MAX_IOVEC) && (msg->in_size[in_len] != 0)) {
125 in_len++;
126 }
127
128 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
129 if (in_len < 1) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100130 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100131 }
132 /* Initialise the first iovec with the IOV read when parsing */
133 in_vec[0].base = iov;
134 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
135
136 /* Alloc/read from the second element as the first is read when parsing */
137 for (i = 1; i < in_len; i++) {
138 /* Allocate necessary space in the internal scratch */
139 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
140 if (status != PSA_SUCCESS) {
141 return status;
142 }
143 /* Read from the IPC framework inputs into the scratch */
144 read_size = psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
145 /* 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 */
151 while ((out_len < PSA_MAX_IOVEC) && (msg->out_size[out_len] != 0)) {
152 out_len++;
153 }
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) {
159 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
166 /* Call the uniform signature API */
167 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
168
169 /* Write into the IPC framework outputs from the scratch */
170 for (i = 0; i < out_len; i++) {
171 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
172 }
173
174 /* Clear the allocated internal scratch before returning */
175 if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100176 return PSA_ERROR_GENERIC_ERROR;
Antonio de Angelis4743e672019-04-11 11:38:48 +0100177 }
178
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
198 if (iov->sfn_id >= TFM_CRYPTO_SFID_MAX) {
199 *sfn_id_p = TFM_CRYPTO_SFID_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;
213 uint32_t sfn_id = TFM_CRYPTO_SFID_INVALID;
214 struct tfm_crypto_pack_iovec iov = {0};
215
216 while (1) {
217 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
218 if (signals & TFM_CRYPTO_SIG) {
219 /* Extract the message */
220 if (psa_get(TFM_CRYPTO_SIG, &msg) != PSA_SUCCESS) {
221 /* 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);
236 /* Call the dispatcher based on the SFID passed as type */
237 if (sfn_id != TFM_CRYPTO_SFID_INVALID) {
238 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
258 /* This is unreachable */
259 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
268#define TFM_CRYPTO_ENGINE_BUF_SIZE (1024)
269#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{
279 /* Initialise the Mbed Crypto memory allocator to use static
280 * memory allocation from the provided buffer instead of using
281 * the heap
282 */
283 mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
284 TFM_CRYPTO_ENGINE_BUF_SIZE);
285
286 /* Previous function does not return any value, so just call the
287 * initialisation function of the Mbed Crypto layer
288 */
289 return psa_crypto_init();
290}
291
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000292static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100293{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100294 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000295 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100296}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100297
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000298psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100299{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100300 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100301
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100302 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000303 status = tfm_crypto_module_init();
304 if (status != PSA_SUCCESS) {
305 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100306 }
307
Jamie Fox0e54ebc2019-04-09 14:21:04 +0100308 /* Initialise the engine layer */
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100309 status = tfm_crypto_engine_init();
310 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100311 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100312 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100313
Antonio de Angelis4743e672019-04-11 11:38:48 +0100314#ifdef TFM_PSA_API
315 /* Should not return in normal operations */
316 tfm_crypto_ipc_handler();
317#endif
318
319 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100320}