blob: aaabea87e8ba38a78ebc8101b4a14c54b3ccd9f9 [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
Antonio de Angelis8908f472018-08-31 15:44:25 +01008#include "tfm_crypto_api.h"
Antonio de Angelisab85ccd2019-03-25 15:14:29 +00009#include "crypto_engine.h"
Antonio de Angelis8908f472018-08-31 15:44:25 +010010
Antonio de Angelis4743e672019-04-11 11:38:48 +010011#ifdef TFM_PSA_API
12#include "psa_service.h"
13#include "tfm_crypto_signal.h"
14#include "secure_fw/core/tfm_memory_utils.h"
15
16/**
17 * \brief Table containing all the Uniform Signature API exposed
18 * by the TF-M Crypto partition
19 */
20static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SFID_MAX] = {
21 tfm_crypto_import_key,
22 tfm_crypto_destroy_key,
23 tfm_crypto_get_key_information,
24 tfm_crypto_export_key,
25 tfm_crypto_key_policy_init,
26 tfm_crypto_key_policy_set_usage,
27 tfm_crypto_key_policy_get_usage,
28 tfm_crypto_key_policy_get_algorithm,
29 tfm_crypto_set_key_policy,
30 tfm_crypto_get_key_policy,
31 tfm_crypto_set_key_lifetime,
32 tfm_crypto_get_key_lifetime,
33 tfm_crypto_cipher_set_iv,
34 tfm_crypto_cipher_encrypt_setup,
35 tfm_crypto_cipher_decrypt_setup,
36 tfm_crypto_cipher_update,
37 tfm_crypto_cipher_abort,
38 tfm_crypto_cipher_finish,
39 tfm_crypto_hash_setup,
40 tfm_crypto_hash_update,
41 tfm_crypto_hash_finish,
42 tfm_crypto_hash_verify,
43 tfm_crypto_hash_abort,
44 tfm_crypto_mac_sign_setup,
45 tfm_crypto_mac_verify_setup,
46 tfm_crypto_mac_update,
47 tfm_crypto_mac_sign_finish,
48 tfm_crypto_mac_verify_finish,
49 tfm_crypto_mac_abort,
50 tfm_crypto_aead_encrypt,
51 tfm_crypto_aead_decrypt
52};
53
54/**
55 * \brief Aligns a value x up to an alignment a.
56 */
57#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
58
59/**
60 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
61 * partition.
62 */
63#define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
64
65/**
66 * \brief Default size of the internal scratch buffer used for IOVec allocations
67 * in bytes
68 */
69#ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
70#define TFM_CRYPTO_IOVEC_BUFFER_SIZE (1024)
71#endif
72
73/**
74 * \brief Internal scratch used for IOVec allocations
75 *
76 */
77static struct tfm_crypto_scratch {
78 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
79 uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
80 uint32_t alloc_index;
81} scratch = {.buf = {0}, .alloc_index = 0};
82
83static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
84{
85 /* Ensure alloc_index remains aligned to the required iovec alignment */
86 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
87
88 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
89 return PSA_ERROR_INSUFFICIENT_MEMORY;
90 }
91
92 /* Compute the pointer to the allocated space */
93 *buf = (void *)&scratch.buf[scratch.alloc_index];
94
95 /* Increase the allocated size */
96 scratch.alloc_index += requested_size;
97
98 return PSA_SUCCESS;
99}
100
101static psa_status_t tfm_crypto_clear_scratch(void)
102{
103 scratch.alloc_index = 0;
104 (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
105
106 return PSA_SUCCESS;
107}
108
109static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
110 struct tfm_crypto_pack_iovec *iov,
111 const uint32_t sfn_id)
112{
113 psa_status_t status = PSA_SUCCESS;
114 size_t in_len = 0, out_len = 0, i, read_size;
115 psa_invec in_vec[PSA_MAX_IOVEC] = { {0} };
116 psa_outvec out_vec[PSA_MAX_IOVEC] = { {0} };
117 void *alloc_buf_ptr = NULL;
118
119 /* Check the number of in_vec filled */
120 while ((in_len < PSA_MAX_IOVEC) && (msg->in_size[in_len] != 0)) {
121 in_len++;
122 }
123
124 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
125 if (in_len < 1) {
126 return PSA_ERROR_UNKNOWN_ERROR;
127 }
128 /* Initialise the first iovec with the IOV read when parsing */
129 in_vec[0].base = iov;
130 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
131
132 /* Alloc/read from the second element as the first is read when parsing */
133 for (i = 1; i < in_len; i++) {
134 /* Allocate necessary space in the internal scratch */
135 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
136 if (status != PSA_SUCCESS) {
137 return status;
138 }
139 /* Read from the IPC framework inputs into the scratch */
140 read_size = psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
141 /* Populate the fields of the input to the secure function */
142 in_vec[i].base = alloc_buf_ptr;
143 in_vec[i].len = msg->in_size[i];
144 }
145
146 /* Check the number of out_vec filled */
147 while ((out_len < PSA_MAX_IOVEC) && (msg->out_size[out_len] != 0)) {
148 out_len++;
149 }
150
151 for (i = 0; i < out_len; i++) {
152 /* Allocate necessary space for the output in the internal scratch */
153 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
154 if (status != PSA_SUCCESS) {
155 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
162 /* Call the uniform signature API */
163 status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
164
165 /* Write into the IPC framework outputs from the scratch */
166 for (i = 0; i < out_len; i++) {
167 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
168 }
169
170 /* Clear the allocated internal scratch before returning */
171 if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
172 return PSA_ERROR_UNKNOWN_ERROR;
173 }
174
175 return status;
176}
177
178static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
179 struct tfm_crypto_pack_iovec *iov,
180 uint32_t *sfn_id_p)
181{
182 size_t read_size;
183
184 /* Read the in_vec[0] which holds the IOVEC always */
185 read_size = psa_read(msg->handle,
186 0,
187 iov,
188 sizeof(struct tfm_crypto_pack_iovec));
189
190 if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
191 return PSA_ERROR_UNKNOWN_ERROR;
192 }
193
194 if (iov->sfn_id >= TFM_CRYPTO_SFID_MAX) {
195 *sfn_id_p = TFM_CRYPTO_SFID_INVALID;
196 return PSA_ERROR_UNKNOWN_ERROR;
197 }
198
199 *sfn_id_p = iov->sfn_id;
200
201 return PSA_SUCCESS;
202}
203
204static void tfm_crypto_ipc_handler(void)
205{
206 psa_signal_t signals = 0;
207 psa_msg_t msg;
208 psa_status_t status = PSA_SUCCESS;
209 uint32_t sfn_id = TFM_CRYPTO_SFID_INVALID;
210 struct tfm_crypto_pack_iovec iov = {0};
211
212 while (1) {
213 signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
214 if (signals & TFM_CRYPTO_SIG) {
215 /* Extract the message */
216 if (psa_get(TFM_CRYPTO_SIG, &msg) != PSA_SUCCESS) {
217 /* FIXME: Should be replaced by TF-M error handling */
218 while (1) {
219 ;
220 }
221 }
222
223 /* Process the message type */
224 switch (msg.type) {
225 case PSA_IPC_CONNECT:
226 case PSA_IPC_DISCONNECT:
227 psa_reply(msg.handle, PSA_SUCCESS);
228 break;
229 case PSA_IPC_CALL:
230 /* Parse the message */
231 status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
232 /* Call the dispatcher based on the SFID passed as type */
233 if (sfn_id != TFM_CRYPTO_SFID_INVALID) {
234 status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
235 } else {
236 status = PSA_ERROR_UNKNOWN_ERROR;
237 }
238 psa_reply(msg.handle, status);
239 break;
240 default:
241 /* FIXME: Should be replaced by TF-M error handling */
242 while (1) {
243 ;
244 }
245 }
246 } else {
247 /* FIXME: Should be replaced by TF-M error handling */
248 while (1) {
249 ;
250 }
251 }
252 }
253
254 /* This is unreachable */
255 return;
256}
257#endif /* TFM_PSA_API */
258
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000259static psa_status_t tfm_crypto_module_init(void)
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100260{
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000261 psa_status_t status = PSA_SUCCESS;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100262
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100263 /* Init the Key module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000264 status = tfm_crypto_init_key();
265 if (status != PSA_SUCCESS) {
266 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100267 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100268
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100269 /* Init the Alloc module */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000270 return tfm_crypto_init_alloc();
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100271}
Antonio de Angelis8908f472018-08-31 15:44:25 +0100272
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000273psa_status_t tfm_crypto_init(void)
Antonio de Angelis8908f472018-08-31 15:44:25 +0100274{
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100275 psa_status_t status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100276
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100277 /* Initialise other modules of the service */
Antonio de Angelisab85ccd2019-03-25 15:14:29 +0000278 status = tfm_crypto_module_init();
279 if (status != PSA_SUCCESS) {
280 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100281 }
282
283 /* Initialise the engine interface module */
284 status = tfm_crypto_engine_init();
285 if (status != PSA_SUCCESS) {
Antonio de Angelis4743e672019-04-11 11:38:48 +0100286 return status;
Antonio de Angeliscf85ba22018-10-09 13:29:40 +0100287 }
Antonio de Angelis8908f472018-08-31 15:44:25 +0100288
Antonio de Angelis4743e672019-04-11 11:38:48 +0100289#ifdef TFM_PSA_API
290 /* Should not return in normal operations */
291 tfm_crypto_ipc_handler();
292#endif
293
294 return status;
Antonio de Angelis8908f472018-08-31 15:44:25 +0100295}