Skip to content

Adds ATECC608 secure element support for Espressif esp32 #173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,15 @@ build/

# ESP-IDF config files
sdkconfig*
dependencies.lock

# Gate build directories
/build_pc_linux
/build_nxp_mimxrt1060
/build_st_b-l4s5i-iot01a
/build_st_b-l475e-iot01a
/build_st_stm32h745i-disco

# VSCode settings
**/settings.json
**/c_cpp_properties.json
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "libs/azure-iot-middleware-freertos"]
path = libs/azure-iot-middleware-freertos
url = https://github.com/Azure/azure-iot-middleware-freertos.git

51 changes: 51 additions & 0 deletions demos/projects/ESPRESSIF/esp32/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "ESP32-Debug",
"type": "cppdbg",
"request": "launch",
"MIMode": "gdb",
"miDebuggerPath": "${command:espIdf.getXtensaGdb}",
"program": "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
"windows": {
"program": "${workspaceFolder}\\build\\${command:espIdf.getProjectName}.elf"
},
"cwd": "${workspaceFolder}",
"environment": [{ "name": "PATH", "value": "${config:idf.customExtraPaths}" }],
"setupCommands": [
{ "text": "target remote :3333" },
{ "text": "set remote hardware-watchpoint-limit 2"},
{ "text": "mon reset halt" },
{ "text": "thb app_main" },
{ "text": "flushregs" }
],
"externalConsole": false,
"logging": {
"engineLogging": false
}
},
{
"name": "ESP32-Attach",
"type": "cppdbg",
"request": "launch",
"MIMode": "gdb",
"miDebuggerPath": "${command:espIdf.getXtensaGdb}",
"program": "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
"windows": {
"program": "${workspaceFolder}\\build\\${command:espIdf.getProjectName}.elf"
},
"cwd": "${workspaceFolder}",
"environment": [{ "name": "PATH", "value": "${config:idf.customExtraPaths}" }],
"setupCommands": [
{ "text": "target remote :3333" },
{ "text": "set remote hardware-watchpoint-limit 2"},
{ "text": "flushregs" }
],
"externalConsole": false,
"logging": {
"engineLogging": false
}
}
]
}
15 changes: 15 additions & 0 deletions demos/projects/ESPRESSIF/esp32/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,18 @@ cmake_minimum_required(VERSION 3.13)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(azure_iot_freertos_esp32)

if(${CONFIG_ESP_TLS_USE_SECURE_ELEMENT})
if(${CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN} AND ${CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY})
include(FetchContent)
if(NOT esp-cryptoauthlib_POPULATED)
FetchContent_Populate(esp-cryptoauthlib
GIT_REPOSITORY https://github.com/espressif/esp-cryptoauthlib
GIT_TAG 985ea960f83f67f66881e2dae57097e2a07b92a0
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/components/esp-cryptoauthlib"
)
endif()
else()
message(FATAL_ERROR "To use the Microchip ATECC608 secure element, refer to the README_ATECC608_Support.md !!")
endif()
endif()
56 changes: 56 additions & 0 deletions demos/projects/ESPRESSIF/esp32/README_ATECC608_Support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Support for Microchip ATECC608 Secure Element For ESP32 Plaforms

## Pre-conditions

- Ensure that the project is clean. Use `rm -rf build/` to ensure a clean slate.
- Ensure that you are using the default sdkconfig. Use `rm sdkconfig` just to be sure.
- Ensure internet connectivity to enable successful download of `esp-cryptoauthlib` component

## Steps to add Microchip ATECC608 Secure Element support

Perform the below steps **before doing any application level configuration like Wi-Fi settings, Azure Samples configuration, etc.**

### Step 1 - Kconfig configuration

- Open kconfig menu using `idf.py menuconfig`
- Navigate: `Component Config` --> `ESP-TLS`
- Enable: `Use Secure Element (ATECC608A) with ESP-TLS`
![ESP-TLS Configuration](images/Step1_ESPTLS_Config.png)

- Navigate: `Component Config` --> `mbedTLS`
- Enable: `Enable hardware ECDSA Sign acceleration when using ATECC608A`
- Enable: `Enable hardware ECDSA Verify acceleration when using ATECC608A`
![mbedTLS Configuration](images/Step1_mbedTLS_Config.png)

- Save configuration and exit

### Step 2 - Run menuconfig again

- Open kconfig menu again using `idf.py menuconfig` - observe the output, esp-cryptoauthlib should be downloaded this time since secure element support is now enabled.
![esp-cryptoauthlib downloaded](images/Step2_esp-cryptoauthlib_downloaded.png)

- Exit the kconfig menu - we are ready to try a build now
- Observe that `esp-cryptoauthlib` is located inside `components/` folder and should be picked up by Ninja during the test build
![esp-cryptoauthlib location](images/Step2_esp-cryptoauthlib_inside_components.png)

### Step 3 - Try a build

- Try a build using `idf.py build` - observe the output, esp-cryptoauthlib should be built along with relevant mbedTLS support

**If build is successful**, you are now ready to make application level configurations like Wi-Fi settings, Azure Samples settings, ATECC608 pin settings, etc.

**If build fails**, ensure that above steps are followed correctly. Before re-attempting the process,
- delete the build directory using `rm -rf build/`
- delete the sdkconfig file by using `rm sdkconfig`.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we need more information and steps how to provision the ATECC as well as how to configure the application. I think we can move forward with this PR and add more documentation later.

## FAQ

**Q:** Why do I need to open the menuconfig a second time after enabling secure element support?

**A:** If this step is not done, although the esp-cryptoauthlib gets downloaded correctly during the build attempt, the build fails due to the way mbedTLS component is configured at build time. Running the menuconfig command immediately after enabling secure element support does the necessary linkages that can be picked up at the first build attempt.
<br />

**Q:** What is the right way to remove ATECC608 support?

**A:** To completely remove ATECC608 support, it is best to start with a clean slate to avoid any dependency issues. Ddelete the build folder (`rm -rf build/`), delete the sdkconfig (`rm sdkconfig`) and delete the esp-cryptoauthlib from components/ folder.
<br />
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,181 @@
/* TLS includes. */
#include "esp_transport_ssl.h"

#include "demo_config.h"

/* For using the ATECC608 secure element if support is configured */
#ifdef democonfigUSE_HSM
#include "cryptoauthlib.h"
#endif

static const char *TAG = "tls_freertos";

#ifdef democonfigUSE_HSM

#if defined(CONFIG_ATECC608A_TNG)
/**
* @brief [Trust&GO] Dynamically generate and write the registration ID as a
* string into the passed pointer
*
* @param[in,out] ppcRegistrationId Input: Pointer to a null pointer,
* Output: Pointer to a null-terminated string
* @param[in] pucHsmData Pointer to a buffer holding data to be passed
* (if any) to help generate the Registration ID
* @param[in] ulHsmDataLength Length of the buffer passed in the
* second parameter
*
* @return 0 if everything went through correctly
*/
static uint32_t getRegistrationIdFromTNG( char **ppcRegistrationId,\
uint8_t *pucHsmData,\
uint32_t ulHsmDataLength ) {

/* We don't check for NULL-ness of the input or the
ability to talk to the HSM - the getRegistrationId(...)
function does that already
*/

*ppcRegistrationId = malloc(21);
if(*ppcRegistrationId == NULL) {
return 3;
}
sprintf(*ppcRegistrationId,"sn%02X%02X%02X%02X%02X%02X%02X%02X%02X",pucHsmData[0],pucHsmData[1],\
pucHsmData[2],pucHsmData[3],pucHsmData[4],pucHsmData[5],pucHsmData[6],pucHsmData[7],pucHsmData[8]);
*(*ppcRegistrationId + 20) = '\0';

return 0;
}

#elif defined(CONFIG_ATECC608A_TFLEX)
/**
* @brief [TrustFLEX] Dynamically generate and write the registration ID as a
* string into the passed pointer
*
* @param[in,out] ppcRegistrationId Input: Pointer to a null pointer,
* Output: Pointer to a null-terminated string
* @param[in] pucHsmData Pointer to a buffer holding data to be passed
* (if any) to help generate the Registration ID
* @param[in] ulHsmDataLength Length of the buffer passed in the
* second parameter
*
* @return 0 if everything went through correctly
*/
static uint32_t getRegistrationIdFromTFLX( char **ppcRegistrationId,\
uint8_t *pucHsmData,\
uint32_t ulHsmDataLength ) {

/* We don't check for NULL-ness of the input or the
ability to talk to the HSM - the getRegistrationId(...)
function does that already
*/
/* TODO: Replace the below with your own implementation - the provided
implementation is applicable to TFLX-PROTO devices only
*/
*ppcRegistrationId = malloc(21);
if(*ppcRegistrationId == NULL) {
return 3;
}
sprintf(*ppcRegistrationId,"sn%02X%02X%02X%02X%02X%02X%02X%02X%02X",pucHsmData[0],pucHsmData[1],\
pucHsmData[2],pucHsmData[3],pucHsmData[4],pucHsmData[5],pucHsmData[6],pucHsmData[7],pucHsmData[8]);
*(*ppcRegistrationId + 20) = '\0';

return 0;
}

#elif defined(CONFIG_ATECC608A_TCUSTOM)
/**
* @brief [TrustCUSTOM] Dynamically generate and write the registration ID as a
* string into the passed pointer
*
* @param[in,out] ppcRegistrationId Input: Pointer to a null pointer,
* Output: Pointer to a null-terminated string
* @param[in] pucHsmData Pointer to a buffer holding data to be passed
* (if any) to help generate the Registration ID
* @param[in] ulHsmDataLength Length of the buffer passed in the
* second parameter
*
* @return 0 if everything went through correctly
*/
static uint32_t getRegistrationIdFromTCSM( char **ppcRegistrationId,\
uint8_t *pucHsmData,\
uint32_t ulHsmDataLength ) {

/* We don't check for NULL-ness of the input or the
ability to talk to the HSM - the getRegistrationId(...)
function does that already
*/
/* TODO: Replace the below with your own implementation - the provided
implementation is applicable to certs generated using esp-cryptoauth
tool only
*/
*ppcRegistrationId = malloc(19);
if(*ppcRegistrationId == NULL) {
return 3;
}

sprintf(*ppcRegistrationId,"%02X%02X%02X%02X%02X%02X%02X%02X%02X",pucHsmData[0],pucHsmData[1],\
pucHsmData[2],pucHsmData[3],pucHsmData[4],pucHsmData[5],pucHsmData[6],pucHsmData[7],pucHsmData[8]);
*(*ppcRegistrationId + 18) = '\0';
return 0;
}
#endif

/**
* @brief Dynamically generate and write the registration ID as a
* string into the passed pointer
*
* @param[in,out] ppcRegistrationId Input: Pointer to a null pointer,
* Output: Pointer to a null-terminated string
*
* @return 1 if the input is not a pointer to a NULL pointer,
* 2 if we are not able to talk to the HSM
* 3 if something else went wrong (eg: memory allocation failed)
* 0 if everything went through correctly
*/
uint32_t getRegistrationId( char **ppcRegistrationId ) {

if(*ppcRegistrationId != NULL) {
return 1;
}
uint32_t ret = 0;
uint8_t sernum[9];
ATCA_STATUS s;
s = atcab_read_serial_number(sernum);
if(s != ATCA_SUCCESS) {
ESP_LOGE( TAG, "Failed to read serial number from ATECC608" );
return 2;
}

#if defined(CONFIG_ATECC608A_TNG)
ret = getRegistrationIdFromTNG(ppcRegistrationId,sernum,9);
if(ret != 0) {
ESP_LOGE(TAG, "[TNG] Registration ID Gen Error!");
return ret;
}

#elif defined(CONFIG_ATECC608A_TFLEX)
ret = getRegistrationIdFromTFLX(ppcRegistrationId,sernum,9);
if(ret != 0) {
ESP_LOGE(TAG, "[TFLX] Registration ID Gen Error!");
return ret;
}

#elif defined(CONFIG_ATECC608A_TCUSTOM)
ret = getRegistrationIdFromTCSM(ppcRegistrationId,sernum,9);
if(ret != 0) {
ESP_LOGE(TAG, "[TCSM] Registration ID Gen Error!");
return ret;
}

#endif

ESP_LOGI( TAG, "Registration ID is %s", *ppcRegistrationId );
return 0;
}

#endif /* democonfigUSE_HSM */


/**
* @brief Definition of the network context for the transport interface
* implementation that uses mbedTLS and FreeRTOS+TLS sockets.
Expand All @@ -49,7 +224,7 @@ struct NetworkContext
uint32_t ulSendTimeoutMs;
};

static const char *TAG = "tls_freertos";

/*-----------------------------------------------------------*/

TlsTransportStatus_t TLS_Socket_Connect( NetworkContext_t * pNetworkContext,
Expand Down Expand Up @@ -90,6 +265,28 @@ TlsTransportStatus_t TLS_Socket_Connect( NetworkContext_t * pNetworkContext,
{
esp_transport_ssl_set_cert_data_der( pNetworkContext->xTransport, ( const char * ) pNetworkCredentials->pucRootCa, pNetworkCredentials->xRootCaSize );
}
#ifdef democonfigUSE_HSM

esp_transport_ssl_use_secure_element( pNetworkContext->xTransport );

#if defined(CONFIG_ATECC608A_TCUSTOM) || defined(CONFIG_ATECC608A_TFLEX)
/* This is TrustCUSTOM or TrustFLEX chip - the private key will be used from the ATECC608 device slot 0.
We will plug in your custom device certificate here (should be in DER format).
*/
if ( pNetworkCredentials->pucClientCert )
{
esp_transport_ssl_set_client_cert_data_der( pNetworkContext->xTransport, ( const char *) pNetworkCredentials->pucClientCert, pNetworkCredentials->xClientCertSize );
}


#else
/* This is the Trust&GO chip - the private key will be used from ATECC608 device slot 0.
We don't need to add certs to the network context as the esp-tls does that for us using cryptoauthlib API.
*/

#endif

#else

if ( pNetworkCredentials->pucClientCert )
{
Expand All @@ -101,6 +298,8 @@ TlsTransportStatus_t TLS_Socket_Connect( NetworkContext_t * pNetworkContext,
esp_transport_ssl_set_client_key_data_der( pNetworkContext->xTransport, (const char *) pNetworkCredentials->pucPrivateKey, pNetworkCredentials->xPrivateKeySize );
}

#endif

if ( esp_transport_connect( pNetworkContext->xTransport, pHostName, usPort, ulReceiveTimeoutMs ) < 0 )
{
ESP_LOGE( TAG, "Failed establishing TLS connection (esp_transport_connect failed)" );
Expand Down
Loading