| /***************************************************************************//** |
| * @file em_se.h |
| * @brief Secure Element API |
| * @version 5.6.0 |
| ******************************************************************************* |
| * # License |
| * <b>Copyright 2017 Silicon Laboratories, Inc. http://www.silabs.com</b> |
| ******************************************************************************* |
| * |
| * Permission is granted to anyone to use this software for any purpose, |
| * including commercial applications, and to alter it and redistribute it |
| * freely, subject to the following restrictions: |
| * |
| * 1. The origin of this software must not be misrepresented; you must not |
| * claim that you wrote the original software. |
| * 2. Altered source versions must be plainly marked as such, and must not be |
| * misrepresented as being the original software. |
| * 3. This notice may not be removed or altered from any source distribution. |
| * |
| * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no |
| * obligation to support this Software. Silicon Labs is providing the |
| * Software "AS IS", with no express or implied warranties of any kind, |
| * including, but not limited to, any implied warranties of merchantability |
| * or fitness for any particular purpose or warranties against infringement |
| * of any proprietary rights of a third party. |
| * |
| * Silicon Labs will not be liable for any consequential, incidental, or |
| * special damages, or any other relief, or for any claim by any third party, |
| * arising from your use of this Software. |
| * |
| ******************************************************************************/ |
| #ifndef EM_SE_H |
| #define EM_SE_H |
| |
| #include "em_device.h" |
| |
| #if defined(SEMAILBOX_PRESENT) |
| |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /***************************************************************************//** |
| * @addtogroup emlib |
| * @{ |
| ******************************************************************************/ |
| |
| /***************************************************************************//** |
| * @addtogroup SE |
| * |
| * @brief Secure Element peripheral API |
| * |
| * @details |
| * Abstraction of the Secure Element's mailbox interface. |
| * |
| * @{ |
| ******************************************************************************/ |
| |
| /******************************************************************************* |
| ****************************** DEFINES *********************************** |
| ******************************************************************************/ |
| |
| /* Command words for the Secure Element. */ |
| #define SE_COMMAND_CREATE_KEY 0x02000000UL |
| |
| #define SE_COMMAND_HASH 0x03000000UL |
| #define SE_COMMAND_HASHUPDATE 0x03010000UL |
| #define SE_COMMAND_HMAC 0x03020000UL |
| |
| #define SE_COMMAND_AES_ENCRYPT 0x04000000UL |
| #define SE_COMMAND_AES_DECRYPT 0x04010000UL |
| #define SE_COMMAND_AES_CMAC 0x04040000UL |
| #define SE_COMMAND_AES_CCM_ENCRYPT 0x04050000UL |
| #define SE_COMMAND_AES_CCM_DECRYPT 0x04060000UL |
| |
| #define SE_COMMAND_SIGNATURE_SIGN 0x06000000UL |
| #define SE_COMMAND_SIGNATURE_VERIFY 0x06010000UL |
| |
| #define SE_COMMAND_TRNG_GET_RANDOM 0x07000000UL |
| |
| #define SE_COMMAND_DH 0x0E000000UL |
| |
| #define SE_COMMAND_WRITE_USER_DATA 0x43090000UL |
| #define SE_COMMAND_ERASE_USER_DATA 0x430A0000UL |
| |
| /* Command options for the Secure Element commands. */ |
| /** Use SHA1 as hash algorithm */ |
| #define SE_COMMAND_OPTION_HASH_SHA1 0x00000200UL |
| /** Use SHA224 as hash algorithm */ |
| #define SE_COMMAND_OPTION_HASH_SHA224 0x00000300UL |
| /** Use SHA256 as hash algorithm */ |
| #define SE_COMMAND_OPTION_HASH_SHA256 0x00000400UL |
| /** Use SHA384 as hash algorithm */ |
| #define SE_COMMAND_OPTION_HASH_SHA384 0x00000500UL |
| /** Use SHA512 as hash algorithm */ |
| #define SE_COMMAND_OPTION_HASH_SHA512 0x00000600UL |
| |
| /** Execute algorithm in ECB mode */ |
| #define SE_COMMAND_OPTION_MODE_ECB 0x00000100UL |
| /** Execute algorithm in CBC mode */ |
| #define SE_COMMAND_OPTION_MODE_CBC 0x00000200UL |
| /** Execute algorithm in CTR mode */ |
| #define SE_COMMAND_OPTION_MODE_CTR 0x00000300UL |
| /** Execute algorithm in CFB mode */ |
| #define SE_COMMAND_OPTION_MODE_CFB 0x00000400UL |
| |
| /** Run the whole algorithm, all data present */ |
| #define SE_COMMAND_OPTION_CONTEXT_WHOLE 0x00000000UL |
| /** Start the algorithm, but get a context to later add more data */ |
| #define SE_COMMAND_OPTION_CONTEXT_START 0x00000001UL |
| /** End the algorithm, get the result */ |
| #define SE_COMMAND_OPTION_CONTEXT_END 0x00000002UL |
| /** Add more data input to the algorithm. Need to supply previous context, |
| * and get a context back */ |
| #define SE_COMMAND_OPTION_CONTEXT_ADD 0x00000003UL |
| |
| /** Magic paramater for deleting user data */ |
| #define SE_COMMAND_OPTION_ERASE_UD 0xDE1E7EADUL |
| |
| /* Response status codes for the Secure Element */ |
| #define SE_RESPONSE_MASK 0x000F0000UL |
| /** Command executed successfully or signature was successfully validated. */ |
| #define SE_RESPONSE_OK 0x00000000UL |
| /** |
| * Command was not recognized as a valid command, or is not allowed in the |
| * current context. |
| */ |
| #define SE_RESPONSE_INVALID_COMMAND 0x00010000UL |
| /** |
| * User did not provide the required credentials to be allowed to execute the |
| * command. |
| */ |
| #define SE_RESPONSE_AUTHORIZATION_ERROR 0x00020000UL |
| /** |
| * Signature validation command (e.g. SE_COMMAND_SIGNATURE_VERIFY) failed to |
| * verify the given signature as being correct. |
| */ |
| #define SE_RESPONSE_INVALID_SIGNATURE 0x00030000UL |
| /** A command started in non-secure mode is trying to access secure memory. */ |
| #define SE_RESPONSE_BUS_ERROR 0x00040000UL |
| /** Internal test failed */ |
| #define SE_RESPONSE_TEST_FAILED 0x00050000UL |
| /** An internal error was raised and the command did not execute. */ |
| #define SE_RESPONSE_CRYPTO_ERROR 0x00060000UL |
| /** One of the passed parameters is deemed invalid (e.g. out of bounds). */ |
| #define SE_RESPONSE_INVALID_PARAMETER 0x00070000UL |
| |
| #define SE_DATATRANSFER_STOP 0x00000001UL |
| #define SE_DATATRANSFER_DISCARD 0x40000000UL |
| #define SE_DATATRANSFER_REALIGN 0x20000000UL |
| #define SE_DATATRANSFER_CONSTADDRESS 0x10000000UL |
| #define SE_DATATRANSFER_LENGTH_MASK 0x0FFFFFFFUL |
| |
| /** Maximum amount of parameters for largest command in defined command set */ |
| #ifndef SE_MAX_PARAMETERS |
| #define SE_MAX_PARAMETERS 4U |
| #endif |
| |
| /** Maximum amount of parameters supported by the hardware FIFO */ |
| #define SE_FIFO_MAX_PARAMETERS 13U |
| |
| /* Sanity-check defines */ |
| #if SE_MAX_PARAMETERS > SE_FIFO_MAX_PARAMETERS |
| #error "Trying to configure more parameters than supported by the hardware" |
| #endif |
| |
| /******************************************************************************* |
| ****************************** TYPEDEFS *********************************** |
| ******************************************************************************/ |
| |
| /** |
| * SE DMA transfer descriptor. Can be linked to each other to provide |
| * scatter-gather behavior. |
| */ |
| typedef struct { |
| void* volatile data; |
| void* volatile next; |
| volatile uint32_t length; |
| } SE_DataTransfer_t; |
| |
| /** Default initialization of data transfer struct */ |
| #define SE_DATATRANSFER_DEFAULT(address, length) \ |
| { \ |
| (address), /* Pointer to data block */ \ |
| (void*)SE_DATATRANSFER_STOP, /* This is the last block by default */ \ |
| (length) | SE_DATATRANSFER_REALIGN /* Add size, use realign by default */ \ |
| } |
| |
| /** |
| * SE Command structure to which all commands to the SE must adhere. |
| */ |
| typedef struct { |
| uint32_t command; |
| SE_DataTransfer_t* data_in; |
| SE_DataTransfer_t* data_out; |
| uint32_t parameters[SE_MAX_PARAMETERS]; |
| size_t num_parameters; |
| } SE_Command_t; |
| |
| /** Default initialization of command struct */ |
| #define SE_COMMAND_DEFAULT(command) \ |
| { \ |
| (command), /* Given command */ \ |
| NULL, /* No data in */ \ |
| NULL, /* No data out */ \ |
| { 0, 0, 0, 0 }, /* No parameters */ \ |
| 0 /* No parameters */ \ |
| } |
| |
| /** Possible responses to a command */ |
| typedef uint32_t SE_Response_t; |
| |
| /******************************************************************************* |
| ***************************** PROTOTYPES ********************************** |
| ******************************************************************************/ |
| |
| void SE_addDataInput(SE_Command_t *command, |
| SE_DataTransfer_t *data); |
| |
| void SE_addDataOutput(SE_Command_t *command, |
| SE_DataTransfer_t *data); |
| |
| void SE_addParameter(SE_Command_t *command, uint32_t parameter); |
| |
| void SE_executeCommand(SE_Command_t *command); |
| |
| SE_Response_t SE_writeUserData(uint32_t offset, |
| void *data, |
| uint32_t numBytes); |
| |
| SE_Response_t SE_eraseUserData(void); |
| |
| __STATIC_INLINE bool SE_isCommandCompleted(void); |
| |
| __STATIC_INLINE void SE_waitCommandCompletion(void); |
| |
| __STATIC_INLINE SE_Response_t SE_readCommandResponse(void); |
| |
| __STATIC_INLINE void SE_disableInterrupt(uint32_t flags); |
| |
| __STATIC_INLINE void SE_enableInterrupt(uint32_t flags); |
| |
| /***************************************************************************//** |
| * @brief |
| * Check whether the running command has completed. |
| * |
| * @details |
| * This function polls the SE-to-host mailbox interrupt flag. |
| * |
| * @return True if a command has completed and the result is available |
| ******************************************************************************/ |
| __STATIC_INLINE bool SE_isCommandCompleted(void) |
| { |
| return (bool)(SEMAILBOX_HOST->RX_STATUS & SEMAILBOX_RX_STATUS_RXINT); |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Wait for completion of the current command. |
| * |
| * @details |
| * This function "busy"-waits until the execution of the ongoing instruction |
| * has completed. |
| ******************************************************************************/ |
| __STATIC_INLINE void SE_waitCommandCompletion(void) |
| { |
| /* Wait for completion */ |
| while (!SE_isCommandCompleted()) { |
| } |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Read the status of the previously executed command. |
| * |
| * @details |
| * This function reads the status of the previously executed command. |
| * |
| * @note |
| * The command response needs to be read for every executed command, and can |
| * only be read once per executed command (FIFO behavior). |
| * |
| * @return |
| * One of the SE_RESPONSE return codes: |
| * SE_RESPONSE_OK when the command was executed successfully or a signature |
| * was successfully verified, |
| * SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized, |
| * SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized, |
| * SE_RESPONSE_INVALID_SIGNATURE when signature verification failed, |
| * SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command, e.g. |
| * because of conflicting Secure/Non-Secure memory accesses, |
| * SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or |
| * SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed |
| ******************************************************************************/ |
| __STATIC_INLINE SE_Response_t SE_readCommandResponse(void) |
| { |
| SE_waitCommandCompletion(); |
| return (SE_Response_t)(SEMAILBOX_HOST->RX_HEADER & SE_RESPONSE_MASK); |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Disable one or more SE interrupts. |
| * |
| * @param[in] flags |
| * SE interrupt sources to disable. Use a bitwise logic OR combination of |
| * valid interrupt flags for the Secure Element module |
| * (SE_CONFIGURATION_(TX/RX)INTEN). |
| ******************************************************************************/ |
| __STATIC_INLINE void SE_disableInterrupt(uint32_t flags) |
| { |
| SEMAILBOX_HOST->CONFIGURATION &= ~flags; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Enable one or more SE interrupts. |
| * |
| * @param[in] flags |
| * SE interrupt sources to enable. Use a bitwise logic OR combination of |
| * valid interrupt flags for the Secure Element module |
| * (SEMAILBOX_CONFIGURATION_TXINTEN or SEMAILBOX_CONFIGURATION_RXINTEN). |
| ******************************************************************************/ |
| __STATIC_INLINE void SE_enableInterrupt(uint32_t flags) |
| { |
| SEMAILBOX_HOST->CONFIGURATION |= flags; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /** @} (end addtogroup SE) */ |
| /** @} (end addtogroup emlib) */ |
| |
| #endif /* defined(SEMAILBOX_PRESENT) */ |
| |
| #endif /* EM_SE_H */ |