1 /*
2  * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
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_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_api_dispatcher(psa_invec in_vec[],size_t in_len,psa_outvec out_vec[],size_t out_len)195 static psa_status_t tfm_crypto_api_dispatcher(psa_invec in_vec[],
196                                               size_t in_len,
197                                               psa_outvec out_vec[],
198                                               size_t out_len)
199 {
200     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
201     const struct tfm_crypto_pack_iovec *iov = in_vec[0].base;
202     int32_t caller_id = 0;
203     struct tfm_crypto_key_id_s encoded_key = TFM_CRYPTO_KEY_ID_S_INIT;
204     bool is_key_required = false;
205     enum tfm_crypto_group_id_t group_id;
206 
207     if (in_vec[0].len != sizeof(struct tfm_crypto_pack_iovec)) {
208         return PSA_ERROR_PROGRAMMER_ERROR;
209     }
210 
211     group_id = TFM_CRYPTO_GET_GROUP_ID(iov->function_id);
212 
213     is_key_required = !((group_id == TFM_CRYPTO_GROUP_ID_HASH) ||
214                         (group_id == TFM_CRYPTO_GROUP_ID_RANDOM));
215 
216     if (is_key_required) {
217         status = tfm_crypto_get_caller_id(&caller_id);
218         if (status != PSA_SUCCESS) {
219             return status;
220         }
221         /* The caller_id being set in the owner field is the partition ID
222          * of the calling partition
223          */
224         encoded_key.key_id = iov->key_id;
225         encoded_key.owner = caller_id;
226     }
227 
228     /* Dispatch to each sub-module based on the Group ID */
229     switch (group_id) {
230     case TFM_CRYPTO_GROUP_ID_KEY_MANAGEMENT:
231         return tfm_crypto_key_management_interface(in_vec, out_vec,
232                                                    &encoded_key);
233     case TFM_CRYPTO_GROUP_ID_HASH:
234         return tfm_crypto_hash_interface(in_vec, out_vec);
235     case TFM_CRYPTO_GROUP_ID_MAC:
236         return tfm_crypto_mac_interface(in_vec, out_vec, &encoded_key);
237     case TFM_CRYPTO_GROUP_ID_CIPHER:
238         return tfm_crypto_cipher_interface(in_vec, out_vec, &encoded_key);
239     case TFM_CRYPTO_GROUP_ID_AEAD:
240         return tfm_crypto_aead_interface(in_vec, out_vec, &encoded_key);
241     case TFM_CRYPTO_GROUP_ID_ASYM_SIGN:
242         return tfm_crypto_asymmetric_sign_interface(in_vec, out_vec,
243                                                     &encoded_key);
244     case TFM_CRYPTO_GROUP_ID_ASYM_ENCRYPT:
245         return tfm_crypto_asymmetric_encrypt_interface(in_vec, out_vec,
246                                                        &encoded_key);
247     case TFM_CRYPTO_GROUP_ID_KEY_DERIVATION:
248         return tfm_crypto_key_derivation_interface(in_vec, out_vec,
249                                                    &encoded_key);
250     case TFM_CRYPTO_GROUP_ID_RANDOM:
251         return tfm_crypto_random_interface(in_vec, out_vec);
252     default:
253         ERROR("[Crypto] Unsupported request!\n");
254         return PSA_ERROR_NOT_SUPPORTED;
255     }
256 }
257 
tfm_crypto_call_srv(const psa_msg_t * msg)258 static psa_status_t tfm_crypto_call_srv(const psa_msg_t *msg)
259 {
260     psa_status_t status = PSA_SUCCESS;
261     size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
262     psa_invec in_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
263     psa_outvec out_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
264     struct tfm_crypto_pack_iovec iov = {0};
265 
266     /* Check the number of in_vec filled */
267     while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
268         in_len--;
269     }
270 
271     /* Check the number of out_vec filled */
272     while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
273         out_len--;
274     }
275 
276     /* There will always be a tfm_crypto_pack_iovec in the first iovec */
277     if (in_len < 1) {
278         return PSA_ERROR_GENERIC_ERROR;
279     }
280 
281     if (psa_read(msg->handle, 0, &iov, sizeof(iov)) != sizeof(iov)) {
282         return PSA_ERROR_GENERIC_ERROR;
283     }
284 
285     /* Initialise the first iovec with the IOV read when parsing */
286     in_vec[0].base = &iov;
287     in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
288 
289     status = tfm_crypto_init_iovecs(msg, in_vec, in_len, out_vec, out_len);
290     if (status != PSA_SUCCESS) {
291         return status;
292     }
293 
294     tfm_crypto_set_caller_id(msg->client_id);
295 
296     /* Call the dispatcher to the functions that implement the PSA Crypto API */
297     status = tfm_crypto_api_dispatcher(in_vec, in_len, out_vec, out_len);
298 
299 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
300     for (i = 0; i < out_len; i++) {
301         if (out_vec[i].base != NULL) {
302             psa_unmap_outvec(msg->handle, i, out_vec[i].len);
303         }
304     }
305 
306     /*
307      * Unmap from the second element because the first element is read when
308      * parsing the message, hence it is never mapped.
309      */
310     for (i = 1; i < in_len; i++) {
311         if (in_vec[i].base != NULL) {
312             psa_unmap_invec(msg->handle, i);
313         }
314     }
315 #else
316     /* Write into the IPC framework outputs from the scratch */
317     for (i = 0; i < out_len; i++) {
318         psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
319     }
320 
321     /* Clear the allocated internal scratch before returning */
322     tfm_crypto_clear_scratch();
323 #endif
324 
325     return status;
326 }
327 
tfm_crypto_engine_init(void)328 static psa_status_t tfm_crypto_engine_init(void)
329 {
330     psa_status_t status = PSA_ERROR_GENERIC_ERROR;
331     char *library_info = NULL;
332 
333 #if CRYPTO_NV_SEED
334     INFO("[Crypto] Provision entropy seed...\n");
335     if (tfm_plat_crypto_provision_entropy_seed() != TFM_CRYPTO_NV_SEED_SUCCESS) {
336         return PSA_ERROR_GENERIC_ERROR;
337     }
338     INFO("[Crypto] Provision entropy seed... \033[0;32mcomplete\033[0m.\n");
339 #endif /* CRYPTO_NV_SEED */
340 
341     /* Initialise the underlying Cryptographic library that provides the
342      * PSA Crypto core layer
343      */
344     library_info = tfm_crypto_library_get_info();
345     VERBOSE("[Crypto] Init \033[0;32m%s\033[0m...\n", library_info);
346     status = tfm_crypto_core_library_init();
347     if (status != PSA_SUCCESS) {
348         return status;
349     }
350     VERBOSE("[Crypto] Init \033[0;32m%s\033[0m... \033[0;32mcomplete\033[0m.\n", library_info);
351 
352     /* Initialise the crypto accelerator if one is enabled. If the driver API is
353      * the one defined by the PSA Unified Driver interface, the initialisation is
354      * performed directly through psa_crypto_init() while the PSA subsystem is
355      * initialised
356      */
357 #if defined(CRYPTO_HW_ACCELERATOR) && defined(LEGACY_DRIVER_API_ENABLED)
358     INFO("[Crypto] Init HW accelerator...\n");
359     if (crypto_hw_accelerator_init() != 0) {
360         return PSA_ERROR_HARDWARE_FAILURE;
361     }
362     INFO("[Crypto] Init HW accelerator... \033[0;32mcomplete\033[0m.\n");
363 #endif /* CRYPTO_HW_ACCELERATOR */
364 
365     /* Perform the initialisation of the PSA subsystem available through the chosen
366      * Cryptographic library. If a driver is built using the PSA Driver interface,
367      * the function below will perform also the same operations done by the HAL init
368      * crypto_hw_accelerator_init()
369      */
370     return psa_crypto_init();
371 }
372 
tfm_crypto_module_init(void)373 static psa_status_t tfm_crypto_module_init(void)
374 {
375     /* Init the Alloc module */
376     return tfm_crypto_init_alloc();
377 }
378 
379 /*!
380  * \defgroup init This group implements the partition initialisation
381  *                function to be called during TF-M boot, and the SFN
382  *                servicing call to be called when a SFN request needs
383  *                to be handled by the SPM. When built in IPC mode, the
384  *                SPM directly provides a scheduling handler that deals
385  *                with messages and calls the SFN entry point below just
386  *                when needed, i.e. no need for a dedicated message handler
387  *                needs to be implemented here
388  */
389 
390 /*!@{*/
tfm_crypto_init(void)391 psa_status_t tfm_crypto_init(void)
392 {
393     psa_status_t status;
394 
395     /* Initialise other modules of the service */
396     status = tfm_crypto_module_init();
397     if (status != PSA_SUCCESS) {
398         return status;
399     }
400 
401     /* Initialise the engine layer */
402     status =  tfm_crypto_engine_init();
403     if (status != PSA_SUCCESS) {
404         return status;
405     }
406 
407     return PSA_SUCCESS;
408 }
409 
tfm_crypto_sfn(const psa_msg_t * msg)410 psa_status_t tfm_crypto_sfn(const psa_msg_t *msg)
411 {
412     /* Process the message type */
413     switch (msg->type) {
414     case PSA_IPC_CALL:
415         return tfm_crypto_call_srv(msg);
416     default:
417         return PSA_ERROR_NOT_SUPPORTED;
418     }
419 }
420 /*!@}*/
421