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     /* Ensure alloc_index remains aligned to the required iovec alignment */
116     requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
117 
118     if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
119         return PSA_ERROR_INSUFFICIENT_MEMORY;
120     }
121 
122     /* Compute the pointer to the allocated space */
123     *buf = (void *)&scratch.buf[scratch.alloc_index];
124 
125     /* Increase the allocated size */
126     scratch.alloc_index += requested_size;
127 
128     return PSA_SUCCESS;
129 }
130 
tfm_crypto_clear_scratch(void)131 static void tfm_crypto_clear_scratch(void)
132 {
133     scratch.owner = 0;
134     (void)memset(scratch.buf, 0, scratch.alloc_index);
135     scratch.alloc_index = 0;
136 }
137 
tfm_crypto_set_caller_id(int32_t id)138 static void tfm_crypto_set_caller_id(int32_t id)
139 {
140     /* Set the owner of the data in the scratch */
141     (void)tfm_crypto_set_scratch_owner(id);
142 }
143 
tfm_crypto_get_caller_id(int32_t * id)144 psa_status_t tfm_crypto_get_caller_id(int32_t *id)
145 {
146     return tfm_crypto_get_scratch_owner(id);
147 }
148 
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)149 static psa_status_t tfm_crypto_init_iovecs(const psa_msg_t *msg,
150                                            psa_invec in_vec[],
151                                            size_t in_len,
152                                            psa_outvec out_vec[],
153                                            size_t out_len)
154 {
155     uint32_t i;
156     void *alloc_buf_ptr = NULL;
157     psa_status_t status;
158 
159     /* Alloc/read from the second element as the first is read when parsing */
160     for (i = 1; i < in_len; i++) {
161         /* Allocate necessary space in the internal scratch */
162         status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
163         if (status != PSA_SUCCESS) {
164             tfm_crypto_clear_scratch();
165             return status;
166         }
167         /* Read from the IPC framework inputs into the scratch */
168         in_vec[i].len =
169                        psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
170         /* Populate the fields of the input to the secure function */
171         in_vec[i].base = alloc_buf_ptr;
172     }
173 
174     for (i = 0; i < out_len; i++) {
175         /* Allocate necessary space for the output in the internal scratch */
176         status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
177         if (status != PSA_SUCCESS) {
178             tfm_crypto_clear_scratch();
179             return status;
180         }
181         /* Populate the fields of the output to the secure function */
182         out_vec[i].base = alloc_buf_ptr;
183         out_vec[i].len = msg->out_size[i];
184     }
185 
186     return PSA_SUCCESS;
187 }
188 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC == 1 */
189 
tfm_crypto_call_srv(const psa_msg_t * msg)190 static psa_status_t tfm_crypto_call_srv(const psa_msg_t *msg)
191 {
192     psa_status_t status = PSA_SUCCESS;
193     size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
194     psa_invec in_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
195     psa_outvec out_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
196     struct tfm_crypto_pack_iovec iov = {0};
197 
198     /* Check the number of in_vec filled */
199     while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
200         in_len--;
201     }
202 
203     /* Check the number of out_vec filled */
204     while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
205         out_len--;
206     }
207 
208     /* There will always be a tfm_crypto_pack_iovec in the first iovec */
209     if (in_len < 1) {
210         return PSA_ERROR_GENERIC_ERROR;
211     }
212 
213     if (psa_read(msg->handle, 0, &iov, sizeof(iov)) != sizeof(iov)) {
214         return PSA_ERROR_GENERIC_ERROR;
215     }
216 
217     /* Initialise the first iovec with the IOV read when parsing */
218     in_vec[0].base = &iov;
219     in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
220 
221     status = tfm_crypto_init_iovecs(msg, in_vec, in_len, out_vec, out_len);
222     if (status != PSA_SUCCESS) {
223         return status;
224     }
225 
226     tfm_crypto_set_caller_id(msg->client_id);
227 
228     /* Call the dispatcher to the functions that implement the PSA Crypto API */
229     status = tfm_crypto_api_dispatcher(in_vec, in_len, out_vec, out_len);
230 
231 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
232     for (i = 0; i < out_len; i++) {
233         if (out_vec[i].base != NULL) {
234             psa_unmap_outvec(msg->handle, i, out_vec[i].len);
235         }
236     }
237 #else
238     /* Write into the IPC framework outputs from the scratch */
239     for (i = 0; i < out_len; i++) {
240         psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
241     }
242 
243     /* Clear the allocated internal scratch before returning */
244     tfm_crypto_clear_scratch();
245 #endif
246 
247     return status;
248 }
249 
tfm_crypto_engine_init(void)250 static psa_status_t tfm_crypto_engine_init(void)
251 {
252     psa_status_t status = PSA_ERROR_GENERIC_ERROR;
253     char *library_info = NULL;
254 
255 #if CRYPTO_NV_SEED
256     LOG_INFFMT("[INF][Crypto] ");
257     LOG_INFFMT("Provisioning entropy seed... ");
258     if (tfm_plat_crypto_provision_entropy_seed() != TFM_CRYPTO_NV_SEED_SUCCESS) {
259         return PSA_ERROR_GENERIC_ERROR;
260     }
261     LOG_INFFMT("\033[0;32mcomplete.\033[0m\r\n");
262 #endif /* CRYPTO_NV_SEED */
263 
264     /* Initialise the underlying Cryptographic library that provides the
265      * PSA Crypto core layer
266      */
267     library_info = tfm_crypto_library_get_info();
268     LOG_DBGFMT("[DBG][Crypto] Initialising \033[0;32m%s\033[0m as PSA Crypto backend library... ", library_info);
269     status = tfm_crypto_core_library_init();
270     if (status != PSA_SUCCESS) {
271         return status;
272     }
273     LOG_DBGFMT("\033[0;32mcomplete.\033[0m\r\n");
274 
275     /* Initialise the crypto accelerator if one is enabled. If the driver API is
276      * the one defined by the PSA Unified Driver interface, the initialisation is
277      * performed directly through psa_crypto_init() while the PSA subsystem is
278      * initialised
279      */
280 #if defined(CRYPTO_HW_ACCELERATOR) && defined(LEGACY_DRIVER_API_ENABLED)
281     LOG_INFFMT("[INF][Crypto] Initialising HW accelerator... ");
282     if (crypto_hw_accelerator_init() != 0) {
283         return PSA_ERROR_HARDWARE_FAILURE;
284     }
285     LOG_INFFMT("\033[0;32mcomplete.\033[0m\r\n");
286 #endif /* CRYPTO_HW_ACCELERATOR */
287 
288     /* Perform the initialisation of the PSA subsystem available through the chosen
289      * Cryptographic library. If a driver is built using the PSA Driver interface,
290      * the function below will perform also the same operations done by the HAL init
291      * crypto_hw_accelerator_init()
292      */
293     return psa_crypto_init();
294 }
295 
tfm_crypto_module_init(void)296 static psa_status_t tfm_crypto_module_init(void)
297 {
298     /* Init the Alloc module */
299     return tfm_crypto_init_alloc();
300 }
301 
tfm_crypto_init(void)302 psa_status_t tfm_crypto_init(void)
303 {
304     psa_status_t status;
305 
306     /* Initialise other modules of the service */
307     status = tfm_crypto_module_init();
308     if (status != PSA_SUCCESS) {
309         return status;
310     }
311 
312     /* Initialise the engine layer */
313     status =  tfm_crypto_engine_init();
314     if (status != PSA_SUCCESS) {
315         return status;
316     }
317 
318     return PSA_SUCCESS;
319 }
320 
tfm_crypto_sfn(const psa_msg_t * msg)321 psa_status_t tfm_crypto_sfn(const psa_msg_t *msg)
322 {
323     /* Process the message type */
324     switch (msg->type) {
325     case PSA_IPC_CALL:
326         return tfm_crypto_call_srv(msg);
327     default:
328         return PSA_ERROR_NOT_SUPPORTED;
329     }
330 
331     return PSA_ERROR_GENERIC_ERROR;
332 }
333 
tfm_crypto_api_dispatcher(psa_invec in_vec[],size_t in_len,psa_outvec out_vec[],size_t out_len)334 psa_status_t tfm_crypto_api_dispatcher(psa_invec in_vec[],
335                                        size_t in_len,
336                                        psa_outvec out_vec[],
337                                        size_t out_len)
338 {
339     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
340     const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
341     int32_t caller_id = 0;
342     struct tfm_crypto_key_id_s encoded_key = TFM_CRYPTO_KEY_ID_S_INIT;
343     bool is_key_required = false;
344     enum tfm_crypto_group_id group_id;
345 
346     if (in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) {
347         return PSA_ERROR_PROGRAMMER_ERROR;
348     }
349 
350     group_id = TFM_CRYPTO_GET_GROUP_ID(iov->function_id);
351 
352     is_key_required = !((group_id == TFM_CRYPTO_GROUP_ID_HASH) ||
353                         (group_id == TFM_CRYPTO_GROUP_ID_RANDOM));
354 
355     if (is_key_required) {
356         status = tfm_crypto_get_caller_id(&caller_id);
357         if (status != PSA_SUCCESS) {
358             return status;
359         }
360         /* The caller_id being set in the owner field is the partition ID
361          * of the calling partition
362          */
363         encoded_key.key_id = iov->key_id;
364         encoded_key.owner = caller_id;
365     }
366 
367     /* Dispatch to each sub-module based on the Group ID */
368     switch (group_id) {
369     case TFM_CRYPTO_GROUP_ID_KEY_MANAGEMENT:
370         return tfm_crypto_key_management_interface(in_vec, out_vec,
371                                                    &encoded_key);
372     case TFM_CRYPTO_GROUP_ID_HASH:
373         return tfm_crypto_hash_interface(in_vec, out_vec);
374     case TFM_CRYPTO_GROUP_ID_MAC:
375         return tfm_crypto_mac_interface(in_vec, out_vec, &encoded_key);
376     case TFM_CRYPTO_GROUP_ID_CIPHER:
377         return tfm_crypto_cipher_interface(in_vec, out_vec, &encoded_key);
378     case TFM_CRYPTO_GROUP_ID_AEAD:
379         return tfm_crypto_aead_interface(in_vec, out_vec, &encoded_key);
380     case TFM_CRYPTO_GROUP_ID_ASYM_SIGN:
381         return tfm_crypto_asymmetric_sign_interface(in_vec, out_vec,
382                                                     &encoded_key);
383     case TFM_CRYPTO_GROUP_ID_ASYM_ENCRYPT:
384         return tfm_crypto_asymmetric_encrypt_interface(in_vec, out_vec,
385                                                        &encoded_key);
386     case TFM_CRYPTO_GROUP_ID_KEY_DERIVATION:
387         return tfm_crypto_key_derivation_interface(in_vec, out_vec,
388                                                    &encoded_key);
389     case TFM_CRYPTO_GROUP_ID_RANDOM:
390         return tfm_crypto_random_interface(in_vec, out_vec);
391     default:
392         LOG_ERRFMT("[ERR][Crypto] Unsupported request!\r\n");
393         return PSA_ERROR_NOT_SUPPORTED;
394     }
395 
396     return PSA_ERROR_NOT_SUPPORTED;
397 }
398