mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
feat(core): add hw_model field to vendor headers
This commit is contained in:
parent
da14c22712
commit
b6c2f2e5ba
1
core/.changelog.d/3048.added
Normal file
1
core/.changelog.d/3048.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
Added hw model field to all vendor headers.
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"header_len": 4608,
|
"header_len": 4608,
|
||||||
"text": "UNSAFE, FACTORY TEST ONLY",
|
"text": "UNSAFE, FACTORY TEST ONLY",
|
||||||
|
"hw_model": null,
|
||||||
"expiry": 0,
|
"expiry": 0,
|
||||||
"version": [0, 0],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"header_len": 4608,
|
"header_len": 4608,
|
||||||
"text": "QA ONLY, DO NOT USE!",
|
"text": "QA ONLY, DO NOT USE!",
|
||||||
|
"hw_model": null,
|
||||||
"expiry": 0,
|
"expiry": 0,
|
||||||
"version": [0, 0],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"header_len": 4608,
|
"header_len": 4608,
|
||||||
"text": "SatoshiLabs",
|
"text": "SatoshiLabs",
|
||||||
|
"hw_model": null,
|
||||||
"expiry": 0,
|
"expiry": 0,
|
||||||
"version": [0, 1],
|
"version": [0, 1],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"header_len": 4608,
|
"header_len": 4608,
|
||||||
"text": "UNSAFE, DO NOT USE!",
|
"text": "UNSAFE, DO NOT USE!",
|
||||||
|
"hw_model": null,
|
||||||
"expiry": 0,
|
"expiry": 0,
|
||||||
"version": [0, 1],
|
"version": [0, 1],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
|
@ -27,6 +27,10 @@ def build_vendorheader(specfile, image, outfile):
|
|||||||
spec["image"] = toif.ToifStruct.parse(image.read())
|
spec["image"] = toif.ToifStruct.parse(image.read())
|
||||||
spec["sigmask"] = 0
|
spec["sigmask"] = 0
|
||||||
spec["signature"] = b"\x00" * 64
|
spec["signature"] = b"\x00" * 64
|
||||||
|
if spec["hw_model"] is None:
|
||||||
|
spec["hw_model"] = b"\x00\x00\x00\x00"
|
||||||
|
else:
|
||||||
|
spec["hw_model"] = spec["hw_model"].encode("ascii")
|
||||||
|
|
||||||
min_length = minimum_header_len(spec)
|
min_length = minimum_header_len(spec)
|
||||||
if "header_len" not in spec:
|
if "header_len" not in spec:
|
||||||
|
1
python/.changelog.d/3048.added
Normal file
1
python/.changelog.d/3048.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
Recognize hw model field in vendor headers.
|
@ -264,6 +264,7 @@ class LegacySignedImage(SignableImageProto, Protocol):
|
|||||||
|
|
||||||
|
|
||||||
class CosiSignatureHeaderProto(Protocol):
|
class CosiSignatureHeaderProto(Protocol):
|
||||||
|
hw_model: t.Union[fw_models.Model, bytes]
|
||||||
signature: bytes
|
signature: bytes
|
||||||
sigmask: int
|
sigmask: int
|
||||||
|
|
||||||
@ -280,6 +281,11 @@ class CosiSignedMixin:
|
|||||||
def get_header(self) -> CosiSignatureHeaderProto:
|
def get_header(self) -> CosiSignatureHeaderProto:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_model_keys(self, dev_keys: bool) -> fw_models.ModelKeys:
|
||||||
|
hw_model = self.get_header().hw_model
|
||||||
|
model = fw_models.Model.from_hw_model(hw_model)
|
||||||
|
return model.model_keys(dev_keys)
|
||||||
|
|
||||||
|
|
||||||
class VendorHeader(firmware.VendorHeader, CosiSignedMixin):
|
class VendorHeader(firmware.VendorHeader, CosiSignedMixin):
|
||||||
NAME: t.ClassVar[str] = "vendorheader"
|
NAME: t.ClassVar[str] = "vendorheader"
|
||||||
@ -318,10 +324,7 @@ class VendorHeader(firmware.VendorHeader, CosiSignedMixin):
|
|||||||
return self._format(terse=False)
|
return self._format(terse=False)
|
||||||
|
|
||||||
def public_keys(self, dev_keys: bool = False) -> t.Sequence[bytes]:
|
def public_keys(self, dev_keys: bool = False) -> t.Sequence[bytes]:
|
||||||
if not dev_keys:
|
return self.get_model_keys(dev_keys).bootloader_keys
|
||||||
return fw_models.TREZOR_T.bootloader_keys
|
|
||||||
else:
|
|
||||||
return fw_models.TREZOR_T_DEV.bootloader_keys
|
|
||||||
|
|
||||||
|
|
||||||
class VendorFirmware(firmware.VendorFirmware, CosiSignedMixin):
|
class VendorFirmware(firmware.VendorFirmware, CosiSignedMixin):
|
||||||
@ -362,18 +365,6 @@ class BootloaderImage(firmware.FirmwareImage, CosiSignedMixin):
|
|||||||
NAME: t.ClassVar[str] = "bootloader"
|
NAME: t.ClassVar[str] = "bootloader"
|
||||||
DEV_KEYS = _make_dev_keys(b"\x41", b"\x42")
|
DEV_KEYS = _make_dev_keys(b"\x41", b"\x42")
|
||||||
|
|
||||||
def get_model(self) -> fw_models.Model:
|
|
||||||
if isinstance(self.header.hw_model, fw_models.Model):
|
|
||||||
return self.header.hw_model
|
|
||||||
return fw_models.Model.T
|
|
||||||
|
|
||||||
def get_model_keys(self, dev_keys: bool) -> fw_models.ModelKeys:
|
|
||||||
model = self.get_model()
|
|
||||||
if dev_keys:
|
|
||||||
return fw_models.MODEL_MAP_DEV[model]
|
|
||||||
else:
|
|
||||||
return fw_models.MODEL_MAP[model]
|
|
||||||
|
|
||||||
def get_header(self) -> CosiSignatureHeaderProto:
|
def get_header(self) -> CosiSignatureHeaderProto:
|
||||||
return self.header
|
return self.header
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class FirmwareHeader(Struct):
|
|||||||
code_length: int
|
code_length: int
|
||||||
version: t.Tuple[int, int, int, int]
|
version: t.Tuple[int, int, int, int]
|
||||||
fix_version: t.Tuple[int, int, int, int]
|
fix_version: t.Tuple[int, int, int, int]
|
||||||
hw_model: Model
|
hw_model: t.Union[Model, bytes]
|
||||||
hw_revision: int
|
hw_revision: int
|
||||||
monotonic: int
|
monotonic: int
|
||||||
hashes: t.List[bytes]
|
hashes: t.List[bytes]
|
||||||
|
@ -18,12 +18,30 @@ import typing as t
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
if t.TYPE_CHECKING:
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
|
||||||
class Model(Enum):
|
class Model(Enum):
|
||||||
ONE = b"T1B1"
|
ONE = b"T1B1"
|
||||||
T = b"T2T1"
|
T = b"T2T1"
|
||||||
R = b"T2B1"
|
R = b"T2B1"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_hw_model(cls, hw_model: t.Union["Self", bytes]) -> "Self":
|
||||||
|
if isinstance(hw_model, cls):
|
||||||
|
return hw_model
|
||||||
|
if hw_model == b"\x00\x00\x00\x00":
|
||||||
|
return cls.T
|
||||||
|
raise ValueError(f"Unknown hardware model: {hw_model}")
|
||||||
|
|
||||||
|
def model_keys(self, dev_keys: bool = False) -> "ModelKeys":
|
||||||
|
if dev_keys:
|
||||||
|
model_map = MODEL_MAP_DEV
|
||||||
|
else:
|
||||||
|
model_map = MODEL_MAP
|
||||||
|
return model_map[self]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ModelKeys:
|
class ModelKeys:
|
||||||
|
@ -23,9 +23,9 @@ from construct_classes import Struct, subcon
|
|||||||
|
|
||||||
from .. import cosi
|
from .. import cosi
|
||||||
from ..toif import ToifStruct
|
from ..toif import ToifStruct
|
||||||
from ..tools import TupleAdapter
|
from ..tools import EnumAdapter, TupleAdapter
|
||||||
from . import util
|
from . import util
|
||||||
from .models import TREZOR_T, TREZOR_T_DEV
|
from .models import Model
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"VendorTrust",
|
"VendorTrust",
|
||||||
@ -75,6 +75,7 @@ class VendorHeader(Struct):
|
|||||||
version: t.Tuple[int, int]
|
version: t.Tuple[int, int]
|
||||||
sig_m: int
|
sig_m: int
|
||||||
# sig_n: int
|
# sig_n: int
|
||||||
|
hw_model: t.Union[Model, bytes]
|
||||||
pubkeys: t.List[bytes]
|
pubkeys: t.List[bytes]
|
||||||
text: str
|
text: str
|
||||||
image: t.Dict[str, t.Any]
|
image: t.Dict[str, t.Any]
|
||||||
@ -93,7 +94,8 @@ class VendorHeader(Struct):
|
|||||||
"sig_m" / c.Int8ul,
|
"sig_m" / c.Int8ul,
|
||||||
"sig_n" / c.Rebuild(c.Int8ul, c.len_(c.this.pubkeys)),
|
"sig_n" / c.Rebuild(c.Int8ul, c.len_(c.this.pubkeys)),
|
||||||
"trust" / VendorTrust.SUBCON,
|
"trust" / VendorTrust.SUBCON,
|
||||||
"_reserved" / c.Padding(14),
|
"hw_model" / EnumAdapter(c.Bytes(4), Model),
|
||||||
|
"_reserved" / c.Padding(10),
|
||||||
"pubkeys" / c.Bytes(32)[c.this.sig_n],
|
"pubkeys" / c.Bytes(32)[c.this.sig_n],
|
||||||
"text" / c.Aligned(4, c.PascalString(c.Int8ul, "utf-8")),
|
"text" / c.Aligned(4, c.PascalString(c.Int8ul, "utf-8")),
|
||||||
"image" / ToifStruct,
|
"image" / ToifStruct,
|
||||||
@ -128,19 +130,13 @@ class VendorHeader(Struct):
|
|||||||
|
|
||||||
def verify(self, dev_keys: bool = False) -> None:
|
def verify(self, dev_keys: bool = False) -> None:
|
||||||
digest = self.digest()
|
digest = self.digest()
|
||||||
if not dev_keys:
|
model_keys = Model.from_hw_model(self.hw_model).model_keys(dev_keys)
|
||||||
public_keys = TREZOR_T.bootloader_keys
|
|
||||||
sigs_needed = TREZOR_T.bootloader_sigs_needed
|
|
||||||
else:
|
|
||||||
public_keys = TREZOR_T_DEV.bootloader_keys
|
|
||||||
sigs_needed = TREZOR_T_DEV.bootloader_sigs_needed
|
|
||||||
# TODO: add model awareness
|
|
||||||
try:
|
try:
|
||||||
cosi.verify(
|
cosi.verify(
|
||||||
self.signature,
|
self.signature,
|
||||||
digest,
|
digest,
|
||||||
sigs_needed,
|
model_keys.bootloader_sigs_needed,
|
||||||
public_keys,
|
model_keys.bootloader_keys,
|
||||||
self.sigmask,
|
self.sigmask,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -29,6 +29,7 @@ VENDOR_HEADER = (
|
|||||||
/ "core"
|
/ "core"
|
||||||
/ "embed"
|
/ "embed"
|
||||||
/ "vendorheader"
|
/ "vendorheader"
|
||||||
|
/ "T2T1"
|
||||||
/ "vendorheader_satoshilabs_signed_prod.bin"
|
/ "vendorheader_satoshilabs_signed_prod.bin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user