diff --git a/psptool/key_store_file.py b/psptool/key_store_file.py index fe17c96..523a22e 100644 --- a/psptool/key_store_file.py +++ b/psptool/key_store_file.py @@ -81,9 +81,13 @@ def __init__(self, file): self.certifying_id = KeyId(self, 0x10, buffer_offset=0x38) - self._unknown_constant_1 = NestedBuffer(self, 0x4, buffer_offset=0x30) - self._unknown_constant_2 = NestedBuffer(self, 0x4, buffer_offset=0x34) - assert self.unknown_constants == (b'\1\0\0\0', b'\2\0\0\0') + # Same fields as in a HeaderFile. Early Renoir key stores leave the + # signature type at 0 next to a 0x200 byte signature, so + # signature_size is derived from the sizes instead. + self._signed = NestedBuffer(self, 0x4, buffer_offset=0x30) + self._signature_type = NestedBuffer(self, 0x4, buffer_offset=0x34) + assert self.signed == 1 + assert self.signature_type in {0, 2} self._keystore_type = NestedBuffer(self, 0x4, buffer_offset=0x7c) assert self.keystore_type in File.KEY_STORE_TYPES or self.keystore_type == 0 @@ -130,11 +134,12 @@ def signature_size(self) -> int: return self.parent_buffer.buffer_size - self.body_size - self.HEADER_SIZE @property - def unknown_constants(self) -> (bytes, bytes, bytes): - return ( - self._unknown_constant_1.get_bytes(), - self._unknown_constant_2.get_bytes(), - ) + def signed(self) -> int: + return int.from_bytes(self._signed.get_bytes(), 'little') + + @property + def signature_type(self) -> int: + return int.from_bytes(self._signature_type.get_bytes(), 'little') class KeyStore(NestedBuffer): diff --git a/tests/unit/test_key_store_file.py b/tests/unit/test_key_store_file.py new file mode 100644 index 0000000..875c90b --- /dev/null +++ b/tests/unit/test_key_store_file.py @@ -0,0 +1,91 @@ +# PSPTool - Display, extract and manipulate PSP firmware inside UEFI images +# Copyright (C) 2026 contributors +# +# 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. + +"""Synthetic ROMs holding a single 0x50 key store. + +Key stores in early ThinkPad T14/X13 Gen 1 AMD releases have no $PS1 +magic and signature type 0 next to a 0x200 byte signature. +""" + +import contextlib +import io +import os +import struct +import tempfile +import unittest + +from psptool import PSPTool +from psptool.blob import Blob +from psptool.utils import fletcher32 + +ROM_SIZE = 8 * 1024 * 1024 +FET_OFFSET = Blob.POSSIBLE_FET_OFFSETS[0] +PSP_DIR_OFFSET = FET_OFFSET + 0x1000 +KEY_STORE_OFFSET = FET_OFFSET + 0x2000 +HEADER_FILE_SIZE = 0x100 + +# Directory additional_info: version bit set, address mode 1 (flash offset) +FLASH_OFFSET_MODE = (1 << 31) | (1 << 24) + + +def key_store_file(magic: bytes, signature_type: int) -> bytes: + modulus_size = 0x100 + key = struct.pack(' bytes: + blob = bytearray(ROM_SIZE) + blob[FET_OFFSET - 4:FET_OFFSET] = b'\xff' * 4 + blob[FET_OFFSET:FET_OFFSET + 4] = Blob._FIRMWARE_ENTRY_MAGIC + blob[FET_OFFSET + 4:FET_OFFSET + 8] = struct.pack('