mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-01 19:38:33 +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',
|
'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:
|
if 'sd_card' in FEATURES_AVAILABLE:
|
||||||
SDCARD = True
|
SDCARD = True
|
||||||
else:
|
else:
|
||||||
@ -411,8 +416,15 @@ BINARY_NAME += "-" + tools.get_git_revision_short_hash()
|
|||||||
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
|
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
|
||||||
BINARY_NAME += ".bin"
|
BINARY_NAME += ".bin"
|
||||||
|
|
||||||
|
if TREZOR_MODEL in ('T3B1', 'T3T1'):
|
||||||
action_bin=[
|
action_bin=[
|
||||||
'$OBJCOPY -O binary -j .flash -j .data -j .confidential -j .gnu.sgstubs $SOURCE ${TARGET}',
|
'$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,
|
'$CP $TARGET ' + BINARY_NAME,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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
|
// 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 KERNEL_START (FIRMWARE_START + SECMON_SIZE)
|
#define KERNEL_START (FIRMWARE_START + SECMON_SIZE)
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
@ -28,7 +28,8 @@ _confidential_section_end = ADDR(.confidential) + SIZEOF(.confidential);
|
|||||||
_bootargs_ram_start = BOOTARGS_START;
|
_bootargs_ram_start = BOOTARGS_START;
|
||||||
_bootargs_ram_end = BOOTARGS_START + BOOTARGS_SIZE;
|
_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 {
|
SECTIONS {
|
||||||
.vendorheader : ALIGN(4) {
|
.vendorheader : ALIGN(4) {
|
||||||
@ -40,6 +41,15 @@ SECTIONS {
|
|||||||
. = ALIGN(CODE_ALIGNMENT);
|
. = ALIGN(CODE_ALIGNMENT);
|
||||||
} >FLASH
|
} >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) {
|
.flash : ALIGN(CODE_ALIGNMENT) {
|
||||||
KEEP(*(.vector_table));
|
KEEP(*(.vector_table));
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -61,9 +61,9 @@ extern uint8_t _sgstubs_section_end;
|
|||||||
#define SGSTUBS_SIZE (SGSTUBS_END - SGSTUBS_START)
|
#define SGSTUBS_SIZE (SGSTUBS_END - SGSTUBS_START)
|
||||||
|
|
||||||
// defined in linker script
|
// 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_START (FIRMWARE_START + SECMON_SIZE)
|
||||||
#define NONSECURE_CODE_SIZE (FIRMWARE_MAXSIZE - 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."""
|
"""Recalculate the code hashes inside the header."""
|
||||||
if isinstance(fw, firmware.FirmwareImage):
|
if isinstance(fw, firmware.FirmwareImage):
|
||||||
fw.header.hashes = fw.code_hashes()
|
fw.header.hashes = fw.code_hashes()
|
||||||
|
if isinstance(fw, firmware.SecmonImage):
|
||||||
|
fw.header.hash = fw.code_hash()
|
||||||
elif isinstance(fw, firmware_headers.VendorFirmware):
|
elif isinstance(fw, firmware_headers.VendorFirmware):
|
||||||
fw.firmware.header.hashes = fw.firmware.code_hashes()
|
fw.firmware.header.hashes = fw.firmware.code_hashes()
|
||||||
# else: do nothing, other kinds of images do not need rehashing
|
# else: do nothing, other kinds of images do not need rehashing
|
||||||
@ -100,8 +102,8 @@ def cli(
|
|||||||
"""Manage firmware headers.
|
"""Manage firmware headers.
|
||||||
|
|
||||||
This tool supports three types of files: raw vendor headers (TRZV), bootloader
|
This tool supports three types of files: raw vendor headers (TRZV), bootloader
|
||||||
images (TRZB), and firmware images which are prefixed with a vendor header
|
images (TRZB), firmware images which are prefixed with a vendor header
|
||||||
(TRZV+TRZF).
|
(TRZV+TRZF), and secmon images (TSEC).
|
||||||
|
|
||||||
Run with no options on a file to dump information about that file.
|
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 .consts import * # noqa: F401, F403
|
||||||
from .core import * # noqa: F401, F403
|
from .core import * # noqa: F401, F403
|
||||||
from .legacy import * # noqa: F401, F403
|
from .legacy import * # noqa: F401, F403
|
||||||
|
from .secmon import * # noqa: F401, F403
|
||||||
from .util import ( # noqa: F401
|
from .util import ( # noqa: F401
|
||||||
FirmwareIntegrityError,
|
FirmwareIntegrityError,
|
||||||
InvalidSignatureError,
|
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