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:
parent
d38546e229
commit
fcf2bd0d48
@ -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 = """
|
||||
|
28
core/embed/projects/secmon/header.S
Normal file
28
core/embed/projects/secmon/header.S
Normal 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:
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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,
|
||||
|
116
python/src/trezorlib/firmware/secmon.py
Normal file
116
python/src/trezorlib/firmware/secmon.py
Normal 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
|
Loading…
Reference in New Issue
Block a user