Update LoRaMac-node to Version 4.4.4,fix Security breach found by Tencent Blade Team please refer to security advisory - CVE-2020-11068

fix Security breach found by Tencent Blade Team please refer to security advisory - CVE-2020-11068
This commit is contained in:
supowang
2020-05-29 11:59:05 +08:00
parent 5d9895cecc
commit f9bd2588a2
137 changed files with 10401 additions and 4328 deletions

View File

@@ -22,17 +22,62 @@ cmake_minimum_required(VERSION 3.6)
# Target
#---------------------------------------------------------------------------------------
file(GLOB ${PROJECT_NAME}_SOURCES "*.c"
"soft-se/*.c")
if(${SECURE_ELEMENT} MATCHES SOFT_SE)
file(GLOB ${PROJECT_NAME}_SOURCES "*.c" "soft-se/*.c")
else()
if(${SECURE_ELEMENT} MATCHES LR1110_SE)
if (${RADIO} MATCHES lr1110)
file(GLOB ${PROJECT_NAME}_SOURCES "*.c" "lr1110-se/*.c")
else()
message(FATAL_ERROR "LR1110_SE secure elemeent can only be used when LR1110 radio is selected.")
endif()
elseif((${SECURE_ELEMENT} MATCHES ATECC608A_TNGLORA_SE))
file(GLOB ${PROJECT_NAME}_SOURCES "*.c"
"atecc608a-tnglora-se/*.c"
"atecc608a-tnglora-se/cryptoauthlib/lib/*.c"
"atecc608a-tnglora-se/cryptoauthlib/lib/basic/*.c"
"atecc608a-tnglora-se/cryptoauthlib/lib/crypto/*.c"
"atecc608a-tnglora-se/cryptoauthlib/lib/crypto/hashes/*.c"
"atecc608a-tnglora-se/cryptoauthlib/lib/hal/atca_hal.c"
"atecc608a-tnglora-se/cryptoauthlib/lib/host/*.c"
)
else()
message(FATAL_ERROR "No secure-element selected.")
endif()
endif()
add_library(${PROJECT_NAME} OBJECT EXCLUDE_FROM_ALL ${${PROJECT_NAME}_SOURCES})
if(${SECURE_ELEMENT_PRE_PROVISIONED} MATCHES ON)
target_compile_definitions(${PROJECT_NAME} PRIVATE -DSECURE_ELEMENT_PRE_PROVISIONED)
endif()
if(${SECURE_ELEMENT} MATCHES SOFT_SE)
target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/soft-se)
else()
if(${SECURE_ELEMENT} MATCHES LR1110_SE)
if(${RADIO} MATCHES lr1110)
target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lr1110-se)
endif()
elseif((${SECURE_ELEMENT} MATCHES ATECC608A_TNGLORA_SE))
target_include_directories( ${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/basic
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/crypto
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/crypto/hashes
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/hal
${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/host
)
endif()
endif()
target_include_directories( ${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/soft-se
$<TARGET_PROPERTY:board,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:system,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:mac,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:radio,INTERFACE_INCLUDE_DIRECTORIES>
)
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11)

View File

@@ -0,0 +1,27 @@
/* Cryptoauthlib Configuration File */
#ifndef ATCA_CONFIG_H
#define ATCA_CONFIG_H
/* Include HALS */
#define ATCA_HAL_I2C
/* Included device support */
#define ATCA_ATECC608A_SUPPORT
/* ATECC608A I2C bus configuration */
#define ATCA_HAL_ATECC608A_I2C_FREQUENCY 100000U
#define ATCA_HAL_ATECC608A_I2C_BUS_PINS 2U
#define ATCA_HAL_ATECC608A_I2C_ADDRESS 0x59U
#define ATCA_HAL_ATECC608A_I2C_RX_RETRIES 20
#define ATCA_HAL_ATECC608A_I2C_WAKEUP_DELAY 1500U
/* \brief How long to wait after an initial wake failure for the POST to
* complete.
* If Power-on self test (POST) is enabled, the self test will run on waking
* from sleep or during power-on, which delays the wake reply.
*/
#ifndef ATCA_POST_DELAY_MSEC
#define ATCA_POST_DELAY_MSEC 25
#endif
#endif

View File

@@ -0,0 +1,299 @@
/**
* @file atecc608a-tnglora-se-hal.c
*
* @brief Secure Element hardware abstraction layer implementation
*
* @remark Current implementation only supports LoRaWAN 1.0.x version
*
* @copyright Copyright (c) 2020 The Things Industries B.V.
*
* Revised BSD License
* Copyright The Things Industries B.V 2020. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Things Industries B.V nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
#include "atca_hal.h"
#include "atca_device.h"
#include "atca_execution.h"
#include "atca_status.h"
#include "i2c-board.h"
#include "delay.h"
#include "radio.h"
#include "atecc608a-tnglora-se-hal.h"
uint32_t ATECC608ASeHalGetRandomNumber( void )
{
return Radio.Random( );
}
/** @brief This function delays for a number of microseconds.
*
* @param[in] delay number of 0.001 milliseconds to delay
*/
void atca_delay_us(uint32_t delay)
{
// use ASF supplied delay
DelayMs(delay / 1000);
}
/** @brief This function delays for a number of tens of microseconds.
*
* @param[in] delay number of 0.01 milliseconds to delay
*/
void atca_delay_10us(uint32_t delay)
{
// use ASF supplied delay
DelayMs(delay / 100);
}
/** @brief This function delays for a number of milliseconds.
*
* You can override this function if you like to do
* something else in your system while delaying.
* @param[in] delay number of milliseconds to delay
*/
void atca_delay_ms(uint32_t delay)
{
// use ASF supplied delay
DelayMs(delay);
}
/** @brief discover i2c buses available for this hardware
* this maintains a list of logical to physical bus mappings freeing the application
* of the a-priori knowledge
* @param[in] i2c_buses - an array of logical bus numbers
* @param[in] max_buses - maximum number of buses the app wants to attempt to discover
* @return ATCA_SUCCESS
*/
ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses)
{
return ATCA_SUCCESS;
}
/** @brief discover any CryptoAuth devices on a given logical bus number
* @param[in] bus_num logical bus number on which to look for CryptoAuth devices
* @param[out] cfg pointer to head of an array of interface config structures which get filled in by this method
* @param[out] found number of devices found on this bus
* @return ATCA_SUCCESS
*/
ATCA_STATUS hal_i2c_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found)
{
return ATCA_SUCCESS;
}
/** @brief
- this HAL implementation assumes you've included the ASF SERCOM I2C libraries in your project, otherwise,
the HAL layer will not compile because the ASF I2C drivers are a dependency *
*/
/** @brief hal_i2c_init manages requests to initialize a physical interface. it manages use counts so when an interface
* has released the physical layer, it will disable the interface for some other use.
* You can have multiple ATCAIFace instances using the same bus, and you can have multiple ATCAIFace instances on
* multiple i2c buses, so hal_i2c_init manages these things and ATCAIFace is abstracted from the physical details.
*/
/** @brief initialize an I2C interface using given config
* @param[in] hal - opaque ptr to HAL data
* @param[in] cfg - interface configuration
* @return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg)
{
return ATCA_SUCCESS;
}
/** @brief HAL implementation of I2C post init
* @param[in] iface instance
* @return ATCA_SUCCESS
*/
ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
{
return ATCA_SUCCESS;
}
/** @brief HAL implementation of I2C send over ASF
* @param[in] iface instance
* @param[in] txdata pointer to space to bytes to send
* @param[in] txlength number of bytes to send
* @return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
{
txdata[0] = 0x3;
txlength++;
if (I2cMcuWriteBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, txdata, (size_t)txlength) == 1)
{
return ATCA_SUCCESS;
}
else
{
return ATCA_TX_FAIL;
}
}
/** @brief HAL implementation of I2C receive function for ASF I2C
* @param[in] iface Device to interact with.
* @param[out] rxdata Data received will be returned here.
* @param[inout] rxlength As input, the size of the rxdata buffer.
* As output, the number of bytes received.
* @return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
{
// read procedure is:
// 1. read 1 byte, this will be the length of the package
// 2. read the rest of the package
uint8_t lengthPackage[1] = {0};
int r = -1;
int retries = iface->mIfaceCFG->rx_retries;
while (--retries > 0 && r != 1)
{
r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, lengthPackage, 1);
}
if (r != 1)
{
return ATCA_RX_TIMEOUT;
}
uint8_t bytesToRead = lengthPackage[0] - 1;
if (bytesToRead > *rxlength)
{
printf("hal_i2c_receive buffer too small, requested %u, but have %u", bytesToRead, *rxlength);
return ATCA_SMALL_BUFFER;
}
memset(rxdata, 0, *rxlength);
rxdata[0] = lengthPackage[0];
r = -1;
retries = iface->mIfaceCFG->rx_retries;
while (--retries > 0 && r != 1)
{
r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, rxdata + 1, bytesToRead);
}
if (r != 1)
{
return ATCA_RX_TIMEOUT;
}
*rxlength = lengthPackage[0];
return ATCA_SUCCESS;
}
/** @brief method to change the bus speec of I2C
* @param[in] iface interface on which to change bus speed
* @param[in] speed baud rate (typically 100000 or 400000)
*/
void change_i2c_speed(ATCAIface iface, uint32_t speed)
{
return;
}
/** @brief wake up CryptoAuth device using I2C bus
* @param[in] iface interface to logical device to wakeup
* @return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_wake(ATCAIface iface)
{
// 2. Send NULL buffer to address 0x0 (NACK)
uint8_t emptybuff[1] = {0};
int r = I2cMcuWriteBuffer((I2c_t *)NULL, 0x00, 0, emptybuff, (size_t)0);
// 3. Wait for wake_delay
atca_delay_us(iface->mIfaceCFG->wake_delay);
uint8_t rx_buffer[4] = {0};
// 4. Read from normal slave_address
r = -1;
int retries = iface->mIfaceCFG->rx_retries;
while (--retries > 0 && r != 1)
{
r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, rx_buffer, 4);
}
// 5. Set frequency back to requested one
const uint8_t expected_response[4] = {0x04, 0x11, 0x33, 0x43};
uint8_t selftest_fail_resp[4] = {0x04, 0x07, 0xC4, 0x40};
if (memcmp(rx_buffer, expected_response, 4) == 0)
{
return ATCA_SUCCESS;
}
if (memcmp(rx_buffer, selftest_fail_resp, 4) == 0)
{
return ATCA_STATUS_SELFTEST_ERROR;
}
return ATCA_WAKE_FAILED;
}
/** @brief idle CryptoAuth device using I2C bus
* @param[in] iface interface to logical device to idle
* @return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_idle(ATCAIface iface)
{
uint8_t buffer[1] = { 0x2 }; // idle word address value
I2cMcuWriteBuffer((I2c_t*)NULL, iface->mIfaceCFG->atcai2c.slave_address,0, buffer, (size_t)1);
return ATCA_SUCCESS;
}
/** @brief sleep CryptoAuth device using I2C bus
* @param[in] iface interface to logical device to sleep
* @return ATCA_SUCCESS on success, otherwise an error code.
*/
ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
{
uint8_t buffer[1] = { 0x1 }; // sleep word address value
I2cMcuWriteBuffer((I2c_t*)NULL, iface->mIfaceCFG->atcai2c.slave_address,0, buffer, (size_t)1);
return ATCA_SUCCESS;
}
/** @brief manages reference count on given bus and releases resource if no more refences exist
* @param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation
* return ATCA_SUCCESS
*/
ATCA_STATUS hal_i2c_release(void *hal_data)
{
return ATCA_SUCCESS;
}

View File

@@ -0,0 +1,58 @@
/**
* @file atecc608a-tnglora-se-hal.h
*
* @brief Secure Element hardware abstraction layer
*
* @remark Current implementation only supports LoRaWAN 1.0.x version
*
* @copyright Copyright (c) 2020 The Things Industries B.V.
*
* Revised BSD License
* Copyright The Things Industries B.V 2020. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Things Industries B.V nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATECC608A_TNGLORA_SE_HAL_H__
#define __ATECC608A_TNGLORA_SE_HAL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/*!
* \brief Get a random number
*
* \remark The number SHALL NOT be generated using a pseudo random number
* generator
* \retval number 32 bit random value
*/
uint32_t ATECC608ASeHalGetRandomNumber( void );
#ifdef __cplusplus
}
#endif
#endif // __ATECC608A_TNGLORA_SE_HAL_H__

View File

@@ -0,0 +1,644 @@
/**
* @file atecc608a-tnglora-se.c
*
* @brief ATECC608A-TNGLORA Secure Element hardware implementation
*
* @remark Current implementation only supports LoRaWAN 1.0.x version
*
* @copyright Copyright (c) 2020 The Things Industries B.V.
*
* Revised BSD License
* Copyright The Things Industries B.V 2020. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Things Industries B.V nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "atca_basic.h"
#include "cryptoauthlib.h"
#include "atca_devtypes.h"
#include "secure-element.h"
#include "se-identity.h"
#include "atecc608a-tnglora-se-hal.h"
/*!
* Number of supported crypto keys
*/
#define NUM_OF_KEYS 15
#define DEV_EUI_ASCII_SIZE_BYTE 16U
/*!
* Identifier value pair type for Keys
*/
typedef struct sKey
{
/*
* Key identifier (used for maping the stack MAC key to the ATECC608A-TNGLoRaWAN slot)
*/
KeyIdentifier_t KeyID;
/*
* Key slot number
*/
uint16_t KeySlotNumber;
/*
* Key block index within slot (each block can contain two keys, so index is either 0 or 1)
*/
uint8_t KeyBlockIndex;
} Key_t;
/*
* Secure Element Non Volatile Context structure
*/
typedef struct sSecureElementNvCtx
{
/*!
* DevEUI storage
*/
uint8_t DevEui[SE_EUI_SIZE];
/*!
* Join EUI storage
*/
uint8_t JoinEui[SE_EUI_SIZE];
/*!
* Pin storage
*/
uint8_t Pin[SE_PIN_SIZE];
/*!
* LoRaWAN key list
*/
Key_t KeyList[NUM_OF_KEYS];
} SecureElementNvCtx_t;
/*!
* Secure element context
*/
static SecureElementNvCtx_t SeNvmCtx = {
/*!
* end-device IEEE EUI (big endian)
*/
.DevEui = { 0 },
/*!
* App/Join server IEEE EUI (big endian)
*/
.JoinEui = { 0 },
/*!
* Secure-element pin (big endian)
*/
.Pin = SECURE_ELEMENT_PIN,
/*!
* LoRaWAN key list
*/
.KeyList = ATECC608A_SE_KEY_LIST
};
static SecureElementNvmEvent SeNvmCtxChanged;
static ATCAIfaceCfg atecc608_i2c_config;
static ATCA_STATUS convert_ascii_devEUI( uint8_t* devEUI_ascii, uint8_t* devEUI );
static ATCA_STATUS atcab_read_joinEUI( uint8_t* joinEUI )
{
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t read_buf[ATCA_BLOCK_SIZE];
if( joinEUI == NULL )
{
return ATCA_BAD_PARAM;
}
do
{
status = atcab_read_zone( ATCA_ZONE_DATA, TNGLORA_JOIN_EUI_SLOT, 0, 0, read_buf, ATCA_BLOCK_SIZE );
if( status != ATCA_SUCCESS )
{
break;
}
memcpy1( joinEUI, read_buf, SE_EUI_SIZE );
} while( 0 );
return status;
}
static ATCA_STATUS atcab_read_ascii_devEUI( uint8_t* devEUI_ascii )
{
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t read_buf[ATCA_BLOCK_SIZE];
if( devEUI_ascii == NULL )
{
return ATCA_BAD_PARAM;
}
do
{
status = atcab_read_zone( ATCA_ZONE_DATA, TNGLORA_DEV_EUI_SLOT, 0, 0, read_buf, ATCA_BLOCK_SIZE );
if( status != ATCA_SUCCESS )
{
break;
}
memcpy1( devEUI_ascii, read_buf, DEV_EUI_ASCII_SIZE_BYTE );
} while( 0 );
return status;
}
static ATCA_STATUS convert_ascii_devEUI( uint8_t* devEUI_ascii, uint8_t* devEUI )
{
for( size_t pos = 0; pos < DEV_EUI_ASCII_SIZE_BYTE; pos += 2 )
{
uint8_t temp = 0;
if( ( devEUI_ascii[pos] >= '0' ) && ( devEUI_ascii[pos] <= '9' ) )
{
temp = ( devEUI_ascii[pos] - '0' ) << 4;
}
else if( ( devEUI_ascii[pos] >= 'A' ) && ( devEUI_ascii[pos] <= 'F' ) )
{
temp = ( ( devEUI_ascii[pos] - 'A' ) + 10 ) << 4;
}
else
{
return ATCA_BAD_PARAM;
}
if( ( devEUI_ascii[pos + 1] >= '0' ) && ( devEUI_ascii[pos + 1] <= '9' ) )
{
temp |= devEUI_ascii[pos + 1] - '0';
}
else if( ( devEUI_ascii[pos + 1] >= 'A' ) && ( devEUI_ascii[pos + 1] <= 'F' ) )
{
temp |= ( devEUI_ascii[pos + 1] - 'A' ) + 10;
}
else
{
return ATCA_BAD_PARAM;
}
devEUI[pos / 2] = temp;
}
return ATCA_SUCCESS;
}
static ATCA_STATUS atcab_read_devEUI( uint8_t* devEUI )
{
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t devEUI_ascii[DEV_EUI_ASCII_SIZE_BYTE];
status = atcab_read_ascii_devEUI( devEUI_ascii );
if( status != ATCA_SUCCESS )
{
return status;
}
status = convert_ascii_devEUI( devEUI_ascii, devEUI );
return status;
}
/*
* Gets key item from key list.
*
* cmac = aes128_cmac(keyID, B0 | msg)
*
* \param[IN] keyID - Key identifier
* \param[OUT] keyItem - Key item reference
* \retval - Status of the operation
*/
SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
{
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
if( SeNvmCtx.KeyList[i].KeyID == keyID )
{
*keyItem = &( SeNvmCtx.KeyList[i] );
return SECURE_ELEMENT_SUCCESS;
}
}
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
/*
* Dummy callback in case if the user provides NULL function pointer
*/
static void DummyCB( void )
{
return;
}
/*
* 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;
}
uint8_t Cmac[16] = { 0 };
Key_t* keyItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
}
atca_aes_cmac_ctx_t atcaAesCmacCtx;
ATCA_STATUS status =
atcab_aes_cmac_init( &atcaAesCmacCtx, keyItem->KeySlotNumber, keyItem->KeyBlockIndex );
if( ATCA_SUCCESS == status )
{
if( micBxBuffer != NULL )
{
atcab_aes_cmac_update( &atcaAesCmacCtx, micBxBuffer, 16 );
}
atcab_aes_cmac_update( &atcaAesCmacCtx, buffer, size );
atcab_aes_cmac_finish( &atcaAesCmacCtx, Cmac, 16 );
*cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 |
( uint32_t ) Cmac[0] );
return SECURE_ELEMENT_SUCCESS;
}
else
{
return SECURE_ELEMENT_ERROR;
}
}
SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
{
#if !defined( SECURE_ELEMENT_PRE_PROVISIONED )
#error "ATECC608A is always pre-provisioned. Please set SECURE_ELEMENT_PRE_PROVISIONED to ON"
#endif
atecc608_i2c_config.iface_type = ATCA_I2C_IFACE;
atecc608_i2c_config.atcai2c.baud = ATCA_HAL_ATECC608A_I2C_FREQUENCY;
atecc608_i2c_config.atcai2c.bus = ATCA_HAL_ATECC608A_I2C_BUS_PINS;
atecc608_i2c_config.atcai2c.slave_address = ATCA_HAL_ATECC608A_I2C_ADDRESS;
atecc608_i2c_config.devtype = ATECC608A;
atecc608_i2c_config.rx_retries = ATCA_HAL_ATECC608A_I2C_RX_RETRIES;
atecc608_i2c_config.wake_delay = ATCA_HAL_ATECC608A_I2C_WAKEUP_DELAY;
if( atcab_init( &atecc608_i2c_config ) != ATCA_SUCCESS )
{
return SECURE_ELEMENT_ERROR;
}
if( atcab_read_devEUI( SeNvmCtx.DevEui ) != ATCA_SUCCESS )
{
return SECURE_ELEMENT_ERROR;
}
if( atcab_read_joinEUI( SeNvmCtx.JoinEui ) != ATCA_SUCCESS )
{
return SECURE_ELEMENT_ERROR;
}
// Assign callback
if( seNvmCtxChanged != 0 )
{
SeNvmCtxChanged = seNvmCtxChanged;
}
else
{
SeNvmCtxChanged = DummyCB;
}
return SECURE_ELEMENT_SUCCESS;
}
SecureElementStatus_t SecureElementRestoreNvmCtx( void* seNvmCtx )
{
// Restore nvm context
if( seNvmCtx != 0 )
{
memcpy1( ( uint8_t* ) &SeNvmCtx, ( uint8_t* ) seNvmCtx, sizeof( SeNvmCtx ) );
return SECURE_ELEMENT_SUCCESS;
}
else
{
return SECURE_ELEMENT_ERROR_NPE;
}
}
void* SecureElementGetNvmCtx( size_t* seNvmCtxSize )
{
*seNvmCtxSize = sizeof( SeNvmCtx );
return &SeNvmCtx;
}
SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
{
// No key setting for HW SE, can only derive keys
return SECURE_ELEMENT_SUCCESS;
}
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;
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;
}
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;
}
Key_t* pItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &pItem );
if( retval == SECURE_ELEMENT_SUCCESS )
{
uint8_t block = 0;
while( size != 0 )
{
atcab_aes_encrypt( pItem->KeySlotNumber, pItem->KeyBlockIndex, &buffer[block], &encBuffer[block] );
block = block + 16;
size = size - 16;
}
}
return retval;
}
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
KeyIdentifier_t targetKeyID )
{
if( input == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
// Source key slot is the LSB and target key slot is the MSB
uint16_t source_target_ids = 0;
Key_t* source_key;
Key_t* target_key;
ATCA_STATUS status = ATCA_SUCCESS;
// 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( ( rootKeyID == APP_KEY ) || ( rootKeyID == MC_ROOT_KEY ) || ( rootKeyID == MC_KE_KEY ) )
{
// Allow the stack to move forward as these rootkeys dont exist inside SE.
return SECURE_ELEMENT_SUCCESS;
}
if( GetKeyByID( rootKeyID, &source_key ) != SECURE_ELEMENT_SUCCESS )
{
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
if( GetKeyByID( targetKeyID, &target_key ) != SECURE_ELEMENT_SUCCESS )
{
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
source_target_ids = target_key->KeySlotNumber << 8;
source_target_ids += source_key->KeySlotNumber;
uint32_t detail = source_key->KeyBlockIndex;
status = atcab_kdf( KDF_MODE_ALG_AES | KDF_MODE_SOURCE_SLOT | KDF_MODE_TARGET_SLOT, source_target_ids, detail,
input, NULL, NULL );
if( status == ATCA_SUCCESS )
{
return SECURE_ELEMENT_SUCCESS;
}
else
{
return SECURE_ELEMENT_ERROR;
}
}
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;
if( joinReqType != JOIN_REQ )
{
encKeyID = J_S_ENC_KEY;
}
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
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 = ATECC608ASeHalGetRandomNumber( );
return SECURE_ELEMENT_SUCCESS;
}
SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
{
if( devEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvmCtx.DevEui, devEui, SE_EUI_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetDevEui( void )
{
return SeNvmCtx.DevEui;
}
SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
{
if( joinEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvmCtx.JoinEui, joinEui, SE_EUI_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetJoinEui( void )
{
return SeNvmCtx.JoinEui;
}
SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
{
if( pin == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvmCtx.Pin, pin, SE_PIN_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetPin( void )
{
return SeNvmCtx.Pin;
}

View File

@@ -0,0 +1,250 @@
/*!
* \file se-identity.h
*
* \brief Secure Element identity and keys
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#ifndef __SOFT_SE_IDENTITY_H__
#define __SOFT_SE_IDENTITY_H__
#ifdef __cplusplus
extern "C" {
#endif
/*!
******************************************************************************
********************************** WARNING ***********************************
******************************************************************************
The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
versions of the specification.
Thus it has been decided to use the 1.1.x keys and EUI name definitions.
The below table shows the names equivalence between versions:
+---------------------+-------------------------+
| 1.0.x | 1.1.x |
+=====================+=========================+
| LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
+---------------------+-------------------------+
| LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
+---------------------+-------------------------+
| LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
+---------------------+-------------------------+
| LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
+---------------------+-------------------------+
| LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
+---------------------+-------------------------+
******************************************************************************
******************************************************************************
******************************************************************************
*/
/*!
* Secure-element pin
*/
#define SECURE_ELEMENT_PIN \
{ \
0x00, 0x00, 0x00, 0x00 \
}
/*!
* When set to 1 DevAdd is LORAWAN_DEVICE_ADDRESS
* When set to 0 DevAdd is automatically generated using a pseudo random generator
*/
#define STATIC_DEVICE_ADDRESS 0
/*!
* Device address on the network (big endian)
*
* \remark In this application the value is automatically generated using
* a pseudo random generator seeded with a value derived from
* BoardUniqueId value if LORAWAN_DEVICE_ADDRESS is set to 0
*/
#define LORAWAN_DEVICE_ADDRESS ( uint32_t ) 0x00000000
/*
* =============================================================================
* BELOW LINES SHOULDN'T BE MODIFIED
* =============================================================================
*/
/*!
* ATECC608A predefined key slots setup
*/
#define TNGLORA_DEV_EUI_SLOT 10U
#define TNGLORA_JOIN_EUI_SLOT 9U
#define TNGLORA_APP_KEY_SLOT 0U
#define TNGLORA_NWK_KEY_SLOT 0U
#define TNGLORA_S_NWK_S_INT_KEY_SLOT 4U
#define TNGLORA_F_NWK_S_INT_KEY_SLOT 5U
#define TNGLORA_J_S_INT_KEY_SLOT 6U
#define TNGLORA_J_S_ENC_KEY_SLOT 7U
#define TNGLORA_APP_S_KEY_SLOT 2U
#define TNGLORA_NWK_S_ENC_KEY_SLOT 3U
#define TNGLORA_MC_APP_S_KEY_0_SLOT 11U
#define TNGLORA_MC_NWK_S_KEY_0_SLOT 12U
#define TNGLORA_APP_KEY_BLOCK_INDEX 1U
#define TNGLORA_REMAINING_KEYS_BLOCK_INDEX 0U
#define ATECC608A_SE_KEY_LIST \
{ \
{ \
/*! \
* Application root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
*/ \
.KeyID = APP_KEY, \
.KeySlotNumber = TNGLORA_APP_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_APP_KEY_BLOCK_INDEX, \
}, \
{ \
/*! \
* Network root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
*/ \
.KeyID = NWK_KEY, \
.KeySlotNumber = TNGLORA_APP_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_APP_KEY_BLOCK_INDEX, \
}, \
{ \
/*! \
* Join session integrity key (Dynamically updated) \
* WARNING: NOT USED FOR 1.0.x DEVICES \
*/ \
.KeyID = J_S_INT_KEY, \
.KeySlotNumber = TNGLORA_J_S_INT_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Join session encryption key (Dynamically updated) \
* WARNING: NOT USED FOR 1.0.x DEVICES \
*/ \
.KeyID = J_S_ENC_KEY, \
.KeySlotNumber = TNGLORA_J_S_ENC_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Forwarding Network session integrity key \
* WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
*/ \
.KeyID = F_NWK_S_INT_KEY, \
.KeySlotNumber = TNGLORA_F_NWK_S_INT_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Serving Network session integrity key \
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
*/ \
.KeyID = S_NWK_S_INT_KEY, \
.KeySlotNumber = TNGLORA_S_NWK_S_INT_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Network session encryption key \
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
*/ \
.KeyID = NWK_S_ENC_KEY, \
.KeySlotNumber = TNGLORA_NWK_S_ENC_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Application session key \
*/ \
.KeyID = APP_S_KEY, \
.KeySlotNumber = TNGLORA_APP_S_KEY_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Multicast root key (Dynamically updated) \
* WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
* TODO: Add support \
*/ \
.KeyID = MC_ROOT_KEY, \
.KeySlotNumber = 0, \
.KeyBlockIndex = 0, \
}, \
{ \
/*! \
* Multicast key encryption key (Dynamically updated) \
* WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
* TODO: Add support \
*/ \
.KeyID = MC_KE_KEY, \
.KeySlotNumber = 0, \
.KeyBlockIndex = 0, \
}, \
{ \
/*! \
* Multicast group #0 root key (Dynamically updated) \
* WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
* TODO: Add support \
*/ \
.KeyID = MC_KEY_0, \
.KeySlotNumber = 0, \
.KeyBlockIndex = 0, \
}, \
{ \
/*! \
* Multicast group #0 application session key (Dynamically updated) \
*/ \
.KeyID = MC_APP_S_KEY_0, \
.KeySlotNumber = TNGLORA_MC_APP_S_KEY_0_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* Multicast group #0 network session key (Dynamically updated) \
*/ \
.KeyID = MC_NWK_S_KEY_0, \
.KeySlotNumber = TNGLORA_MC_NWK_S_KEY_0_SLOT, \
.KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
}, \
{ \
/*! \
* All zeros key. (ClassB usage)(constant) \
* WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
* TODO: Add support \
* SE should provide a slot for SLOT_RAND_ZERO_KEY. \
* .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
* 0x00, 0x00 } \
*/ \
.KeyID = SLOT_RAND_ZERO_KEY, \
.KeySlotNumber = 0, \
.KeyBlockIndex = 0, \
}, \
},
#ifdef __cplusplus
}
#endif
#endif // __SOFT_SE_IDENTITY_H__

View File

@@ -23,6 +23,11 @@
#ifndef __GPIO_IOE_H__
#define __GPIO_IOE_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include "gpio.h"
@@ -95,4 +100,8 @@ uint32_t GpioIoeRead( Gpio_t *obj );
*/
void GpioIoeInterruptHandler( void );
#ifdef __cplusplus
}
#endif
#endif // __GPIO_IOE_H__

View File

@@ -0,0 +1,39 @@
/*!
* \file soft-se-hal.h
*
* \brief Secure Element hardware abstraction layer implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#include "board.h"
#include "radio.h"
#include "lr1110-se-hal.h"
void LR1110SeHalGetUniqueId( uint8_t *id )
{
BoardGetUniqueId( id );
}
uint32_t LR1110SeHalGetRandomNumber( void )
{
return Radio.Random( );
}

View File

@@ -0,0 +1,56 @@
/*!
* \file lr1110-se-hal.h
*
* \brief Secure Element hardware abstraction layer
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#ifndef __LR1110_SE_HAL_H__
#define __LR1110_SE_HAL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/*!
* \brief Get a 64 bits unique ID
*
* \param [IN] id Pointer to an array that will contain the Unique ID
*/
void LR1110SeHalGetUniqueId( uint8_t *id );
/*!
* \brief Get a random number
*
* \remark The number SHALL NOT be generated using a pseudo random number
* generator
* \retval number 32 bit random value
*/
uint32_t LR1110SeHalGetRandomNumber( void );
#ifdef __cplusplus
}
#endif
#endif // __LR1110_SE_HAL_H__

View File

@@ -0,0 +1,506 @@
/*!
* \file lr1110-se.c
*
* \brief LR1110 Secure Element hardware implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2019-2019 Semtech
*
* \endcode
*
* \authors Semtech WSP Applications Team
*/
#include <stdlib.h>
#include <stdint.h>
#include "lr1110.h"
#include "lr1110_system.h"
#include "lr1110_crypto_engine.h"
#include "secure-element.h"
#include "se-identity.h"
#include "lr1110-se-hal.h"
/*!
* Number of supported crypto keys
*/
#define NUM_OF_KEYS 23
/*
* CMAC/AES Message Integrity Code (MIC) Block B0 size
*/
#define MIC_BLOCK_BX_SIZE 16
/*
* Maximum size of the message that can be handled by the crypto operations
*/
#define CRYPTO_MAXMESSAGE_SIZE 256
/*
* Maximum size of the buffer for crypto operations
*/
#define CRYPTO_BUFFER_SIZE CRYPTO_MAXMESSAGE_SIZE + MIC_BLOCK_BX_SIZE
/*!
* Secure-element LoRaWAN identity local storage.
*/
typedef struct sSecureElementNvCtx
{
/*
* DevEUI storage
*/
uint8_t DevEui[SE_EUI_SIZE];
/*
* Join EUI storage
*/
uint8_t JoinEui[SE_EUI_SIZE];
/*
* PIN of the LR1110
*/
uint8_t Pin[SE_PIN_SIZE];
} SecureElementNvCtx_t;
static SecureElementNvCtx_t SeContext = {
/*!
* 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,
/*!
* Secure-element pin (big endian)
*/
.Pin = SECURE_ELEMENT_PIN,
};
static SecureElementNvmEvent SeNvmCtxChanged;
/*!
* LR1110 radio context
*/
extern lr1110_t LR1110;
/*!
* Converts key ids from SecureElement to LR1110
*
* \param [IN] key_id SecureElement key id to be converted
*
* \retval key_id Converted LR1110 key id
*/
static lr1110_crypto_keys_idx_t convert_key_id_from_se_to_lr1110( KeyIdentifier_t key_id );
/*!
* Dummy callback in case if the user provides NULL function pointer
*/
static void DummyCB( void )
{
return;
}
SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
{
lr1110_crypto_status_t status = LR1110_CRYPTO_STATUS_ERROR;
// Assign callback
if( seNvmCtxChanged != 0 )
{
SeNvmCtxChanged = seNvmCtxChanged;
}
else
{
SeNvmCtxChanged = DummyCB;
}
lr1110_crypto_restore_from_flash( &LR1110, &status );
#if defined( SECURE_ELEMENT_PRE_PROVISIONED )
// Read LR1110 pre-provisioned identity
lr1110_system_read_uid( &LR1110, SeContext.DevEui );
lr1110_system_read_join_eui( &LR1110, SeContext.JoinEui );
lr1110_system_read_pin( &LR1110, SeContext.Pin );
#else
#if( STATIC_DEVICE_EUI == 0 )
// Get a DevEUI from MCU unique ID
LR1110SeHalGetUniqueId( SeContext.DevEui );
#endif
#endif
SeNvmCtxChanged( );
return ( SecureElementStatus_t ) status;
}
SecureElementStatus_t SecureElementRestoreNvmCtx( void* seNvmCtx )
{
lr1110_crypto_status_t status = LR1110_CRYPTO_STATUS_ERROR;
if( seNvmCtx == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
// Restore lr1110 crypto context
lr1110_crypto_restore_from_flash( &LR1110, &status );
// Restore nvm context
memcpy1( ( uint8_t* ) &SeContext, ( uint8_t* ) seNvmCtx, sizeof( SeContext ) );
return ( SecureElementStatus_t ) status;
}
void* SecureElementGetNvmCtx( size_t* seNvmCtxSize )
{
*seNvmCtxSize = sizeof( SeContext );
return &SeContext;
}
SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
{
if( key == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
{ // Decrypt the key if its a Mckey
lr1110_crypto_derive_and_store_key( &LR1110, ( lr1110_crypto_status_t* ) &status,
convert_key_id_from_se_to_lr1110( MC_KE_KEY ),
convert_key_id_from_se_to_lr1110( keyID ), key );
if( status == SECURE_ELEMENT_SUCCESS )
{
lr1110_crypto_store_to_flash( &LR1110, ( lr1110_crypto_status_t* ) &status );
}
return status;
}
else
{
lr1110_crypto_set_key( &LR1110, ( lr1110_crypto_status_t* ) &status, convert_key_id_from_se_to_lr1110( keyID ),
key );
if( status == SECURE_ELEMENT_SUCCESS )
{
lr1110_crypto_store_to_flash( &LR1110, ( lr1110_crypto_status_t* ) &status );
}
return status;
}
}
SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
KeyIdentifier_t keyID, uint32_t* cmac )
{
SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
uint16_t localSize = size;
uint8_t* localbuffer = buffer;
if( micBxBuffer != NULL )
{
uint8_t micBuff[CRYPTO_BUFFER_SIZE];
memset1( micBuff, 0, CRYPTO_BUFFER_SIZE );
memcpy1( micBuff, micBxBuffer, MIC_BLOCK_BX_SIZE );
memcpy1( ( micBuff + MIC_BLOCK_BX_SIZE ), buffer, size );
localSize += MIC_BLOCK_BX_SIZE;
localbuffer = micBuff;
}
lr1110_crypto_compute_aes_cmac( &LR1110, ( lr1110_crypto_status_t* ) &status,
convert_key_id_from_se_to_lr1110( keyID ), localbuffer, localSize,
( uint8_t* ) cmac );
return status;
}
SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac,
KeyIdentifier_t keyID )
{
SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
if( buffer == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
lr1110_crypto_verify_aes_cmac( &LR1110, ( lr1110_crypto_status_t* ) &status,
convert_key_id_from_se_to_lr1110( keyID ), buffer, size,
( uint8_t* ) &expectedCmac );
return status;
}
SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
uint8_t* encBuffer )
{
SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
if( ( buffer == NULL ) || ( encBuffer == NULL ) )
{
return SECURE_ELEMENT_ERROR_NPE;
}
lr1110_crypto_aes_encrypt_01( &LR1110, ( lr1110_crypto_status_t* ) &status,
convert_key_id_from_se_to_lr1110( keyID ), buffer, size, encBuffer );
return status;
}
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
KeyIdentifier_t targetKeyID )
{
SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
if( input == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
lr1110_crypto_derive_and_store_key( &LR1110, ( lr1110_crypto_status_t* ) &status,
convert_key_id_from_se_to_lr1110( rootKeyID ),
convert_key_id_from_se_to_lr1110( targetKeyID ), input );
lr1110_crypto_store_to_flash( &LR1110, ( lr1110_crypto_status_t* ) &status );
return status;
}
SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
uint16_t devNonce, uint8_t* encJoinAccept,
uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
uint8_t* versionMinor )
{
SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
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;
if( joinReqType != JOIN_REQ )
{
encKeyID = J_S_ENC_KEY;
}
// - 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)]
// Try first to process LoRaWAN 1.0.x JoinAccept
uint8_t micHeader10[1] = { 0x20 };
// cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList |
// CFListType)
lr1110_crypto_process_join_accept(
&LR1110, ( lr1110_crypto_status_t* ) &status, convert_key_id_from_se_to_lr1110( encKeyID ),
convert_key_id_from_se_to_lr1110( NWK_KEY ), ( lr1110_crypto_lorawan_version_t ) 0, micHeader10,
encJoinAccept + 1, encJoinAcceptSize - 1, decJoinAccept + 1 );
if( status == SECURE_ELEMENT_SUCCESS )
{
*versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
if( *versionMinor == 0 )
{
// Network server is operating according to LoRaWAN 1.0.x
return SECURE_ELEMENT_SUCCESS;
}
}
#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
// 1.0.x trial failed. Trying to process LoRaWAN 1.1.x JoinAccept
uint8_t micHeader11[JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
uint16_t bufItr = 0;
// cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr |
// DLSettings | RxDelay | CFList | CFListType)
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;
micHeader11[bufItr++] = 0x20;
lr1110_crypto_process_join_accept(
&LR1110, ( lr1110_crypto_status_t* ) &status, convert_key_id_from_se_to_lr1110( encKeyID ),
convert_key_id_from_se_to_lr1110( J_S_INT_KEY ), ( lr1110_crypto_lorawan_version_t ) 1, micHeader11,
encJoinAccept + 1, encJoinAcceptSize - 1, decJoinAccept + 1 );
if( status == SECURE_ELEMENT_SUCCESS )
{
*versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
if( *versionMinor == 1 )
{
// Network server is operating according to LoRaWAN 1.1.x
return SECURE_ELEMENT_SUCCESS;
}
}
#endif
return status;
}
SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum )
{
if( randomNum == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
*randomNum = LR1110SeHalGetRandomNumber( );
return SECURE_ELEMENT_SUCCESS;
}
SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
{
if( devEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeContext.DevEui, devEui, SE_EUI_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetDevEui( void )
{
return SeContext.DevEui;
}
SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
{
if( joinEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeContext.JoinEui, joinEui, SE_EUI_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetJoinEui( void )
{
return SeContext.JoinEui;
}
SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
{
if( pin == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeContext.Pin, pin, SE_PIN_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetPin( void )
{
return SeContext.Pin;
}
static lr1110_crypto_keys_idx_t convert_key_id_from_se_to_lr1110( KeyIdentifier_t key_id )
{
lr1110_crypto_keys_idx_t id = LR1110_CRYPTO_KEYS_IDX_GP0;
switch( key_id )
{
case APP_KEY:
id = LR1110_CRYPTO_KEYS_IDX_APP_KEY;
break;
case NWK_KEY:
id = LR1110_CRYPTO_KEYS_IDX_NWK_KEY;
break;
case J_S_INT_KEY:
id = LR1110_CRYPTO_KEYS_IDX_J_S_INT_KEY;
break;
case J_S_ENC_KEY:
id = LR1110_CRYPTO_KEYS_IDX_J_S_ENC_KEY;
break;
case F_NWK_S_INT_KEY:
id = LR1110_CRYPTO_KEYS_IDX_F_NWK_S_INT_KEY;
break;
case S_NWK_S_INT_KEY:
id = LR1110_CRYPTO_KEYS_IDX_S_NWK_S_INT_KEY;
break;
case NWK_S_ENC_KEY:
id = LR1110_CRYPTO_KEYS_IDX_NWK_S_ENC_KEY;
break;
case APP_S_KEY:
id = LR1110_CRYPTO_KEYS_IDX_APP_S_KEY;
break;
case MC_ROOT_KEY:
id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_5;
break;
case MC_KE_KEY:
id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_4;
break;
case MC_KEY_0:
id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_0;
break;
case MC_APP_S_KEY_0:
id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_0;
break;
case MC_NWK_S_KEY_0:
id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_0;
break;
case MC_KEY_1:
id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_1;
break;
case MC_APP_S_KEY_1:
id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_1;
break;
case MC_NWK_S_KEY_1:
id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_1;
break;
case MC_KEY_2:
id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_2;
break;
case MC_APP_S_KEY_2:
id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_2;
break;
case MC_NWK_S_KEY_2:
id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_2;
break;
case MC_KEY_3:
id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_3;
break;
case MC_APP_S_KEY_3:
id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_3;
break;
case MC_NWK_S_KEY_3:
id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_3;
break;
case SLOT_RAND_ZERO_KEY:
id = LR1110_CRYPTO_KEYS_IDX_GP0;
break;
default:
id = LR1110_CRYPTO_KEYS_IDX_GP1;
break;
}
return id;
}

View File

@@ -0,0 +1,102 @@
/*!
* \file se-identity.h
*
* \brief Secure Element identity and keys
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#ifndef __SOFT_SE_IDENTITY_H__
#define __SOFT_SE_IDENTITY_H__
#ifdef __cplusplus
extern "C" {
#endif
/*!
******************************************************************************
********************************** WARNING ***********************************
******************************************************************************
The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
versions of the specification.
Thus it has been decided to use the 1.1.x keys and EUI name definitions.
The below table shows the names equivalence between versions:
+---------------------+-------------------------+
| 1.0.x | 1.1.x |
+=====================+=========================+
| LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
+---------------------+-------------------------+
| LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
+---------------------+-------------------------+
| LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
+---------------------+-------------------------+
| LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
+---------------------+-------------------------+
| LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
+---------------------+-------------------------+
******************************************************************************
******************************************************************************
******************************************************************************
*/
/*!
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
* When set to 0 DevEui is automatically set with a value provided by MCU platform
*/
#define STATIC_DEVICE_EUI 0
/*!
* end-device IEEE EUI (big endian)
*/
#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
/*!
* App/Join server IEEE EUI (big endian)
*/
#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
/*!
* Secure-element pin
*/
#define SECURE_ELEMENT_PIN { 0x00, 0x00, 0x00, 0x00 }
/*!
* When set to 1 DevAddr is LORAWAN_DEVICE_ADDRESS
* When set to 0 DevAddr is automatically set with a value provided by a pseudo
* random generator seeded with a value provided by the MCU platform
*/
#define STATIC_DEVICE_ADDRESS 0
/*!
* Device address on the network (big endian)
*/
#define LORAWAN_DEVICE_ADDRESS ( uint32_t )0x00000000
#ifdef __cplusplus
}
#endif
#endif // __SOFT_SE_IDENTITY_H__

View File

@@ -43,21 +43,21 @@ uint8_t MAG3110Init( void )
MAG3110Read( MAG3110_ID, &regVal );
if( regVal != 0xC4 ) // Fixed Device ID Number = 0xC4
{
return LORA_FAIL;
return FAIL;
}
MAG3110Reset( );
}
return LORA_SUCCESS;
return SUCCESS;
}
uint8_t MAG3110Reset( void )
{
if( MAG3110Write( 0x11, 0x10 ) == LORA_SUCCESS ) // Reset the MAG3110 with CTRL_REG2
if( MAG3110Write( 0x11, 0x10 ) == SUCCESS ) // Reset the MAG3110 with CTRL_REG2
{
return LORA_SUCCESS;
return SUCCESS;
}
return LORA_FAIL;
return FAIL;
}
uint8_t MAG3110Write( uint8_t addr, uint8_t data )

View File

@@ -23,6 +23,11 @@
#ifndef __MAG3110_H__
#define __MAG3110_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
/*!
@@ -38,14 +43,14 @@
/*!
* \brief Initializes the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Init( void );
/*!
* \brief Resets the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Reset( void );
@@ -54,7 +59,7 @@ uint8_t MAG3110Reset( void );
*
* \param [IN]: addr
* \param [IN]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Write( uint8_t addr, uint8_t data );
@@ -64,7 +69,7 @@ uint8_t MAG3110Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -73,7 +78,7 @@ uint8_t MAG3110WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Read( uint8_t addr, uint8_t *data );
@@ -83,7 +88,7 @@ uint8_t MAG3110Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -101,4 +106,8 @@ void MAG3110SetDeviceAddr( uint8_t addr );
*/
uint8_t MAG3110GetDeviceAddr( void );
#ifdef __cplusplus
}
#endif
#endif // __MAG3110_H__

View File

@@ -36,7 +36,7 @@ static bool MMA8451Initialized = false;
*
* \param [IN]: addr
* \param [IN]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Write( uint8_t addr, uint8_t data );
@@ -46,7 +46,7 @@ uint8_t MMA8451Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -55,7 +55,7 @@ uint8_t MMA8451WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Read( uint8_t addr, uint8_t *data );
@@ -65,7 +65,7 @@ uint8_t MMA8451Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -96,7 +96,7 @@ uint8_t MMA8451Init( void )
MMA8451Read( MMA8451_ID, &regVal );
if( regVal != 0x1A ) // Fixed Device ID Number = 0x1A
{
return LORA_FAIL;
return FAIL;
}
MMA8451Reset( );
@@ -105,17 +105,17 @@ uint8_t MMA8451Init( void )
MMA8451Write( MMA8451_CTRL_REG3, 0x01 );
MMA8451OrientDetect( );
}
return LORA_SUCCESS;
return SUCCESS;
}
uint8_t MMA8451Reset( )
{
if( MMA8451Write( 0x2B, 0x40 ) == LORA_SUCCESS ) // Reset the MMA8451 with CTRL_REG2
if( MMA8451Write( 0x2B, 0x40 ) == SUCCESS ) // Reset the MMA8451 with CTRL_REG2
{
return LORA_SUCCESS;
return SUCCESS;
}
return LORA_FAIL;
return FAIL;
}
uint8_t MMA8451Write( uint8_t addr, uint8_t data )

View File

@@ -23,6 +23,11 @@
#ifndef __MMA8451_H__
#define __MMA8451_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
/*
@@ -58,14 +63,14 @@
/*!
* \brief Initializes the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Init( void );
/*!
* \brief Resets the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Reset( void );
@@ -83,4 +88,8 @@ void MMA8451OrientDetect( void );
*/
uint8_t MMA8451GetOrientation( void );
#ifdef __cplusplus
}
#endif
#endif // __MMA8451_H__

View File

@@ -52,7 +52,7 @@ typedef enum
*
* \param [IN]: addr
* \param [IN]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Write( uint8_t addr, uint8_t data );
@@ -62,7 +62,7 @@ uint8_t MPL3115Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -71,7 +71,7 @@ uint8_t MPL3115WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Read( uint8_t addr, uint8_t *data );
@@ -81,7 +81,7 @@ uint8_t MPL3115Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -141,24 +141,24 @@ uint8_t MPL3115Init( void )
MPL3115Read( MPL3115_ID, &regVal );
if( regVal != 0xC4 )
{
return LORA_FAIL;
return FAIL;
}
MPL3115Write( PT_DATA_CFG_REG, DREM | PDEFE | TDEFE ); // Enable data ready flags for pressure and temperature )
MPL3115Write( CTRL_REG1, ALT | OS_32 | SBYB ); // Set sensor to active state with oversampling ratio 128 (512 ms between samples)
MPL3115Initialized = true;
}
return LORA_SUCCESS;
return SUCCESS;
}
uint8_t MPL3115Reset( void )
{
// Reset all registers to POR values
if( MPL3115Write( CTRL_REG1, RST ) == LORA_SUCCESS )
if( MPL3115Write( CTRL_REG1, RST ) == SUCCESS )
{
return LORA_SUCCESS;
return SUCCESS;
}
return LORA_FAIL;
return FAIL;
}
uint8_t MPL3115Write( uint8_t addr, uint8_t data )

View File

@@ -23,6 +23,11 @@
#ifndef __MPL3115_H__
#define __MPL3115_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
/*
@@ -123,14 +128,14 @@
/*!
* \brief Initializes the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Init( void );
/*!
* \brief Resets the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Reset( void );
@@ -155,4 +160,8 @@ float MPL3115ReadPressure( void );
*/
float MPL3115ReadTemperature( void );
#ifdef __cplusplus
}
#endif
#endif // __MPL3115_H__

View File

@@ -43,7 +43,7 @@ bool PAM7QGetGpsData( uint8_t *nmeaString, uint8_t *nmeaStringSize, uint16_t nme
status = PAM7QReadBuffer( MESSAGE_SIZE_1, nmeaString, 2 );
if( status == LORA_SUCCESS )
if( status == SUCCESS )
{
// build a 16bit number
pendingBytes = ( uint16_t )( ( nmeaString[0] << 8 ) | nmeaString[1] );
@@ -63,7 +63,7 @@ bool PAM7QGetGpsData( uint8_t *nmeaString, uint8_t *nmeaStringSize, uint16_t nme
status = PAM7QReadBuffer( PAYLOAD, nmeaString, pendingBytes );
// make sure the string is terminated
if( status == LORA_SUCCESS )
if( status == SUCCESS )
{
nmeaString[pendingBytes] = 0x00;

View File

@@ -23,6 +23,11 @@
#ifndef __PAM7Q_H__
#define __PAM7Q_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdbool.h>
#include <stdint.h>
@@ -55,5 +60,9 @@ void GpsMcuOnPpsSignal( void );
#define PAYLOAD 0xFF
#ifdef __cplusplus
}
#endif
#endif // __PAM7Q_H__

View File

@@ -31,6 +31,10 @@
#ifndef AES_H
#define AES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#if 1
@@ -159,4 +163,8 @@ void aes_decrypt_256( const uint8_t in[N_BLOCK],
uint8_t o_key[2 * N_BLOCK] );
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -4,150 +4,151 @@ Copyright (C) 2009 Lander Casado, Philippas Tsigas
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
a copy of this software and associated documentation files
(the "Software"), to deal with the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
the following conditions:
Redistributions of source code must retain the above copyright notice,
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers. Redistributions in
binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimers in the documentation and/or
conditions and the following disclaimers in the documentation and/or
other materials provided with the distribution.
In no event shall the authors or copyright holders be liable for any special,
incidental, indirect or consequential damages of any kind, or any damages
whatsoever resulting from loss of use, data or profits, whether or not
advised of the possibility of damage, and on any theory of liability,
incidental, indirect or consequential damages of any kind, or any damages
whatsoever resulting from loss of use, data or profits, whether or not
advised of the possibility of damage, and on any theory of liability,
arising out of or in connection with the use or performance of this software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS WITH THE SOFTWARE
*****************************************************************************/
//#include <sys/param.h>
//#include <sys/systm.h>
#include <stdint.h>
#include "aes.h"
#include "cmac.h"
#include "utilities.h"
#define LSHIFT(v, r) do { \
int32_t i; \
for (i = 0; i < 15; i++) \
(r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \
(r)[15] = (v)[15] << 1; \
} while (0)
#define XOR(v, r) do { \
int32_t i; \
for (i = 0; i < 16; i++) \
{ \
(r)[i] = (r)[i] ^ (v)[i]; \
} \
} while (0) \
#define LSHIFT( v, r ) \
do \
{ \
int32_t i; \
for( i = 0; i < 15; i++ ) \
( r )[i] = ( v )[i] << 1 | ( v )[i + 1] >> 7; \
( r )[15] = ( v )[15] << 1; \
} while( 0 )
#define XOR( v, r ) \
do \
{ \
int32_t i; \
for( i = 0; i < 16; i++ ) \
{ \
( r )[i] = ( r )[i] ^ ( v )[i]; \
} \
} while( 0 )
void AES_CMAC_Init(AES_CMAC_CTX *ctx)
void AES_CMAC_Init( AES_CMAC_CTX* ctx )
{
memset1(ctx->X, 0, sizeof ctx->X);
ctx->M_n = 0;
memset1(ctx->rijndael.ksch, '\0', 240);
}
void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH])
{
//rijndael_set_key_enc_only(&ctx->rijndael, key, 128);
aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael);
}
void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len)
{
uint32_t mlen;
uint8_t in[16];
if (ctx->M_n > 0) {
mlen = MIN(16 - ctx->M_n, len);
memcpy1(ctx->M_last + ctx->M_n, data, mlen);
ctx->M_n += mlen;
if (ctx->M_n < 16 || len == mlen)
return;
XOR(ctx->M_last, ctx->X);
//rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
aes_encrypt( ctx->X, ctx->X, &ctx->rijndael);
data += mlen;
len -= mlen;
}
while (len > 16) { /* not last block */
XOR(data, ctx->X);
//rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
aes_encrypt( in, in, &ctx->rijndael);
memcpy1(&ctx->X[0], in, 16);
data += 16;
len -= 16;
}
/* potential last block, save it */
memcpy1(ctx->M_last, data, len);
ctx->M_n = len;
}
void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx)
{
uint8_t K[16];
uint8_t in[16];
/* generate subkey K1 */
memset1(K, '\0', 16);
//rijndael_encrypt(&ctx->rijndael, K, K);
aes_encrypt( K, K, &ctx->rijndael);
if (K[0] & 0x80) {
LSHIFT(K, K);
K[15] ^= 0x87;
} else
LSHIFT(K, K);
if (ctx->M_n == 16) {
/* last block was a complete block */
XOR(K, ctx->M_last);
} else {
/* generate subkey K2 */
if (K[0] & 0x80) {
LSHIFT(K, K);
K[15] ^= 0x87;
} else
LSHIFT(K, K);
/* padding(M_last) */
ctx->M_last[ctx->M_n] = 0x80;
while (++ctx->M_n < 16)
ctx->M_last[ctx->M_n] = 0;
XOR(K, ctx->M_last);
}
XOR(ctx->M_last, ctx->X);
//rijndael_encrypt(&ctx->rijndael, ctx->X, digest);
memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
aes_encrypt(in, digest, &ctx->rijndael);
memset1(K, 0, sizeof K);
memset1( ctx->X, 0, sizeof ctx->X );
ctx->M_n = 0;
memset1( ctx->rijndael.ksch, '\0', 240 );
}
void AES_CMAC_SetKey( AES_CMAC_CTX* ctx, const uint8_t key[AES_CMAC_KEY_LENGTH] )
{
aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael );
}
void AES_CMAC_Update( AES_CMAC_CTX* ctx, const uint8_t* data, uint32_t len )
{
uint32_t mlen;
uint8_t in[16];
if( ctx->M_n > 0 )
{
mlen = MIN( 16 - ctx->M_n, len );
memcpy1( ctx->M_last + ctx->M_n, data, mlen );
ctx->M_n += mlen;
if( ctx->M_n < 16 || len == mlen )
return;
XOR( ctx->M_last, ctx->X );
memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
aes_encrypt( in, in, &ctx->rijndael );
memcpy1( &ctx->X[0], in, 16 );
data += mlen;
len -= mlen;
}
while( len > 16 )
{ /* not last block */
XOR( data, ctx->X );
memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
aes_encrypt( in, in, &ctx->rijndael );
memcpy1( &ctx->X[0], in, 16 );
data += 16;
len -= 16;
}
/* potential last block, save it */
memcpy1( ctx->M_last, data, len );
ctx->M_n = len;
}
void AES_CMAC_Final( uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX* ctx )
{
uint8_t K[16];
uint8_t in[16];
/* generate subkey K1 */
memset1( K, '\0', 16 );
aes_encrypt( K, K, &ctx->rijndael );
if( K[0] & 0x80 )
{
LSHIFT( K, K );
K[15] ^= 0x87;
}
else
LSHIFT( K, K );
if( ctx->M_n == 16 )
{
/* last block was a complete block */
XOR( K, ctx->M_last );
}
else
{
/* generate subkey K2 */
if( K[0] & 0x80 )
{
LSHIFT( K, K );
K[15] ^= 0x87;
}
else
LSHIFT( K, K );
/* padding(M_last) */
ctx->M_last[ctx->M_n] = 0x80;
while( ++ctx->M_n < 16 )
ctx->M_last[ctx->M_n] = 0;
XOR( K, ctx->M_last );
}
XOR( ctx->M_last, ctx->X );
memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
aes_encrypt( in, digest, &ctx->rijndael );
memset1( K, 0, sizeof K );
}

View File

@@ -36,6 +36,10 @@ DEALINGS WITH THE SOFTWARE
#ifndef _CMAC_H_
#define _CMAC_H_
#ifdef __cplusplus
extern "C"
#endif
#include "aes.h"
#define AES_CMAC_KEY_LENGTH 16
@@ -59,5 +63,9 @@ void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *
// __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH)));
//__END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _CMAC_H_ */

View File

@@ -0,0 +1,297 @@
/*!
* \file se-identity.h
*
* \brief Secure Element identity and keys
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#ifndef __SOFT_SE_IDENTITY_H__
#define __SOFT_SE_IDENTITY_H__
#ifdef __cplusplus
extern "C" {
#endif
/*!
******************************************************************************
********************************** WARNING ***********************************
******************************************************************************
The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
versions of the specification.
Thus it has been decided to use the 1.1.x keys and EUI name definitions.
The below table shows the names equivalence between versions:
+---------------------+-------------------------+
| 1.0.x | 1.1.x |
+=====================+=========================+
| LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
+---------------------+-------------------------+
| LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
+---------------------+-------------------------+
| LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
+---------------------+-------------------------+
| LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
+---------------------+-------------------------+
| LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
+---------------------+-------------------------+
| LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
+---------------------+-------------------------+
******************************************************************************
******************************************************************************
******************************************************************************
*/
/*!
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
* When set to 0 DevEui is automatically set with a value provided by MCU platform
*/
#define STATIC_DEVICE_EUI 0
/*!
* end-device IEEE EUI (big endian)
*/
#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
/*!
* App/Join server IEEE EUI (big endian)
*/
#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
/*!
* Secure-element pin
*/
#define SECURE_ELEMENT_PIN { 0x00, 0x00, 0x00, 0x00 }
/*!
* When set to 1 DevAddr is LORAWAN_DEVICE_ADDRESS
* When set to 0 DevAddr is automatically set with a value provided by a pseudo
* random generator seeded with a value provided by the MCU platform
*/
#define STATIC_DEVICE_ADDRESS 0
/*!
* Device address on the network (big endian)
*/
#define LORAWAN_DEVICE_ADDRESS ( uint32_t )0x00000000
#define SOFT_SE_KEY_LIST \
{ \
{ \
/*! \
* Application root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
*/ \
.KeyID = APP_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
0x3C }, \
}, \
{ \
/*! \
* Network root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
*/ \
.KeyID = NWK_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
0x3C }, \
}, \
{ \
/*! \
* Join session integrity key (Dynamically updated) \
* WARNING: NOT USED FOR 1.0.x DEVICES \
*/ \
.KeyID = J_S_INT_KEY, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Join session encryption key (Dynamically updated) \
* WARNING: NOT USED FOR 1.0.x DEVICES \
*/ \
.KeyID = J_S_ENC_KEY, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Forwarding Network session integrity key \
* WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
*/ \
.KeyID = F_NWK_S_INT_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
0x3C }, \
}, \
{ \
/*! \
* Serving Network session integrity key \
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
*/ \
.KeyID = S_NWK_S_INT_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
0x3C }, \
}, \
{ \
/*! \
* Network session encryption key \
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
*/ \
.KeyID = NWK_S_ENC_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
0x3C }, \
}, \
{ \
/*! \
* Application session key \
*/ \
.KeyID = APP_S_KEY, \
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
0x3C }, \
}, \
{ \
/*! \
* Multicast root key (Dynamically updated) \
*/ \
.KeyID = MC_ROOT_KEY, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast key encryption key (Dynamically updated) \
*/ \
.KeyID = MC_KE_KEY, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #0 root key (Dynamically updated) \
*/ \
.KeyID = MC_KEY_0, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #0 application session key (Dynamically updated) \
*/ \
.KeyID = MC_APP_S_KEY_0, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #0 network session key (Dynamically updated) \
*/ \
.KeyID = MC_NWK_S_KEY_0, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #1 root key (Dynamically updated) \
*/ \
.KeyID = MC_KEY_1, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #1 application session key (Dynamically updated) \
*/ \
.KeyID = MC_APP_S_KEY_1, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #1 network session key (Dynamically updated) \
*/ \
.KeyID = MC_NWK_S_KEY_1, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #2 root key (Dynamically updated) \
*/ \
.KeyID = MC_KEY_2, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #2 application session key (Dynamically updated) \
*/ \
.KeyID = MC_APP_S_KEY_2, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #2 network session key (Dynamically updated) \
*/ \
.KeyID = MC_NWK_S_KEY_2, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #3 root key (Dynamically updated) \
*/ \
.KeyID = MC_KEY_3, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #3 application session key (Dynamically updated) \
*/ \
.KeyID = MC_APP_S_KEY_3, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* Multicast group #3 network session key (Dynamically updated) \
*/ \
.KeyID = MC_NWK_S_KEY_3, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
{ \
/*! \
* All zeros key. (ClassB usage)(constant) \
*/ \
.KeyID = SLOT_RAND_ZERO_KEY, \
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00 }, \
}, \
},
#ifdef __cplusplus
}
#endif
#endif // __SOFT_SE_IDENTITY_H__

View File

@@ -0,0 +1,39 @@
/*!
* \file soft-se-hal.h
*
* \brief Secure Element hardware abstraction layer implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#include "board.h"
#include "radio.h"
#include "soft-se-hal.h"
void SoftSeHalGetUniqueId( uint8_t *id )
{
BoardGetUniqueId( id );
}
uint32_t SoftSeHalGetRandomNumber( void )
{
return Radio.Random( );
}

View File

@@ -0,0 +1,56 @@
/*!
* \file soft-se-hal.h
*
* \brief Secure Element hardware abstraction layer
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2020 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
*/
#ifndef __SOFT_SE_HAL_H__
#define __SOFT_SE_HAL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/*!
* \brief Get a 64 bits unique ID
*
* \param [IN] id Pointer to an array that will contain the Unique ID
*/
void SoftSeHalGetUniqueId( uint8_t *id );
/*!
* \brief Get a random number
*
* \remark The number SHALL NOT be generated using a pseudo random number
* generator
* \retval number 32 bit random value
*/
uint32_t SoftSeHalGetRandomNumber( void );
#ifdef __cplusplus
}
#endif
#endif // __SOFT_SE_HAL_H__

View File

@@ -1,36 +1,45 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: Secure Element software implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ),
Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
*/
#include "secure-element.h"
/*!
* \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
*
*/
#include <stdlib.h>
#include <stdint.h>
#include "LoRaMacCrypto.h"
#include "utilities.h"
#include "aes.h"
#include "cmac.h"
#include "radio.h"
#define NUM_OF_KEYS 22
#define KEY_SIZE 16
#include "LoRaMacHeaderTypes.h"
#include "secure-element.h"
#include "se-identity.h"
#include "soft-se-hal.h"
/*!
* Number of supported crypto keys
*/
#define NUM_OF_KEYS 23
/*!
* Identifier value pair type for Keys
@@ -44,7 +53,7 @@ typedef struct sKey
/*
* Key value
*/
uint8_t KeyValue[KEY_SIZE];
uint8_t KeyValue[SE_KEY_SIZE];
} Key_t;
/*
@@ -53,25 +62,49 @@ typedef struct sKey
typedef struct sSecureElementNvCtx
{
/*
* AES computation context variable
* DevEUI storage
*/
aes_context AesContext;
uint8_t DevEui[SE_EUI_SIZE];
/*
* CMAC computation context variable
* Join EUI storage
*/
AES_CMAC_CTX AesCmacCtx[1];
uint8_t JoinEui[SE_EUI_SIZE];
/*
* Pin storage
*/
uint8_t Pin[SE_PIN_SIZE];
/*
* Key List
*/
Key_t KeyList[NUM_OF_KEYS];
}SecureElementNvCtx_t;
} SecureElementNvCtx_t;
/*
* Module context
/*!
* Secure element context
*/
static SecureElementNvCtx_t SeNvmCtx;
static SecureElementNvCtx_t SeNvmCtx = {
/*!
* 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,
/*!
* Secure-element pin (big endian)
*/
.Pin = SECURE_ELEMENT_PIN,
/*!
* LoRaWAN key list
*/
.KeyList = SOFT_SE_KEY_LIST
};
static EventNvmCtxChanged SeNvmCtxChanged;
static SecureElementNvmEvent SeNvmCtxChanged;
/*
* Local functions
@@ -80,13 +113,11 @@ static EventNvmCtxChanged SeNvmCtxChanged;
/*
* Gets key item from key list.
*
* cmac = aes128_cmac(keyID, B0 | msg)
*
* \param[IN] keyID - Key identifier
* \param[OUT] keyItem - Key item reference
* \retval - Status of the operation
*/
SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
static SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
{
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
@@ -99,44 +130,6 @@ SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
/*
* Computes a CMAC
*
* \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
*/
SecureElementStatus_t ComputeCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac )
{
if( buffer == NULL || cmac == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
uint8_t Cmac[16];
AES_CMAC_Init( SeNvmCtx.AesCmacCtx );
Key_t* keyItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
if( retval == SECURE_ELEMENT_SUCCESS )
{
AES_CMAC_SetKey( SeNvmCtx.AesCmacCtx, keyItem->KeyValue );
AES_CMAC_Update( SeNvmCtx.AesCmacCtx, buffer, size );
AES_CMAC_Final( Cmac, SeNvmCtx.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] );
}
return retval;
}
/*
* Dummy callback in case if the user provides NULL function pointer
*/
@@ -145,37 +138,61 @@ static void DummyCB( void )
return;
}
/*
* 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;
}
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] );
}
return retval;
}
/*
* API functions
*/
SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged )
SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
{
// Initialize with defaults
uint8_t itr = 0;
SeNvmCtx.KeyList[itr++].KeyID = APP_KEY;
SeNvmCtx.KeyList[itr++].KeyID = NWK_KEY;
SeNvmCtx.KeyList[itr++].KeyID = J_S_INT_KEY;
SeNvmCtx.KeyList[itr++].KeyID = J_S_ENC_KEY;
SeNvmCtx.KeyList[itr++].KeyID = F_NWK_S_INT_KEY;
SeNvmCtx.KeyList[itr++].KeyID = S_NWK_S_INT_KEY;
SeNvmCtx.KeyList[itr++].KeyID = NWK_S_ENC_KEY;
SeNvmCtx.KeyList[itr++].KeyID = APP_S_KEY;
SeNvmCtx.KeyList[itr++].KeyID = MC_KE_KEY;
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_0;
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_0;
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_0;
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_1;
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_1;
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_1;
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_2;
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_2;
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_2;
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_3;
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_3;
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_3;
SeNvmCtx.KeyList[itr++].KeyID = SLOT_RAND_ZERO_KEY;
// Assign callback
if( seNvmCtxChanged != 0 )
{
@@ -186,6 +203,15 @@ SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged )
SeNvmCtxChanged = DummyCB;
}
#if !defined( SECURE_ELEMENT_PRE_PROVISIONED )
#if( STATIC_DEVICE_EUI == 0 )
// Get a DevEUI from MCU unique ID
SoftSeHalGetUniqueId( SeNvmCtx.DevEui );
#endif
#endif
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
@@ -215,26 +241,26 @@ SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
{
return SECURE_ELEMENT_ERROR_NPE;
}
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
if( SeNvmCtx.KeyList[i].KeyID == keyID )
{
if( LORAMAC_CRYPTO_MULITCAST_KEYS < SeNvmCtx.KeyList[i].KeyID )
{ // Decrypt the key if its a Mulitcast key
uint8_t decryptedKey[16] = { 0 };
if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
{ // 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 );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
}
memcpy1( SeNvmCtx.KeyList[i].KeyValue, decryptedKey, SE_KEY_SIZE );
SeNvmCtxChanged( );
return retval;
}
else
{
memcpy1( SeNvmCtx.KeyList[i].KeyValue, key, KEY_SIZE );
memcpy1( SeNvmCtx.KeyList[i].KeyValue, key, SE_KEY_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
@@ -244,28 +270,29 @@ SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac )
SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
KeyIdentifier_t keyID, uint32_t* cmac )
{
if( keyID >= LORAMAC_CRYPTO_MULITCAST_KEYS )
if( keyID >= LORAMAC_CRYPTO_MULTICAST_KEYS )
{
//Never accept multicast key identifier for cmac computation
// Never accept multicast key identifier for cmac computation
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
return ComputeCmac( buffer, size, keyID, cmac );
return ComputeCmac( micBxBuffer, buffer, size, keyID, cmac );
}
SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac, KeyIdentifier_t keyID )
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;
uint32_t compCmac = 0;
retval = ComputeCmac( buffer, size, keyID, &compCmac );
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
uint32_t compCmac = 0;
retval = ComputeCmac( NULL, buffer, size, keyID, &compCmac );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
@@ -279,7 +306,8 @@ SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size
return retval;
}
SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint8_t* encBuffer )
SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
uint8_t* encBuffer )
{
if( buffer == NULL || encBuffer == NULL )
{
@@ -292,55 +320,48 @@ SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, K
return SECURE_ELEMENT_ERROR_BUF_SIZE;
}
memset1( SeNvmCtx.AesContext.ksch, '\0', 240 );
aes_context aesContext;
memset1( aesContext.ksch, '\0', 240 );
Key_t* pItem;
Key_t* pItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &pItem );
if( retval == SECURE_ELEMENT_SUCCESS )
{
aes_set_key( pItem->KeyValue, 16, &SeNvmCtx.AesContext );
aes_set_key( pItem->KeyValue, 16, &aesContext );
uint8_t block = 0;
while( size != 0 )
{
aes_encrypt( &buffer[block], &encBuffer[block], &SeNvmCtx.AesContext );
aes_encrypt( &buffer[block], &encBuffer[block], &aesContext );
block = block + 16;
size = size - 16;
size = size - 16;
}
}
return retval;
}
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID, KeyIdentifier_t targetKeyID )
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
KeyIdentifier_t targetKeyID )
{
if( input == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
uint8_t key[16] = { 0 };
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
uint8_t key[16] = { 0 };
// In case of MC_KE_KEY, prevent other keys than NwkKey or AppKey for LoRaWAN 1.1 or later
// In case of MC_KE_KEY, only McRootKey can be used as root key
if( targetKeyID == MC_KE_KEY )
{
if( ( ( rootKeyID == APP_KEY ) && ( version.Fields.Minor == 0 ) ) || ( rootKeyID == NWK_KEY ) )
if( rootKeyID != MC_ROOT_KEY )
{
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
}
// In case of McKEKey derivation, the parameter input is concatenated: nonce | DevEUI | pad16
// where nonce SHALL be greater than 15
uint16_t nonce = input[0];
nonce |= ( ( uint16_t ) input[1] << 8 );
if( ( targetKeyID == MC_KE_KEY ) && ( nonce < 16 ) )
{
return retval;
}
// Derive key
retval = SecureElementAesEncrypt( input, 16, rootKeyID, key );
if( retval != SECURE_ELEMENT_SUCCESS )
@@ -358,12 +379,159 @@ SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t
return SECURE_ELEMENT_SUCCESS;
}
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;
if( joinReqType != JOIN_REQ )
{
encKeyID = J_S_ENC_KEY;
}
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
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( );
*randomNum = SoftSeHalGetRandomNumber( );
return SECURE_ELEMENT_SUCCESS;
}
SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
{
if( devEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvmCtx.DevEui, devEui, SE_EUI_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetDevEui( void )
{
return SeNvmCtx.DevEui;
}
SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
{
if( joinEui == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvmCtx.JoinEui, joinEui, SE_EUI_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetJoinEui( void )
{
return SeNvmCtx.JoinEui;
}
SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
{
if( pin == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
memcpy1( SeNvmCtx.Pin, pin, SE_PIN_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
uint8_t* SecureElementGetPin( void )
{
return SeNvmCtx.Pin;
}

View File

@@ -44,14 +44,14 @@ void SX1509Init( void )
uint8_t SX1509Reset( )
{
if( SX1509Write( RegReset, 0x12 ) == LORA_SUCCESS )
if( SX1509Write( RegReset, 0x12 ) == SUCCESS )
{
if( SX1509Write( RegReset, 0x34 ) == LORA_SUCCESS )
if( SX1509Write( RegReset, 0x34 ) == SUCCESS )
{
return LORA_SUCCESS;
return SUCCESS;
}
}
return LORA_FAIL;
return FAIL;
}
uint8_t SX1509Write( uint8_t addr, uint8_t data )

View File

@@ -23,6 +23,11 @@
#ifndef __SX1509_H__
#define __SX1509_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#define SX1509_I2C_ADDRESS 0x3E
@@ -156,7 +161,7 @@ void SX1509Init( void );
/*!
* \brief Resets the device
*
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509Reset( void );
@@ -165,7 +170,7 @@ uint8_t SX1509Reset( void );
*
* \param [IN]: addr
* \param [IN]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509Write( uint8_t addr, uint8_t data );
@@ -175,7 +180,7 @@ uint8_t SX1509Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -184,7 +189,7 @@ uint8_t SX1509WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509Read( uint8_t addr, uint8_t *data );
@@ -194,7 +199,7 @@ uint8_t SX1509Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
* \retval status [LORA_SUCCESS, LORA_FAIL]
* \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -212,4 +217,8 @@ void SX1509SetDeviceAddr( uint8_t addr );
*/
uint8_t SX1509GetDeviceAddr( void );
#ifdef __cplusplus
}
#endif
#endif // __SX1509_H__

View File

@@ -44,21 +44,21 @@ uint8_t SX9500Init( void )
SX9500Read( SX9500_REG_PROXCTRL0, &regVal );
if( regVal != 0x0F )
{
return LORA_FAIL;
return FAIL;
}
SX9500Reset( );
}
return LORA_SUCCESS;
return SUCCESS;
}
uint8_t SX9500Reset( )
{
if( SX9500Write( SX9500_REG_RESET, SX9500_RESET_CMD ) == LORA_SUCCESS )
if( SX9500Write( SX9500_REG_RESET, SX9500_RESET_CMD ) == SUCCESS )
{
return LORA_SUCCESS;
return SUCCESS;
}
return LORA_FAIL;
return FAIL;
}
uint8_t SX9500Write( uint8_t addr, uint8_t data )

View File

@@ -23,6 +23,11 @@
#ifndef __SX9500_H__
#define __SX9500_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#define SX9500_I2C_ADDRESS 0x28
@@ -118,4 +123,8 @@ uint8_t SX9500GetDeviceAddr( void );
*/
void SX9500LockUntilDetection( void );
#ifdef __cplusplus
}
#endif
#endif // __SX1509_H__