TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
crypto_init.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
9 
10 #include "tfm_crypto_api.h"
11 #include "tfm_crypto_defs.h"
12 #include "log/tfm_log.h"
13 
14 /*
15  * \brief This Mbed TLS include is needed to initialise the memory allocator
16  * inside the Mbed TLS layer of Mbed Crypto
17  */
18 #include "mbedtls/memory_buffer_alloc.h"
19 
20 #ifndef TFM_PSA_API
21 #include "tfm_secure_api.h"
22 #endif
23 
24 #ifdef CRYPTO_HW_ACCELERATOR
25 #include "crypto_hw.h"
26 #endif /* CRYPTO_HW_ACCLERATOR */
27 
28 #ifdef TFM_PSA_API
29 #include "psa/service.h"
31 #include "tfm_memory_utils.h"
32 
37 static const tfm_crypto_us_t sfid_func_table[TFM_CRYPTO_SID_MAX] = {
38 #define X(api_name) api_name,
40 #undef X
41 };
42 
46 #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
47 
52 #define TFM_CRYPTO_IOVEC_ALIGNMENT (4u)
53 
58 #ifndef TFM_CRYPTO_IOVEC_BUFFER_SIZE
59 #error TFM_CRYPTO_IOVEC_BUFFER_SIZE is not defined
60 #endif
61 
66 static struct tfm_crypto_scratch {
67  __attribute__((__aligned__(TFM_CRYPTO_IOVEC_ALIGNMENT)))
68  uint8_t buf[TFM_CRYPTO_IOVEC_BUFFER_SIZE];
69  uint32_t alloc_index;
70  int32_t owner;
71 } scratch = {.buf = {0}, .alloc_index = 0};
72 
73 static psa_status_t tfm_crypto_set_scratch_owner(int32_t id)
74 {
75  scratch.owner = id;
76  return PSA_SUCCESS;
77 }
78 
79 static psa_status_t tfm_crypto_get_scratch_owner(int32_t *id)
80 {
81  *id = scratch.owner;
82  return PSA_SUCCESS;
83 }
84 
85 static psa_status_t tfm_crypto_alloc_scratch(size_t requested_size, void **buf)
86 {
87  /* Ensure alloc_index remains aligned to the required iovec alignment */
88  requested_size = ALIGN(requested_size, TFM_CRYPTO_IOVEC_ALIGNMENT);
89 
90  if (requested_size > (sizeof(scratch.buf) - scratch.alloc_index)) {
92  }
93 
94  /* Compute the pointer to the allocated space */
95  *buf = (void *)&scratch.buf[scratch.alloc_index];
96 
97  /* Increase the allocated size */
98  scratch.alloc_index += requested_size;
99 
100  return PSA_SUCCESS;
101 }
102 
103 static psa_status_t tfm_crypto_clear_scratch(void)
104 {
105  scratch.alloc_index = 0;
106  scratch.owner = 0;
107  (void)tfm_memset(scratch.buf, 0, sizeof(scratch.buf));
108 
109  return PSA_SUCCESS;
110 }
111 
112 static psa_status_t tfm_crypto_call_sfn(psa_msg_t *msg,
113  struct tfm_crypto_pack_iovec *iov,
114  const uint32_t sfn_id)
115 {
116  psa_status_t status = PSA_SUCCESS;
117  size_t in_len = PSA_MAX_IOVEC, out_len = PSA_MAX_IOVEC, i;
118  psa_invec in_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
119  psa_outvec out_vec[PSA_MAX_IOVEC] = { {NULL, 0} };
120  void *alloc_buf_ptr = NULL;
121 
122  /* Check the number of in_vec filled */
123  while ((in_len > 0) && (msg->in_size[in_len - 1] == 0)) {
124  in_len--;
125  }
126 
127  /* There will always be a tfm_crypto_pack_iovec in the first iovec */
128  if (in_len < 1) {
130  }
131  /* Initialise the first iovec with the IOV read when parsing */
132  in_vec[0].base = iov;
133  in_vec[0].len = sizeof(struct tfm_crypto_pack_iovec);
134 
135  /* Alloc/read from the second element as the first is read when parsing */
136  for (i = 1; i < in_len; i++) {
137  /* Allocate necessary space in the internal scratch */
138  status = tfm_crypto_alloc_scratch(msg->in_size[i], &alloc_buf_ptr);
139  if (status != PSA_SUCCESS) {
140  (void)tfm_crypto_clear_scratch();
141  return status;
142  }
143  /* Read from the IPC framework inputs into the scratch */
144  (void) psa_read(msg->handle, i, alloc_buf_ptr, msg->in_size[i]);
145  /* Populate the fields of the input to the secure function */
146  in_vec[i].base = alloc_buf_ptr;
147  in_vec[i].len = msg->in_size[i];
148  }
149 
150  /* Check the number of out_vec filled */
151  while ((out_len > 0) && (msg->out_size[out_len - 1] == 0)) {
152  out_len--;
153  }
154 
155  for (i = 0; i < out_len; i++) {
156  /* Allocate necessary space for the output in the internal scratch */
157  status = tfm_crypto_alloc_scratch(msg->out_size[i], &alloc_buf_ptr);
158  if (status != PSA_SUCCESS) {
159  (void)tfm_crypto_clear_scratch();
160  return status;
161  }
162  /* Populate the fields of the output to the secure function */
163  out_vec[i].base = alloc_buf_ptr;
164  out_vec[i].len = msg->out_size[i];
165  }
166 
167  /* Set the owner of the data in the scratch */
168  (void)tfm_crypto_set_scratch_owner(msg->client_id);
169 
170  /* Call the uniform signature API */
171  status = sfid_func_table[sfn_id](in_vec, in_len, out_vec, out_len);
172 
173  /* Write into the IPC framework outputs from the scratch */
174  for (i = 0; i < out_len; i++) {
175  psa_write(msg->handle, i, out_vec[i].base, out_vec[i].len);
176  }
177 
178  /* Clear the allocated internal scratch before returning */
179  if (tfm_crypto_clear_scratch() != PSA_SUCCESS) {
181  }
182 
183  return status;
184 }
185 
186 static psa_status_t tfm_crypto_parse_msg(psa_msg_t *msg,
187  struct tfm_crypto_pack_iovec *iov,
188  uint32_t *sfn_id_p)
189 {
190  size_t read_size;
191 
192  /* Read the in_vec[0] which holds the IOVEC always */
193  read_size = psa_read(msg->handle,
194  0,
195  iov,
196  sizeof(struct tfm_crypto_pack_iovec));
197 
198  if (read_size != sizeof(struct tfm_crypto_pack_iovec)) {
200  }
201 
202  if (iov->sfn_id >= TFM_CRYPTO_SID_MAX) {
203  *sfn_id_p = TFM_CRYPTO_SID_INVALID;
205  }
206 
207  *sfn_id_p = iov->sfn_id;
208 
209  return PSA_SUCCESS;
210 }
211 
212 static void tfm_crypto_ipc_handler(void)
213 {
214  psa_signal_t signals = 0;
215  psa_msg_t msg;
216  psa_status_t status = PSA_SUCCESS;
217  uint32_t sfn_id = TFM_CRYPTO_SID_INVALID;
218  struct tfm_crypto_pack_iovec iov = {0};
219 
220  while (1) {
221  signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
222  if (signals & TFM_CRYPTO_SIGNAL) {
223  /* Extract the message */
224  if (psa_get(TFM_CRYPTO_SIGNAL, &msg) != PSA_SUCCESS) {
225  /* FIXME: Should be replaced by TF-M error handling */
226  while (1) {
227  ;
228  }
229  }
230 
231  /* Process the message type */
232  switch (msg.type) {
233  case PSA_IPC_CONNECT:
234  case PSA_IPC_DISCONNECT:
236  break;
237  case PSA_IPC_CALL:
238  /* Parse the message */
239  status = tfm_crypto_parse_msg(&msg, &iov, &sfn_id);
240  /* Call the dispatcher based on the SID passed as type */
241  if (sfn_id != TFM_CRYPTO_SID_INVALID) {
242  status = tfm_crypto_call_sfn(&msg, &iov, sfn_id);
243  } else {
244  status = PSA_ERROR_GENERIC_ERROR;
245  }
246  psa_reply(msg.handle, status);
247  break;
248  default:
249  /* FIXME: Should be replaced by TF-M error handling */
250  while (1) {
251  ;
252  }
253  }
254  } else {
255  /* FIXME: Should be replaced by TF-M error handling */
256  while (1) {
257  ;
258  }
259  }
260  }
261 
262  /* NOTREACHED */
263  return;
264 }
265 #endif /* TFM_PSA_API */
266 
271 #ifndef TFM_CRYPTO_ENGINE_BUF_SIZE
272 #error TFM_CRYPTO_ENGINE_BUF_SIZE is not defined
273 #endif
274 
279 static uint8_t mbedtls_mem_buf[TFM_CRYPTO_ENGINE_BUF_SIZE] = {0};
280 
281 static psa_status_t tfm_crypto_engine_init(void)
282 {
283  /* Log unsafe entropy source */
284 #if defined (MBEDTLS_TEST_NULL_ENTROPY)
285  LOG_MSG("\033[1;34m[Crypto] MBEDTLS_TEST_NULL_ENTROPY is not suitable for production!\033[0m\r\n");
286 #endif
287 
288  /* Initialise the Mbed Crypto memory allocator to use static
289  * memory allocation from the provided buffer instead of using
290  * the heap
291  */
292  mbedtls_memory_buffer_alloc_init(mbedtls_mem_buf,
293  TFM_CRYPTO_ENGINE_BUF_SIZE);
294 
295  /* Initialise the crypto accelerator if one is enabled */
296 #ifdef CRYPTO_HW_ACCELERATOR
297  if (crypto_hw_accelerator_init() != 0) {
299  }
300 #endif /* CRYPTO_HW_ACCELERATOR */
301 
302  /* Previous function does not return any value, so just call the
303  * initialisation function of the Mbed Crypto layer
304  */
305  return psa_crypto_init();
306 }
307 
308 static psa_status_t tfm_crypto_module_init(void)
309 {
310  /* Init the Alloc module */
311  return tfm_crypto_init_alloc();
312 }
313 
315 {
316 #ifdef TFM_PSA_API
317  return tfm_crypto_get_scratch_owner(id);
318 #else
319  int32_t res;
320 
322  if (res != TFM_SUCCESS) {
324  } else {
325  return PSA_SUCCESS;
326  }
327 #endif
328 }
329 
331 {
332  psa_status_t status;
333 
334  /* Initialise other modules of the service */
335  status = tfm_crypto_module_init();
336  if (status != PSA_SUCCESS) {
337  return status;
338  }
339 
340  /* Initialise the engine layer */
341  status = tfm_crypto_engine_init();
342  if (status != PSA_SUCCESS) {
343  return status;
344  }
345 
346 #ifdef TFM_PSA_API
347  /* Should not return in normal operations */
348  tfm_crypto_ipc_handler();
349 #endif
350 
351  return status;
352 }
psa_status_t tfm_crypto_init(void)
Initialise the service.
Definition: crypto_init.c:330
Structure used to pack non-pointer types in a call.
uint32_t psa_signal_t
Definition: service.h:50
#define LOG_MSG(...)
Definition: tfm_log.h:15
void * base
Definition: client.h:75
#define PSA_BLOCK
Definition: service.h:31
__STATIC_INLINE void * tfm_memset(void *ptr, int value, size_t num)
int32_t type
Definition: service.h:56
#define PSA_SUCCESS
Definition: crypto_values.h:35
size_t len
Definition: client.h:68
#define TFM_CRYPTO_SID_INVALID
Define an invalid value for an SID.
int32_t client_id
Definition: service.h:64
#define psa_crypto_init
Definition: crypto_spe.h:25
#define LIST_TFM_CRYPTO_UNIFORM_SIGNATURE_API
#define PSA_ERROR_INSUFFICIENT_MEMORY
psa_status_t tfm_crypto_get_caller_id(int32_t *id)
Returns the ID of the caller.
Definition: crypto_init.c:314
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx, void *buffer, size_t num_bytes)
Read a message parameter or part of a message parameter from a client input vector.
Definition: psa_service.c:40
psa_handle_t handle
Definition: service.h:61
#define PSA_MAX_IOVEC
Definition: client.h:54
#define PSA_ERROR_GENERIC_ERROR
Definition: crypto_values.h:43
#define PSA_IPC_DISCONNECT
Definition: service.h:47
#define PSA_ERROR_NOT_PERMITTED
Definition: crypto_values.h:65
#define PSA_WAIT_ANY
Definition: service.h:36
size_t in_size[PSA_MAX_IOVEC]
Definition: service.h:70
#define PSA_ERROR_HARDWARE_FAILURE
int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
Definition: arch.c:28
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, const void *buffer, size_t num_bytes)
Write a message response to a client output vector.
Definition: psa_service.c:58
void psa_reply(psa_handle_t msg_handle, psa_status_t status)
Complete handling of a specific message and unblock the client.
Definition: psa_service.c:67
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
Return the Secure Partition interrupt signals that have been asserted from a subset of signals provid...
Definition: psa_service.c:15
size_t len
Definition: client.h:76
psa_status_t tfm_crypto_init_alloc(void)
Initialise the Alloc module.
Definition: crypto_alloc.c:87
#define PSA_IPC_CONNECT
Definition: service.h:45
size_t out_size[PSA_MAX_IOVEC]
Definition: service.h:73
#define PSA_IPC_CALL
Definition: client.h:59
const void * base
Definition: client.h:67
#define TFM_CRYPTO_SIGNAL
Definition: tfm_crypto.h:17
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
Retrieve the message which corresponds to a given RoT Service signal and remove the message from the ...
Definition: psa_service.c:24
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43