1 /*
2 * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <stdbool.h>
8
9 #include "config_tfm.h"
10 #include "config_crypto_check.h"
11 #include "tfm_mbedcrypto_include.h"
12
13 #include "tfm_crypto_api.h"
14 #include "tfm_crypto_key.h"
15 #include "tfm_crypto_defs.h"
16 #include "tfm_sp_log.h"
17 #include "crypto_check_config.h"
18 #include "tfm_plat_crypto_keys.h"
19
20 #include "crypto_library.h"
21
22 #if CRYPTO_NV_SEED
23 #include "tfm_plat_crypto_nv_seed.h"
24 #endif /* CRYPTO_NV_SEED */
25
26 #ifdef CRYPTO_HW_ACCELERATOR
27 #include "crypto_hw.h"
28 #endif /* CRYPTO_HW_ACCELERATOR */
29
30 #include <string.h>
31 #include "psa/framework_feature.h"
32 #include "psa/service.h"
33 #include "psa_manifest/tfm_crypto.h"
34
35 /**
36 * \brief Aligns a value x up to an alignment a.
37 */
38 #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
39
40 /**
41 * \brief Maximum alignment required by any iovec parameters to the TF-M Crypto
42 * partition.
43 */
44 #define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
45
46 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
47 static int32_t g_client_id;
48
tfm_crypto_set_caller_id(int32_t id)49 static void tfm_crypto_set_caller_id(int32_t id)
50 {
51 g_client_id = id;
52 }
53
tfm_crypto_get_caller_id(int32_t * id)54 psa_status_t tfm_crypto_get_caller_id(int32_t *id)
55 {
56 *id = g_client_id;
57 return PSA_SUCCESS;
58 }
59
tfm_crypto_init_iovecs(const psa_msg_t * msg,psa_invec in_vec[],size_t in_len,psa_outvec out_vec[],size_t out_len)60 static psa_status_t tfm_crypto_init_iovecs(const psa_msg_t *msg,
61 psa_invec in_vec[],
62 size_t in_len,
63 psa_outvec out_vec[],
64 size_t out_len)
65 {
66 uint32_t i;
67
68 /* Map from the second element as the first is read when parsing */
69 for (i = 1; i < in_len; i++) {
70 in_vec[i].len = msg->in_size[i];
71 if (in_vec[i].len != 0) {
72 in_vec[i].base = psa_map_invec(msg->handle, i);
73 } else {
74 in_vec[i].base = NULL;
75 }
76 }
77
78 for (i = 0; i < out_len; i++) {
79 out_vec[i].len = msg->out_size[i];
80 if (out_vec[i].len != 0) {
81 out_vec[i].base = psa_map_outvec(msg->handle, i);
82 } else {
83 out_vec[i].base = NULL;
84 }
85 }
86
87 return PSA_SUCCESS;
88 }
89 #else /* PSA_FRAMEWORK_HAS_MM_IOVEC == 1 */
90 /**
91 * \brief Internal scratch used for IOVec allocations
92 *
93 */
94 static struct tfm_crypto_scratch {
95 __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
96 uint8_t buf[CRYPTO_IOVEC_BUFFER_SIZE];
97 uint32_t alloc_index;
98 int32_t owner;
99 } scratch = {.buf = {0}, .alloc_index = 0};
100
tfm_crypto_set_scratch_owner(int32_t id)101 static psa_status_t tfm_crypto_set_scratch_owner(int32_t id)
102 {
103 scratch.owner = id;
104 return PSA_SUCCESS;
105 }
106
tfm_crypto_get_scratch_owner(int32_t * id)107 static psa_status_t tfm_crypto_get_scratch_owner(int32_t *id)
108 {
109 *id = scratch.owner;
110 return PSA_SUCCESS;
111 }
112
tfm_crypto_alloc_scratch(size_t requested_size,void ** buf)113 static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
114 {
115 /* Prevent ALIGN() from overflowing */
116 if (requested_size > SIZE_MAX - (TFM_CRYPTO_IOVEC_ALIGNMENT - 1)) {
117 return PSA_ERROR_INSUFFICIENT_MEMORY;
118 }
119
120 /* Ensure alloc_index remains aligned to the required iovec alignment */
121 requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
122
123 if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
124 return PSA_ERROR_INSUFFICIENT_MEMORY;
125 }
126
127 /* Compute the pointer to the allocated space */
128 *buf = (void *)&scratch.buf[scratch.alloc_index];
129
130 /* Increase the allocated size */
131 scratch.alloc_index += requested_size;
132
133 return PSA_SUCCESS;
134 }
135
tfm_crypto_clear_scratch(void)136 static void tfm_crypto_clear_scratch(void)
137 {
138 scratch.owner = 0;
139 (void)memset(scratch.buf, 0, scratch.alloc_index);
140 scratch.alloc_index = 0;
141 }
142
tfm_crypto_set_caller_id(int32_t id)143 static void tfm_crypto_set_caller_id(int32_t id)
144 {
145 /* Set the owner of the data in the scratch */
146 (void)tfm_crypto_set_scratch_owner(id);
147 }
148
tfm_crypto_get_caller_id(int32_t * id)149 psa_status_t tfm_crypto_get_caller_id(int32_t *id)
150 {
151 return tfm_crypto_get_scratch_owner(id);
152 }
153
tfm_crypto_init_iovecs(const psa_msg_t * msg,psa_invec in_vec[],size_t in_len,psa_outvec out_vec[],size_t out_len)154 static psa_status_t tfm_crypto_init_iovecs(const psa_msg_t *msg,
155 psa_invec in_vec[],
156 size_t in_len,
157 psa_outvec out_vec[],
158 size_t out_len)
159 {
160 uint32_t i;
161 void *alloc_buf_ptr = NULL;
162 psa_status_t status;
163
164 /* Alloc/read from the second element as the first is read when parsing */
165 for (i = 1; i < in_len; i++) {
166 /* Allocate necessary space in the internal scratch */
167 status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
168 if (status != PSA_SUCCESS) {
169 tfm_crypto_clear_scratch();
170 return status;
171 }
172 /* Read from the IPC framework inputs into the scratch */
173 in_vec[i].len =
174 psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
175 /* Populate the fields of the input to the secure function */
176 in_vec[i].base = alloc_buf_ptr;
177 }
178
179 for (i = 0; i < out_len; i++) {
180 /* Allocate necessary space for the output in the internal scratch */
181 status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
182 if (status != PSA_SUCCESS) {
183 tfm_crypto_clear_scratch();
184 return status;
185 }
186 /* Populate the fields of the output to the secure function */
187 out_vec[i].base = alloc_buf_ptr;
188 out_vec[i].len = msg->out_size[i];
189 }
190
191 return PSA_SUCCESS;
192 }
193 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC == 1 */
194
tfm_crypto_call_srv(const psa_msg_t * msg)195 static psa_status_t tfm_crypto_call_srv(const psa_msg_t *msg)
196 {
197 psa_status_t status = PSA_SUCCESS;
198 size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
199 psa_invec in_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
200 psa_outvec out_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
201 struct tfm_crypto_pack_iovec iov = {0};
202
203 /* Check the number of in_vec filled */
204 while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
205 in_len--;
206 }
207
208 /* Check the number of out_vec filled */
209 while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
210 out_len--;
211 }
212
213 /* There will always be a tfm_crypto_pack_iovec in the first iovec */
214 if (in_len < 1) {
215 return PSA_ERROR_GENERIC_ERROR;
216 }
217
218 if (psa_read(msg->handle, 0, &iov, sizeof(iov)) != sizeof(iov)) {
219 return PSA_ERROR_GENERIC_ERROR;
220 }
221
222 /* Initialise the first iovec with the IOV read when parsing */
223 in_vec[0].base = &iov;
224 in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
225
226 status = tfm_crypto_init_iovecs(msg, in_vec, in_len, out_vec, out_len);
227 if (status != PSA_SUCCESS) {
228 return status;
229 }
230
231 tfm_crypto_set_caller_id(msg->client_id);
232
233 /* Call the dispatcher to the functions that implement the PSA Crypto API */
234 status = tfm_crypto_api_dispatcher(in_vec, in_len, out_vec, out_len);
235
236 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
237 for (i = 0; i < out_len; i++) {
238 if (out_vec[i].base != NULL) {
239 psa_unmap_outvec(msg->handle, i, out_vec[i].len);
240 }
241 }
242 #else
243 /* Write into the IPC framework outputs from the scratch */
244 for (i = 0; i < out_len; i++) {
245 psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
246 }
247
248 /* Clear the allocated internal scratch before returning */
249 tfm_crypto_clear_scratch();
250 #endif
251
252 return status;
253 }
254
tfm_crypto_engine_init(void)255 static psa_status_t tfm_crypto_engine_init(void)
256 {
257 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
258 char *library_info = NULL;
259
260 #if CRYPTO_NV_SEED
261 LOG_INFFMT("[INF][Crypto] Provision entropy seed...\r\n");
262 if (tfm_plat_crypto_provision_entropy_seed() != TFM_CRYPTO_NV_SEED_SUCCESS) {
263 return PSA_ERROR_GENERIC_ERROR;
264 }
265 LOG_INFFMT("[INF][Crypto] Provision entropy seed... \033[0;32mcomplete\033[0m.\r\n");
266 #endif /* CRYPTO_NV_SEED */
267
268 /* Initialise the underlying Cryptographic library that provides the
269 * PSA Crypto core layer
270 */
271 library_info = tfm_crypto_library_get_info();
272 LOG_DBGFMT("[DBG][Crypto] Init \033[0;32m%s\033[0m...\r\n", library_info);
273 status = tfm_crypto_core_library_init();
274 if (status != PSA_SUCCESS) {
275 return status;
276 }
277 LOG_DBGFMT("[DBG][Crypto] Init \033[0;32m%s\033[0m... \033[0;32mcomplete\033[0m.\r\n", library_info);
278
279 /* Initialise the crypto accelerator if one is enabled. If the driver API is
280 * the one defined by the PSA Unified Driver interface, the initialisation is
281 * performed directly through psa_crypto_init() while the PSA subsystem is
282 * initialised
283 */
284 #if defined(CRYPTO_HW_ACCELERATOR) && defined(LEGACY_DRIVER_API_ENABLED)
285 LOG_INFFMT("[INF][Crypto] Init HW accelerator...\r\n");
286 if (crypto_hw_accelerator_init() != 0) {
287 return PSA_ERROR_HARDWARE_FAILURE;
288 }
289 LOG_INFFMT("[INF][Crypto] Init HW accelerator... \033[0;32mcomplete\033[0m.\r\n");
290 #endif /* CRYPTO_HW_ACCELERATOR */
291
292 /* Perform the initialisation of the PSA subsystem available through the chosen
293 * Cryptographic library. If a driver is built using the PSA Driver interface,
294 * the function below will perform also the same operations done by the HAL init
295 * crypto_hw_accelerator_init()
296 */
297 return psa_crypto_init();
298 }
299
tfm_crypto_module_init(void)300 static psa_status_t tfm_crypto_module_init(void)
301 {
302 /* Init the Alloc module */
303 return tfm_crypto_init_alloc();
304 }
305
tfm_crypto_init(void)306 psa_status_t tfm_crypto_init(void)
307 {
308 psa_status_t status;
309
310 /* Initialise other modules of the service */
311 status = tfm_crypto_module_init();
312 if (status != PSA_SUCCESS) {
313 return status;
314 }
315
316 /* Initialise the engine layer */
317 status = tfm_crypto_engine_init();
318 if (status != PSA_SUCCESS) {
319 return status;
320 }
321
322 return PSA_SUCCESS;
323 }
324
tfm_crypto_sfn(const psa_msg_t * msg)325 psa_status_t tfm_crypto_sfn(const psa_msg_t *msg)
326 {
327 /* Process the message type */
328 switch (msg->type) {
329 case PSA_IPC_CALL:
330 return tfm_crypto_call_srv(msg);
331 default:
332 return PSA_ERROR_NOT_SUPPORTED;
333 }
334
335 return PSA_ERROR_GENERIC_ERROR;
336 }
337
tfm_crypto_api_dispatcher(psa_invec in_vec[],size_t in_len,psa_outvec out_vec[],size_t out_len)338 psa_status_t tfm_crypto_api_dispatcher(psa_invec in_vec[],
339 size_t in_len,
340 psa_outvec out_vec[],
341 size_t out_len)
342 {
343 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
344 const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
345 int32_t caller_id = 0;
346 struct tfm_crypto_key_id_s encoded_key = TFM_CRYPTO_KEY_ID_S_INIT;
347 bool is_key_required = false;
348 enum tfm_crypto_group_id_t group_id;
349
350 if (in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) {
351 return PSA_ERROR_PROGRAMMER_ERROR;
352 }
353
354 group_id = TFM_CRYPTO_GET_GROUP_ID(iov->function_id);
355
356 is_key_required = !((group_id == TFM_CRYPTO_GROUP_ID_HASH) ||
357 (group_id == TFM_CRYPTO_GROUP_ID_RANDOM));
358
359 if (is_key_required) {
360 status = tfm_crypto_get_caller_id(&caller_id);
361 if (status != PSA_SUCCESS) {
362 return status;
363 }
364 /* The caller_id being set in the owner field is the partition ID
365 * of the calling partition
366 */
367 encoded_key.key_id = iov->key_id;
368 encoded_key.owner = caller_id;
369 }
370
371 /* Dispatch to each sub-module based on the Group ID */
372 switch (group_id) {
373 case TFM_CRYPTO_GROUP_ID_KEY_MANAGEMENT:
374 return tfm_crypto_key_management_interface(in_vec, out_vec,
375 &encoded_key);
376 case TFM_CRYPTO_GROUP_ID_HASH:
377 return tfm_crypto_hash_interface(in_vec, out_vec);
378 case TFM_CRYPTO_GROUP_ID_MAC:
379 return tfm_crypto_mac_interface(in_vec, out_vec, &encoded_key);
380 case TFM_CRYPTO_GROUP_ID_CIPHER:
381 return tfm_crypto_cipher_interface(in_vec, out_vec, &encoded_key);
382 case TFM_CRYPTO_GROUP_ID_AEAD:
383 return tfm_crypto_aead_interface(in_vec, out_vec, &encoded_key);
384 case TFM_CRYPTO_GROUP_ID_ASYM_SIGN:
385 return tfm_crypto_asymmetric_sign_interface(in_vec, out_vec,
386 &encoded_key);
387 case TFM_CRYPTO_GROUP_ID_ASYM_ENCRYPT:
388 return tfm_crypto_asymmetric_encrypt_interface(in_vec, out_vec,
389 &encoded_key);
390 case TFM_CRYPTO_GROUP_ID_KEY_DERIVATION:
391 return tfm_crypto_key_derivation_interface(in_vec, out_vec,
392 &encoded_key);
393 case TFM_CRYPTO_GROUP_ID_RANDOM:
394 return tfm_crypto_random_interface(in_vec, out_vec);
395 default:
396 LOG_ERRFMT("[ERR][Crypto] Unsupported request!\r\n");
397 return PSA_ERROR_NOT_SUPPORTED;
398 }
399
400 return PSA_ERROR_NOT_SUPPORTED;
401 }
402