blob: bb4f10f61576ee15eee9421983aba3ad298b248c [file] [log] [blame]
/*
*
* Copyright 2018,2019 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _FSL_SSCP_H_
#define _FSL_SSCP_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "fsl_sscp_commands.h"
/*!
@defgroup sscp Security Subsystem Communication Protocol (SSCP)
# SSCP protocol description
SSCP is very simple remote procedure call protocol.
Function parameters are described by one or multiple SSCP operation descriptor(s).
One parameter descriptor describes up to 7 function parameters as contexts, buffers, values or aggregates.
Multiple parameter descriptors can be linked by the aggregate parameter type (kSSCP_ParamType_Aggregate).
Function arguments are described as a buffer (address and size), a value (a tuple of two words),
a context (pointer and type id) or an aggregate.
If the parameter is the aggregate (kSSCP_ParamType_Aggregate type), then it will contain a pointer to another
sscp_operation_t. This allows to link additional sscp_operation_t.
The protocol allows for remote calling by a copy of all arguments (including buffer contents),
that is, to remote call to a sub-system having no physical access to Host CPU memory.
If a sub-system has access to Host CPU memory, the SSCP transport implementation can decide to transfer
only the buffer descriptor (pointer and size) without physically transmitting the buffer content,
as the buffer content can be accessed by the sub-system when the remote function executes.
The same holds for the context descriptor (pointer and type id). The actual SSCP implementation
can transfer only pointer to a sub-system, if the sub-system has the memory, where the context data
structure is located, and if it has an application level knowledge of the context data structure
layout (either based on the command id or the context type id).
Byte length (for void* and uintptr_t) and endianess is inherited from the host CPU.
# SSCP operation descriptors
A remote function is invoked by transmitting a command id (unique identifier to specify a remote function),
followed by SSCP operation descriptors ::sscp_operation_t. There is always one descriptor and optionally
it can link another descriptor, if the number of ::sscp_operation_t params is not sufficient
to described all function parameters. In the example below, the last params[n-1] on the left side is an aggregate
that links secondary descriptor.
@code
command
paramTypes
params[0]
...
params[n-1] ------------- paramTypes
params[0]
...
params[n-1]
@endcode
where n = 1, 2, ..., 7.
These operation descriptors serve as an input to ::sscp_invoke_command() function.
The serialization to the communication system is implementation specific.
For example, implementations may decide to transfer only pointers and values (without payloads),
because security sub-system has access to memory, so it can read and write payloads on its own during function
execution. Other implementations may need to serialize everything to a communication bus.
This implementation specific data transfer is implemented by an invoke() function.
During implementation specific initialization of the SSCP transfer, sscp_<Implementation>_init() function,
a pointer to implementation specific invoke() function is stored in the sscp_<Implementation>_context_t.
@code
sscp_mu_init(ctx, invoke = sscp_mu_invoke_command)
...
ctx->invoke()
...
ctx->invoke()
...
sscp_deinit(ctx)
@endcode
# Example for SSCP protocol implementation with S3MU
The ::sscp_invoke_command() implementation for the S3MU (Sentinel), ::sscp_mu_invoke_command(),
builds up the serial message as follows:
word 0 | word 1 | word 2 | word 3 | ... | word (n*2 + 1)
-------|-----------|-------------|-------------|-----|---------------
CMD |paramTypes | params[0].a | params[0].b | ... | params[n-1].b
where the n value is CMD specific and it is present in the CMD word.
Passing this message through S3MU to the Sentinel sub-system is done by simply moving the 16 words into S3MU Tx A
registers.
# Example with the SSS API
@code
sss_status_t sss_aead_one_go(sss_aead_t *context,
const uint8_t *srcData,
uint8_t *destData,
size_t size,
uint8_t *nonce,
size_t nonceLen,
const uint8_t *aad,
size_t aadLen,
uint8_t *tag,
size_t tagLen);
uint32_t cmd = kSSCP_CMD_SSS_AeadOneGo(n=6);
sscp_operation_t op = (0);
sscp_status_t status = kStatus_SSCP_Fail;
uint32_t ret = 0;
if (context->mode == Encrypt)
{
op.paramTypes = SSCP_OP_SET_PARAM(kSSCP_ParamType_ContextReference,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_MemrefOutput,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_MemrefOutput,
kSSCP_ParamType_None);
}
else
{
op.paramTypes = SSCP_OP_SET_PARAM(kSSCP_ParamType_ContextReference,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_MemrefOutput,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_MemrefInput,
kSSCP_ParamType_None);
}
... context is an aggregate data type ...
... implementation specific sscp_operation_t to serialize the context data ...
op.params[0].context.ptr = context;
op.params[0].context.type = kSSCP_ParamContextType_SSS_Aead;
... function parameters ...
op.params[1].memref.buffer = srcData;
op.params[1].memref.size = size;
op.params[2].memref.buffer = destData;
op.params[2].memref.size = size;
op.params[3].memref.buffer = nonce;
op.params[3].memref.size = nonceLen;
op.params[4].memref.buffer = aad;
op.params[4].memref.size = aadLen;
op.params[5].memref.buffer = tag;
op.params[5].memref.size = tagLen;
... Serialize to the link ...
status = context->session->sscp->invoke(context->sscpSession, cmd, &op, &ret);
if (status != kStatus_SSCP_Success)
{
return kStatus_SSS_Fail;
}
return (sss_status_t)ret;
@endcode
# Example with the SSCP Client API
@code
SSCP_Result SSCP_InvokeCommand(SSCP_Session *sessionSSCP,
uint32_t commandID,
SSCP_Operation *operation,
uint32_t *returnOrigin);
uint32_t cmd = kSSCP_CMD_SSCP_InvokeCommand;
sscp_operation_t op = {0};
sscp_status_t status = kStatus_SSCP_Fail;
uint32_t ret = 0;
op.paramTypes = SSCP_OP_SET_PARAM(kSSCP_ParamType_ContextReference,
kSSCP_ParamType_ValueInput,
kSSCP_ParamType_ContextReference,
kSSCP_ParamType_MemrefOutput,
kSSCP_ParamType_None,
kSSCP_ParamType_None,
kSSCP_ParamType_None);
op.params[0].context.ptr = sessionSSCP;
op.params[0].context.type = kSSCP_ParamContextType_SSCP_Session;
op.params[1].value.a = commandID;
op.params[1].value.b = 0;
op.params[2].context.ptr = operation;
op.params[2].context.type = kSSCP_ParamContextType_SSCP_Operation;
op.params[3].memref.buffer = returnOrigin;
op.params[3].memref.size = sizeof(*returnOrigin);
@endcode
*/
/*!
* @addtogroup sscp
* @{
*/
/*! @brief Maximum number of parameters to be supported in one sscp_operation_t */
#define SSCP_OPERATION_PARAM_COUNT (7)
/*! @brief Default SSCP context is a pointer to memory. */
#ifndef SSCP_MAX_CONTEXT_SIZE
#define SSCP_MAX_CONTEXT_SIZE (sizeof(void *))
#endif
/*! @brief Set parameter types for the SSCP operation. Each param type is encoded into 4-bits bit field. */
#define SSCP_OP_SET_PARAM(p0, p1, p2, p3, p4, p5, p6) \
(((uint32_t)p0 & 0xFu)) | (((uint32_t)p1 & 0xFu) << 4u) | (((uint32_t)p2 & 0xFu) << 8u) | \
(((uint32_t)p3 & 0xFu) << 12u) | (((uint32_t)p4 & 0xFu) << 16u) | (((uint32_t)p5 & 0xFu) << 20u) | \
(((uint32_t)p6 & 0xFu) << 24u);
/*! @brief Decode i-th parameter as 4-bit unsigned integer. */
#define SSCP_OP_GET_PARAM(i, paramTypes) ((uint32_t)((((uint32_t)paramTypes) >> i * 4) & 0xFu))
/*! @brief Data type for SSCP function return values */
typedef uint32_t sscp_status_t;
typedef struct _sscp_context sscp_context_t;
/**
* @brief SSCP operation descriptor
*
*/
typedef struct _sscp_operation sscp_operation_t;
/*! @brief Typedef for a function that sends a command and associated parameters to security sub-system
*
* The commandID and operation content is serialized and sent over to the selected security sub-system.
* This is implementation specific function.
* The function can invoke both blocking and non-blocking secure functions in the selected security sub-system.
*
* @param context Initialized SSCP context
* @param commandID Command - an id of a remote secure function to be invoked
* @param op Description of function arguments as a sequence of buffers, values, context references and aggregates
* @param ret Return code of the remote secure function (application layer return value)
*
* @returns Status of the operation
* @retval kStatus_SSCP_Success A blocking command has completed or a non-blocking command has been accepted.
* @retval kStatus_SSCP_Fail Operation failure, for example hardware fail.
* @retval kStatus_SSCP_InvalidArgument One of the arguments is invalid for the function to execute.
*/
typedef sscp_status_t (*fn_sscp_invoke_command_t)(
sscp_context_t *context, uint32_t commandID, sscp_operation_t *op, uint32_t *ret);
/**
* struct _sscp_context - SSCP context struct
*
* This data type is used to keep context of the SSCP link.
* It has one mandatory member - pointer to invoke() function.
* Otherwise it is completely implementation specific.
*
* @param invoke Pointer to implementation specific invoke() function
* @param context Container for the implementation specific data.
*/
struct _sscp_context
{
fn_sscp_invoke_command_t invoke;
// sscp_status_t (*sscp_invoke_command)(sscp_context_t *context, uint32_t commandID, sscp_operation_t *op);
/*! Implementation specific part */
struct
{
uint8_t data[SSCP_MAX_CONTEXT_SIZE];
} context;
};
/**
* struct _sscp_memref - Buffer
*
* This data type is used to describe a function argument as a buffer.
*
* @param buffer Memory address
* @param size Length of the buffer in bytes
*/
typedef struct _sscp_memref
{
void *buffer;
size_t size;
} sscp_memref_t;
/**
* struct _sscp_value - Small raw data
*
* This data type is used to describe a function argument as a tuple of two 32-bit values.
*
* @param a First 32-bit data value.
* @param b Second 32-bit data value.
*/
typedef struct _sscp_value
{
uint32_t a;
uint32_t b;
} sscp_value_t;
/**
* @brief SSCP descriptor for an aggregate
*
* This data type is used to link additional SSCP operation.
*
* @param op Pointer to sscp_operation_t.
*/
typedef struct _sscp_aggregate_operation
{
sscp_operation_t *op;
} sscp_aggregate_operation_t;
/**
* @brief SSCP descriptor for a context struct
*
* This data type is used pass context struct to SSCP by reference
*
* @param ptr Pointer to a data structure
* @param type 32-bit identifier specifying context struct type
*/
typedef struct _sscp_context_operation
{
void *ptr;
uint32_t type;
} sscp_context_reference_t;
/**
* @brief Data structure representing a function argument.
*
* Either the client uses a shared memory reference, or a small raw
* data container.
*
* @param value Small raw data container
* @param memref Memory reference
* @param aggregate Reference to another SSCP descriptor
* @param context Pointer to a data struct to be passed to SSCP by reference
*/
typedef union _sscp_parameter {
sscp_value_t value;
sscp_memref_t memref;
sscp_aggregate_operation_t aggregate;
sscp_context_reference_t context;
} sscp_parameter_t;
/**
* @brief Data structure describing function arguments.
* Function argument are described as a sequence of buffers, values, context references and aggregates.
* It serves as an input to ::sscp_invoke_command(), an implementation specific serialization function.
*
* @param paramTypes Type of data passed.
* @param params Array of parameters of type sscp_parameter_t.
*
*/
struct _sscp_operation
{
uint32_t paramTypes;
sscp_parameter_t params[SSCP_OPERATION_PARAM_COUNT];
};
/**
* @brief Enum with SSCP operation parameters.
*/
typedef enum _sscp_param_types
{
kSSCP_ParamType_None = 0, /*! Parameter not in use */
kSSCP_ParamType_Aggregate = 0x1u, /*! Link to another ::sscp_operation_t */
kSSCP_ParamType_ContextReference, /*! Reference to a context structure - pointer and type */
kSSCP_ParamType_MemrefInput, /*! Reference to a memory buffer - input to remote function or service */
kSSCP_ParamType_MemrefOutput, /*! Reference to a memory buffer - output by remote function or service.
Implementations shall update the size member of the ::sscp_memref_t
with the actual number of bytes written. */
kSSCP_ParamType_MemrefInOut, /*! Reference to a memory buffer - input to and ouput from remote function or service
*/
kSSCP_ParamType_ValueInput, /*! Tuple of two 32-bit integers - input to remote function or service */
kSSCP_ParamType_ValueOutput, /*! Tuple of two 32-bit integers - output by remote function or service */
} sscp_param_types_t;
/**
* @brief Enum with return values from SSCP functions
*/
enum _sscp_return_values
{
kStatus_SSCP_Success = 0x10203040u,
kStatus_SSCP_Fail = 0x40302010u,
};
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif
/*! @brief Sends a command and associated parameters to security sub-system
*
* The commandID and operation content is serialized and sent over to the selected security sub-system.
* This is implementation specific function.
* The function can invoke both blocking and non-blocking secure functions in the selected security sub-system.
*
* @param context Initialized SSCP context
* @param commandID Command - an id of a remote secure function to be invoked
* @param op Description of function arguments as a sequence of buffers and values
* @param ret Return code of the remote secure function (application layer return value)
*
* @returns Status of the operation
* @retval kStatus_SSCP_Success A blocking command has completed or a non-blocking command has been accepted.
* @retval kStatus_SSCP_Fail Operation failure, for example hardware fail.
* @retval kStatus_SSCP_InvalidArgument One of the arguments is invalid for the function to execute.
*/
sscp_status_t sscp_invoke_command(sscp_context_t *context, uint32_t commandID, sscp_operation_t *op, uint32_t *ret);
#if defined(__cplusplus)
}
#endif
/*!
*@}
*/ /* end of sscp */
#endif /* _FSL_SSCP_H_ */