1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-06 10:16:07 +00:00

fix(core): fix tamper setting

[no changelog]
This commit is contained in:
tychovrahe 2025-02-27 20:06:07 +01:00 committed by TychoVrahe
parent bf119fbee4
commit d535e725c0
8 changed files with 200 additions and 153 deletions

View File

@ -198,4 +198,6 @@
#define HW_REVISION_2_PORT GPIOI
#define HW_REVISION_2_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define TAMPER_INPUT_2 1
#endif // TREZOR_T3W1_REVA_H_

View File

@ -171,4 +171,6 @@
#define HW_REVISION_2_PORT GPIOI
#define HW_REVISION_2_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define TAMPER_INPUT_2 1
#endif // TREZOR_T3W1_REVA_H_

View File

@ -198,4 +198,6 @@
#define HW_REVISION_2_PORT GPIOI
#define HW_REVISION_2_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define TAMPER_INPUT_2 1
#endif // TREZOR_T3W1_REVA_H_

View File

@ -63,6 +63,9 @@
#ifdef USE_HASH_PROCESSOR
#include <sec/hash_processor.h>
#endif
#ifdef USE_TAMPER
#include <sys/tamper.h>
#endif
#include <io/usb.h>
#include "version.h"
@ -101,18 +104,26 @@ static void drivers_init(secbool *touch_initialized) {
display_init(DISPLAY_RESET_CONTENT);
unit_properties_init();
#ifdef USE_TOUCH
secbool allow_touchless_mode = secfalse;
#if defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3W1
// on T3T1 and T3W1, tester needs to run without touch, so making an exception
// until unit variant is written in OTP
#if (defined TREZOR_MODEL_T3T1 || defined TREZOR_MODEL_T3W1)
// on T3T1 and T3W1, tester needs to run without touch and tamper, so making
// an exception until unit variant is written in OTP
const secbool manufacturing_mode =
unit_properties()->locked ? secfalse : sectrue;
allow_touchless_mode = manufacturing_mode;
#else
const secbool manufacturing_mode = secfalse;
(void)manufacturing_mode; // suppress unused variable warning
#endif
#ifdef USE_TAMPER
tamper_init();
if (manufacturing_mode != sectrue) {
tamper_external_enable();
}
#endif
#ifdef USE_TOUCH
*touch_initialized = touch_init();
if (allow_touchless_mode != sectrue) {
if (manufacturing_mode != sectrue) {
ensure(*touch_initialized, "Touch screen panel was not loaded properly.");
}
#endif

View File

@ -90,6 +90,10 @@
#include <util/hw_revision.h>
#endif
#ifdef USE_TAMPER
#include <sys/tamper.h>
#endif
#ifdef TREZOR_MODEL_T2T1
#define MODEL_IDENTIFIER "TREZOR2-"
#else
@ -180,6 +184,9 @@ static void drivers_init(void) {
display_init(DISPLAY_RESET_CONTENT);
#ifdef USE_TAMPER
tamper_init();
#endif
#ifdef USE_STORAGE_HWKEY
secure_aes_init();
#endif

View File

@ -69,6 +69,58 @@ uint32_t SystemCoreClock = DEFAULT_FREQ * 1000000U;
#pragma GCC optimize( \
"no-stack-protector") // applies to all functions in this file
// This function replaces calls to universal, but flash-wasting
// function HAL_RCC_OscConfig.
//
// This is the configuration before the optimization:
// osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI;
// osc_init_def.LSIState = RCC_LSI_ON;
// HAL_RCC_OscConfig(&osc_init_def);
void lsi_init(void) {
// Update LSI configuration in Backup Domain control register
// Requires to enable write access to Backup Domain of necessary
if (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) {
// Enable write access to Backup domain
SET_BIT(PWR->DBPR, PWR_DBPR_DBP);
// Wait for Backup domain Write protection disable
while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP))
;
}
uint32_t bdcr_temp = RCC->BDCR;
if (RCC_LSI_DIV1 != (bdcr_temp & RCC_BDCR_LSIPREDIV)) {
if (((bdcr_temp & RCC_BDCR_LSIRDY) == RCC_BDCR_LSIRDY) &&
((bdcr_temp & RCC_BDCR_LSION) != RCC_BDCR_LSION)) {
// If LSIRDY is set while LSION is not enabled, LSIPREDIV can't be updated
// The LSIPREDIV cannot be changed if the LSI is used by the IWDG or by
// the RTC
return;
}
// Turn off LSI before changing RCC_BDCR_LSIPREDIV
if ((bdcr_temp & RCC_BDCR_LSION) == RCC_BDCR_LSION) {
__HAL_RCC_LSI_DISABLE();
// Wait till LSI is disabled
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) != 0U)
;
}
// Set LSI division factor
MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, 0);
}
// Enable the Internal Low Speed oscillator (LSI)
__HAL_RCC_LSI_ENABLE();
// Wait till LSI is ready
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) == 0U)
;
}
void SystemInit(void) {
// set flash wait states for an increasing HCLK frequency
@ -171,6 +223,12 @@ void SystemInit(void) {
// enable power supply for GPIOG 2 to 15
PWR->SVMCR |= PWR_SVMCR_IO2SV;
#ifdef USE_LSE
// TODO
#else
lsi_init();
#endif
__HAL_RCC_PWR_CLK_DISABLE();
// this will be overriden by static initialization

View File

@ -17,8 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TREZOR_HAL_TAMPER_H
#define TREZOR_HAL_TAMPER_H
#pragma once
#include <trezor_types.h>
@ -28,15 +27,12 @@
// as well as external tamper input if it's available on the device
// Initializes the tamper detection
void tamper_init(void);
bool 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);
// Get status of external tamper inputs
uint8_t tamper_external_read(void);
// Enable external tamper inputs
void tamper_external_enable(void);
#endif // KERNEL_MODE
#endif // TREZOR_HAL_TAMPER_H

View File

@ -22,6 +22,7 @@
#include <sys/irq.h>
#include <sys/mpu.h>
#include <sys/systick.h>
#include <sys/tamper.h>
#ifdef KERNEL_MODE
@ -32,153 +33,85 @@
#define TAMP_CR3_ITAMP7NOER_Msk (0x1UL << TAMP_CR3_ITAMP7NOER_Pos)
#define TAMP_CR3_ITAMP7NOER TAMP_CR3_ITAMP7NOER_Msk
/*
* This function replaces calls to universal, but flash-wasting
* functions HAL_RCC_OscConfig and HAL_RCCEx_PeriphCLKConfig.
*
* This is the configuration before the optimization:
* osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI;
* osc_init_def.LSIState = RCC_LSI_ON;
* HAL_RCC_OscConfig(&osc_init_def);
*
* clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC;
* clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
* HAL_RCCEx_PeriphCLKConfig(&clk_init_def);
*/
HAL_StatusTypeDef lsi_init(void) {
uint32_t tickstart = 0U;
// This function replaces calls to universal, but flash-wasting
// functions HAL_RCC_OscConfig and HAL_RCCEx_PeriphCLKConfig.
//
// This is the configuration before the optimization:
// clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC;
// clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI (or
// RCC_RTCCLKSOURCE_LSE); HAL_RCCEx_PeriphCLKConfig(&clk_init_def);
static HAL_StatusTypeDef clk_init(uint32_t source) {
bool pwrclkchanged = false;
FlagStatus pwrclkchanged = RESET;
/* Update LSI configuration in Backup Domain control register */
/* Requires to enable write access to Backup Domain of necessary */
// Enable Power Clock
if (__HAL_RCC_PWR_IS_CLK_DISABLED()) {
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
pwrclkchanged = true;
}
if (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) {
/* Enable write access to Backup domain */
SET_BIT(PWR->DBPR, PWR_DBPR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) {
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
/* Restore clock configuration if changed */
if (pwrclkchanged == SET) {
__HAL_RCC_PWR_CLK_DISABLE();
}
return HAL_TIMEOUT;
}
}
}
uint32_t bdcr_temp = RCC->BDCR;
if (RCC_LSI_DIV1 != (bdcr_temp & RCC_BDCR_LSIPREDIV)) {
if (((bdcr_temp & RCC_BDCR_LSIRDY) == RCC_BDCR_LSIRDY) &&
((bdcr_temp & RCC_BDCR_LSION) != RCC_BDCR_LSION)) {
/* If LSIRDY is set while LSION is not enabled, LSIPREDIV can't be updated
*/
/* The LSIPREDIV cannot be changed if the LSI is used by the IWDG or by
* the RTC */
/* Restore clock configuration if changed */
if (pwrclkchanged == SET) {
__HAL_RCC_PWR_CLK_DISABLE();
}
return HAL_ERROR;
}
/* Turn off LSI before changing RCC_BDCR_LSIPREDIV */
if ((bdcr_temp & RCC_BDCR_LSION) == RCC_BDCR_LSION) {
__HAL_RCC_LSI_DISABLE();
tickstart = HAL_GetTick();
/* Wait till LSI is disabled */
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) != 0U)
;
}
/* Set LSI division factor */
MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, 0);
}
/* Enable the Internal Low Speed oscillator (LSI) */
__HAL_RCC_LSI_ENABLE();
/* Wait till LSI is ready */
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) == 0U)
;
/* Check for RTC Parameters used to output RTCCLK */
assert_param(IS_RCC_RTCCLKSOURCE(pPeriphClkInit->RTCClockSelection));
/* Enable Power Clock */
if (__HAL_RCC_PWR_IS_CLK_DISABLED()) {
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
}
/* Enable write access to Backup domain */
// Enable write access to Backup domain
SET_BIT(PWR->DBPR, PWR_DBPR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
// Wait for Backup domain Write protection disable
uint32_t deadline = ticks_timeout(RCC_DBP_TIMEOUT_VALUE);
while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) {
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) {
if (ticks_expired(deadline)) {
return HAL_TIMEOUT;
}
}
/* Reset the Backup domain only if the RTC Clock source selection is modified
* from default */
bdcr_temp = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL);
// Reset the Backup domain only if the RTC Clock source selection is modified
// from default
uint32_t bdcr_temp = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL);
if ((bdcr_temp != RCC_RTCCLKSOURCE_NO_CLK) &&
(bdcr_temp != RCC_RTCCLKSOURCE_LSI)) {
/* Store the content of BDCR register before the reset of Backup Domain */
if ((bdcr_temp != RCC_RTCCLKSOURCE_NO_CLK) && (bdcr_temp != source)) {
// Store the content of BDCR register before the reset of Backup Domain
bdcr_temp = READ_BIT(RCC->BDCR, ~(RCC_BDCR_RTCSEL));
/* RTC Clock selection can be changed only if the Backup Domain is reset */
// RTC Clock selection can be changed only if the Backup Domain is reset
__HAL_RCC_BACKUPRESET_FORCE();
__HAL_RCC_BACKUPRESET_RELEASE();
/* Restore the Content of BDCR register */
// Restore the Content of BDCR register
RCC->BDCR = bdcr_temp;
}
/* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */
// Wait for LSE reactivation if LSE was enabled prior to Backup Domain reset
if (HAL_IS_BIT_SET(bdcr_temp, RCC_BDCR_LSEON)) {
/* Get Start Tick*/
tickstart = HAL_GetTick();
deadline = ticks_timeout(RCC_LSE_TIMEOUT_VALUE);
/* Wait till LSE is ready */
// Wait till LSE is ready
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) {
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) {
if (ticks_expired(deadline)) {
return HAL_TIMEOUT;
}
}
}
/* Apply new RTC clock source selection */
__HAL_RCC_RTC_CONFIG(RCC_PERIPHCLK_RTC);
// Apply new RTC clock source selection
__HAL_RCC_RTC_CONFIG(source);
/* Restore clock configuration if changed */
if (pwrclkchanged == SET) {
// Restore clock configuration if changed
if (pwrclkchanged) {
__HAL_RCC_PWR_CLK_DISABLE();
}
return HAL_OK;
}
void tamper_init(void) {
// Enable LSI clock
lsi_init();
bool tamper_init(void) {
#ifdef USE_LSE
HAL_StatusTypeDef res = clk_init(RCC_RTCCLKSOURCE_LSE);
#else
HAL_StatusTypeDef res = clk_init(RCC_RTCCLKSOURCE_LSI);
#endif
if (res != HAL_OK) {
return false;
}
// 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
// They may be some as RTC/TAMP peripherals reside 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 |
@ -193,37 +126,37 @@ void tamper_init(void) {
PWR->BDCR1 |= PWR_BDCR1_MONEN;
// HAL_PWR_DisableBkUpAccess();
// Enable all internal tampers (4th and 10th are intentionally skipped)
// We select all of them despite some of them are never triggered
TAMP->CR1 =
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
// // 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 internal tampers (4th and 10th are intentionally skipped)
// We select all of them despite some of them are never triggered
TAMP->CR1 |=
(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 peripherals 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 tampers to the "confirmed" mode
// => all secrets all deleted when any tamper event is triggered
TAMP->CR3 = 0;
#ifdef TAMPER_INPUT_2
// TAMP_IN2 level high
TAMP->CR2 |= TAMP_CR2_TAMP2TRG;
#endif
// 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 |
@ -233,6 +166,36 @@ void tamper_init(void) {
// Enable TAMP interrupt at NVIC controller
NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_HIGHEST);
NVIC_EnableIRQ(TAMP_IRQn);
return true;
}
uint8_t tamper_external_read(void) {
uint8_t val = 0;
#ifdef TAMPER_INPUT_2
GPIO_InitTypeDef gpio = {0};
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pull = GPIO_PULLUP;
gpio.Pin = GPIO_PIN_0;
gpio.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOA, &gpio);
systick_delay_us(1);
val |= GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) ? 2 : 0;
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0);
#endif
return val;
}
void tamper_external_enable(void) {
// Enable external tampers
#ifdef TAMPER_INPUT_2
TAMP->CR1 |= TAMP_CR1_TAMP2E;
#endif
}
// Interrupt handle for all tamper events
@ -240,6 +203,12 @@ void tamper_init(void) {
void TAMP_IRQHandler(void) {
mpu_reconfig(MPU_MODE_DEFAULT);
// Disable external tamper, as its level detected
// and it would trigger again. We don't need it until reset.
#ifdef TAMPER_INPUT_2
TAMP->CR1 &= ~TAMP_CR1_TAMP2E;
#endif
uint32_t sr = TAMP->SR;
TAMP->SCR = sr;