From d06e0fd382f123a0a8d798d8115ace1860b7e8f1 Mon Sep 17 00:00:00 2001 From: cepetr Date: Wed, 4 Oct 2023 14:17:08 +0200 Subject: [PATCH] feat(core): introduce tamper detection on STM32U5 --- core/embed/firmware/main.c | 7 + core/embed/trezorhal/stm32f4/irq.h | 3 + .../trezorhal/stm32u5/stm32u5xx_hal_conf.h | 2 +- core/embed/trezorhal/stm32u5/tamper.c | 201 ++++++++++++++++++ core/embed/trezorhal/tamper.h | 38 ++++ core/site_scons/boards/stm32u5_common.py | 6 +- 6 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 core/embed/trezorhal/stm32u5/tamper.c create mode 100644 core/embed/trezorhal/tamper.h diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index 0051b7ddf..04c846977 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -87,6 +87,9 @@ #ifdef USE_SECP256K1_ZKP #include "zkp_context.h" #endif +#if USE_TAMPERS +#include "tamper.h" +#endif // from util.s extern void shutdown_privileged(void); @@ -165,6 +168,10 @@ int main(void) { touch_init(); #endif +#if USE_TAMPERS + tamper_init(); +#endif + #ifdef USE_SD_CARD sdcard_init(); #endif diff --git a/core/embed/trezorhal/stm32f4/irq.h b/core/embed/trezorhal/stm32f4/irq.h index 1d06d4f95..319755f1c 100644 --- a/core/embed/trezorhal/stm32f4/irq.h +++ b/core/embed/trezorhal/stm32f4/irq.h @@ -160,4 +160,7 @@ static inline void restore_irq_pri(uint32_t state) { #define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) #define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +// !@# TAMPER interrupt priority should be probably much higher +#define IRQ_PRI_TAMP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) + #endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h index 325d229bd..f619bcca5 100644 --- a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h @@ -69,7 +69,7 @@ extern "C" { /*#define HAL_PKA_MODULE_ENABLED */ /*#define HAL_QSPI_MODULE_ENABLED */ /*#define HAL_RNG_MODULE_ENABLED */ -/*#define HAL_RTC_MODULE_ENABLED */ +#define HAL_RTC_MODULE_ENABLED /*#define HAL_SAI_MODULE_ENABLED */ /*#define HAL_CRYP_MODULE_ENABLED */ /*#define HAL_SD_MODULE_ENABLED */ diff --git a/core/embed/trezorhal/stm32u5/tamper.c b/core/embed/trezorhal/stm32u5/tamper.c new file mode 100644 index 000000000..fd4b9d18c --- /dev/null +++ b/core/embed/trezorhal/stm32u5/tamper.c @@ -0,0 +1,201 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include STM32_HAL_H + +// Fixes a typo in CMSIS Device library for STM32U5 +#undef TAMP_CR3_ITAMP7NOER_Msk +#undef TAMP_CR3_ITAMP7NOER +#define TAMP_CR3_ITAMP7NOER_Msk (0x1UL << TAMP_CR3_ITAMP7NOER_Pos) +#define TAMP_CR3_ITAMP7NOER TAMP_CR3_ITAMP7NOER_Msk + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// Temporary solution for STM32U5A9 Discovery Board experiments +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +void tamper_init() { + RCC_PeriphCLKInitTypeDef clk_init_def = {0}; + RCC_OscInitTypeDef osc_init_def = {0}; + + // Enable LSI clock + osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI; + osc_init_def.LSIState = RCC_LSI_ON; + HAL_RCC_OscConfig(&osc_init_def); + + // Select RTC peripheral clock source + clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC; + clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + HAL_RCCEx_PeriphCLKConfig(&clk_init_def); + + // Enable RTC peripheral (tampers are part of it) + __HAL_RCC_RTC_ENABLE(); + __HAL_RCC_RTCAPB_CLK_ENABLE(); + + // Clear all pending interrupts + // They may be some as RTC/TAMP peripherals resides inside the + // backup voltage domain + TAMP->SCR = TAMP_SCR_CTAMP2F | TAMP_SCR_CITAMP1F | TAMP_SCR_CITAMP2F | + TAMP_SCR_CITAMP3F | TAMP_SCR_CITAMP5F | TAMP_SCR_CITAMP6F | + TAMP_SCR_CITAMP7F | TAMP_SCR_CITAMP8F | TAMP_SCR_CITAMP9F | + TAMP_SCR_CITAMP11F | TAMP_SCR_CITAMP12F | TAMP_SCR_CITAMP13F; + + NVIC_ClearPendingIRQ(TAMP_IRQn); + + // Enable battery and power monitoring (!@# rework it) + RCC->AHB3ENR |= RCC_AHB3ENR_PWREN; + // HAL_PWR_EnableBkUpAccess(); + HAL_PWREx_EnableMonitoring(); + // HAL_PWR_DisableBkUpAccess(); + + // Enable all internal tampers (4th and 10th are intentionally skipped) + // Enable TAMP_IN2 external input (PA0) + // We select all of them despite some of them are never triggered + TAMP->CR1 = + TAMP_CR1_TAMP2E | // external TAMP_IN2 + TAMP_CR1_ITAMP1E | // backup domain voltage monitoring + TAMP_CR1_ITAMP2E | // temperature monitoring + TAMP_CR1_ITAMP3E | // LSE monitoring (LSECSS) + TAMP_CR1_ITAMP5E | // RTC calendar overflow + TAMP_CR1_ITAMP6E | // JTAG/SWD access when RDP > 0 + TAMP_CR1_ITAMP7E | // ADC4 analog watchdog monitoring 1 + TAMP_CR1_ITAMP8E | // Monotonic counter 1 overflow + TAMP_CR1_ITAMP9E | // Crypto periherals fault (SAES, AES, PKA, TRNG) + TAMP_CR1_ITAMP11E | // IWDG reset when tamper flag is set + TAMP_CR1_ITAMP12E | // ADC4 analog watchdog monitoring 2 + TAMP_CR1_ITAMP13E; // ADC4 analog watchdog monitoring 3 + + // Switch all internal tampers to the "confirmed" mode + // => all secrets all deleted when any tamper event is triggered + TAMP->CR3 = 0; + + // Setup external tampers + // TAMP_IN2 active low, "confirmed" mode + TAMP->CR2 = 0; + // TAMP_CR2_TAMP2TRG; + + // Set external tamper input filter + TAMP->FLTCR = + // TAMP_FLTCR_TAMPPUDIS | // disable pre-charge of TAMP_INx pins + (3 << TAMP_FLTCR_TAMPPRCH_Pos) | // pre-charge 8 RTCCLK cycles + (2 << TAMP_FLTCR_TAMPFLT_Pos) | // activated after 4 same samples + (7 << TAMP_FLTCR_TAMPFREQ_Pos); // sampling period RTCCLK / 256 (128Hz) + + // Enable all interrupts for all internal tampers + TAMP->IER = TAMP_IER_TAMP2IE | TAMP_IER_ITAMP1IE | TAMP_IER_ITAMP2IE | + TAMP_IER_ITAMP3IE | TAMP_IER_ITAMP5IE | TAMP_IER_ITAMP6IE | + TAMP_IER_ITAMP7IE | TAMP_IER_ITAMP8IE | TAMP_IER_ITAMP9IE | + TAMP_IER_ITAMP11IE | TAMP_IER_ITAMP12IE | TAMP_IER_ITAMP13IE; + + // Enable TAMP interrupt at NVIC controller + NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_TAMP); + NVIC_EnableIRQ(TAMP_IRQn); + + // svc_setpriority(TAMP_IRQn, IRQ_PRI_TAMP); + // svc_enableIRQ(TAMP_IRQn); +} + +// Interrupt handle for all tamper events +// It displays an error message +void TAMP_IRQHandler(void) { + const char* reason = "UNKNOWN"; + + uint32_t sr = TAMP->SR; + + if (sr & TAMP_SR_TAMP1F) { + reason = "INPUT1"; + } else if (sr & TAMP_SR_TAMP2F) { + reason = "INPUT2"; + } else if (sr & TAMP_SR_ITAMP1F) { + reason = "VOLTAGE"; + } else if (sr & TAMP_SR_ITAMP2F) { + reason = "TEMPERATURE"; + } else if (sr & TAMP_SR_ITAMP3F) { + reason = "LSE CLOCK"; + } else if (sr & TAMP_SR_ITAMP5F) { + reason = "RTC OVERFLOW"; + } else if (sr & TAMP_SR_ITAMP6F) { + reason = "SWD ACCESS"; + } else if (sr & TAMP_SR_ITAMP7F) { + reason = "ANALOG WDG1"; + } else if (sr & TAMP_SR_ITAMP8F) { + reason = "MONO COUNTER"; + } else if (sr & TAMP_SR_ITAMP9F) { + reason = "CRYPTO ERROR"; + } else if (sr & TAMP_SR_ITAMP11F) { + reason = "IWDG"; + } else if (sr & TAMP_SR_ITAMP12F) { + reason = "ANALOG WDG2"; + } else if (sr & TAMP_SR_ITAMP13F) { + reason = "ANALOG WDG3"; + } + + error_shutdown("INTERNAL TAMPER", reason); +} + +// Triggers ITAMP5 by overflowing RTC date/time +static void tamper_test_rtc_overflow(void) { + RTC_HandleTypeDef hrtc; + RTC_DateTypeDef date = {0}; + RTC_TimeTypeDef time = {0}; + + // Initialize RTC and select BCD format for date & time + hrtc.Instance = RTC; + hrtc.Init.HourFormat = RTC_HOURFORMAT_24; + hrtc.Init.AsynchPrediv = 127; + hrtc.Init.SynchPrediv = 255; + hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; + hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; + hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; + hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE; + hrtc.Init.BinMode = RTC_BINARY_NONE; + HAL_RTC_Init(&hrtc); + + // set date 99/12/31 + date.Year = 0x99; + date.Month = 0x12; + date.Date = 0x31; + date.WeekDay = 0x00; + HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BCD); + + // set time 23:59:50 + time.Hours = 0x23; + time.Minutes = 0x59; + time.Seconds = 0x50; + HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BCD); +} + +// Triggers ITAMP8 by overflowing monotonic counter +static void tamper_test_counter_overflow(void) { + for (uint32_t i = 0; i < UINT32_MAX; i++) { + TAMP->COUNTR = 0; + } + TAMP->COUNTR = 0; +} + +void tamper_test(uint32_t tamper_bit) { + if (tamper_bit & TAMP_CR1_ITAMP5E) { + tamper_test_rtc_overflow(); + } else if (tamper_bit & TAMP_CR1_ITAMP8E) { + tamper_test_counter_overflow(); + } +} diff --git a/core/embed/trezorhal/tamper.h b/core/embed/trezorhal/tamper.h new file mode 100644 index 000000000..5d3fe12b0 --- /dev/null +++ b/core/embed/trezorhal/tamper.h @@ -0,0 +1,38 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TREZOR_HAL_TAMPER_H +#define TREZOR_HAL_TAMPER_H + +#include + +// Tamper module enables the internal tamper detection on STM32 microcontroller +// as well as external tamper input if it's available on the device + +// Initializes the tamper detection +void tamper_init(void); + +// Triggers one of internal tampers. +// The function is intended for experimentation with internal tamper mechanism +// Use TAMP_CR1_xxx constants to as a parameter +// Only TAMP_CR1_ITAMP5E (RTC) and TAMP_CR1_ITAMP8E (monotonic counter) +// are supported +void tamper_test(uint32_t tamper_type); + +#endif // TREZOR_HAL_TAMPER_H diff --git a/core/site_scons/boards/stm32u5_common.py b/core/site_scons/boards/stm32u5_common.py index 89bcf5575..83f2a7dc1 100644 --- a/core/site_scons/boards/stm32u5_common.py +++ b/core/site_scons/boards/stm32u5_common.py @@ -2,9 +2,7 @@ from __future__ import annotations def stm32u5_common_files(env, defines, sources, paths): - defines += [ - ("STM32_HAL_H", '""'), - ] + defines += [("STM32_HAL_H", '""'), "USE_TAMPERS"] paths += [ "embed/trezorhal/stm32u5", @@ -34,6 +32,7 @@ def stm32u5_common_files(env, defines, sources, paths): "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_pwr_ex.c", "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rcc.c", "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rcc_ex.c", + "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_rtc.c", "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_sd.c", "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_spi.c", "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_sram.c", @@ -53,6 +52,7 @@ def stm32u5_common_files(env, defines, sources, paths): "embed/trezorhal/stm32u5/systick.c", "embed/trezorhal/stm32u5/random_delays.c", "embed/trezorhal/stm32u5/rng.c", + "embed/trezorhal/stm32u5/tamper.c", "embed/trezorhal/stm32u5/vectortable.s", ]