Irreversible Examples¶
To provide better orientation, we highlight specific properties of each example, namely:
- Reversibility,
- Model compatibility,
- Level of complexity (🐣 -> 🐤 -> 🐓).
The source code for the examples can be found in the examples/
directory and also within this document inside "Source Code" boxes.
Tip
You can copy the example code using the icon located in the top-right corner of each source code listing.
lt_ex_hw_wallet.c¶
- ⚠️ Irreversible
- ✅ Compatible with the model
- 🐓 Level: Advanced
This example demonstrates how to use configuration objects and different pairing keys to manage access to TROPIC01 features. A hardware wallet device scenario is used as a model for this example.
In this example, you will:
- Understand how the R-config is structured and how permissions are managed using the R-config.
- Learn how the R-config can be modified using the libtropic API:
lt_r_config_erase()
: L3 command to erase the R-config.lt_write_whole_R_config()
: helper function to write the whole R-config with an instance ofstruct lt_config_t
.lt_read_whole_R_config()
: helper function to read the whole R-config into an instance ofstruct lt_config_t
.Note
If you need to modify only one entry in the R-config, you can use
lt_r_config_write()
orlt_r_config_read()
.
- Learn how to manage pairing keys:
lt_pairing_key_write()
: L3 command to write a pairing key.lt_pairing_key_invalidate()
: L3 command to invalidate a pairing key.
- Learn how to work with keys based on elliptic curves (ECC) on TROPIC01:
lt_ecc_key_store()
: L3 command to store an ECC key.lt_ecc_key_read()
: L3 command to read an ECC key.lt_ecc_key_generate()
: L3 command to generate an ECC key.
- Learn how to use EDDSA to sign messages and verify signatures.
- Learn how to use a monotonic counter.
Source code
/**
* @file lt_ex_hw_wallet.c
* @brief Example usage of TROPIC01 chip in a generic *hardware wallet* project.
* @author Tropic Square s.r.o.
*
* @license For the license see file LICENSE.txt file in the root directory of this source tree.
*/
#include <inttypes.h>
#include "libtropic.h"
#include "libtropic_common.h"
#include "libtropic_examples.h"
#include "libtropic_logging.h"
#include "string.h"
/** @brief Message to send with Ping L3 command. */
#define PING_MSG "Ping message for TROPIC01"
/** @brief Size of the Ping message, including '\0'. */
#define PING_MSG_SIZE 26
/** @brief Attestation key for ECC slot 0. */
uint8_t attestation_key[TR01_CURVE_PRIVKEY_LEN]
= {0x22, 0x57, 0xa8, 0x2f, 0x85, 0x8f, 0x13, 0x32, 0xfa, 0x0f, 0xf6, 0x0c, 0x76, 0x29, 0x42, 0x70,
0xa9, 0x58, 0x9d, 0xfd, 0x47, 0xa5, 0x23, 0x78, 0x18, 0x4d, 0x2d, 0x38, 0xf0, 0xa7, 0xc4, 0x01};
/**
* @brief Creates an HW wallet example config from the virgin R config.
*
* @param r_config R config to modify
*/
static void create_example_r_config(struct lt_config_t *r_config)
{
//-------CFG_START_UP------------------------------------
// Enable MBIST and RNGTEST (DIS in their names stands for disable, so writing 0 enables them)
r_config->obj[TR01_CFG_START_UP_IDX]
&= ~(BOOTLOADER_CO_CFG_START_UP_MBIST_DIS_MASK | BOOTLOADER_CO_CFG_START_UP_RNGTEST_DIS_MASK);
//-------CFG_SENSORS-------------------------------------
// Enable all sensors (DIS in their names stands for disable, so writing 0 enables them)
r_config->obj[TR01_CFG_SENSORS_IDX] &= ~(
BOOTLOADER_CO_CFG_SENSORS_PTRNG0_TEST_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_PTRNG1_TEST_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_OSCILLATOR_MON_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_SHIELD_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_VOLTAGE_MON_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_GLITCH_DET_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_TEMP_SENS_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_LASER_DET_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_EM_PULSE_DET_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_CPU_ALERT_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_PIN_VERIF_BIT_FLIP_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_SCB_BIT_FLIP_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_CPB_BIT_FLIP_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_ECC_BIT_FLIP_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_R_MEM_BIT_FLIP_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_EKDB_BIT_FLIP_DIS_MASK
| BOOTLOADER_CO_CFG_SENSORS_I_MEM_BIT_FLIP_DIS_MASK | BOOTLOADER_CO_CFG_SENSORS_PLATFORM_BIT_FLIP_DIS_MASK);
//-------CFG_DEBUG---------------------------------------
// Disable FW logging
r_config->obj[TR01_CFG_DEBUG_IDX] &= ~BOOTLOADER_CO_CFG_DEBUG_FW_LOG_EN_MASK;
//-------TR01_CFG_GPO-----------------------------------------
// Keep at reset value
//-------TR01_CFG_SLEEP_MODE----------------------------------
// Enable sleep mode
r_config->obj[TR01_CFG_SLEEP_MODE_IDX] |= APPLICATION_CO_CFG_SLEEP_MODE_SLEEP_MODE_EN_MASK;
//------- TR01_CFG_UAP_PAIRING_KEY_WRITE ---------------------
// Disable writing pairing keys for all slots
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_WRITE_IDX] &= ~LT_TO_PAIRING_KEY_SH0(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_WRITE_IDX] &= ~LT_TO_PAIRING_KEY_SH1(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_WRITE_IDX] &= ~LT_TO_PAIRING_KEY_SH2(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_WRITE_IDX] &= ~LT_TO_PAIRING_KEY_SH3(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_PAIRING_KEY_READ ----------------------
// All sessions can read pairing keys
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_READ_IDX] |= LT_TO_PAIRING_KEY_SH0(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_READ_IDX] |= LT_TO_PAIRING_KEY_SH1(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_READ_IDX] |= LT_TO_PAIRING_KEY_SH2(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_READ_IDX] |= LT_TO_PAIRING_KEY_SH3(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_PAIRING_KEY_INVALIDATE ----------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] &= ~LT_TO_PAIRING_KEY_SH0(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] &= ~LT_TO_PAIRING_KEY_SH1(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] &= ~LT_TO_PAIRING_KEY_SH2(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] &= ~LT_TO_PAIRING_KEY_SH3(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Pairing key SH0PUB can be invalidated only from session with SH0PUB
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] |= LT_TO_PAIRING_KEY_SH0(LT_SESSION_SH0_HAS_ACCESS);
// 3. Pairing keys SH1PUB, SH2PUB and SH3PUB can be invalidated only from session with SH3PUB
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] |= LT_TO_PAIRING_KEY_SH1(LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] |= LT_TO_PAIRING_KEY_SH2(LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_PAIRING_KEY_INVALIDATE_IDX] |= LT_TO_PAIRING_KEY_SH3(LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_R_CONFIG_WRITE_ERASE ------------------
// Keep at reset value, not used currently
//------- TR01_CFG_UAP_R_CONFIG_READ -------------------------
// Keep at reset value, not used currently
//------- TR01_CFG_UAP_I_CONFIG_WRITE ------------------------
// Keep at reset value, not used currently
//------- TR01_CFG_UAP_I_CONFIG_READ -------------------------
// Keep at reset value, not used currently
//------- TR01_CFG_UAP_PING ----------------------------------
// Enable for all pairing keys
r_config->obj[TR01_CFG_UAP_PING_IDX] |= (LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS
| LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_R_MEM_DATA_WRITE ----------------------
// Reset value, not used currently
//------- TR01_CFG_UAP_R_MEM_DATA_READ -----------------------
// Reset value, not used currently
//------- TR01_CFG_UAP_R_MEM_DATA_ERASE ----------------------
// Reset value, not used currently
//------- TR01_CFG_UAP_RANDOM_VALUE_GET ----------------------
// Enable for all pairing keys
r_config->obj[TR01_CFG_UAP_RANDOM_VALUE_GET_IDX] |= (LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS
| LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_ECC_KEY_GENERATE ----------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_ECC_KEY_GENERATE_IDX] &= ~LT_TO_ECC_KEY_SLOT_0_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_GENERATE_IDX] &= ~LT_TO_ECC_KEY_SLOT_8_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_GENERATE_IDX] &= ~LT_TO_ECC_KEY_SLOT_16_23(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_GENERATE_IDX] &= ~LT_TO_ECC_KEY_SLOT_24_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Only session with SH3PUB can generate keys in slots 8-31
r_config->obj[TR01_CFG_UAP_ECC_KEY_GENERATE_IDX]
|= (LT_TO_ECC_KEY_SLOT_8_15(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_ECC_KEY_SLOT_16_23(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_24_31(LT_SESSION_SH3_HAS_ACCESS));
//------- TR01_CFG_UAP_ECC_KEY_STORE -------------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_ECC_KEY_STORE_IDX] &= ~LT_TO_ECC_KEY_SLOT_0_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_STORE_IDX] &= ~LT_TO_ECC_KEY_SLOT_8_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_STORE_IDX] &= ~LT_TO_ECC_KEY_SLOT_16_23(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_STORE_IDX] &= ~LT_TO_ECC_KEY_SLOT_24_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH1PUB can store key into ECC key slot 0-7
r_config->obj[TR01_CFG_UAP_ECC_KEY_STORE_IDX] |= LT_TO_ECC_KEY_SLOT_0_7(LT_SESSION_SH1_HAS_ACCESS);
// 3. Session with SH3PUB can store key into ECC key slot 8-31
r_config->obj[TR01_CFG_UAP_ECC_KEY_STORE_IDX] |= LT_TO_ECC_KEY_SLOT_8_15(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_16_23(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_24_31(LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_ECC_KEY_READ --------------------------
// Enable for all pairing keys
r_config->obj[TR01_CFG_UAP_ECC_KEY_READ_IDX] |= LT_TO_ECC_KEY_SLOT_0_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_READ_IDX] |= LT_TO_ECC_KEY_SLOT_8_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_READ_IDX] |= LT_TO_ECC_KEY_SLOT_16_23(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_READ_IDX] |= LT_TO_ECC_KEY_SLOT_24_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_ECC_KEY_ERASE -------------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_ECC_KEY_ERASE_IDX] &= ~LT_TO_ECC_KEY_SLOT_0_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_ERASE_IDX] &= ~LT_TO_ECC_KEY_SLOT_8_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_ERASE_IDX] &= ~LT_TO_ECC_KEY_SLOT_16_23(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECC_KEY_ERASE_IDX] &= ~LT_TO_ECC_KEY_SLOT_24_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH1PUB can erase ECC key slots 0-7
r_config->obj[TR01_CFG_UAP_ECC_KEY_ERASE_IDX] |= LT_TO_ECC_KEY_SLOT_0_7(LT_SESSION_SH1_HAS_ACCESS);
// 3. Session with SH3PUB can erase ECC key slots 8-31
r_config->obj[TR01_CFG_UAP_ECC_KEY_ERASE_IDX] |= LT_TO_ECC_KEY_SLOT_8_15(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_16_23(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_24_31(LT_SESSION_SH3_HAS_ACCESS);
//------- TR01_CFG_UAP_ECDSA_SIGN ----------------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_ECDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_0_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_8_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_16_23(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_ECDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_24_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH3PUB can sign with all ECC key slots
r_config->obj[TR01_CFG_UAP_ECDSA_SIGN_IDX]
|= (LT_TO_ECC_KEY_SLOT_0_7(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_ECC_KEY_SLOT_8_15(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_16_23(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_24_31(LT_SESSION_SH3_HAS_ACCESS));
//------- TR01_CFG_UAP_EDDSA_SIGN ----------------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_EDDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_0_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_EDDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_8_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_EDDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_16_23(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_EDDSA_SIGN_IDX] &= ~LT_TO_ECC_KEY_SLOT_24_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH3PUB can sign with all ECC key slots
r_config->obj[TR01_CFG_UAP_EDDSA_SIGN_IDX]
|= (LT_TO_ECC_KEY_SLOT_0_7(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_ECC_KEY_SLOT_8_15(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_16_23(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_ECC_KEY_SLOT_24_31(LT_SESSION_SH3_HAS_ACCESS));
//------- TR01_CFG_UAP_MCOUNTER_INIT -------------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_MCOUNTER_INIT_IDX] &= ~LT_TO_MCOUNTER_0_3(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_INIT_IDX] &= ~LT_TO_MCOUNTER_4_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_INIT_IDX] &= ~LT_TO_MCOUNTER_8_11(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_INIT_IDX] &= ~LT_TO_MCOUNTER_12_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH3PUB can init all mcounters
r_config->obj[TR01_CFG_UAP_MCOUNTER_INIT_IDX]
|= (LT_TO_MCOUNTER_0_3(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_MCOUNTER_4_7(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_MCOUNTER_8_11(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_MCOUNTER_12_15(LT_SESSION_SH3_HAS_ACCESS));
//------- TR01_CFG_UAP_MCOUNTER_GET --------------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_MCOUNTER_GET_IDX] &= ~LT_TO_MCOUNTER_0_3(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_GET_IDX] &= ~LT_TO_MCOUNTER_4_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_GET_IDX] &= ~LT_TO_MCOUNTER_8_11(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_GET_IDX] &= ~LT_TO_MCOUNTER_12_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH3PUB can get all mcounters
r_config->obj[TR01_CFG_UAP_MCOUNTER_GET_IDX]
|= (LT_TO_MCOUNTER_0_3(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_MCOUNTER_4_7(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_MCOUNTER_8_11(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_MCOUNTER_12_15(LT_SESSION_SH3_HAS_ACCESS));
//------- TR01_CFG_UAP_MCOUNTER_UPDATE -----------------------
// 1. Disable all, then enable only specific ones
r_config->obj[TR01_CFG_UAP_MCOUNTER_UPDATE_IDX] &= ~LT_TO_MCOUNTER_0_3(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_UPDATE_IDX] &= ~LT_TO_MCOUNTER_4_7(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_UPDATE_IDX] &= ~LT_TO_MCOUNTER_8_11(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MCOUNTER_UPDATE_IDX] &= ~LT_TO_MCOUNTER_12_15(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
// 2. Session with SH3PUB can update all mcounters
r_config->obj[TR01_CFG_UAP_MCOUNTER_UPDATE_IDX]
|= (LT_TO_MCOUNTER_0_3(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_MCOUNTER_4_7(LT_SESSION_SH3_HAS_ACCESS)
| LT_TO_MCOUNTER_8_11(LT_SESSION_SH3_HAS_ACCESS) | LT_TO_MCOUNTER_12_15(LT_SESSION_SH3_HAS_ACCESS));
//------- TR01_CFG_UAP_MAC_AND_DESTROY_ADDR -----------------------
// Enable for all pairing key slots
r_config->obj[TR01_CFG_UAP_MAC_AND_DESTROY_IDX] |= LT_TO_MACANDD_SLOT_0_31(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MAC_AND_DESTROY_IDX] |= LT_TO_MACANDD_SLOT_32_63(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MAC_AND_DESTROY_IDX] |= LT_TO_MACANDD_SLOT_64_95(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
r_config->obj[TR01_CFG_UAP_MAC_AND_DESTROY_IDX] |= LT_TO_MACANDD_SLOT_96_127(
LT_SESSION_SH0_HAS_ACCESS | LT_SESSION_SH1_HAS_ACCESS | LT_SESSION_SH2_HAS_ACCESS | LT_SESSION_SH3_HAS_ACCESS);
}
/**
* @brief Initial session, when chip is powered for the first time during manufacturing.
* This function writes chip's configuration into R config.
*
* @param h Device's handle
* @return 0 if success, -1 otherwise
*/
static int session_initial(lt_handle_t *h)
{
lt_ret_t ret;
struct lt_config_t r_config;
uint8_t *pub_keys[] = {sh0pub, sh1pub, sh2pub, sh3pub};
LT_LOG_INFO("Initializing handle");
ret = lt_init(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Starting Secure Session with key %d", (int)TR01_PAIRING_KEY_SLOT_INDEX_0);
ret = lt_verify_chip_and_start_secure_session(h, sh0priv, sh0pub, TR01_PAIRING_KEY_SLOT_INDEX_0);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to start Secure Session with key %d, ret=%s", (int)TR01_PAIRING_KEY_SLOT_INDEX_0,
lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Reading the whole R config:");
ret = lt_read_whole_R_config(h, &r_config);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to read R config, ret=%s", lt_ret_verbose(ret));
return -1;
}
for (int i = 0; i < LT_CONFIG_OBJ_CNT; i++) {
LT_LOG_INFO("%s: 0x%08" PRIx32, cfg_desc_table[i].desc, r_config.obj[i]);
}
LT_LOG_INFO("Creating an example config from the read R config...");
create_example_r_config(&r_config);
LT_LOG_INFO("Erasing R config in case it is already written...");
ret = lt_r_config_erase(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to erase R config, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Writing the whole R config with the example config...");
ret = lt_write_whole_R_config(h, &r_config);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to write R config, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Reading the whole R config again:");
ret = lt_read_whole_R_config(h, &r_config);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to read R config, ret=%s", lt_ret_verbose(ret));
return -1;
}
for (int i = 0; i < LT_CONFIG_OBJ_CNT; i++) {
LT_LOG_INFO("%s: 0x%08" PRIx32, cfg_desc_table[i].desc, r_config.obj[i]);
}
// Write pairing keys into slots 1,2,3
for (uint8_t i = TR01_PAIRING_KEY_SLOT_INDEX_1; i <= TR01_PAIRING_KEY_SLOT_INDEX_3; i++) {
LT_LOG_INFO("Writing to pairing key slot %" PRIu8 "...", i);
ret = lt_pairing_key_write(h, pub_keys[i], i);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to write pairing key, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
}
LT_LOG_INFO("Invalidating pairing key slot %d...", (int)TR01_PAIRING_KEY_SLOT_INDEX_0);
ret = lt_pairing_key_invalidate(h, TR01_PAIRING_KEY_SLOT_INDEX_0);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to invalidate pairing key slot, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Aborting Secure Session");
ret = lt_session_abort(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to abort Secure Session, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Rebooting TROPIC01 to apply changes...");
ret = lt_reboot(h, TR01_REBOOT);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to reboot, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Deinitializing handle");
ret = lt_deinit(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to deinitialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
return 0;
}
/**
* @brief Session with pairing key slot 0
*
* @param h Device's handle
* @return 0 if success, -1 otherwise
*/
static int session0(lt_handle_t *h)
{
lt_ret_t ret;
LT_LOG_INFO("Initializing handle");
ret = lt_init(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Starting Secure Session with key %d (should fail)", (int)TR01_PAIRING_KEY_SLOT_INDEX_0);
ret = lt_verify_chip_and_start_secure_session(h, sh0priv, sh0pub, TR01_PAIRING_KEY_SLOT_INDEX_0);
if (LT_L2_HSK_ERR != ret) {
LT_LOG_ERROR("Return value is not LT_L2_HSK_ERR, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Deinitializing handle");
ret = lt_deinit(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to deinitialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
return 0;
}
/**
* @brief Session with pairing key slot 1
*
* @param h Device's handle
* @return 0 if success, -1 otherwise
*/
static int session1(lt_handle_t *h)
{
lt_ret_t ret;
LT_LOG_INFO("Initializing handle");
ret = lt_init(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Starting Secure Session with key %d", (int)TR01_PAIRING_KEY_SLOT_INDEX_1);
ret = lt_verify_chip_and_start_secure_session(h, sh1priv, sh1pub, TR01_PAIRING_KEY_SLOT_INDEX_1);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to start Secure Session with key %d, ret=%s", (int)TR01_PAIRING_KEY_SLOT_INDEX_1,
lt_ret_verbose(ret));
return -1;
}
uint8_t recv_buf[PING_MSG_SIZE];
LT_LOG_INFO("Sending Ping command with message:");
LT_LOG_INFO("\t\"%s\"", PING_MSG);
ret = lt_ping(h, (const uint8_t *)PING_MSG, recv_buf, PING_MSG_SIZE);
if (LT_OK != ret) {
LT_LOG_ERROR("Ping command failed, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Message received from TROPIC01:");
LT_LOG_INFO("\t\"%s\"", recv_buf);
LT_LOG_INFO("Storing attestation key into ECC slot %d...", (int)TR01_ECC_SLOT_0);
ret = lt_ecc_key_store(h, TR01_ECC_SLOT_0, TR01_CURVE_ED25519, attestation_key);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to store ECC key to slot %d, ret=%s", (int)TR01_ECC_SLOT_0, lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
uint8_t dummy_key[TR01_SHIPUB_LEN] = {0};
LT_LOG_INFO("Writing all pairing key slots (should fail):");
for (uint8_t i = TR01_PAIRING_KEY_SLOT_INDEX_0; i <= TR01_PAIRING_KEY_SLOT_INDEX_3; i++) {
LT_LOG_INFO("\tWriting pairing key slot %" PRIu8 "...", i);
ret = lt_pairing_key_write(h, dummy_key, i);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\t\tOK");
}
LT_LOG_INFO("Aborting Secure Session");
ret = lt_session_abort(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to abort Secure Session, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Deinitializing handle");
ret = lt_deinit(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to deinitialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
return 0;
}
/**
* @brief Session with pairing key slot 2
*
* @param h Device's handle
* @return 0 if success, -1 otherwise
*/
static int session2(lt_handle_t *h)
{
lt_ret_t ret;
LT_LOG_INFO("Initializing handle");
ret = lt_init(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Starting Secure Session with key %d", (int)TR01_PAIRING_KEY_SLOT_INDEX_2);
ret = lt_verify_chip_and_start_secure_session(h, sh2priv, sh2pub, TR01_PAIRING_KEY_SLOT_INDEX_2);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to start Secure Session with key %d, ret=%s", (int)TR01_PAIRING_KEY_SLOT_INDEX_2,
lt_ret_verbose(ret));
return -1;
}
uint8_t recv_buf[PING_MSG_SIZE];
LT_LOG_INFO("Sending Ping command with message:");
LT_LOG_INFO("\t\"%s\"", PING_MSG);
ret = lt_ping(h, (const uint8_t *)PING_MSG, recv_buf, PING_MSG_SIZE);
if (LT_OK != ret) {
LT_LOG_ERROR("Ping command failed, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Message received from TROPIC01:");
LT_LOG_INFO("\t\"%s\"", recv_buf);
uint8_t dummy_key[TR01_CURVE_PRIVKEY_LEN] = {0};
LT_LOG_INFO("Trying to store key into ECC slot %d (should fail)", (int)TR01_ECC_SLOT_0);
ret = lt_ecc_key_store(h, TR01_ECC_SLOT_0, TR01_CURVE_ED25519, dummy_key);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Writing all pairing key slots (should fail):");
for (uint8_t i = TR01_PAIRING_KEY_SLOT_INDEX_0; i <= TR01_PAIRING_KEY_SLOT_INDEX_3; i++) {
LT_LOG_INFO("\tWriting pairing key slot %" PRIu8 "...", i);
ret = lt_pairing_key_write(h, dummy_key, i);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\t\tOK");
}
uint32_t mcounter_value = 0x000000ff;
LT_LOG_INFO("Initializing mcounter 0 (should fail)...");
ret = lt_mcounter_init(h, TR01_MCOUNTER_INDEX_0, mcounter_value);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Updating mcounter 0 (should fail)...");
ret = lt_mcounter_update(h, TR01_MCOUNTER_INDEX_0);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Getting mcounter 0 (should fail)...");
ret = lt_mcounter_get(h, TR01_MCOUNTER_INDEX_0, &mcounter_value);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Aborting Secure Session");
ret = lt_session_abort(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to abort Secure Session, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Deinitializing handle");
ret = lt_deinit(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to deinitialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
return 0;
}
/**
* @brief Session with pairing key slot 3
*
* @param h Device's handle
* @return 0 if success, -1 otherwise
*/
static int session3(lt_handle_t *h)
{
lt_ret_t ret;
LT_LOG_INFO("Initializing handle");
ret = lt_init(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Starting Secure Session with key %d", (int)TR01_PAIRING_KEY_SLOT_INDEX_3);
ret = lt_verify_chip_and_start_secure_session(h, sh3priv, sh3pub, TR01_PAIRING_KEY_SLOT_INDEX_3);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to start Secure Session with key %d, ret=%s", (int)TR01_PAIRING_KEY_SLOT_INDEX_3,
lt_ret_verbose(ret));
return -1;
}
uint8_t recv_buf[PING_MSG_SIZE];
LT_LOG_INFO("Sending Ping command with message:");
LT_LOG_INFO("\t\"%s\"", PING_MSG);
ret = lt_ping(h, (const uint8_t *)PING_MSG, recv_buf, PING_MSG_SIZE);
if (LT_OK != ret) {
LT_LOG_ERROR("Ping command failed, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Message received from TROPIC01:");
LT_LOG_INFO("\t\"%s\"", recv_buf);
LT_LOG_INFO("Signing with attestation key which was updated through pairing key slot 1");
uint8_t msg[] = {'a', 'h', 'o', 'j'};
uint8_t rs[TR01_ECDSA_EDDSA_SIGNATURE_LENGTH];
ret = lt_ecc_eddsa_sign(h, TR01_ECC_SLOT_0, msg, sizeof(msg), rs);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to sign, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Reading ECC key slot %d...", (int)TR01_ECC_SLOT_0);
uint8_t ed25519_pubkey[TR01_CURVE_ED25519_PUBKEY_LEN];
lt_ecc_curve_type_t curve;
lt_ecc_key_origin_t origin;
ret = lt_ecc_key_read(h, TR01_ECC_SLOT_0, ed25519_pubkey, sizeof(ed25519_pubkey), &curve, &origin);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to read ECC slot, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Verifying with lt_ecc_eddsa_sig_verify()...");
ret = lt_ecc_eddsa_sig_verify(msg, sizeof(msg), ed25519_pubkey, rs);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to verify, ret%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Generating ECC key in slot %d...", (int)TR01_ECC_SLOT_8);
ret = lt_ecc_key_generate(h, TR01_ECC_SLOT_8, TR01_CURVE_ED25519);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to generate ECC key, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Generating ECC key in slot %d...", (int)TR01_ECC_SLOT_16);
ret = lt_ecc_key_generate(h, TR01_ECC_SLOT_16, TR01_CURVE_ED25519);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to generate ECC key, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Generating ECC key in slot %d...", (int)TR01_ECC_SLOT_24);
ret = lt_ecc_key_generate(h, TR01_ECC_SLOT_24, TR01_CURVE_ED25519);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to generate ECC key, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Getting %d random bytes...", (int)TR01_RANDOM_VALUE_GET_LEN_MAX);
uint8_t buff[TR01_RANDOM_VALUE_GET_LEN_MAX];
ret = lt_random_value_get(h, buff, TR01_RANDOM_VALUE_GET_LEN_MAX);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to get random bytes, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
uint32_t mcounter_value = 0x000000ff;
LT_LOG_INFO("Initializing mcounter 0...");
ret = lt_mcounter_init(h, TR01_MCOUNTER_INDEX_0, mcounter_value);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize mcounter, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Updating mcounter 0...");
ret = lt_mcounter_update(h, TR01_MCOUNTER_INDEX_0);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to update mcounter, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Getting mcounter 0...");
ret = lt_mcounter_get(h, TR01_MCOUNTER_INDEX_0, &mcounter_value);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to get mcounter, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
uint8_t dummy_key[TR01_CURVE_PRIVKEY_LEN];
LT_LOG_INFO("Trying to store key into ECC slot %d (should fail)", (int)TR01_ECC_SLOT_0);
ret = lt_ecc_key_store(h, TR01_ECC_SLOT_0, TR01_CURVE_ED25519, dummy_key);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\tOK");
LT_LOG_INFO("Writing all pairing key slots (should fail):");
for (uint8_t i = TR01_PAIRING_KEY_SLOT_INDEX_0; i <= TR01_PAIRING_KEY_SLOT_INDEX_3; i++) {
LT_LOG_INFO("\tWriting pairing key slot %" PRIu8 "...", i);
ret = lt_pairing_key_write(h, dummy_key, i);
if (LT_L3_UNAUTHORIZED != ret) {
LT_LOG_ERROR("Return value is not LT_L3_UNAUTHORIZED, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("\t\tOK");
}
LT_LOG_INFO("Aborting Secure Session");
ret = lt_session_abort(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to abort Secure Session, ret=%s", lt_ret_verbose(ret));
return -1;
}
LT_LOG_INFO("Deinitializing handle");
ret = lt_deinit(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to deinitialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
return 0;
}
int lt_ex_hardware_wallet(lt_handle_t *h)
{
LT_LOG_INFO("==========================================");
LT_LOG_INFO("==== TROPIC01 Hardware Wallet Example ====");
LT_LOG_INFO("==========================================");
LT_LOG_LINE();
LT_LOG_INFO("Initial session with pairing key slot 0");
if (session_initial(h) == -1) {
if (h->l3.session_status == LT_SECURE_SESSION_ON) lt_session_abort(h);
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG_INFO("Session with pairing key slot 0");
if (session0(h) == -1) {
if (h->l3.session_status == LT_SECURE_SESSION_ON) lt_session_abort(h);
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG_INFO("Session with pairing key slot 1");
if (session1(h) == -1) {
if (h->l3.session_status == LT_SECURE_SESSION_ON) lt_session_abort(h);
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG_INFO("Session with pairing key slot 2");
if (session2(h) == -1) {
if (h->l3.session_status == LT_SECURE_SESSION_ON) lt_session_abort(h);
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG_INFO("Session with pairing key slot 3");
if (session3(h) == -1) {
if (h->l3.session_status == LT_SECURE_SESSION_ON) lt_session_abort(h);
lt_deinit(h);
return -1;
}
return 0;
}
lt_ex_fw_update.c¶
- ⚠️ Irreversible
- ❌ Incompatible with the model
- 🐤 Level: Moderate
This example explains the firmware update process for both ABAB and ACAB silicon revisions. Use this example as a reference for integrating TROPIC01 firmware updates into your application. You will learn:
- How to read the current firmware versions.
- How to update the firmware using
lt_do_mutable_fw_update()
.
Tip
For more information about the firmware itself, refer to the TROPIC01 Firmware section.
Source code
/**
* @file lt_ex_fw_update.c
* @name Firmware update
* @brief This code performs firmware update of TROPIC01 chip, works on both ABAB and ACAB silicon revisions.
*
* @author Tropic Square s.r.o.
*
* @license For the license see file LICENSE.txt file in the root directory of this source tree.
*/
#include <inttypes.h>
#include "fw_CPU.h"
#include "fw_SPECT.h"
#include "libtropic.h"
#include "libtropic_common.h"
#include "libtropic_examples.h"
#include "libtropic_logging.h"
#include "string.h"
/**
* @brief Example how to update TROPIC01 firmware. Process is described in detail in 'ODN_TR01_app_007_fw_update.pdf'
* Application Note.
*
* It is recommended to update both Application firmware banks with the same Application firmware
* and both SPECT firmware banks with the same SPECT firmware.
*
* @param h Pointer to lt_handle_t structure
* @returns 0 on success, -1 otherwise
*/
int lt_ex_fw_update(lt_handle_t *h)
{
LT_LOG_INFO("====================================");
LT_LOG_INFO("==== TROPIC01 FW update Example ====");
LT_LOG_INFO("====================================");
lt_ret_t ret;
LT_LOG_INFO("Initializing handle");
ret = lt_init(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to initialize handle, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
// The chip must be rebooted into MAINTENANCE mode to perform a firmware update.
LT_LOG_LINE();
LT_LOG_INFO("Updating TR01_FW_BANK_FW1 and TR01_FW_BANK_SPECT1");
LT_LOG_INFO("Rebooting into Maintenance mode");
ret = lt_reboot(h, TR01_MAINTENANCE_REBOOT);
if (ret != LT_OK) {
LT_LOG_ERROR("lt_reboot() failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
if (h->l2.mode == LT_TR01_MAINTENANCE_MODE) {
LT_LOG_INFO("Chip is in maintenance mode, executing bootloader");
LT_LOG_INFO("Updating RISC-V FW");
ret = lt_do_mutable_fw_update(h, fw_CPU, sizeof(fw_CPU), TR01_FW_BANK_FW1);
if (ret != LT_OK) {
LT_LOG_ERROR("RISC-V FW update failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
LT_LOG_INFO("OK");
LT_LOG_INFO("Updating SPECT FW");
ret = lt_do_mutable_fw_update(h, fw_SPECT, sizeof(fw_SPECT), TR01_FW_BANK_SPECT1);
if (ret != LT_OK) {
LT_LOG_ERROR("SPECT FW update failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
LT_LOG_INFO("OK");
}
else {
LT_LOG_ERROR("Chip couldn't get into MAINTENANCE mode");
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
// The chip must be rebooted into MAINTENANCE mode to perform a firmware update.
LT_LOG_INFO("Updating TR01_FW_BANK_FW2 and TR01_FW_BANK_SPECT2");
LT_LOG_INFO("Rebooting into Maintenance mode");
ret = lt_reboot(h, TR01_MAINTENANCE_REBOOT);
if (ret != LT_OK) {
LT_LOG_ERROR("lt_reboot() failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
if (h->l2.mode == LT_TR01_MAINTENANCE_MODE) {
LT_LOG_INFO("Chip is in maintenance mode, executing bootloader");
LT_LOG_INFO("Updating RISC-V FW");
ret = lt_do_mutable_fw_update(h, fw_CPU, sizeof(fw_CPU), TR01_FW_BANK_FW2);
if (ret != LT_OK) {
LT_LOG_ERROR("RISC-V FW update failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
LT_LOG_INFO("OK");
LT_LOG_INFO("Updating SPECT FW");
ret = lt_do_mutable_fw_update(h, fw_SPECT, sizeof(fw_SPECT), TR01_FW_BANK_SPECT2);
if (ret != LT_OK) {
LT_LOG_ERROR("SPECT FW update failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
LT_LOG_INFO("OK");
}
else {
LT_LOG_ERROR("Chip couldn't get into MAINTENANCE mode");
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG("Successfully updated all 4 FW banks");
LT_LOG_LINE();
ret = lt_print_fw_header(h, TR01_FW_BANK_FW1, printf);
if (ret != LT_OK) {
LT_LOG_ERROR("Failed to print TR01_FW_BANK_FW1 header, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
ret = lt_print_fw_header(h, TR01_FW_BANK_FW2, printf);
if (ret != LT_OK) {
LT_LOG_ERROR("Failed to print TR01_FW_BANK_FW2 header, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
ret = lt_print_fw_header(h, TR01_FW_BANK_SPECT1, printf);
if (ret != LT_OK) {
LT_LOG_ERROR("Failed to print TR01_FW_BANK_SPECT1 header, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
ret = lt_print_fw_header(h, TR01_FW_BANK_SPECT2, printf);
if (ret != LT_OK) {
LT_LOG_ERROR("Failed to print TR01_FW_BANK_SPECT2 header, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG_INFO("Rebooting into Application mode");
ret = lt_reboot(h, TR01_REBOOT);
if (ret != LT_OK) {
LT_LOG_ERROR("lt_reboot() failed, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
if (h->l2.mode == LT_TR01_APP_MODE) {
LT_LOG_INFO("Chip is executing firmwares of following versions:");
LT_LOG_INFO("Reading RISC-V FW version");
// This variable is reused on more places in this block to store different firmware versions
uint8_t fw_ver[TR01_L2_GET_INFO_RISCV_FW_SIZE] = {0};
ret = lt_get_info_riscv_fw_ver(h, fw_ver);
if (ret == LT_OK) {
LT_LOG_INFO("Chip is executing RISC-V application FW version: %02" PRIX8 ".%02" PRIX8 ".%02" PRIX8
" (+ .%02" PRIX8 ")",
fw_ver[3], fw_ver[2], fw_ver[1], fw_ver[0]);
}
else {
LT_LOG_ERROR("Failed to get RISC-V FW version, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
LT_LOG_INFO("Reading SPECT FW version");
ret = lt_get_info_spect_fw_ver(h, fw_ver);
if (ret == LT_OK) {
LT_LOG_INFO("Chip is executing SPECT firmware version: %02" PRIX8 ".%02" PRIX8 ".%02" PRIX8
" (+ .%02" PRIX8 ")",
fw_ver[3], fw_ver[2], fw_ver[1], fw_ver[0]);
}
else {
LT_LOG_ERROR("Failed to get SPECT firmware version, ret=%s", lt_ret_verbose(ret));
lt_deinit(h);
return -1;
}
}
else {
LT_LOG_ERROR("Chip couldn't get into APP mode, APP and SPECT firmwares in fw banks are not valid");
lt_deinit(h);
return -1;
}
LT_LOG_LINE();
LT_LOG_INFO("Deinitializing handle");
ret = lt_deinit(h);
if (LT_OK != ret) {
LT_LOG_ERROR("Failed to deinitialize handle, ret=%s", lt_ret_verbose(ret));
return -1;
}
return 0;
}