1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-31 09:50:58 +00:00

refactor(core): enclose monotonic counter to platform specific module

[no changelog]
This commit is contained in:
tychovrahe 2024-08-27 12:36:35 +02:00 committed by TychoVrahe
parent d334b92073
commit c1864a2a91
11 changed files with 395 additions and 58 deletions

View File

@ -149,6 +149,7 @@ SOURCE_TREZORHAL = [
'embed/trezorhal/unix/fault_handlers.c',
'embed/trezorhal/unix/flash.c',
'embed/trezorhal/unix/flash_otp.c',
'embed/trezorhal/unix/monoctr.c',
'embed/trezorhal/unix/random_delays.c',
'embed/trezorhal/unix/rng.c',
'embed/trezorhal/unix/secret.c',

View File

@ -54,6 +54,7 @@
#include "lowlevel.h"
#include "model.h"
#include "monoctr.h"
#include "version.h"
#include "memzero.h"
@ -76,45 +77,17 @@ static const uint8_t * const BOARDLOADER_KEYS[] = {
#endif
};
#ifdef STM32U5
uint8_t get_bootloader_min_version(void) {
const uint8_t *counter_addr =
flash_area_get_address(&SECRET_AREA, SECRET_MONOTONIC_COUNTER_OFFSET,
SECRET_MONOTONIC_COUNTER_LEN);
ensure((counter_addr != NULL) * sectrue, "counter_addr is NULL");
int counter = 0;
for (int i = 0; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) {
secbool not_cleared = sectrue;
for (int j = 0; j < 16; j++) {
if (counter_addr[i * 16 + j] != 0xFF) {
not_cleared = secfalse;
break;
}
}
if (not_cleared != sectrue) {
counter++;
} else {
break;
}
}
return counter;
static uint8_t get_bootloader_min_version(void) {
uint8_t version = 0;
ensure(monoctr_read(MONOCTR_BOOTLOADER_VERSION, &version), "monoctr read");
return version;
}
void write_bootloader_min_version(uint8_t version) {
static void write_bootloader_min_version(uint8_t version) {
if (version > get_bootloader_min_version()) {
for (int i = 0; i < version; i++) {
uint32_t data[4] = {0};
secret_write((uint8_t *)data, SECRET_MONOTONIC_COUNTER_OFFSET + i * 16,
16);
}
ensure(monoctr_write(MONOCTR_BOOTLOADER_VERSION, version), "monoctr write");
}
}
#endif
struct BoardCapabilities capabilities
__attribute__((section(".capabilities_section"))) = {
@ -197,11 +170,9 @@ static uint32_t check_sdcard(void) {
}
}
#ifdef STM32U5
if (hdr->monotonic < get_bootloader_min_version()) {
return 0;
}
#endif
return hdr->codelen;
}
@ -310,7 +281,6 @@ int main(void) {
#if defined USE_SD_CARD
sdcard_init();
#ifdef STM32U5
// If the bootloader is being updated from SD card, we need to preserve the
// monotonic counter from the old bootloader. This is in case that the old
// bootloader did not have the chance yet to write its monotonic counter to
@ -327,7 +297,6 @@ int main(void) {
check_image_contents(old_hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA))) {
write_bootloader_min_version(old_hdr->monotonic);
}
#endif
if (check_sdcard()) {
return copy_sdcard() == sectrue ? 0 : 3;
@ -348,14 +317,12 @@ int main(void) {
ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA),
"invalid bootloader hash");
#ifdef STM32U5
uint8_t bld_min_version = get_bootloader_min_version();
ensure((hdr->monotonic >= bld_min_version) * sectrue,
"BOOTLOADER DOWNGRADED");
// Write the bootloader version to the secret area.
// This includes the version of bootloader potentially updated from SD card.
write_bootloader_min_version(hdr->monotonic);
#endif
ensure_compatible_settings();

View File

@ -69,6 +69,7 @@
#include "bootui.h"
#include "messages.h"
#include "monoctr.h"
#include "rust_ui.h"
#include "unit_variant.h"
@ -265,24 +266,10 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
#if PRODUCTION && !defined STM32U5
static void check_bootloader_version(void) {
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
if (i < VERSION_MONOTONIC) {
bits[i / 8] &= ~(1 << (7 - (i % 8)));
} else {
bits[i / 8] |= (1 << (7 - (i % 8)));
}
}
ensure(flash_otp_write(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits,
FLASH_OTP_BLOCK_SIZE),
NULL);
uint8_t bits2[FLASH_OTP_BLOCK_SIZE];
ensure(flash_otp_read(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits2,
FLASH_OTP_BLOCK_SIZE),
NULL);
ensure(sectrue * (0 == memcmp(bits, bits2, FLASH_OTP_BLOCK_SIZE)),
ensure(monoctr_write(MONOCTR_BOOTLOADER_VERSION, VERSION_MONOTONIC), NULL);
uint8_t val = 0;
ensure(monoctr_read(MONOCTR_BOOTLOADER_VERSION, &val), NULL);
ensure(sectrue * (val == VERSION_MONOTONIC),
"Bootloader downgrade protection");
}

View File

@ -9,6 +9,7 @@
#define FLASH_OTP_BLOCK_VENDOR_HEADER_LOCK 2
#define FLASH_OTP_BLOCK_RANDOMNESS 3
#define FLASH_OTP_BLOCK_DEVICE_VARIANT 4
#define FLASH_OTP_BLOCK_FIRMWARE_VERSION 5
#define STORAGE_AREAS_COUNT (2)

View File

@ -0,0 +1,39 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_MONOCTR
#define TREZORHAL_MONOCTR
// Monoctr module provides monotonic counter functionality
#define MONOCTR_MAX_VALUE 63
#include <stdint.h>
#include "secbool.h"
typedef enum {
MONOCTR_BOOTLOADER_VERSION = 0,
MONOCTR_FIRMWARE_VERSION = 1,
} monoctr_type_t;
secbool monoctr_write(monoctr_type_t type, uint8_t value);
secbool monoctr_read(monoctr_type_t type, uint8_t* value);
#endif

View File

@ -9,6 +9,7 @@
#define SECRET_MONOTONIC_COUNTER_OFFSET 48
#define SECRET_MONOTONIC_COUNTER_LEN 1024
#define SECRET_MONOTONIC_COUNTER2_OFFSET (SECRET_MONOTONIC_COUNTER_LEN + 48)
#define SECRET_BHK_OFFSET (1024 * 8)
#define SECRET_BHK_LEN 32

View File

@ -0,0 +1,119 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "monoctr.h"
#include "flash_otp.h"
#include "model.h"
#include "string.h"
#if PRODUCTION
static int get_otp_block(monoctr_type_t type) {
switch (type) {
case MONOCTR_BOOTLOADER_VERSION:
return FLASH_OTP_BLOCK_BOOTLOADER_VERSION;
case MONOCTR_FIRMWARE_VERSION:
return FLASH_OTP_BLOCK_FIRMWARE_VERSION;
default:
return -1;
}
}
#endif
secbool monoctr_write(monoctr_type_t type, uint8_t value) {
#if PRODUCTION
if (value > MONOCTR_MAX_VALUE) {
return secfalse;
}
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
if (i < value) {
bits[i / 8] &= ~(1 << (7 - (i % 8)));
} else {
bits[i / 8] |= (1 << (7 - (i % 8)));
}
}
int block = get_otp_block(type);
if (block < 0) {
return secfalse;
}
ensure(flash_otp_write(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
#endif
return sectrue;
}
secbool monoctr_read(monoctr_type_t type, uint8_t* value) {
#if PRODUCTION
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
int block = get_otp_block(type);
if (block < 0) {
return secfalse;
}
ensure(flash_otp_read(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
int result = 0;
int i;
// Iterate through each bit position in the bit field
for (i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
// Calculate the byte and bit index within the byte
int byteIndex = i / 8;
int bitIndex = 7 - (i % 8);
// Check if the current bit is 0
if ((bits[byteIndex] & (1 << bitIndex)) == 0) {
// If the bit is 0, increment the value
result++;
} else {
// Stop when we find the first 1 bit
break;
}
}
for (; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
// Calculate the byte and bit index within the byte
int byteIndex = i / 8;
int bitIndex = 7 - (i % 8);
if ((bits[byteIndex] & (1 << bitIndex)) == 0) {
// If the bit is 0, return false - the monotonic counter is not valid
return secfalse;
}
}
if (value != NULL) {
*value = result;
} else {
return secfalse;
}
#else
*value = 0;
#endif
return sectrue;
}

View File

@ -0,0 +1,111 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "monoctr.h"
#include "flash_area.h"
#include "model.h"
#include "secret.h"
static int32_t get_offset(monoctr_type_t type) {
switch (type) {
case MONOCTR_BOOTLOADER_VERSION:
return SECRET_MONOTONIC_COUNTER_OFFSET;
case MONOCTR_FIRMWARE_VERSION:
return SECRET_MONOTONIC_COUNTER2_OFFSET;
default:
return -1;
}
}
secbool monoctr_write(monoctr_type_t type, uint8_t value) {
if (value > MONOCTR_MAX_VALUE) {
return secfalse;
}
int32_t offset = get_offset(type);
if (offset < 0) {
return secfalse;
}
for (int i = 0; i < value; i++) {
uint32_t data[4] = {0};
secret_write((uint8_t *)data, offset + i * 16, 16);
}
return sectrue;
}
secbool monoctr_read(monoctr_type_t type, uint8_t *value) {
int32_t offset = get_offset(type);
if (offset < 0) {
return secfalse;
}
const uint8_t *counter_addr = flash_area_get_address(
&SECRET_AREA, offset, SECRET_MONOTONIC_COUNTER_LEN);
if (counter_addr == NULL) {
return secfalse;
}
int counter = 0;
int i = 0;
for (i = 0; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) {
secbool not_cleared = sectrue;
for (int j = 0; j < 16; j++) {
if (counter_addr[i * 16 + j] != 0xFF) {
not_cleared = secfalse;
break;
}
}
if (not_cleared != sectrue) {
counter++;
} else {
break;
}
}
for (; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) {
secbool not_cleared = sectrue;
for (int j = 0; j < 16; j++) {
if (counter_addr[i * 16 + j] != 0xFF) {
not_cleared = secfalse;
break;
}
}
if (not_cleared != sectrue) {
// monotonic counter is not valid
return secfalse;
}
}
if (value != NULL) {
*value = counter;
} else {
return secfalse;
}
return sectrue;
}

View File

@ -0,0 +1,109 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "monoctr.h"
#include "flash_otp.h"
#include "model.h"
#include "string.h"
static int get_otp_block(monoctr_type_t type) {
switch (type) {
case MONOCTR_BOOTLOADER_VERSION:
return FLASH_OTP_BLOCK_BOOTLOADER_VERSION;
case MONOCTR_FIRMWARE_VERSION:
return FLASH_OTP_BLOCK_FIRMWARE_VERSION;
default:
return -1;
}
}
secbool monoctr_write(monoctr_type_t type, uint8_t value) {
if (value > MONOCTR_MAX_VALUE) {
return secfalse;
}
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
if (i < value) {
bits[i / 8] &= ~(1 << (7 - (i % 8)));
} else {
bits[i / 8] |= (1 << (7 - (i % 8)));
}
}
int block = get_otp_block(type);
if (block < 0) {
return secfalse;
}
ensure(flash_otp_write(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
return sectrue;
}
secbool monoctr_read(monoctr_type_t type, uint8_t* value) {
uint8_t bits[FLASH_OTP_BLOCK_SIZE];
int block = get_otp_block(type);
if (block < 0) {
return secfalse;
}
ensure(flash_otp_read(block, 0, bits, FLASH_OTP_BLOCK_SIZE), NULL);
int result = 0;
int i;
// Iterate through each bit position in the bit field
for (i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
// Calculate the byte and bit index within the byte
int byteIndex = i / 8;
int bitIndex = 7 - (i % 8);
// Check if the current bit is 0
if ((bits[byteIndex] & (1 << bitIndex)) == 0) {
// If the bit is 0, increment the value
result++;
} else {
// Stop when we find the first 1 bit
break;
}
}
for (; i < FLASH_OTP_BLOCK_SIZE * 8; i++) {
// Calculate the byte and bit index within the byte
int byteIndex = i / 8;
int bitIndex = 7 - (i % 8);
if ((bits[byteIndex] & (1 << bitIndex)) == 0) {
// If the bit is 0, return false - the monotonic counter is not valid
return secfalse;
}
}
if (value != NULL) {
*value = result;
} else {
return secfalse;
}
return sectrue;
}

View File

@ -47,6 +47,7 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/flash.c",
"embed/trezorhal/stm32f4/flash_otp.c",
"embed/trezorhal/stm32f4/lowlevel.c",
"embed/trezorhal/stm32f4/monoctr.c",
"embed/trezorhal/stm32f4/mpu.c",
"embed/trezorhal/stm32f4/platform.c",
"embed/trezorhal/stm32f4/secret.c",

View File

@ -57,6 +57,7 @@ def stm32u5_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32u5/flash_otp.c",
"embed/trezorhal/stm32u5/lowlevel.c",
"embed/trezorhal/stm32u5/hash_processor.c",
"embed/trezorhal/stm32u5/monoctr.c",
"embed/trezorhal/stm32u5/mpu.c",
"embed/trezorhal/stm32u5/platform.c",
"embed/trezorhal/stm32u5/secret.c",