1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-29 18:08:19 +00:00

feat(core): add secmon header

[no changelog]
This commit is contained in:
tychovrahe 2025-06-15 19:30:28 +02:00 committed by TychoVrahe
parent d38546e229
commit fcf2bd0d48
8 changed files with 180 additions and 11 deletions

View File

@ -271,6 +271,11 @@ SOURCE_FIRMWARE = [
'embed/projects/secmon/main.c',
]
if TREZOR_MODEL not in ('T3B1', 'T3T1'):
SOURCE_FIRMWARE += [
'embed/projects/secmon/header.S',
]
if 'sd_card' in FEATURES_AVAILABLE:
SDCARD = True
else:
@ -411,10 +416,17 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
action_bin=[
'$OBJCOPY -O binary -j .flash -j .data -j .confidential -j .gnu.sgstubs $SOURCE ${TARGET}',
'$CP $TARGET ' + BINARY_NAME,
]
if TREZOR_MODEL in ('T3B1', 'T3T1'):
action_bin=[
'$OBJCOPY -O binary -j .secmon_header -j .flash -j .data -j .confidential -j .gnu.sgstubs $SOURCE ${TARGET}',
'$CP $TARGET ' + BINARY_NAME,
]
else:
action_bin=[
'$OBJCOPY -O binary -j .secmon_header -j .flash -j .data -j .confidential -j .gnu.sgstubs $SOURCE ${TARGET}',
'$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''),
'$CP $TARGET ' + BINARY_NAME,
]
if STORAGE_INSECURE_TESTING_MODE:
INSECURE_TESTING_MODE_STR = """

View File

@ -0,0 +1,28 @@
.syntax unified
#include "version.h"
.section .secmon_header, "a"
.type g_header, %object
.size g_header, .-g_header
// Secure monitor header
g_header:
.byte 'T','S','E','C' // magic
.word g_header_end - g_header // hdrlen
.word _codelen // codelen
.byte VERSION_MAJOR // vmajor
.byte VERSION_MINOR // vminor
.byte VERSION_PATCH // vpatch
.byte VERSION_BUILD // vbuild
.word HW_MODEL // type of the designated hardware
.byte HW_REVISION // revision of the designated hardware
. = . + 3 // reserved
. = . + 32 // hash of entire secmon
. = . + 391 // reserved
.byte 0 // sigmask
. = . + 64 // sig
g_header_end:

View File

@ -107,8 +107,8 @@ static void secmon_panic(const systask_postmortem_t *pminfo) {
}
// defined in linker script
extern uint32_t _codelen;
#define SECMON_SIZE ((uint32_t) & _codelen)
extern uint32_t _secmon_size;
#define SECMON_SIZE ((uint32_t) & _secmon_size)
#define KERNEL_START (FIRMWARE_START + SECMON_SIZE)
int main(void) {

View File

@ -28,7 +28,8 @@ _confidential_section_end = ADDR(.confidential) + SIZEOF(.confidential);
_bootargs_ram_start = BOOTARGS_START;
_bootargs_ram_end = BOOTARGS_START + BOOTARGS_SIZE;
_codelen = _secmon_flash_end - ORIGIN(FLASH);
_codelen = _secmon_flash_end - _secmon_code_start;
_secmon_size = _secmon_flash_end - ORIGIN(FLASH);
SECTIONS {
.vendorheader : ALIGN(4) {
@ -40,6 +41,15 @@ SECTIONS {
. = ALIGN(CODE_ALIGNMENT);
} >FLASH
.secmon_header : ALIGN(4) {
KEEP(*(.secmon_header));
} >FLASH
.padding : ALIGN(4) {
_secmon_code_start = .;
. = ALIGN(CODE_ALIGNMENT);
} >FLASH AT>FLASH
.flash : ALIGN(CODE_ALIGNMENT) {
KEEP(*(.vector_table));
. = ALIGN(4);

View File

@ -61,9 +61,9 @@ extern uint8_t _sgstubs_section_end;
#define SGSTUBS_SIZE (SGSTUBS_END - SGSTUBS_START)
// defined in linker script
extern uint32_t _codelen;
extern uint32_t _secmon_size;
#define SECMON_SIZE ((uint32_t) & _codelen)
#define SECMON_SIZE ((uint32_t) & _secmon_size)
#define NONSECURE_CODE_START (FIRMWARE_START + SECMON_SIZE)
#define NONSECURE_CODE_SIZE (FIRMWARE_MAXSIZE - SECMON_SIZE)

View File

@ -28,6 +28,8 @@ def do_rehash(fw: firmware_headers.SignableImageProto) -> None:
"""Recalculate the code hashes inside the header."""
if isinstance(fw, firmware.FirmwareImage):
fw.header.hashes = fw.code_hashes()
if isinstance(fw, firmware.SecmonImage):
fw.header.hash = fw.code_hash()
elif isinstance(fw, firmware_headers.VendorFirmware):
fw.firmware.header.hashes = fw.firmware.code_hashes()
# else: do nothing, other kinds of images do not need rehashing
@ -100,8 +102,8 @@ def cli(
"""Manage firmware headers.
This tool supports three types of files: raw vendor headers (TRZV), bootloader
images (TRZB), and firmware images which are prefixed with a vendor header
(TRZV+TRZF).
images (TRZB), firmware images which are prefixed with a vendor header
(TRZV+TRZF), and secmon images (TSEC).
Run with no options on a file to dump information about that file.

View File

@ -33,6 +33,7 @@ if True:
from .consts import * # noqa: F401, F403
from .core import * # noqa: F401, F403
from .legacy import * # noqa: F401, F403
from .secmon import * # noqa: F401, F403
from .util import ( # noqa: F401
FirmwareIntegrityError,
InvalidSignatureError,

View File

@ -0,0 +1,116 @@
# This file is part of the Trezor project.
#
# Copyright (C) 2012-2022 SatoshiLabs and contributors
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# This library 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 Lesser General Public License for more details.
#
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
from __future__ import annotations
from copy import copy
import construct as c
from construct_classes import Struct, subcon
from ..tools import EnumAdapter, TupleAdapter
from . import util
from .models import Model
__all__ = [
"SecmonHeader",
"SecmonImage",
]
class SecmonHeader(Struct):
header_len: int
code_length: int
version: tuple[int, int, int, int]
hw_model: Model | bytes
hw_revision: int
hash: bytes
sigmask: int
signature: bytes
# fmt: off
SUBCON = c.Struct(
"_start_offset" / c.Tell,
"magic" / c.Const(b"TSEC"),
"header_len" / c.Int32ul,
"code_length" / c.Int32ul,
"version" / TupleAdapter(c.Int8ul, c.Int8ul, c.Int8ul, c.Int8ul),
"hw_model" / EnumAdapter(c.Bytes(4), Model),
"hw_revision" / c.Int8ul,
"_reserved" / c.Padding(3),
"hash" / c.Bytes(32),
"_reserved" / c.Padding(391),
"sigmask" / c.Byte,
"signature" / c.Bytes(64),
"_end_offset" / c.Tell,
"_rebuild_header_len" / c.Pointer(
c.this._start_offset + 4,
c.Rebuild(c.Int32ul, c.this._end_offset - c.this._start_offset)
),
)
# fmt: on
class SecmonImage(Struct):
"""Raw secmon image.
Consists of secmon header and code block.
"""
header: SecmonHeader = subcon(SecmonHeader)
_header_end: int
_code_offset: int
code: bytes
SUBCON = c.Struct(
"header" / SecmonHeader.SUBCON,
"code" / c.Bytes(c.this.header.code_length),
c.Terminated,
)
def get_hash_params(self) -> util.FirmwareHashParameters:
return Model.from_hw_model(self.header.hw_model).hash_params()
def code_hash(self) -> bytes:
"""Calculate hash of `code`."""
hash_params = self.get_hash_params()
hash = hash_params.hash_function(self.code).digest()
return hash
def validate_code_hash(self) -> None:
if self.code_hash() != self.header.hash:
raise util.FirmwareIntegrityError("Invalid firmware data.")
def digest(self) -> bytes:
hash_params = self.get_hash_params()
header = copy(self.header)
header.hash = self.code_hash()
header.signature = b"\x00" * 64
header.sigmask = 0
return hash_params.hash_function(header.build()).digest()
def model(self) -> Model | None:
if isinstance(self.header.hw_model, Model):
return self.header.hw_model
return None