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:
@@ -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)
|
||||
|
@@ -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
|
@@ -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;
|
||||
}
|
@@ -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__
|
@@ -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;
|
||||
}
|
@@ -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__
|
@@ -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__
|
||||
|
@@ -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( );
|
||||
}
|
@@ -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__
|
@@ -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;
|
||||
}
|
@@ -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__
|
@@ -43,21 +43,21 @@ uint8_t MAG3110Init( void )
|
||||
MAG3110Read( MAG3110_ID, ®Val );
|
||||
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 )
|
||||
|
@@ -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__
|
||||
|
@@ -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, ®Val );
|
||||
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 )
|
||||
|
@@ -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__
|
||||
|
@@ -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, ®Val );
|
||||
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 )
|
||||
|
@@ -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__
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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__
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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 );
|
||||
}
|
||||
|
@@ -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_ */
|
||||
|
||||
|
@@ -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__
|
@@ -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( );
|
||||
}
|
@@ -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__
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 )
|
||||
|
@@ -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__
|
||||
|
@@ -44,21 +44,21 @@ uint8_t SX9500Init( void )
|
||||
SX9500Read( SX9500_REG_PROXCTRL0, ®Val );
|
||||
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 )
|
||||
|
@@ -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__
|
||||
|
Reference in New Issue
Block a user