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