1 /*
2  * Copyright 2018-2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #ifndef FSL_SSCP_H
8 #define FSL_SSCP_H
9 
10 #include <stddef.h>
11 #include "fsl_sscp_commands.h"
12 
13 /*!
14 @defgroup sscp Security Subsystem Communication Protocol (SSCP)
15 
16     # SSCP protocol description
17 
18     SSCP is very simple remote procedure call protocol.
19     Function parameters are described by one or multiple SSCP operation descriptor(s).
20     One parameter descriptor describes up to 7 function parameters as contexts, buffers, values or aggregates.
21     Multiple parameter descriptors can be linked by the aggregate parameter type (kSSCP_ParamType_Aggregate).
22 
23     Function arguments are described as a buffer (address and size), a value (a tuple of two words),
24     a context (pointer and type id) or an aggregate.
25     If the parameter is the aggregate (kSSCP_ParamType_Aggregate type), then it will contain a pointer to another
26     sscp_operation_t. This allows to link additional sscp_operation_t.
27 
28     The protocol allows for remote calling by a copy of all arguments (including buffer contents),
29     that is, to remote call to a sub-system having no physical access to Host CPU memory.
30     If a sub-system has access to Host CPU memory, the SSCP transport implementation can decide to transfer
31     only the buffer descriptor (pointer and size) without physically transmitting the buffer content,
32     as the buffer content can be accessed by the sub-system when the remote function executes.
33     The same holds for the context descriptor (pointer and type id). The actual SSCP implementation
34     can transfer only pointer to a sub-system, if the sub-system has access to the memory, where the context data
35     structure is located, and if it has an application level knowledge of the context data structure
36     layout (either based on the command id or the context type id).
37 
38     Byte length (for void* and uintptr_t) and endianess is inherited from the host CPU.
39 
40     # SSCP operation descriptors
41 
42     A remote function is invoked by transmitting a command id (unique identifier to specify a remote function),
43     followed by SSCP operation descriptors ::sscp_operation_t. There is always one descriptor and optionally
44     it can link another descriptor, if the number of ::sscp_operation_t params is not sufficient
45     to described all function parameters. In the example below, the last params[n-1] on the left side is an aggregate
46     that links secondary descriptor.
47 
48     @code
49     command
50     paramTypes
51     params[0]
52     ...
53     params[n-1] ------------- paramTypes
54                               params[0]
55                               ...
56                               params[n-1]
57     @endcode
58 
59     where n = 1, 2, ..., 7.
60 
61     These operation descriptors serve as an input to ::sscp_invoke_command() function.
62     The serialization to the communication system is implementation specific.
63     For example, implementations may decide to transfer only pointers and values (without payloads),
64     because security sub-system has access to memory, so it can read and write payloads on its own during function
65     execution. Other implementations may need to serialize everything to a communication bus.
66 
67     This implementation specific data transfer is implemented by an invoke() function.
68     During implementation specific initialization of the SSCP transfer, sscp_<Implementation>_init() function,
69     a pointer to implementation specific invoke() function is stored in the sscp_<Implementation>_context_t.
70 
71     @code
72       sscp_mu_init(ctx, invoke = sscp_mu_invoke_command)
73       ...
74       ctx->invoke()
75       ...
76       ctx->invoke()
77       ...
78       sscp_deinit(ctx)
79     @endcode
80 
81     # Example for SSCP protocol implementation with ELEMU
82 
83     The ::sscp_invoke_command() implementation for the ELEMU (Sentinel), ::sscp_mu_invoke_command(),
84     builds up the serial message as follows:
85 
86       word 0 | word 1    | word 2      | word 3      | ... | word (n*2 + 1)
87       -------|-----------|-------------|-------------|-----|---------------
88       CMD    |paramTypes | params[0].a | params[0].b | ... | params[n-1].b
89 
90     where the n value is CMD specific and it is present in the CMD word.
91     Passing this message through ELEMU to the ELE sub-system is done by simply moving the 16 words into ELEMU Tx A
92     registers.
93 
94     # Example with the SSS API
95 
96     @code
97       sss_status_t sss_aead_one_go(sss_aead_t *context,
98                                    const uint8_t *srcData,
99                                    uint8_t *destData,
100                                    size_t size,
101                                    uint8_t *nonce,
102                                    size_t nonceLen,
103                                    const uint8_t *aad,
104                                    size_t aadLen,
105                                    uint8_t *tag,
106                                    size_t tagLen);
107 
108       uint32_t cmd = kSSCP_CMD_SSS_AeadOneGo(n=6);
109 
110       sscp_operation_t op = (0);
111       sscp_status_t status = kStatus_SSCP_Fail;
112       uint32_t ret = 0;
113 
114       if (context->mode == Encrypt)
115       {
116           op.paramTypes = SSCP_OP_SET_PARAM(kSSCP_ParamType_ContextReference,
117                                             kSSCP_ParamType_MemrefInput,
118                                             kSSCP_ParamType_MemrefOutput,
119                                             kSSCP_ParamType_MemrefInput,
120                                             kSSCP_ParamType_MemrefInput,
121                                             kSSCP_ParamType_MemrefOutput,
122                                             kSSCP_ParamType_None);
123       }
124       else
125       {
126           op.paramTypes = SSCP_OP_SET_PARAM(kSSCP_ParamType_ContextReference,
127                                             kSSCP_ParamType_MemrefInput,
128                                             kSSCP_ParamType_MemrefOutput,
129                                             kSSCP_ParamType_MemrefInput,
130                                             kSSCP_ParamType_MemrefInput,
131                                             kSSCP_ParamType_MemrefInput,
132                                             kSSCP_ParamType_None);
133       }
134 
135       ... context is an aggregate data type ...
136       ... implementation specific sscp_operation_t to serialize the context data ...
137       op.params[0].context.ptr = context;
138       op.params[0].context.type = kSSCP_ParamContextType_SSS_Aead;
139 
140       ... function parameters ...
141       op.params[1].memref.buffer = srcData;
142       op.params[1].memref.size = size;
143 
144       op.params[2].memref.buffer = destData;
145       op.params[2].memref.size = size;
146 
147       op.params[3].memref.buffer = nonce;
148       op.params[3].memref.size = nonceLen;
149 
150       op.params[4].memref.buffer = aad;
151       op.params[4].memref.size = aadLen;
152 
153       op.params[5].memref.buffer = tag;
154       op.params[5].memref.size = tagLen;
155 
156       ... Serialize to the link ...
157       status = context->session->sscp->invoke(context->sscpSession, cmd, &op, &ret);
158       if (status != kStatus_SSCP_Success)
159       {
160           return kStatus_SSS_Fail;
161       }
162 
163       return (sss_status_t)ret;
164 
165     @endcode
166 
167     # Example with the TEE Client API
168 
169       @code
170       TEEC_Result TEEC_InvokeCommand(TEEC_Session *sessionTEEC,
171                                      uint32_t commandID,
172                                      TEEC_Operation *operation,
173                                      uint32_t *returnOrigin);
174 
175 
176       uint32_t cmd = kSSCP_CMD_TEEC_InvokeCommand;
177 
178       sscp_operation_t op = {0};
179       sscp_status_t status = kStatus_SSCP_Fail;
180       uint32_t ret = 0;
181 
182       op.paramTypes = SSCP_OP_SET_PARAM(kSSCP_ParamType_ContextReference,
183                                         kSSCP_ParamType_ValueInput,
184                                         kSSCP_ParamType_ContextReference,
185                                         kSSCP_ParamType_MemrefOutput,
186                                         kSSCP_ParamType_None,
187                                         kSSCP_ParamType_None,
188                                         kSSCP_ParamType_None);
189 
190       op.params[0].context.ptr = sessionTEEC;
191       op.params[0].context.type = kSSCP_ParamContextType_TEEC_Session;
192 
193       op.params[1].value.a = commandID;
194       op.params[1].value.b = 0;
195 
196       op.params[2].context.ptr = operation;
197       op.params[2].context.type = kSSCP_ParamContextType_TEEC_Operation;
198 
199       op.params[3].memref.buffer = returnOrigin;
200       op.params[3].memref.size = sizeof(*returnOrigin);
201 
202       @endcode
203  */
204 
205 /*!
206  * @addtogroup sscp
207  * @{
208  */
209 
210 /*! @brief Maximum number of parameters to be supported in one sscp_operation_t */
211 #define SSCP_OPERATION_PARAM_COUNT   (7u)
212 #define SSCP_OPERATION_RESULTS_COUNT (2u)
213 
214 /*! @brief Default SSCP context is a pointer to memory. */
215 #ifndef SSCP_MAX_CONTEXT_SIZE
216 #define SSCP_MAX_CONTEXT_SIZE (sizeof(void *))
217 #endif
218 
219 /*! @brief Set parameter types for the SSCP operation. Each param type is encoded into 4-bits bit field. */
220 #define SSCP_OP_SET_PARAM(p0, p1, p2, p3, p4, p5, p6)                                                   \
221     (((uint32_t)(p0)&0xFu) << 0) | (((uint32_t)(p1)&0xFu) << 4) | (((uint32_t)(p2)&0xFu) << 8) |        \
222         (((uint32_t)(p3)&0xFu) << 12) | (((uint32_t)(p4)&0xFu) << 16) | (((uint32_t)(p5)&0xFu) << 20) | \
223         (((uint32_t)(p6)&0xFu) << 24)
224 
225 /*! @brief Set parameter types for the SSCP operation. Each param type is encoded into 4-bits bit field. */
226 #define SSCP_OP_SET_RESULT(p0) (((uint32_t)(p0)&0xFu) << 0)
227 
228 /*! @brief Decode i-th parameter as 4-bit unsigned integer. */
229 #define SSCP_OP_GET_PARAM(i, paramTypes) ((((uint32_t)(paramTypes)) >> (i)*4u) & 0xFu)
230 
231 /*! @brief Compile time sizeof() check */
232 #if 0
233 #define SSCP_BUILD_ASSURE(condition, msg) extern int(msg)[1 - 2 * (!(condition))] __attribute__((unused))
234 #else
235 #define SSCP_BUILD_ASSURE(condition, msg)
236 #endif
237 
238 /**
239  * @brief Definitions with return values from SSCP functions
240  */
241 typedef uint32_t sscp_status_t;
242 #define kStatus_SSCP_Success      ((sscp_status_t)0x10203040u)
243 #define kStatus_SSCP_Fail         ((sscp_status_t)0x40302010u)
244 #define kStatus_SSCP_ResourceBusy ((sscp_status_t)0x40302020u)
245 
246 typedef struct sscp_context sscp_context_t;
247 
248 /**
249  * @brief SSCP operation descriptor
250  *
251  */
252 typedef struct sscp_operation sscp_operation_t;
253 
254 /*! @brief Typedef for a function that sends a command and associated parameters to security sub-system
255  *
256  *  The commandID and operation content is serialized and sent over to the selected security sub-system.
257  *  This is implementation specific function.
258  *  The function can invoke both blocking and non-blocking secure functions in the selected security sub-system.
259  *
260  * @param context Initialized SSCP context
261  * @param commandID Command - an id of a remote secure function to be invoked
262  * @param op Description of function arguments as a sequence of buffers, values, context references and aggregates
263  * @param ret Return code of the remote secure function (application layer return value)
264  *
265  * @returns Status of the operation
266  * @retval kStatus_SSCP_Success A blocking command has completed or a non-blocking command has been accepted.
267  * @retval kStatus_SSCP_Fail Operation failure, for example hardware fail.
268  * @retval kStatus_SSCP_InvalidArgument One of the arguments is invalid for the function to execute.
269  */
270 typedef sscp_status_t (*fn_sscp_invoke_command_t)(sscp_context_t *context,
271                                                   sscp_command_t commandID,
272                                                   sscp_operation_t *op,
273                                                   uint32_t *ret);
274 
275 /**
276  * struct _sscp_context - SSCP context struct
277  *
278  * This data type is used to keep context of the SSCP link.
279  * It has one mandatory member - pointer to invoke() function.
280  * Otherwise it is completely implementation specific.
281  *
282  * @param invoke Pointer to implementation specific invoke() function
283  * @param context Container for the implementation specific data.
284  */
285 struct sscp_context
286 {
287     fn_sscp_invoke_command_t invoke;
288     /*sscp_status_t (*sscp_invoke_command)(sscp_context_t *context, uint32_t commandID, sscp_operation_t *op);*/
289 
290     /*! Implementation specific part */
291     struct
292     {
293         uint8_t data[SSCP_MAX_CONTEXT_SIZE];
294     } context;
295 };
296 
297 /**
298  * struct _sscp_memref - Buffer
299  *
300  * This data type is used to describe a function argument as a buffer.
301  *
302  * @param buffer Memory address
303  * @param size Length of the buffer in bytes
304  */
305 typedef struct
306 {
307     uintptr_t buffer;
308     size_t size;
309 } sscp_memref_t;
310 
311 /**
312  * struct sscp_value_t - Small raw data
313  *
314  * This data type is used to describe a function argument as a tuple of two 32-bit values.
315  *
316  * @param a First 32-bit data value.
317  * @param b Second 32-bit data value.
318  */
319 typedef struct
320 {
321     uint32_t a;
322     uint32_t b;
323 } sscp_value_t;
324 
325 /**
326  * @brief SSCP descriptor for an aggregate
327  *
328  * This data type is used to link additional SSCP operation.
329  *
330  * @param op Pointer to sscp_operation_t.
331  */
332 typedef struct
333 {
334     sscp_operation_t *op;
335 } sscp_aggregate_operation_t;
336 
337 /**
338  * @brief SSCP descriptor for a context struct
339  *
340  * This data type is used pass context struct to SSCP by reference
341  *
342  * @param ptr Pointer to a data structure
343  * @param type 32-bit identifier specifying context struct type
344  */
345 typedef struct
346 {
347     void *ptr;
348     uint32_t type;
349 } sscp_context_reference_t;
350 
351 /**
352  * @brief Data structure representing a function argument.
353  *
354  * Either the client uses a shared memory reference, or a small raw
355  * data container.
356  *
357  * @param value Small raw data container
358  * @param memref Memory reference
359  * @param aggregate Reference to another SSCP descriptor
360  * @param context Pointer to a data struct to be passed to SSCP by reference
361  */
362 typedef union
363 {
364     sscp_value_t value;
365     sscp_memref_t memref;
366     sscp_aggregate_operation_t aggregate;
367     sscp_context_reference_t context;
368 } sscp_parameter_t;
369 
370 /**
371  * @brief Data structure describing function arguments.
372  * Function argument are described as a sequence of buffers, values, context references and aggregates.
373  * It serves as an input to ::sscp_invoke_command(), an implementation specific serialization function.
374  *
375  * @param   paramTypes  Type of data passed.
376  * @param   params      Array of parameters of type sscp_parameter_t.
377  *
378  */
379 struct sscp_operation
380 {
381     uint32_t paramTypes;
382     sscp_parameter_t params[SSCP_OPERATION_PARAM_COUNT];
383     uint32_t resultTypes;
384     uint32_t resultCount;
385     sscp_parameter_t result[SSCP_OPERATION_RESULTS_COUNT];
386 };
387 
388 /**
389  * @brief Enum with SSCP operation parameters.
390  */
391 typedef uint32_t sscp_param_types_t;
392 #define kSSCP_ParamType_None      ((sscp_param_types_t)0x0u) /*! Parameter not in use */
393 #define kSSCP_ParamType_Aggregate ((sscp_param_types_t)0x1u) /*! Link to another ::sscp_operation_t */
394 #define kSSCP_ParamType_ContextReference \
395     ((sscp_param_types_t)0x2u)                               /*! Reference to a context structure - pointer and type */
396 #define kSSCP_ParamType_MemrefInputNoSize                                                                      \
397     ((sscp_param_types_t)0x3u) /*! Reference to a memory buffer - input to remote function or service, no size \
398                                   specified */
399 #define kSSCP_ParamType_MemrefOutputNoSize                                                                      \
400     ((sscp_param_types_t)0x4u) /*! Reference to a memory buffer - output by remote function or service, no size \
401                                   specified.*/
402 #define kSSCP_ParamType_MemrefInput \
403     ((sscp_param_types_t)0x5u) /*! Reference to a memory buffer - input to remote function or service */
404 #define kSSCP_ParamType_MemrefOutput                                                                           \
405     ((sscp_param_types_t)0x6u) /*! Reference to a memory buffer - output by remote function or service.        \
406                                   Implementations shall update the size member of the ::sscp_memref_t with the \
407                                   actual number of bytes written. */
408 #define kSSCP_ParamType_MemrefInOut                                                                                  \
409     ((sscp_param_types_t)0x7u) /*! Reference to a memory buffer - input to and ouput from remote function or service \
410                                 */
411 #define kSSCP_ParamType_ValueInputTuple \
412     ((sscp_param_types_t)0x8u) /*! Tuple of two 32-bit integers  - input to remote function or service */
413 #define kSSCP_ParamType_ValueOutputTuple \
414     ((sscp_param_types_t)0x9u) /*! Tuple of two 32-bit integers - output by remote function or service */
415 #define kSSCP_ParamType_ValueInputSingle \
416     ((sscp_param_types_t)0xau) /*! One 32-bit integers  - input to remote function or service */
417 #define kSSCP_ParamType_ValueOutputSingle \
418     ((sscp_param_types_t)0xbu) /*! One 32-bit integers - output by remote function or service */
419 
420 /*******************************************************************************
421  * API
422  ******************************************************************************/
423 #if defined(__cplusplus)
424 extern "C" {
425 #endif
426 
427 /*! @brief Sends a command and associated parameters to security sub-system
428  *
429  *  The commandID and operation content is serialized and sent over to the selected security sub-system.
430  *  This is implementation specific function.
431  *  The function can invoke both blocking and non-blocking secure functions in the selected security sub-system.
432  *
433  * @param context Initialized SSCP context
434  * @param commandID Command - an id of a remote secure function to be invoked
435  * @param op Description of function arguments as a sequence of buffers and values
436  * @param ret Return code of the remote secure function (application layer return value)
437  *
438  * @returns Status of the operation
439  * @retval kStatus_SSCP_Success A blocking command has completed or a non-blocking command has been accepted.
440  * @retval kStatus_SSCP_Fail Operation failure, for example hardware fail.
441  * @retval kStatus_SSCP_InvalidArgument One of the arguments is invalid for the function to execute.
442  */
443 sscp_status_t sscp_invoke_command(sscp_context_t *context, uint32_t commandID, sscp_operation_t *op, uint32_t *ret);
444 
445 #if defined(__cplusplus)
446 }
447 #endif
448 
449 /*!
450  *@}
451  */ /* end of sscp */
452 
453 #endif /* FSL_SSCP_H */
454