STM32CubeWL/Middlewares/Third_Party/LoRaWAN/Crypto/soft-se.c

1278 lines
39 KiB
C

/*!
* \file soft-se.c
*
* \brief Secure Element software implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
/**
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file soft-se.c
* @author MCD Application Team
* @brief Secure Element software implementation
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdint.h>
#include "lorawan_conf.h" /* LORAWAN_KMS */
#include "radio.h" /* needed for Random */
#include "utilities.h"
#include "mw_log_conf.h" /* needed for MW_LOG */
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
#include "lorawan_aes.h"
#include "cmac.h"
#else /* LORAWAN_KMS == 1 */
#include "kms_if.h"
#endif /* LORAWAN_KMS */
#include "LoRaMacHeaderTypes.h"
#include "secure-element.h"
#include "secure-element-nvm.h"
#include "se-identity.h"
/* Private constants ---------------------------------------------------------*/
/*!
* MIC computation offset
* \remark required for 1.1.x support
*/
#define CRYPTO_MIC_COMPUTATION_OFFSET ( JOIN_REQ_TYPE_SIZE\
+ LORAMAC_JOIN_EUI_FIELD_SIZE + DEV_NONCE_SIZE + LORAMAC_MHDR_FIELD_SIZE )
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
#else /* LORAWAN_KMS == 1 */
#define DERIVED_OBJECT_HANDLE_RESET_VAL 0x0UL
#define PAYLOAD_MAX_SIZE 270UL /* 270 PHYPayload: 1+(22+1+242)+4 */
#endif /* LORAWAN_KMS */
/* Private macro -------------------------------------------------------------*/
/*!
* Hex 8 split buffer
*/
#define HEX8(X) X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7]
/*!
* Hex 16 split buffer
*/
#define HEX16(X) HEX8(X), X[8], X[9], X[10], X[11], X[12], X[13], X[14], X[15]
/* Private Types ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/*!
* Secure element context
*/
static SecureElementNvmData_t* SeNvm;
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
#else /* LORAWAN_KMS == 1 */
/* WARNING: Should be modified at the end of product development */
static const CK_ULONG GlobalTemplateLabel = 0x444E524CU;
/*
* Intermediate buffer used for two reasons:
* - align to 32 bits and
* - for Cmac combine InitVector + input buff
*/
static uint8_t input_align_combined_buf[PAYLOAD_MAX_SIZE + SE_KEY_SIZE] ALIGN(4);
static uint8_t output_align[PAYLOAD_MAX_SIZE] ALIGN(4);
static uint8_t tag[SE_KEY_SIZE] ALIGN(4) = {0};
#endif /* LORAWAN_KMS */
/* Private functions prototypes ---------------------------------------------------*/
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
static SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t **keyItem );
#else /* LORAWAN_KMS == 1 */
static SecureElementStatus_t GetKeyIndexByID( KeyIdentifier_t keyID, CK_OBJECT_HANDLE *keyIndex );
static SecureElementStatus_t GetSpecificLabelByID( KeyIdentifier_t keyID, uint32_t *specificLabel );
static SecureElementStatus_t DeleteAllDynamicKeys( void );
#endif /* LORAWAN_KMS */
#if (defined (KEY_EXTRACTABLE) && (KEY_EXTRACTABLE == 1))
static void PrintKey( KeyIdentifier_t key );
#endif /* KEY_EXTRACTABLE */
static SecureElementStatus_t ComputeCmac(uint8_t *micBxBuffer, uint8_t *buffer, uint16_t size, KeyIdentifier_t keyID,
uint32_t *cmac);
/* Private functions ---------------------------------------------------------*/
#if (defined (KEY_EXTRACTABLE) && (KEY_EXTRACTABLE == 1))
static void PrintKey( KeyIdentifier_t key )
{
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
Key_t *keyItem;
retval = SecureElementGetKeyByID(key, &keyItem);
if (retval == SECURE_ELEMENT_SUCCESS)
{
if (key == APP_KEY)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### AppKey: ");
}
else if (key == NWK_KEY)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### NwkKey: ");
}
else if (key == APP_S_KEY)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### AppSKey: ");
}
else if (key == NWK_S_KEY)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### NwkSKey: ");
}
else if (key == MC_ROOT_KEY)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### MCRootKey: ");
}
else if (key == MC_KE_KEY)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### MCKEKey: ");
}
else if (key == MC_KEY_0)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### MCKey_0: ");
}
else if (key == MC_APP_S_KEY_0)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### MCAppSKey_0: ");
}
else if (key == MC_NWK_S_KEY_0)
{
MW_LOG(TS_OFF, VLEVEL_M, "###### MCNwkSKey_0: ");
}
MW_LOG(TS_OFF, VLEVEL_M, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n",
HEX16(keyItem->KeyValue));
}
}
#endif /* KEY_EXTRACTABLE */
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
/*
* Gets key item from key list.
*
* \param[IN] keyID - Key identifier
* \param[OUT] keyItem - Key item reference
* \retval - Status of the operation
*/
static SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
{
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
if( SeNvm->KeyList[i].KeyID == keyID )
{
*keyItem = &( SeNvm->KeyList[i] );
return SECURE_ELEMENT_SUCCESS;
}
}
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
#else /* LORAWAN_KMS == 1 */
/*
* Gets key Index from key list in KMS table
*
* \param[IN] keyID - Key identifier
* \param[OUT] keyIndex - Key item reference
* \retval - Status of the operation
*/
static SecureElementStatus_t GetKeyIndexByID( KeyIdentifier_t keyID, CK_OBJECT_HANDLE *keyIndex )
{
for (uint8_t i = 0; i < NUM_OF_KEYS; i++)
{
if (SeNvm->KeyList[i].KeyID == keyID)
{
*keyIndex = SeNvm->KeyList[i].Object_Index;
return SECURE_ELEMENT_SUCCESS;
}
}
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
static SecureElementStatus_t GetSpecificLabelByID( KeyIdentifier_t keyID, uint32_t *specificLabel )
{
SecureElementStatus_t retval = SECURE_ELEMENT_SUCCESS;
switch (keyID)
{
case APP_KEY:
*specificLabel = 0x5F505041U;
break;
case NWK_KEY:
*specificLabel = 0x5F4B574EU;
break;
#if ( USE_LRWAN_1_1_X_CRYPTO == 1 )
case J_S_INT_KEY:
*specificLabel = 0x314B574EU;
break;
case J_S_ENC_KEY:
*specificLabel = 0x324B574EU;
break;
case F_NWK_S_INT_KEY:
*specificLabel = 0x334B574EU;
break;
case S_NWK_S_INT_KEY:
*specificLabel = 0x344B574EU;
break;
case NWK_S_ENC_KEY:
*specificLabel = 0x354B574EU;
break;
#else /* USE_LRWAN_1_1_X_CRYPTO == 0 */
case NWK_S_KEY:
*specificLabel = 0x534B574EU;
break;
#endif /* USE_LRWAN_1_1_X_CRYPTO */
case APP_S_KEY:
*specificLabel = 0x53505041U;
break;
case MC_ROOT_KEY:
*specificLabel = 0x5452434DU;
break;
case MC_KE_KEY:
*specificLabel = 0x454B434DU;
break;
case MC_KEY_0:
*specificLabel = 0x304B434DU;
break;
case MC_APP_S_KEY_0:
*specificLabel = 0x3053414DU;
break;
case MC_NWK_S_KEY_0:
*specificLabel = 0x30534E4DU;
break;
#if ( LORAMAC_MAX_MC_CTX > 1 )
case MC_KEY_1:
*specificLabel = 0x314B434DU;
break;
case MC_APP_S_KEY_1:
*specificLabel = 0x3153414DU;
break;
case MC_NWK_S_KEY_1:
*specificLabel = 0x31534E4DU;
break;
case MC_KEY_2:
*specificLabel = 0x324B434DU;
break;
case MC_APP_S_KEY_2:
*specificLabel = 0x3253414DU;
break;
case MC_NWK_S_KEY_2:
*specificLabel = 0x32534E4DU;
break;
case MC_KEY_3:
*specificLabel = 0x334B434DU;
break;
case MC_APP_S_KEY_3:
*specificLabel = 0x3353414DU;
break;
case MC_NWK_S_KEY_3:
*specificLabel = 0x33534E4DU;
break;
#endif /* LORAMAC_MAX_MC_CTX > 1 */
default:
retval = SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
break;
}
return retval;
}
static SecureElementStatus_t DeleteAllDynamicKeys( void )
{
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
CK_OBJECT_HANDLE hObject[NUM_OF_KEYS];
uint32_t ulCount = 0;
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Get all keys handle */
if (rv == CKR_OK)
{
rv = C_FindObjectsInit(session, NULL, 0);
}
/* Find all existing keys handle */
if (rv == CKR_OK)
{
rv = C_FindObjects(session, hObject, NUM_OF_KEYS, (CK_ULONG *) &ulCount);
}
if (rv == CKR_OK)
{
rv = C_FindObjectsFinal(session);
}
if (ulCount <= NUM_OF_KEYS)
{
for (uint8_t i = 0; i < ulCount; i++)
{
/* Exclude all Embedded keys */
if (hObject[i] > LAST_KMS_KEY_OBJECT_HANDLE)
{
if (rv == CKR_OK)
{
rv = C_DestroyObject(session, hObject[i]);
}
}
}
}
/* Close sessions */
if (session > 0)
{
(void)C_CloseSession(session);
}
if (rv != CKR_OK)
{
return SECURE_ELEMENT_ERROR;
}
return SECURE_ELEMENT_SUCCESS;
}
#endif /* LORAWAN_KMS */
/*
* Computes a CMAC of a message using provided initial Bx block
*
* cmac = aes128_cmac(keyID, blocks[i].Buffer)
*
* \param[IN] micBxBuffer - Buffer containing the initial Bx block
* \param[IN] buffer - Data buffer
* \param[IN] size - Data buffer size
* \param[IN] keyID - Key identifier to determine the AES key to be used
* \param[OUT] cmac - Computed cmac
* \retval - Status of the operation
*/
static SecureElementStatus_t ComputeCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
uint32_t* cmac )
{
if( ( buffer == NULL ) || ( cmac == NULL ) )
{
return SECURE_ELEMENT_ERROR_NPE;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
uint8_t Cmac[16];
AES_CMAC_CTX aesCmacCtx[1];
AES_CMAC_Init( aesCmacCtx );
Key_t* keyItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
if( retval == SECURE_ELEMENT_SUCCESS )
{
AES_CMAC_SetKey( aesCmacCtx, keyItem->KeyValue );
if( micBxBuffer != NULL )
{
AES_CMAC_Update( aesCmacCtx, micBxBuffer, 16 );
}
AES_CMAC_Update( aesCmacCtx, buffer, size );
AES_CMAC_Final( Cmac, aesCmacCtx );
// Bring into the required format
*cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 |
( uint32_t ) Cmac[0] );
}
#else /* LORAWAN_KMS == 1 */
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
uint32_t tag_lenth = 0;
CK_OBJECT_HANDLE key_handle ;
/* AES CMAC Authentication variables */
CK_MECHANISM aes_cmac_mechanism = { CKM_AES_CMAC, (CK_VOID_PTR)NULL, 0 };
SecureElementStatus_t retval = GetKeyIndexByID(keyID, &key_handle);
if (retval != SECURE_ELEMENT_SUCCESS)
{
return retval;
}
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Configure session to Authentication message in AES CMAC with settings included into the mechanism */
if (rv == CKR_OK)
{
rv = C_SignInit(session, &aes_cmac_mechanism, key_handle);
}
/* Encrypt clear message */
if (rv == CKR_OK)
{
/* work around : need to double-check if possible to use micBxBuffer as IV for Sign */
if (micBxBuffer != NULL)
{
memcpy1((uint8_t *) &input_align_combined_buf[0], (uint8_t *) micBxBuffer, SE_KEY_SIZE);
memcpy1((uint8_t *) &input_align_combined_buf[SE_KEY_SIZE], (uint8_t *) buffer, size);
}
else
{
memcpy1((uint8_t *) &input_align_combined_buf[0], (uint8_t *) buffer, size);
}
}
if (rv == CKR_OK)
{
if (micBxBuffer != NULL)
{
rv = C_Sign(session, (CK_BYTE_PTR)&input_align_combined_buf[0], size + SE_KEY_SIZE, &tag[0],
(CK_ULONG_PTR)&tag_lenth);
}
else
{
rv = C_Sign(session, (CK_BYTE_PTR)&input_align_combined_buf[0], size, &tag[0],
(CK_ULONG_PTR)&tag_lenth);
}
}
/* Close session with KMS */
(void)C_CloseSession(session);
/* combine to a 32bit authentication word (MIC) */
*cmac = (uint32_t)((uint32_t) tag[3] << 24 | (uint32_t) tag[2] << 16 | (uint32_t) tag[1] << 8 |
(uint32_t) tag[0]);
if (rv != CKR_OK)
{
retval = SECURE_ELEMENT_ERROR;
}
#endif /* LORAWAN_KMS */
return retval;
}
/* Exported functions ---------------------------------------------------------*/
/*
* API functions
*/
/* ST_WORKAROUND: Add unique ID callback as input parameter */
SecureElementStatus_t SecureElementInit( SecureElementNvmData_t *nvm, SecureElementGetUniqueId seGetUniqueId )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
SecureElementNvmData_t seNvmInit =
{
/*!
* end-device IEEE EUI (big endian)
*
* \remark In this application the value is automatically generated by
* calling BoardGetUniqueId function
*/
.DevEui = LORAWAN_DEVICE_EUI,
/*!
* App/Join server IEEE EUI (big endian)
*/
.JoinEui = LORAWAN_JOIN_EUI,
/*!
* LoRaWAN key list
*/
.KeyList = SOFT_SE_KEY_LIST
};
if( nvm == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
// Initialize nvm pointer
SeNvm = nvm;
// Initialize data
memcpy1( ( uint8_t* )SeNvm, ( uint8_t* )&seNvmInit, sizeof( seNvmInit ) );
#else /* LORAWAN_KMS == 1 */
uint8_t itr = 0;
uint8_t devEUI[SE_EUI_SIZE] = LORAWAN_DEVICE_EUI;
uint8_t joinEUI[SE_EUI_SIZE] = LORAWAN_JOIN_EUI;
if (nvm == NULL)
{
return SECURE_ELEMENT_ERROR_NPE;
}
/* Initialize nvm pointer */
SeNvm = nvm;
/* Initialize with defaults */
memcpy1((uint8_t *)SeNvm->DevEui, devEUI, SE_EUI_SIZE);
memcpy1((uint8_t *)SeNvm->JoinEui, joinEUI, SE_EUI_SIZE);
SeNvm->KeyList[itr++].KeyID = APP_KEY;
SeNvm->KeyList[itr++].KeyID = NWK_KEY;
#if ( USE_LRWAN_1_1_X_CRYPTO == 1 )
SeNvm->KeyList[itr++].KeyID = J_S_INT_KEY;
SeNvm->KeyList[itr++].KeyID = J_S_ENC_KEY;
SeNvm->KeyList[itr++].KeyID = F_NWK_S_INT_KEY;
SeNvm->KeyList[itr++].KeyID = S_NWK_S_INT_KEY;
SeNvm->KeyList[itr++].KeyID = NWK_S_ENC_KEY;
#else /* USE_LRWAN_1_1_X_CRYPTO == 0 */
SeNvm->KeyList[itr++].KeyID = NWK_S_KEY;
#endif /* USE_LRWAN_1_1_X_CRYPTO */
SeNvm->KeyList[itr++].KeyID = APP_S_KEY;
SeNvm->KeyList[itr++].KeyID = MC_ROOT_KEY;
SeNvm->KeyList[itr++].KeyID = MC_KE_KEY;
SeNvm->KeyList[itr++].KeyID = MC_KEY_0;
SeNvm->KeyList[itr++].KeyID = MC_APP_S_KEY_0;
SeNvm->KeyList[itr++].KeyID = MC_NWK_S_KEY_0;
#if ( LORAMAC_MAX_MC_CTX > 1 )
SeNvm->KeyList[itr++].KeyID = MC_KEY_1;
SeNvm->KeyList[itr++].KeyID = MC_APP_S_KEY_1;
SeNvm->KeyList[itr++].KeyID = MC_NWK_S_KEY_1;
SeNvm->KeyList[itr++].KeyID = MC_KEY_2;
SeNvm->KeyList[itr++].KeyID = MC_APP_S_KEY_2;
SeNvm->KeyList[itr++].KeyID = MC_NWK_S_KEY_2;
SeNvm->KeyList[itr++].KeyID = MC_KEY_3;
SeNvm->KeyList[itr++].KeyID = MC_APP_S_KEY_3;
SeNvm->KeyList[itr++].KeyID = MC_NWK_S_KEY_3;
#endif /*LORAMAC_MAX_MC_CTX > 1 */
SeNvm->KeyList[itr].KeyID = SLOT_RAND_ZERO_KEY;
/* Delete all obsolete keys in NVM */
DeleteAllDynamicKeys();
SecureElementSetObjHandler(APP_KEY, KMS_APP_KEY_OBJECT_HANDLE);
SecureElementSetObjHandler(NWK_KEY, KMS_NWK_KEY_OBJECT_HANDLE);
SecureElementSetObjHandler(APP_S_KEY, KMS_APP_S_KEY_OBJECT_HANDLE);
SecureElementSetObjHandler(NWK_S_KEY, KMS_NWK_S_KEY_OBJECT_HANDLE);
#if ( LORAMAC_CLASSB_ENABLED == 1 )
SecureElementSetObjHandler(SLOT_RAND_ZERO_KEY, KMS_ZERO_KEY_OBJECT_HANDLE);
#endif /* LORAMAC_CLASSB_ENABLED */
#endif /* LORAWAN_KMS */
#if (defined (KEY_EXTRACTABLE) && (KEY_EXTRACTABLE == 1))
MW_LOG(TS_OFF, VLEVEL_M, "###### OTAA ######\r\n");
PrintKey(APP_KEY);
PrintKey(NWK_KEY);
MW_LOG(TS_OFF, VLEVEL_M, "###### ABP ######\r\n");
PrintKey(APP_S_KEY);
PrintKey(NWK_S_KEY);
#endif /* KEY_EXTRACTABLE */
#if !defined( SECURE_ELEMENT_PRE_PROVISIONED )
#if( STATIC_DEVICE_EUI == 0 )
if (seGetUniqueId != NULL)
{
// Get a DevEUI from MCU unique ID
seGetUniqueId(SeNvm->DevEui);
}
#endif /* STATIC_DEVICE_EUI */
#endif /* !SECURE_ELEMENT_PRE_PROVISIONED */
return SECURE_ELEMENT_SUCCESS;
}
/* ST_WORKAROUND_BEGIN: Add KMS specific functions */
SecureElementStatus_t SecureElementGetKeyByID( KeyIdentifier_t keyID, Key_t **keyItem )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
#if (defined (KEY_EXTRACTABLE) && (KEY_EXTRACTABLE == 1))
for (uint8_t i = 0; i < NUM_OF_KEYS; i++)
{
if (SeNvm->KeyList[i].KeyID == keyID)
{
*keyItem = &(SeNvm->KeyList[i]);
return SECURE_ELEMENT_SUCCESS;
}
}
#endif /* KEY_EXTRACTABLE */
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
#else /* LORAWAN_KMS == 1 */
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
CK_OBJECT_HANDLE key_handle = (CK_OBJECT_HANDLE)(~0UL);
CK_ULONG derive_key_template_class = CKO_SECRET_KEY;
uint8_t extractable_key[16] = {0};
CK_ATTRIBUTE key_attribute_template = {CKA_VALUE, (CK_VOID_PTR) &derive_key_template_class, 16UL};
uint8_t index_keylist = 0;
for (index_keylist = 0; index_keylist < NUM_OF_KEYS; index_keylist++)
{
if (SeNvm->KeyList[index_keylist].KeyID == keyID)
{
key_handle = SeNvm->KeyList[index_keylist].Object_Index;
break;
}
}
if (key_handle == (CK_OBJECT_HANDLE)(~0UL))
{
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Get key to display */
if (rv == CKR_OK)
{
key_attribute_template.pValue = extractable_key;
rv = C_GetAttributeValue(session, key_handle, &key_attribute_template, 1UL);
}
if (rv == CKR_OK)
{
memcpy1(SeNvm->KeyList[index_keylist].KeyValue, extractable_key, sizeof(extractable_key));
*keyItem = &(SeNvm->KeyList[index_keylist]);
}
/* Close sessions */
(void)C_CloseSession(session);
if (rv != CKR_OK)
{
return SECURE_ELEMENT_ERROR;
}
return SECURE_ELEMENT_SUCCESS;
#endif /* LORAWAN_KMS == 1 */
}
SecureElementStatus_t SecureElementDeleteDynamicKeys( KeyIdentifier_t keyID, uint32_t *key_label )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
return SECURE_ELEMENT_ERROR;
#else /* LORAWAN_KMS == 1 */
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
CK_OBJECT_HANDLE hObject[NUM_OF_KEYS];
CK_ULONG local_template_label[] = {GlobalTemplateLabel, 0UL};
CK_ATTRIBUTE dynamic_key_template = {CKA_LABEL, (CK_VOID_PTR)local_template_label, sizeof(local_template_label)};
uint32_t ulCount = 0;
if (SECURE_ELEMENT_SUCCESS != GetSpecificLabelByID(keyID, &local_template_label[1]))
{
return SECURE_ELEMENT_ERROR;
}
*key_label = local_template_label[1];
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Search from Template pattern */
if (rv == CKR_OK)
{
rv = C_FindObjectsInit(session, &dynamic_key_template, sizeof(dynamic_key_template) / sizeof(CK_ATTRIBUTE));
}
/* Find all existing keys handle Template pattern */
if (rv == CKR_OK)
{
rv = C_FindObjects(session, hObject, NUM_OF_KEYS, (CK_ULONG *) &ulCount);
}
if (rv == CKR_OK)
{
rv = C_FindObjectsFinal(session);
}
if (ulCount <= NUM_OF_KEYS)
{
for (uint8_t i = 0; i < ulCount; i++)
{
if (rv == CKR_OK)
{
rv = C_DestroyObject(session, hObject[i]);
}
}
}
/* Close sessions */
if (session > 0)
{
(void)C_CloseSession(session);
}
if (rv != CKR_OK)
{
return SECURE_ELEMENT_ERROR;
}
return SECURE_ELEMENT_SUCCESS;
#endif /* LORAWAN_KMS == 1 */
}
SecureElementStatus_t SecureElementSetObjHandler( KeyIdentifier_t keyID, uint32_t keyIndex )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
return SECURE_ELEMENT_ERROR;
#else /* LORAWAN_KMS == 1 */
for (uint8_t i = 0; i < NUM_OF_KEYS; i++)
{
if (SeNvm->KeyList[i].KeyID == keyID)
{
SeNvm->KeyList[i].Object_Index = (CK_OBJECT_HANDLE) keyIndex;
return SECURE_ELEMENT_SUCCESS;
}
}
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
#endif /* LORAWAN_KMS */
}
/* ST_WORKAROUND_END */
SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
{
if( key == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
if( SeNvm->KeyList[i].KeyID == keyID )
{
/* ST_WORKAROUND_BEGIN: reduced LORAMAC_MAX_MC_CTX */
#if ( LORAMAC_MAX_MC_CTX == 1 )
if ( keyID == MC_KEY_0 )
#else /* LORAMAC_MAX_MC_CTX > 1 */
if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
#endif /* LORAMAC_MAX_MC_CTX */
/* ST_WORKAROUND_END */
{ // Decrypt the key if its a Mckey
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
uint8_t decryptedKey[16] = { 0 };
retval = SecureElementAesEncrypt( key, 16, MC_KE_KEY, decryptedKey );
memcpy1( SeNvm->KeyList[i].KeyValue, decryptedKey, SE_KEY_SIZE );
return retval;
}
else
{
memcpy1( SeNvm->KeyList[i].KeyValue, key, SE_KEY_SIZE );
return SECURE_ELEMENT_SUCCESS;
}
}
}
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
#else /* LORAWAN_KMS == 1 */
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
CK_OBJECT_HANDLE key_handle;
CK_ULONG template_class = CKO_SECRET_KEY;
CK_ULONG template_type = CKK_AES;
#if (defined (KEY_EXTRACTABLE) && (KEY_EXTRACTABLE == 1))
CK_ULONG template_true = CK_TRUE;
#else
CK_ULONG template_false = CK_TRUE;
#endif /* KEY_EXTRACTABLE */
uint32_t key_ui32[] =
{
key[3] | (key[2] << 8) | (key[1] << 16) | (key[0] << 24),
key[7] | (key[6] << 8) | (key[5] << 16) | (key[4] << 24),
key[11] | (key[10] << 8) | (key[9] << 16) | (key[8] << 24),
key[15] | (key[14] << 8) | (key[13] << 16) | (key[12] << 24),
};
uint32_t specific_label[] = {GlobalTemplateLabel, 0UL};
CK_ATTRIBUTE key_attribute_template[] =
{
{ CKA_CLASS, (CK_VOID_PTR) &template_class, sizeof(CK_BBOOL) },
{ CKA_KEY_TYPE, (CK_VOID_PTR) &template_type, sizeof(CK_BBOOL) },
{ CKA_VALUE, (CK_VOID_PTR)key_ui32, sizeof(key_ui32) },
#if (defined (KEY_EXTRACTABLE) && (KEY_EXTRACTABLE == 1))
{ CKA_EXTRACTABLE, (CK_VOID_PTR) &template_true, sizeof(CK_BBOOL) },
#else
{ CKA_EXTRACTABLE, (CK_VOID_PTR) &template_false, sizeof(CK_BBOOL) },
#endif /* KEY_EXTRACTABLE */
{ CKA_LABEL, (CK_VOID_PTR)specific_label, sizeof(specific_label)},
};
/* ST_WORKAROUND_BEGIN: reduced LORAMAC_MAX_MC_CTX */
#if ( LORAMAC_MAX_MC_CTX == 1 )
if ( keyID == MC_KEY_0 )
#else /* LORAMAC_MAX_MC_CTX > 1 */
if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
#endif /* LORAMAC_MAX_MC_CTX */
/* ST_WORKAROUND_END */
{ // Decrypt the key if its a Mckey
uint8_t decryptedKey[16] = { 0 };
if (SECURE_ELEMENT_SUCCESS != SecureElementAesEncrypt( key, 16, MC_KE_KEY, decryptedKey ))
{
return SECURE_ELEMENT_ERROR;
}
key_ui32[0] = decryptedKey[3] | (decryptedKey[2] << 8) | (decryptedKey[1] << 16) | (decryptedKey[0] << 24);
key_ui32[1] = decryptedKey[7] | (decryptedKey[6] << 8) | (decryptedKey[5] << 16) | (decryptedKey[4] << 24);
key_ui32[2] = decryptedKey[11] | (decryptedKey[10] << 8) | (decryptedKey[9] << 16) | (decryptedKey[8] << 24);
key_ui32[3] = decryptedKey[15] | (decryptedKey[14] << 8) | (decryptedKey[13] << 16) | (decryptedKey[12] << 24);
}
if (SECURE_ELEMENT_SUCCESS != GetKeyIndexByID(keyID, &key_handle))
{
return SECURE_ELEMENT_ERROR;
}
if (SECURE_ELEMENT_SUCCESS != SecureElementDeleteDynamicKeys(keyID, &specific_label[1]))
{
return SECURE_ELEMENT_ERROR;
}
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Get key to display */
if (rv == CKR_OK)
{
rv = C_CreateObject(session, key_attribute_template, sizeof(key_attribute_template) / sizeof(CK_ATTRIBUTE),
&key_handle);
}
if (rv == CKR_OK)
{
retval = SecureElementSetObjHandler(keyID, key_handle);
}
PrintKey(keyID);
/* Close sessions */
(void)C_CloseSession(session);
if (rv != CKR_OK)
{
retval = SECURE_ELEMENT_ERROR;
}
return retval;
#endif /* LORAWAN_KMS */
}
SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
KeyIdentifier_t keyID, uint32_t* cmac )
{
if( keyID >= LORAMAC_CRYPTO_MULTICAST_KEYS )
{
// Never accept multicast key identifier for cmac computation
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
return ComputeCmac( micBxBuffer, buffer, size, keyID, cmac );
}
SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac,
KeyIdentifier_t keyID )
{
if( buffer == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
uint32_t compCmac = 0;
retval = ComputeCmac( NULL, buffer, size, keyID, &compCmac );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
}
if( expectedCmac != compCmac )
{
retval = SECURE_ELEMENT_FAIL_CMAC;
}
#else /* LORAWAN_KMS == 1 */
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
CK_OBJECT_HANDLE object_handle;
if (buffer == NULL)
{
return SECURE_ELEMENT_ERROR_NPE;
}
/* AES CMAC Authentication variables */
CK_MECHANISM aes_cmac_mechanism = { CKM_AES_CMAC, (CK_VOID_PTR)NULL, 0 };
retval = GetKeyIndexByID(keyID, &object_handle);
if (retval != SECURE_ELEMENT_SUCCESS)
{
return retval;
}
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Configure session to Verify the message in AES CMAC with settings included into the mechanism */
if (rv == CKR_OK)
{
rv = C_VerifyInit(session, &aes_cmac_mechanism, object_handle);
}
/* Verify the message */
if (rv == CKR_OK)
{
memcpy1(input_align_combined_buf, buffer, size);
rv = C_Verify(session, (CK_BYTE_PTR)input_align_combined_buf, size, (CK_BYTE_PTR)&expectedCmac, 4);
}
(void)C_CloseSession(session);
if (rv != CKR_OK)
{
retval = SECURE_ELEMENT_ERROR;
}
#endif /* LORAWAN_KMS */
return retval;
}
SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
uint8_t* encBuffer )
{
if( buffer == NULL || encBuffer == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
// Check if the size is divisible by 16,
if( ( size % 16 ) != 0 )
{
return SECURE_ELEMENT_ERROR_BUF_SIZE;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
lorawan_aes_context aesContext;
memset1( aesContext.ksch, '\0', 240 );
Key_t* pItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &pItem );
if( retval == SECURE_ELEMENT_SUCCESS )
{
lorawan_aes_set_key(pItem->KeyValue, 16, &aesContext);
uint8_t block = 0;
while( size != 0 )
{
lorawan_aes_encrypt(&buffer[block], &encBuffer[block], &aesContext);
block = block + 16;
size = size - 16;
}
}
#else /* LORAWAN_KMS == 1 */
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
uint32_t encrypted_length = 0;
CK_OBJECT_HANDLE object_handle;
uint8_t dummy_tag[SE_KEY_SIZE] = {0};
uint32_t dummy_tag_lenth = 0;
CK_MECHANISM aes_ecb_mechanism = { CKM_AES_ECB, (CK_VOID_PTR *) NULL, 0 };
SecureElementStatus_t retval = GetKeyIndexByID(keyID, &object_handle);
if (retval != SECURE_ELEMENT_SUCCESS)
{
return retval;
}
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Configure session to encrypt message in AES ECB with settings included into the mechanism */
if (rv == CKR_OK)
{
rv = C_EncryptInit(session, &aes_ecb_mechanism, object_handle);
}
/* Encrypt clear message */
if (rv == CKR_OK)
{
memcpy1(input_align_combined_buf, buffer, size);
encrypted_length = sizeof(output_align);
rv = C_EncryptUpdate(session, (CK_BYTE_PTR)input_align_combined_buf, size,
output_align, (CK_ULONG_PTR)&encrypted_length);
memcpy1(encBuffer, output_align, size);
}
/* In this case C_EncryptFinal is just called to Free the Alloc mem */
if (rv == CKR_OK)
{
dummy_tag_lenth = sizeof(tag);
rv = C_EncryptFinal(session, &dummy_tag[0], (CK_ULONG_PTR)&dummy_tag_lenth);
}
/* Close session with KMS */
(void)C_CloseSession(session);
if (rv != CKR_OK)
{
retval = SECURE_ELEMENT_ERROR;
}
#endif /* LORAWAN_KMS */
return retval;
}
SecureElementStatus_t SecureElementDeriveAndStoreKey( uint8_t* input, KeyIdentifier_t rootKeyID,
KeyIdentifier_t targetKeyID )
{
if( input == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
// In case of MC_KE_KEY, only McRootKey can be used as root key
if( targetKeyID == MC_KE_KEY )
{
if( rootKeyID != MC_ROOT_KEY )
{
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
uint8_t key[16] = { 0 };
// Derive key
retval = SecureElementAesEncrypt( input, 16, rootKeyID, key );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
}
// Store key
retval = SecureElementSetKey( targetKeyID, key );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
}
return SECURE_ELEMENT_SUCCESS;
#else /* LORAWAN_KMS == 1 */
CK_RV rv;
CK_SESSION_HANDLE session;
CK_FLAGS session_flags = CKF_SERIAL_SESSION; /* Read ONLY session */
/* Key derivation */
CK_MECHANISM mech = {CKM_AES_ECB_ENCRYPT_DATA, input, SE_KEY_SIZE};
CK_OBJECT_HANDLE derived_object_handle;
CK_OBJECT_HANDLE rootkey_object_handle;
uint32_t specific_label[] = {GlobalTemplateLabel, 0UL};
CK_ATTRIBUTE DeriveKey_template = {CKA_LABEL, (CK_VOID_PTR)specific_label, sizeof(specific_label)};
/* Derive key */
if (SECURE_ELEMENT_SUCCESS != GetKeyIndexByID(rootKeyID, &rootkey_object_handle))
{
return SECURE_ELEMENT_ERROR;
}
if (SECURE_ELEMENT_SUCCESS != GetKeyIndexByID(targetKeyID, &derived_object_handle))
{
return SECURE_ELEMENT_ERROR;
}
if (SECURE_ELEMENT_SUCCESS != SecureElementDeleteDynamicKeys(targetKeyID, &specific_label[1]))
{
return SECURE_ELEMENT_ERROR;
}
/* Open session with KMS */
rv = C_OpenSession(0, session_flags, NULL, 0, &session);
/* Derive key with pass phrase */
if (rv == CKR_OK)
{
rv = C_DeriveKey(session, &(mech), rootkey_object_handle,
&DeriveKey_template, sizeof(DeriveKey_template) / sizeof(CK_ATTRIBUTE), &derived_object_handle);
}
if (rv == CKR_OK)
{
/* Store Derived Index in table */
retval = SecureElementSetObjHandler(targetKeyID, derived_object_handle);
}
PrintKey(targetKeyID);
/* Close session with KMS */
(void)C_CloseSession(session);
if (rv != CKR_OK)
{
retval = SECURE_ELEMENT_ERROR;
}
return retval;
#endif /* LORAWAN_KMS */
}
SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
uint16_t devNonce, uint8_t* encJoinAccept,
uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
uint8_t* versionMinor )
{
if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
{
return SECURE_ELEMENT_ERROR_NPE;
}
// Check that frame size isn't bigger than a JoinAccept with CFList size
if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
{
return SECURE_ELEMENT_ERROR_BUF_SIZE;
}
// Determine decryption key
KeyIdentifier_t encKeyID = NWK_KEY;
/* ST_WORKAROUND_BEGIN: Keep NWK_KEY if 1.1.x keys are not defined */
#if ( USE_LRWAN_1_1_X_CRYPTO == 1 )
if( joinReqType != JOIN_REQ )
{
encKeyID = J_S_ENC_KEY;
}
#endif /* USE_LRWAN_1_1_X_CRYPTO == 1 */
memcpy1( decJoinAccept, encJoinAccept, encJoinAcceptSize );
// Decrypt JoinAccept, skip MHDR
if( SecureElementAesEncrypt( encJoinAccept + LORAMAC_MHDR_FIELD_SIZE, encJoinAcceptSize - LORAMAC_MHDR_FIELD_SIZE,
encKeyID, decJoinAccept + LORAMAC_MHDR_FIELD_SIZE ) != SECURE_ELEMENT_SUCCESS )
{
return SECURE_ELEMENT_FAIL_ENCRYPT;
}
*versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
uint32_t mic = 0;
mic = ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE] << 0 );
mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 1] << 8 );
mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 2] << 16 );
mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 3] << 24 );
// - Header buffer to be used for MIC computation
// - LoRaWAN 1.0.x : micHeader = [MHDR(1)]
// - LoRaWAN 1.1.x : micHeader = [JoinReqType(1), JoinEUI(8), DevNonce(2), MHDR(1)]
// Verify mic
if( *versionMinor == 0 )
{
// For LoRaWAN 1.0.x
// cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList |
// CFListType)
if( SecureElementVerifyAesCmac( decJoinAccept, ( encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE ), mic, NWK_KEY ) !=
SECURE_ELEMENT_SUCCESS )
{
return SECURE_ELEMENT_FAIL_CMAC;
}
}
#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
else if( *versionMinor == 1 )
{
uint8_t micHeader11[JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
uint16_t bufItr = 0;
micHeader11[bufItr++] = ( uint8_t ) joinReqType;
memcpyr( micHeader11 + bufItr, joinEui, LORAMAC_JOIN_EUI_FIELD_SIZE );
bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;
micHeader11[bufItr++] = devNonce & 0xFF;
micHeader11[bufItr++] = ( devNonce >> 8 ) & 0xFF;
// For LoRaWAN 1.1.x and later:
// cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr |
// DLSettings | RxDelay | CFList | CFListType)
// Prepare the msg for integrity check (adding JoinReqType, JoinEUI and DevNonce)
uint8_t localBuffer[LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
memcpy1( localBuffer, micHeader11, JOIN_ACCEPT_MIC_COMPUTATION_OFFSET );
memcpy1( localBuffer + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET - 1, decJoinAccept, encJoinAcceptSize );
if( SecureElementVerifyAesCmac( localBuffer,
encJoinAcceptSize + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET -
LORAMAC_MHDR_FIELD_SIZE - LORAMAC_MIC_FIELD_SIZE,
mic, J_S_INT_KEY ) != SECURE_ELEMENT_SUCCESS )
{
return SECURE_ELEMENT_FAIL_CMAC;
}
}
#endif /* USE_LRWAN_1_1_X_CRYPTO == 1 */
else
{
return SECURE_ELEMENT_ERROR_INVALID_LORAWAM_SPEC_VERSION;
}
return SECURE_ELEMENT_SUCCESS;
}
SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum )
{
if( randomNum == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
*randomNum = Radio.Random();
return SECURE_ELEMENT_SUCCESS;
}
SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
{
if( devEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvm->DevEui, devEui, SE_EUI_SIZE );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetDevEui( void )
{
return SeNvm->DevEui;
}
SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
{
if( joinEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvm->JoinEui, joinEui, SE_EUI_SIZE );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetJoinEui( void )
{
return SeNvm->JoinEui;
}