matejcik 2 weeks ago committed by GitHub
commit 6893628b15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -132,47 +132,118 @@ message DebugLinkLog {
}
/**
* Request: Read memory from device
* Location in the flash memory.enum
* @embed
*/
message DebugFlashMemoryLocation {
/// Selector of the area
required DebugFlashArea area = 1;
/// Offset from area start
required uint32 offset = 2;
enum DebugFlashArea {
Boardloader = 0;
Bootloader = 1;
StorageA = 2;
StorageB = 3;
Firmware = 4;
Translations = 5;
}
}
/**
* Request: Read memory from device (legacy)
* @start
* @next DebugLinkMemory
*/
message DebugLinkMemoryRead {
option deprecated = true;
optional uint32 address = 1;
optional uint32 length = 2;
}
/**
* Request: Read flash contents from device (trezor-core)
* @start
* @next DebugLinkMemory
*/
message DebugLinkFlashRead {
/// Flash memory location
required DebugFlashMemoryLocation location = 1;
/// Length of the memory to read. If unspecified, the whole area is read.
optional uint32 length = 2;
/// If true, only the hash of the memory contents will be returned.
/// Useful if the memory is large and the hash is enough to verify the contents.
optional bool hashed = 3 [default = false];
}
/**
* Response: Device sends memory back
* @end
*/
message DebugLinkMemory {
optional bytes memory = 1;
optional bytes hash = 2;
}
/**
* Request: Write memory to device.
* Request: Write memory to device (legacy).
* WARNING: Writing to the wrong location can irreparably break the device.
* @start
* @next Success
* @next Failure
*/
message DebugLinkMemoryWrite {
option deprecated = true;
optional uint32 address = 1;
optional bytes memory = 2;
optional bool flash = 3;
}
/**
* Request: Erase block of flash on device
* Request: Write to device flash memory (trezor-core).
* WARNING: Writing to the wrong location can irreparably break the device.
* @start
* @next Success
* @next Failure
*/
message DebugLinkFlashWrite {
/// Flash memory location
required DebugFlashMemoryLocation location = 1;
/// Contents of the memory to flash.
required bytes memory = 2;
}
/**
* Request: Erase block of flash on device (legacy)
* WARNING: Writing to the wrong location can irreparably break the device.
* @start
* @next Success
* @next Failure
*/
message DebugLinkFlashErase {
message DebugLinkFlashEraseLegacy {
option deprecated = true;
optional uint32 sector = 1;
}
/**
* Request: Erase block of flash on device (trezor-core)
* WARNING: Writing to the wrong location can irreparably break the device.
* @start
* @next Success
* @next Failure
*/
message DebugLinkFlashErase {
/// Flash memory location
required DebugFlashMemoryLocation location = 1;
/// Erase whole area or just the sector at the given offset.
/// If the offset is not a start of a sector, error is returned.
optional bool whole_area = 2 [default = false];
}
/**
* Request: Erase the SD card

@ -179,16 +179,19 @@ enum MessageType {
MessageType_DebugLinkState = 102 [(bitcoin_only) = true, (wire_debug_out) = true];
MessageType_DebugLinkStop = 103 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkLog = 104 [(bitcoin_only) = true, (wire_debug_out) = true];
MessageType_DebugLinkMemoryRead = 110 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkMemoryRead = 110 [(bitcoin_only) = true, (wire_debug_in) = true, deprecated = true];
MessageType_DebugLinkMemory = 111 [(bitcoin_only) = true, (wire_debug_out) = true];
MessageType_DebugLinkMemoryWrite = 112 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkFlashErase = 113 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkMemoryWrite = 112 [(bitcoin_only) = true, (wire_debug_in) = true, deprecated = true];
MessageType_DebugLinkFlashEraseLegacy = 113 [(bitcoin_only) = true, (wire_debug_in) = true, deprecated = true];
MessageType_DebugLinkLayout = 9001 [(bitcoin_only) = true, (wire_debug_out) = true];
MessageType_DebugLinkReseedRandom = 9002 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkRecordScreen = 9003 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkEraseSdCard = 9005 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkWatchLayout = 9006 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkResetDebugEvents = 9007 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkFlashRead = 9008 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkFlashWrite = 9009 [(bitcoin_only) = true, (wire_debug_in) = true];
MessageType_DebugLinkFlashErase = 9010 [(bitcoin_only) = true, (wire_debug_in) = true];
// Ethereum
MessageType_EthereumGetPublicKey = 450 [(wire_in) = true];

@ -17,7 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "blake2s.h"
#include "common.h"
#include "flash_otp.h"
#include "model.h"
#include "embed/extmod/trezorobj.h"
@ -118,3 +123,303 @@ STATIC const mp_obj_type_t mod_trezorio_FlashOTP_type = {
.make_new = mod_trezorio_FlashOTP_make_new,
.locals_dict = (void *)&mod_trezorio_FlashOTP_locals_dict,
};
/// class FlashArea:
/// """
/// Area of the flash memory
/// """
typedef struct _mp_obj_FlashArea_t {
mp_obj_base_t base;
const flash_area_t *area;
} mp_obj_FlashArea_t;
#define FLASH_READ_CHUNK_SIZE 1024
#define CHUNKS_PER_PROGRESS_STEP ((1024 / FLASH_READ_CHUNK_SIZE) * 16)
static void ui_progress(mp_obj_t ui_wait_callback, uint32_t current) {
if (mp_obj_is_callable(ui_wait_callback)) {
mp_call_function_1_protected(ui_wait_callback, mp_obj_new_int(current));
}
}
/// def size(self) -> int:
/// """
/// Returns size of the flash area
/// """
STATIC mp_obj_t mod_trezorio_FlashArea_size(mp_obj_t obj_self) {
mp_obj_FlashArea_t *self = (mp_obj_FlashArea_t *)MP_OBJ_TO_PTR(obj_self);
return MP_OBJ_NEW_SMALL_INT(flash_area_get_size(self->area));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_FlashArea_size_obj,
mod_trezorio_FlashArea_size);
/// def hash(
/// self,
/// offset: int,
/// length: int,
/// challenge: bytes | None = None,
/// callback: Callable[[int], None] | None = None,
/// ) -> bytes:
/// """
/// Computes a Blake2s hash of a segment of the flash area.
/// Offset and length must be aligned to 1024 bytes.
/// An optional challenge can be used as the Blake2s key.
/// The progress callback will be invoked every 16 kB with the number of
/// bytes processed so far.
/// """
STATIC mp_obj_t mod_trezorio_FlashArea_hash(size_t n_args,
const mp_obj_t *args) {
mp_obj_FlashArea_t *self = (mp_obj_FlashArea_t *)MP_OBJ_TO_PTR(args[0]);
uint32_t offset = trezor_obj_get_uint(args[1]);
uint32_t length = trezor_obj_get_uint(args[2]);
if (offset % FLASH_READ_CHUNK_SIZE != 0 ||
length % FLASH_READ_CHUNK_SIZE != 0) {
mp_raise_ValueError("Offset and length must be aligned to 1024 bytes.");
}
mp_buffer_info_t challenge = {0};
if (n_args > 3 && args[3] != mp_const_none) {
mp_get_buffer_raise(args[3], &challenge, MP_BUFFER_READ);
}
mp_obj_t ui_wait_callback = mp_const_none;
if (n_args > 4) {
ui_wait_callback = args[4];
}
BLAKE2S_CTX ctx;
if (challenge.len != 0) {
if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, challenge.buf,
challenge.len) != 0) {
mp_raise_msg(&mp_type_ValueError, "Invalid challenge.");
}
} else {
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
}
uint32_t area_size = flash_area_get_size(self->area);
if (offset > area_size || area_size - offset < length) {
mp_raise_ValueError("Read too long.");
}
const uint32_t chunks = length / FLASH_READ_CHUNK_SIZE;
ui_progress(ui_wait_callback, 0);
for (int i = 0; i < chunks; i++) {
const uint32_t current_offset = offset + i * FLASH_READ_CHUNK_SIZE;
const void *data = flash_area_get_address(self->area, current_offset,
FLASH_READ_CHUNK_SIZE);
if (data == NULL) {
mp_raise_msg(&mp_type_RuntimeError, "Failed to read flash.");
}
blake2s_Update(&ctx, data, FLASH_READ_CHUNK_SIZE);
if (i % CHUNKS_PER_PROGRESS_STEP == 0) {
ui_progress(ui_wait_callback, i * FLASH_READ_CHUNK_SIZE);
}
}
ui_progress(ui_wait_callback, length);
vstr_t vstr = {0};
vstr_init_len(&vstr, BLAKE2S_DIGEST_LENGTH);
if (blake2s_Final(&ctx, vstr.buf, vstr.len) != 0) {
vstr_clear(&vstr);
mp_raise_msg(&mp_type_RuntimeError, "Failed to finalize hash.");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_FlashArea_hash_obj, 3,
5, mod_trezorio_FlashArea_hash);
/// if __debug__:
/// def read(self, offset: int, data: bytearray) -> None:
/// """
/// Reads data from flash area. Will read exact length of data
/// bytearray. Offset and length of data must be aligned to 1024 bytes.
/// """
#if PYOPT == 0
STATIC mp_obj_t mod_trezorio_FlashArea_read(mp_obj_t obj_self,
mp_obj_t obj_offset,
mp_obj_t obj_data) {
mp_obj_FlashArea_t *self = (mp_obj_FlashArea_t *)MP_OBJ_TO_PTR(obj_self);
uint32_t offset = trezor_obj_get_uint(obj_offset);
mp_buffer_info_t data = {0};
mp_get_buffer_raise(obj_data, &data, MP_BUFFER_WRITE);
if (offset % FLASH_READ_CHUNK_SIZE != 0 ||
data.len % FLASH_READ_CHUNK_SIZE != 0) {
mp_raise_ValueError("Offset and length must be aligned to 1024 bytes.");
}
uint32_t area_size = flash_area_get_size(self->area);
if (offset > area_size || area_size - offset < data.len) {
mp_raise_ValueError("Read too long.");
}
uint32_t chunks = data.len / FLASH_READ_CHUNK_SIZE;
for (int i = 0; i < chunks; i++) {
const uint32_t current_offset = offset + i * FLASH_READ_CHUNK_SIZE;
const void *flash_data = flash_area_get_address(&FIRMWARE_AREA, current_offset,
FLASH_READ_CHUNK_SIZE);
if (flash_data == NULL) {
mp_raise_msg(&mp_type_RuntimeError, "Failed to read flash.");
}
memcpy(data.buf + i * FLASH_READ_CHUNK_SIZE, flash_data, FLASH_READ_CHUNK_SIZE);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_FlashArea_read_obj,
mod_trezorio_FlashArea_read);
/// if __debug__:
/// def write(self, offset: int, data: bytes) -> None:
/// """
/// Writes data to flash area.
/// Offset and written data size must be a multiple of FLASH_BLOCK_SIZE,
/// that is, 4 bytes on F4 or 16 bytes on U5.
/// """
STATIC mp_obj_t mod_trezorio_FlashArea_write(mp_obj_t obj_self,
mp_obj_t obj_offset,
mp_obj_t obj_data) {
mp_obj_FlashArea_t *self = (mp_obj_FlashArea_t *)MP_OBJ_TO_PTR(obj_self);
uint32_t offset = trezor_obj_get_uint(obj_offset);
mp_buffer_info_t data = {0};
mp_get_buffer_raise(obj_data, &data, MP_BUFFER_READ);
if (data.len % FLASH_BLOCK_SIZE != 0) {
mp_raise_ValueError("Write size must be a multiple of write unit.");
}
uint32_t area_size = flash_area_get_size(self->area);
if (offset > area_size || area_size - offset < data.len) {
mp_raise_ValueError("Write too long.");
}
uint32_t blocks = data.len / FLASH_BLOCK_SIZE;
const flash_block_t *data_as_blocks = (const flash_block_t *)data.buf;
ensure(flash_unlock_write(), NULL);
for (int i = 0; i < blocks; i++) {
if (sectrue != flash_area_write_block(self->area,
offset + i * FLASH_BLOCK_SIZE,
data_as_blocks[i])) {
ensure(flash_lock_write(), NULL);
mp_raise_ValueError("Write failed.");
}
}
ensure(flash_lock_write(), NULL);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorio_FlashArea_write_obj,
mod_trezorio_FlashArea_write);
/// if __debug__:
/// def erase_sector(self, offset: int) -> None:
/// """
/// Erases a flash area sector starting at specified offset.
/// """
STATIC mp_obj_t mod_trezorio_FlashArea_erase_sector(mp_obj_t obj_self,
mp_obj_t obj_offset) {
mp_obj_FlashArea_t *self = (mp_obj_FlashArea_t *)MP_OBJ_TO_PTR(obj_self);
uint32_t offset = trezor_obj_get_uint(obj_offset);
uint32_t bytes_erased = 0;
if (sectrue != flash_area_erase_partial(self->area, offset, &bytes_erased)) {
mp_raise_ValueError("Erase failed.");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_FlashArea_erase_sector_obj,
mod_trezorio_FlashArea_erase_sector);
/// if __debug__:
/// def erase(self) -> None:
/// """
/// Erases the whole flash area.
/// """
STATIC mp_obj_t mod_trezorio_FlashArea_erase(mp_obj_t obj_self) {
mp_obj_FlashArea_t *self = (mp_obj_FlashArea_t *)MP_OBJ_TO_PTR(obj_self);
if (sectrue != flash_area_erase(self->area, NULL)) {
mp_raise_ValueError("Erase failed.");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_FlashArea_erase_obj,
mod_trezorio_FlashArea_erase);
#endif // PYOPT == 0
STATIC const mp_rom_map_elem_t mod_trezorio_FlashArea_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&mod_trezorio_FlashArea_size_obj)},
{MP_ROM_QSTR(MP_QSTR_hash), MP_ROM_PTR(&mod_trezorio_FlashArea_hash_obj)},
#if PYOPT == 0
{MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_trezorio_FlashArea_read_obj)},
{MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_trezorio_FlashArea_write_obj)},
{MP_ROM_QSTR(MP_QSTR_erase_sector),
MP_ROM_PTR(&mod_trezorio_FlashArea_erase_sector_obj)},
{MP_ROM_QSTR(MP_QSTR_erase), MP_ROM_PTR(&mod_trezorio_FlashArea_erase_obj)},
#endif
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_FlashArea_locals_dict,
mod_trezorio_FlashArea_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorio_FlashArea_type = {
{&mp_type_type},
.name = MP_QSTR_FlashArea,
.locals_dict = (void *)&mod_trezorio_FlashArea_locals_dict,
};
#define FLASH_AREA(name, area_id) \
STATIC const mp_obj_FlashArea_t mod_trezorio_flash_area_##name = { \
.base = {.type = MP_ROM_PTR(&mod_trezorio_FlashArea_type)}, \
.area = &area_id, \
};
/// mock:global
/// package: trezorio.flash_area
/// from . import FlashArea
/// BOARDLOADER: FlashArea
/// BOOTLOADER: FlashArea
/// FIRMWARE: FlashArea
/// TRANSLATIONS: FlashArea
/// if __debug__:
/// STORAGE_A: FlashArea
/// STORAGE_B: FlashArea
FLASH_AREA(BOARDLOADER, BOARDLOADER_AREA)
FLASH_AREA(BOOTLOADER, BOOTLOADER_AREA)
FLASH_AREA(FIRMWARE, FIRMWARE_AREA)
FLASH_AREA(TRANSLATIONS, TRANSLATIONS_AREA)
#if PYOPT == 0
FLASH_AREA(STORAGE_A, STORAGE_AREAS[0])
FLASH_AREA(STORAGE_B, STORAGE_AREAS[1])
#endif
#define MP_ROM_FLASH_AREA(name) \
{ MP_ROM_QSTR(MP_QSTR_##name), MP_ROM_PTR(&mod_trezorio_flash_area_##name) }
STATIC const mp_rom_map_elem_t mod_trezorio_flash_area_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_flash_area)},
MP_ROM_FLASH_AREA(BOARDLOADER),
MP_ROM_FLASH_AREA(BOOTLOADER),
MP_ROM_FLASH_AREA(FIRMWARE),
MP_ROM_FLASH_AREA(TRANSLATIONS),
#if PYOPT == 0
MP_ROM_FLASH_AREA(STORAGE_A),
MP_ROM_FLASH_AREA(STORAGE_B),
#endif
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorio_flash_area_globals,
mod_trezorio_flash_area_globals_table);
const mp_obj_module_t mod_trezorio_flash_area = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorio_flash_area_globals,
};

@ -57,7 +57,7 @@ bool usb_connected_previously = true;
#endif
/// package: trezorio.__init__
/// from . import fatfs, sdcard
/// from . import fatfs, sdcard, flash_area
/// POLL_READ: int # wait until interface is readable and return read data
/// POLL_WRITE: int # wait until interface is writable
@ -106,6 +106,7 @@ STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = {
#endif
{MP_ROM_QSTR(MP_QSTR_FlashOTP), MP_ROM_PTR(&mod_trezorio_FlashOTP_type)},
{MP_ROM_QSTR(MP_QSTR_flash_area), MP_ROM_PTR(&mod_trezorio_flash_area)},
{MP_ROM_QSTR(MP_QSTR_USB), MP_ROM_PTR(&mod_trezorio_USB_type)},
{MP_ROM_QSTR(MP_QSTR_HID), MP_ROM_PTR(&mod_trezorio_HID_type)},

@ -48,16 +48,6 @@
#include "secret.h"
#endif
#define FW_HASHING_CHUNK_SIZE 1024
static void ui_progress(mp_obj_t ui_wait_callback, uint32_t current,
uint32_t total) {
if (mp_obj_is_callable(ui_wait_callback)) {
mp_call_function_2_protected(ui_wait_callback, mp_obj_new_int(current),
mp_obj_new_int(total));
}
}
/// def consteq(sec: bytes, pub: bytes) -> bool:
/// """
/// Compares the private information in `sec` with public, user-provided
@ -145,68 +135,6 @@ STATIC mp_obj_t mod_trezorutils_halt(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_halt_obj, 0, 1,
mod_trezorutils_halt);
/// def firmware_hash(
/// challenge: bytes | None = None,
/// callback: Callable[[int, int], None] | None = None,
/// ) -> bytes:
/// """
/// Computes the Blake2s hash of the firmware with an optional challenge as
/// the key.
/// """
STATIC mp_obj_t mod_trezorutils_firmware_hash(size_t n_args,
const mp_obj_t *args) {
BLAKE2S_CTX ctx;
mp_buffer_info_t chal = {0};
if (n_args > 0 && args[0] != mp_const_none) {
mp_get_buffer_raise(args[0], &chal, MP_BUFFER_READ);
}
if (chal.len != 0) {
if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, chal.buf, chal.len) != 0) {
mp_raise_msg(&mp_type_ValueError, "Invalid challenge.");
}
} else {
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
}
mp_obj_t ui_wait_callback = mp_const_none;
if (n_args > 1 && args[1] != mp_const_none) {
ui_wait_callback = args[1];
}
uint32_t firmware_size = flash_area_get_size(&FIRMWARE_AREA);
uint32_t chunks = firmware_size / FW_HASHING_CHUNK_SIZE;
ensure((firmware_size % FW_HASHING_CHUNK_SIZE == 0) * sectrue,
"Cannot compute FW hash.");
ui_progress(ui_wait_callback, 0, chunks);
for (int i = 0; i < chunks; i++) {
const void *data = flash_area_get_address(
&FIRMWARE_AREA, i * FW_HASHING_CHUNK_SIZE, FW_HASHING_CHUNK_SIZE);
if (data == NULL) {
mp_raise_msg(&mp_type_RuntimeError, "Failed to read firmware.");
}
blake2s_Update(&ctx, data, FW_HASHING_CHUNK_SIZE);
if (i % 128 == 0) {
ui_progress(ui_wait_callback, i + 1, chunks);
}
}
ui_progress(ui_wait_callback, chunks, chunks);
vstr_t vstr = {0};
vstr_init_len(&vstr, BLAKE2S_DIGEST_LENGTH);
if (blake2s_Final(&ctx, vstr.buf, vstr.len) != 0) {
vstr_clear(&vstr);
mp_raise_msg(&mp_type_RuntimeError, "Failed to finalize firmware hash.");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_firmware_hash_obj, 0,
2, mod_trezorutils_firmware_hash);
/// def firmware_vendor() -> str:
/// """
/// Returns the firmware vendor string from the vendor header.
@ -442,8 +370,6 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR_consteq), MP_ROM_PTR(&mod_trezorutils_consteq_obj)},
{MP_ROM_QSTR(MP_QSTR_memcpy), MP_ROM_PTR(&mod_trezorutils_memcpy_obj)},
{MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&mod_trezorutils_halt_obj)},
{MP_ROM_QSTR(MP_QSTR_firmware_hash),
MP_ROM_PTR(&mod_trezorutils_firmware_hash_obj)},
{MP_ROM_QSTR(MP_QSTR_firmware_vendor),
MP_ROM_PTR(&mod_trezorutils_firmware_vendor_obj)},
{MP_ROM_QSTR(MP_QSTR_reboot_to_bootloader),

@ -31,6 +31,56 @@ class FlashOTP:
"""
# extmod/modtrezorio/modtrezorio-flash.h
class FlashArea:
"""
Area of the flash memory
"""
def size(self) -> int:
"""
Returns size of the flash area
"""
def hash(
self,
offset: int,
length: int,
challenge: bytes | None = None,
callback: Callable[[int], None] | None = None,
) -> bytes:
"""
Computes a Blake2s hash of a segment of the flash area.
Offset and length must be aligned to 1024 bytes.
An optional challenge can be used as the Blake2s key.
The progress callback will be invoked every 16 kB with the number of
bytes processed so far.
"""
if __debug__:
def read(self, offset: int, data: bytearray) -> None:
"""
Reads data from flash area. Will read exact length of data
bytearray. Offset and length of data must be aligned to 1024 bytes.
"""
if __debug__:
def write(self, offset: int, data: bytes) -> None:
"""
Writes data to flash area.
Offset and written data size must be a multiple of FLASH_BLOCK_SIZE,
that is, 4 bytes on F4 or 16 bytes on U5.
"""
if __debug__:
def erase_sector(self, offset: int) -> None:
"""
Erases a flash area sector starting at specified offset.
"""
if __debug__:
def erase(self) -> None:
"""
Erases the whole flash area.
"""
# extmod/modtrezorio/modtrezorio-hid.h
class HID:
"""
@ -190,7 +240,7 @@ class WebUSB:
"""
Sends message using USB WebUSB (device) or UDP (emulator).
"""
from . import fatfs, sdcard
from . import fatfs, sdcard, flash_area
POLL_READ: int # wait until interface is readable and return read data
POLL_WRITE: int # wait until interface is writable
TOUCH: int # interface id of the touch events

@ -0,0 +1,9 @@
from typing import *
from . import FlashArea
BOARDLOADER: FlashArea
BOOTLOADER: FlashArea
FIRMWARE: FlashArea
TRANSLATIONS: FlashArea
if __debug__:
STORAGE_A: FlashArea
STORAGE_B: FlashArea

@ -42,17 +42,6 @@ def halt(msg: str | None = None) -> None:
"""
# extmod/modtrezorutils/modtrezorutils.c
def firmware_hash(
challenge: bytes | None = None,
callback: Callable[[int, int], None] | None = None,
) -> bytes:
"""
Computes the Blake2s hash of the firmware with an optional challenge as
the key.
"""
# extmod/modtrezorutils/modtrezorutils.c
def firmware_vendor() -> str:
"""

@ -101,6 +101,8 @@ trezor.enums.Capability
import trezor.enums.Capability
trezor.enums.DebugButton
import trezor.enums.DebugButton
trezor.enums.DebugFlashArea
import trezor.enums.DebugFlashArea
trezor.enums.DebugPhysicalButton
import trezor.enums.DebugPhysicalButton
trezor.enums.DebugSwipeDirection

@ -9,9 +9,9 @@ if __debug__:
import trezorui2
from storage import debug as storage
from storage.debug import debug_events
from trezor import log, loop, utils, wire
from trezor.enums import MessageType
from trezor.messages import DebugLinkLayout, Success
from trezor import io, log, loop, utils, wire
from trezor.enums import DebugFlashArea, MessageType
from trezor.messages import DebugLinkLayout, DebugLinkMemory, Success
from trezor.ui import display
from trezor.wire import context
@ -21,6 +21,9 @@ if __debug__:
from trezor.messages import (
DebugLinkDecision,
DebugLinkEraseSdCard,
DebugLinkFlashErase,
DebugLinkFlashRead,
DebugLinkFlashWrite,
DebugLinkGetState,
DebugLinkRecordScreen,
DebugLinkReseedRandom,
@ -241,8 +244,6 @@ if __debug__:
return Success()
async def dispatch_DebugLinkEraseSdCard(msg: DebugLinkEraseSdCard) -> Success:
from trezor import io
sdcard = io.sdcard # local_cache_attribute
try:
@ -262,6 +263,66 @@ if __debug__:
sdcard.power_off()
return Success()
def get_flash_area(area: DebugFlashArea) -> io.FlashArea:
if area == DebugFlashArea.Boardloader:
return io.flash_area.BOARDLOADER
if area == DebugFlashArea.Bootloader:
return io.flash_area.BOOTLOADER
if area == DebugFlashArea.Firmware:
return io.flash_area.FIRMWARE
if area == DebugFlashArea.StorageA:
return io.flash_area.STORAGE_A
if area == DebugFlashArea.StorageB:
return io.flash_area.STORAGE_B
if area == DebugFlashArea.Translations:
return io.flash_area.TRANSLATIONS
raise ValueError
async def dispatch_DebugLinkFlashRead(msg: DebugLinkFlashRead) -> DebugLinkMemory:
try:
area = get_flash_area(msg.location.area)
if msg.length is not None:
length = msg.length
else:
length = area.size() - msg.location.offset
if msg.hashed:
return DebugLinkMemory(hash=area.hash(msg.location.offset, length))
else:
data = utils.empty_bytearray(length)
area.read(msg.location.offset, data)
return DebugLinkMemory(memory=data)
except Exception as e:
raise wire.ProcessError(e.args[0])
async def dispatch_DebugLinkFlashWrite(msg: DebugLinkFlashWrite) -> Success:
from trezor import translations
try:
translations.deinit()
area = get_flash_area(msg.location.area)
area.write(msg.location.offset, msg.memory)
return Success()
except Exception as e:
raise wire.ProcessError(e.args[0])
finally:
translations.init()
async def dispatch_DebugLinkFlashErase(msg: DebugLinkFlashErase) -> Success:
from trezor import translations
try:
translations.deinit()
area = get_flash_area(msg.location.area)
if msg.whole_area:
area.erase()
else:
area.erase_sector(msg.location.offset)
return Success()
except Exception as e:
raise wire.ProcessError(e.args[0])
finally:
translations.init()
def boot() -> None:
register = workflow_handlers.register # local_cache_attribute
@ -274,6 +335,9 @@ if __debug__:
register(
MessageType.DebugLinkResetDebugEvents, dispatch_DebugLinkResetDebugEvents
)
register(MessageType.DebugLinkFlashRead, dispatch_DebugLinkFlashRead)
register(MessageType.DebugLinkFlashWrite, dispatch_DebugLinkFlashWrite)
register(MessageType.DebugLinkFlashErase, dispatch_DebugLinkFlashErase)
loop.schedule(debuglink_decision_dispatcher())
if storage.layout_watcher is not LAYOUT_WATCHER_NONE:

@ -2,32 +2,25 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from trezor.messages import FirmwareHash, GetFirmwareHash
from trezor.ui.layouts.common import ProgressLayout
_progress_obj: ProgressLayout | None = None
async def get_firmware_hash(msg: GetFirmwareHash) -> FirmwareHash:
from trezor import wire, workflow
from trezor import io, wire, workflow
from trezor.messages import FirmwareHash
from trezor.ui.layouts.progress import progress
from trezor.utils import firmware_hash
workflow.close_others()
global _progress_obj
_progress_obj = progress()
progress_obj = progress()
try:
hash = firmware_hash(msg.challenge, _render_progress)
area = io.flash_area.FIRMWARE
area_size = area.size()
def report(byte: int) -> None:
progress_obj.report(1000 * byte // area_size)
hash = area.hash(0, area.size(), msg.challenge, report)
except ValueError as e:
raise wire.DataError(str(e))
finally:
_progress_obj = None
return FirmwareHash(hash=hash)
def _render_progress(progress: int, total: int) -> None:
global _progress_obj
if _progress_obj is not None:
_progress_obj.report(1000 * progress // total)

@ -0,0 +1,10 @@
# Automatically generated by pb2py
# fmt: off
# isort:skip_file
Boardloader = 0
Bootloader = 1
StorageA = 2
StorageB = 3
Firmware = 4
Translations = 5

@ -87,16 +87,16 @@ DebugLinkGetState = 101
DebugLinkState = 102
DebugLinkStop = 103
DebugLinkLog = 104
DebugLinkMemoryRead = 110
DebugLinkMemory = 111
DebugLinkMemoryWrite = 112
DebugLinkFlashErase = 113
DebugLinkLayout = 9001
DebugLinkReseedRandom = 9002
DebugLinkRecordScreen = 9003
DebugLinkEraseSdCard = 9005
DebugLinkWatchLayout = 9006
DebugLinkResetDebugEvents = 9007
DebugLinkFlashRead = 9008
DebugLinkFlashWrite = 9009
DebugLinkFlashErase = 9010
if not utils.BITCOIN_ONLY:
SetU2FCounter = 63
GetNextU2FCounter = 80

@ -113,13 +113,16 @@ if TYPE_CHECKING:
DebugLinkMemoryRead = 110
DebugLinkMemory = 111
DebugLinkMemoryWrite = 112
DebugLinkFlashErase = 113
DebugLinkFlashEraseLegacy = 113
DebugLinkLayout = 9001
DebugLinkReseedRandom = 9002
DebugLinkRecordScreen = 9003
DebugLinkEraseSdCard = 9005
DebugLinkWatchLayout = 9006
DebugLinkResetDebugEvents = 9007
DebugLinkFlashRead = 9008
DebugLinkFlashWrite = 9009
DebugLinkFlashErase = 9010
EthereumGetPublicKey = 450
EthereumPublicKey = 451
EthereumGetAddress = 56
@ -482,6 +485,14 @@ if TYPE_CHECKING:
MIDDLE_BTN = 1
RIGHT_BTN = 2
class DebugFlashArea(IntEnum):
Boardloader = 0
Bootloader = 1
StorageA = 2
StorageB = 3
Firmware = 4
Translations = 5
class EthereumDefinitionType(IntEnum):
NETWORK = 0
TOKEN = 1

@ -36,6 +36,7 @@ if TYPE_CHECKING:
from trezor.enums import CardanoTxSigningMode # noqa: F401
from trezor.enums import CardanoTxWitnessType # noqa: F401
from trezor.enums import DebugButton # noqa: F401
from trezor.enums import DebugFlashArea # noqa: F401
from trezor.enums import DebugPhysicalButton # noqa: F401
from trezor.enums import DebugSwipeDirection # noqa: F401
from trezor.enums import DecredStakingSpendType # noqa: F401
@ -2919,29 +2920,49 @@ if TYPE_CHECKING:
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkLog"]:
return isinstance(msg, cls)
class DebugLinkMemoryRead(protobuf.MessageType):
address: "int | None"
class DebugFlashMemoryLocation(protobuf.MessageType):
area: "DebugFlashArea"
offset: "int"
def __init__(
self,
*,
area: "DebugFlashArea",
offset: "int",
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["DebugFlashMemoryLocation"]:
return isinstance(msg, cls)
class DebugLinkFlashRead(protobuf.MessageType):
location: "DebugFlashMemoryLocation"
length: "int | None"
hashed: "bool"
def __init__(
self,
*,
address: "int | None" = None,
location: "DebugFlashMemoryLocation",
length: "int | None" = None,
hashed: "bool | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkMemoryRead"]:
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkFlashRead"]:
return isinstance(msg, cls)
class DebugLinkMemory(protobuf.MessageType):
memory: "bytes | None"
hash: "bytes | None"
def __init__(
self,
*,
memory: "bytes | None" = None,
hash: "bytes | None" = None,
) -> None:
pass
@ -2949,31 +2970,31 @@ if TYPE_CHECKING:
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkMemory"]:
return isinstance(msg, cls)
class DebugLinkMemoryWrite(protobuf.MessageType):
address: "int | None"
memory: "bytes | None"
flash: "bool | None"
class DebugLinkFlashWrite(protobuf.MessageType):
location: "DebugFlashMemoryLocation"
memory: "bytes"
def __init__(
self,
*,
address: "int | None" = None,
memory: "bytes | None" = None,
flash: "bool | None" = None,
location: "DebugFlashMemoryLocation",
memory: "bytes",
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkMemoryWrite"]:
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkFlashWrite"]:
return isinstance(msg, cls)
class DebugLinkFlashErase(protobuf.MessageType):
sector: "int | None"
location: "DebugFlashMemoryLocation"
whole_area: "bool"
def __init__(
self,
*,
sector: "int | None" = None,
location: "DebugFlashMemoryLocation",
whole_area: "bool | None" = None,
) -> None:
pass

@ -18,7 +18,6 @@ from trezorutils import ( # noqa: F401
bootloader_locked,
check_firmware_header,
consteq,
firmware_hash,
firmware_vendor,
halt,
memcpy,

@ -0,0 +1,113 @@
from common import * # isort:skip
from trezor import io
from trezor.crypto import hashlib
class TestTrezorIoFlashArea(unittest.TestCase):
def test_firmware_hash(self):
area = io.flash_area.FIRMWARE
area.erase()
self.assertEqual(
area.hash(0, area.size()),
b"\xd2\xdb\x90\xa7jV6\xa7\x00N\xc3\xb4\x8eq\xa9U\xe0\xcb\xb2\xcbZo\xd7\xae\x9f\xbe\xf8F\xbc\x16l\x8c",
)
self.assertEqual(
area.hash(0, area.size(), b"0123456789abcdef"),
b"\xa0\x93@\x98\xa6\x80\xdb\x07m\xdf~\xe2'E\xf1\x19\xd8\xfd\xa4`\x10H\xf0_\xdbf\xa6N\xdd\xc0\xcf\xed",
)
def test_write(self):
# let's trash the firmware :shrug:
area = io.flash_area.FIRMWARE
size = area.size()
area.write(0, b"")
area.write(1024, b"")
area.write(size, b"")
with self.assertRaises(ValueError):
area.write(size + 16, b"")
# fill whole area
area.write(0, b"\x01" * size)
# do it again
area.write(0, b"\x01" * size)
# can't write more
with self.assertRaises(ValueError):
area.write(0, b"\x01" * (size + 16))
with self.assertRaises(ValueError):
area.write(1, b"\x01" * size)
def test_overwrite(self):
area = io.flash_area.FIRMWARE
size = area.size()
area.erase()
area.write(0, b"\x00" * 1024)
# try writing the same thing
area.write(0, b"\x00" * 1024)
# try writing some ones
with self.assertRaises(ValueError):
area.write(0, b"\x01" * 1024)
def test_read_write(self):
area = io.flash_area.FIRMWARE
size = area.size()
area.erase()
buf = bytearray(256)
for i in range(256):
buf[i] = i
for start in range(0, size, 256):
area.write(start, buf)
all_data = bytearray(size)
area.read(0, all_data)
for i in range(size):
# avoid super-slow assertEqual
if i % 256 != all_data[i]:
self.fail(f"at {i} expected {i % 256}, found {all_data[i]}")
chunk = bytearray(1024)
for start in range(0, size, 1024):
area.read(start, chunk)
for j in range(1024):
# avoid super-slow assertEqual
if (start + j) % 256 != chunk[j]:
self.fail(
f"at {start + j} expected {(start + j) % 256}, found {chunk[j]}"
)
def test_hash(self):
area = io.flash_area.FIRMWARE
size = area.size()
all_data = bytearray(size)
for i in range(size):
all_data[i] = i % 256
hasher = hashlib.blake2s()
hasher.update(all_data)
digest = hasher.digest()
digest2 = area.hash(0, size)
self.assertEqual(digest, digest2)
hasher = hashlib.blake2s()
digest = hasher.digest()
digest2 = area.hash(0, 0)
self.assertEqual(digest, digest2)
hasher = hashlib.blake2s()
hasher.update(all_data[1024:2048])
digest = hasher.digest()
digest2 = area.hash(1024, 1024)
self.assertEqual(digest, digest2)
if __name__ == "__main__":
unittest.main()

@ -2,7 +2,7 @@ from common import * # isort:skip
from trezor import protobuf
from trezor.messages import (
DebugLinkMemoryRead,
PrevOutput,
Failure,
SignMessage,
WebAuthnCredential,
@ -19,12 +19,20 @@ def load_uvarint32(data: bytes) -> int:
def load_uvarint64(data: bytes) -> int:
# use known uint64 field in an all-optional message
buffer = bytearray(len(data) + 1)
buffer[1:] = data
buffer[0] = (2 << 3) | 0 # field number 1, wire type 0
msg = protobuf.decode(buffer, DebugLinkMemoryRead, False)
return msg.length
# use known uint64 field
# message PrevOutput {
# required uint64 amount = 1;
# required bytes script_pubkey = 2;
# optional uint32 decred_script_version = 3;
# }
buffer = bytearray(len(data) + 1 + 2)
buffer[1:-2] = data
buffer[0] = (1 << 3) | 0 # field number 1, wire type 0
# create a zero-length script-pubkey field
buffer[-2] = (2 << 3) | 2 # field number 2, wire type 2
buffer[-1] = 0 # length of the script-pubkey
msg = protobuf.decode(buffer, PrevOutput, False)
return msg.amount
def dump_uvarint32(value: int) -> bytearray:
@ -39,12 +47,14 @@ def dump_uvarint32(value: int) -> bytearray:
def dump_uvarint64(value: int) -> bytearray:
# use known uint64 field in an all-optional message
msg = DebugLinkMemoryRead(length=value)
msg = PrevOutput(amount=value, script_pubkey=b"")
length = protobuf.encoded_length(msg)
buffer = bytearray(length)
protobuf.encode(buffer, msg)
assert buffer[0] == (2 << 3) | 0 # field number 2, wire type 0
return buffer[1:]
assert buffer[0] == (1 << 3) | 0 # field number 1, wire type 0
assert buffer[-2] == (2 << 3) | 2 # field number 2, wire type 2
assert buffer[-1] == 0 # length of the script-pubkey
return buffer[1:-2]
def dump_message(msg: protobuf.MessageType) -> bytearray:

@ -52,16 +52,6 @@ class TestUtils(unittest.TestCase):
utils.truncate_utf8("\u1234\u5678", 7), "\u1234\u5678"
) # b'\xe1\x88\xb4\xe5\x99\xb8
def test_firmware_hash(self):
self.assertEqual(
utils.firmware_hash(),
b"\xd2\xdb\x90\xa7jV6\xa7\x00N\xc3\xb4\x8eq\xa9U\xe0\xcb\xb2\xcbZo\xd7\xae\x9f\xbe\xf8F\xbc\x16l\x8c",
)
self.assertEqual(
utils.firmware_hash(b"0123456789abcdef"),
b"\xa0\x93@\x98\xa6\x80\xdb\x07m\xdf~\xe2'E\xf1\x19\xd8\xfd\xa4`\x10H\xf0_\xdbf\xa6N\xdd\xc0\xcf\xed",
)
if __name__ == "__main__":
unittest.main()

@ -94,7 +94,7 @@ void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) {
}
}
void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) {
void fsm_msgDebugLinkFlashEraseLegacy(const DebugLinkFlashEraseLegacy *msg) {
svc_flash_unlock();
svc_flash_erase_sector(msg->sector);
uint32_t dummy = svc_flash_lock();

@ -4,6 +4,7 @@ endif
SKIPPED_MESSAGES := Binance Cardano DebugMonero Eos Monero Ontology Ripple SdProtect Tezos WebAuthn \
DebugLinkRecordScreen DebugLinkEraseSdCard DebugLinkWatchLayout \
DebugLinkFlashErase DebugLinkFlashRead DebugLinkFlashWrite \
DebugLinkLayout DebugLinkResetDebugEvents GetNonce \
TxAckInput TxAckOutput TxAckPrev TxAckPaymentRequest \
EthereumSignTypedData EthereumTypedDataStructRequest EthereumTypedDataStructAck \

@ -15,6 +15,7 @@ DebugLinkLog.bucket max_size:33
DebugLinkLog.text max_size:256
DebugLinkMemory.memory max_size:1024
DebugLinkMemory.hash max_size:32
DebugLinkMemoryWrite.memory max_size:1024
# Unused messages.

@ -14,6 +14,8 @@
# 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
import json
import logging
import re
@ -435,6 +437,8 @@ class DebugLink:
f"received message: {msg_for_log.__class__.__name__}",
extra={"protobuf": msg_for_log},
)
if isinstance(msg, messages.Failure):
raise TrezorFailure(msg)
return msg
def state(self) -> messages.DebugLinkState:
@ -718,17 +722,33 @@ class DebugLink:
self.t1_take_screenshots = False
@expect(messages.DebugLinkMemory, field="memory", ret_type=bytes)
def memory_read(self, address: int, length: int) -> protobuf.MessageType:
return self._call(messages.DebugLinkMemoryRead(address=address, length=length))
def memory_write(self, address: int, memory: bytes, flash: bool = False) -> None:
self._call(
messages.DebugLinkMemoryWrite(address=address, memory=memory, flash=flash),
nowait=True,
def flash_read(
self, area: messages.DebugFlashArea, offset: int = 0, length: int | None = None
) -> protobuf.MessageType:
location = messages.DebugFlashMemoryLocation(area=area, offset=offset)
return self._call(messages.DebugLinkFlashRead(location=location, length=length))
@expect(messages.DebugLinkMemory, field="hash", ret_type=bytes)
def flash_hash(
self, area: messages.DebugFlashArea, offset: int = 0, length: int | None = None
) -> protobuf.MessageType:
location = messages.DebugFlashMemoryLocation(area=area, offset=offset)
return self._call(
messages.DebugLinkFlashRead(location=location, length=length, hashed=True)
)
def flash_erase(self, sector: int) -> None:
self._call(messages.DebugLinkFlashErase(sector=sector), nowait=True)
def flash_erase(self, area: messages.DebugFlashArea, offset: int) -> None:
location = messages.DebugFlashMemoryLocation(area=area, offset=offset)
self._call(messages.DebugLinkFlashErase(location=location, whole_area=False))
def flash_erase_area(self, area: messages.DebugFlashArea) -> None:
location = messages.DebugFlashMemoryLocation(area=area, offset=0)
self._call(messages.DebugLinkFlashErase(location=location, whole_area=True))
def storage_hash(self) -> bytes:
storage_hash_a = self.flash_hash(messages.DebugFlashArea.StorageA)
storage_hash_b = self.flash_hash(messages.DebugFlashArea.StorageB)
return storage_hash_a + storage_hash_b
@expect(messages.Success)
def erase_sd_card(self, format: bool = True) -> messages.Success:

@ -121,13 +121,16 @@ class MessageType(IntEnum):
DebugLinkMemoryRead = 110
DebugLinkMemory = 111
DebugLinkMemoryWrite = 112
DebugLinkFlashErase = 113
DebugLinkFlashEraseLegacy = 113
DebugLinkLayout = 9001
DebugLinkReseedRandom = 9002
DebugLinkRecordScreen = 9003
DebugLinkEraseSdCard = 9005
DebugLinkWatchLayout = 9006
DebugLinkResetDebugEvents = 9007
DebugLinkFlashRead = 9008
DebugLinkFlashWrite = 9009
DebugLinkFlashErase = 9010
EthereumGetPublicKey = 450
EthereumPublicKey = 451
EthereumGetAddress = 56
@ -521,6 +524,15 @@ class DebugPhysicalButton(IntEnum):
RIGHT_BTN = 2
class DebugFlashArea(IntEnum):
Boardloader = 0
Bootloader = 1
StorageA = 2
StorageB = 3
Firmware = 4
Translations = 5
class EthereumDefinitionType(IntEnum):
NETWORK = 0
TOKEN = 1
@ -4099,6 +4111,23 @@ class DebugLinkLog(protobuf.MessageType):
self.text = text
class DebugFlashMemoryLocation(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
FIELDS = {
1: protobuf.Field("area", "DebugFlashArea", repeated=False, required=True),
2: protobuf.Field("offset", "uint32", repeated=False, required=True),
}
def __init__(
self,
*,
area: "DebugFlashArea",
offset: "int",
) -> None:
self.area = area
self.offset = offset
class DebugLinkMemoryRead(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 110
FIELDS = {
@ -4116,18 +4145,41 @@ class DebugLinkMemoryRead(protobuf.MessageType):
self.length = length
class DebugLinkFlashRead(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 9008
FIELDS = {
1: protobuf.Field("location", "DebugFlashMemoryLocation", repeated=False, required=True),
2: protobuf.Field("length", "uint32", repeated=False, required=False, default=None),
3: protobuf.Field("hashed", "bool", repeated=False, required=False, default=False),
}
def __init__(
self,
*,
location: "DebugFlashMemoryLocation",
length: Optional["int"] = None,
hashed: Optional["bool"] = False,
) -> None:
self.location = location
self.length = length
self.hashed = hashed
class DebugLinkMemory(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 111
FIELDS = {
1: protobuf.Field("memory", "bytes", repeated=False, required=False, default=None),
2: protobuf.Field("hash", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
memory: Optional["bytes"] = None,
hash: Optional["bytes"] = None,
) -> None:
self.memory = memory
self.hash = hash
class DebugLinkMemoryWrite(protobuf.MessageType):
@ -4150,7 +4202,24 @@ class DebugLinkMemoryWrite(protobuf.MessageType):
self.flash = flash
class DebugLinkFlashErase(protobuf.MessageType):
class DebugLinkFlashWrite(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 9009
FIELDS = {
1: protobuf.Field("location", "DebugFlashMemoryLocation", repeated=False, required=True),
2: protobuf.Field("memory", "bytes", repeated=False, required=True),
}
def __init__(
self,
*,
location: "DebugFlashMemoryLocation",
memory: "bytes",
) -> None:
self.location = location
self.memory = memory
class DebugLinkFlashEraseLegacy(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 113
FIELDS = {
1: protobuf.Field("sector", "uint32", repeated=False, required=False, default=None),
@ -4164,6 +4233,23 @@ class DebugLinkFlashErase(protobuf.MessageType):
self.sector = sector
class DebugLinkFlashErase(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 9010
FIELDS = {
1: protobuf.Field("location", "DebugFlashMemoryLocation", repeated=False, required=True),
2: protobuf.Field("whole_area", "bool", repeated=False, required=False, default=False),
}
def __init__(
self,
*,
location: "DebugFlashMemoryLocation",
whole_area: Optional["bool"] = False,
) -> None:
self.location = location
self.whole_area = whole_area
class DebugLinkEraseSdCard(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 9005
FIELDS = {

@ -1,67 +0,0 @@
#!/usr/bin/env python3
# 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>.
import sys
from trezorlib.debuglink import DebugLink
from trezorlib.transport import enumerate_devices
# fmt: off
sectoraddrs = [0x8000000, 0x8004000, 0x8008000, 0x800c000,
0x8010000, 0x8020000, 0x8040000, 0x8060000,
0x8080000, 0x80a0000, 0x80c0000, 0x80f0000]
sectorlens = [0x4000, 0x4000, 0x4000, 0x4000,
0x8000, 0x10000, 0x10000, 0x10000,
0x10000, 0x10000, 0x10000, 0x10000]
# fmt: on
def find_debug() -> DebugLink:
for device in enumerate_devices():
try:
debug_transport = device.find_debug()
debug = DebugLink(debug_transport, auto_interact=False)
debug.open()
return debug
except Exception:
continue
else:
print("No suitable Trezor device found")
sys.exit(1)
def main() -> None:
debug = find_debug()
sector = int(sys.argv[1])
f = open(sys.argv[2], "rb")
content = f.read(sectorlens[sector])
if len(content) != sectorlens[sector]:
print("Not enough bytes in file")
return
debug.flash_erase(sector)
step = 0x400
for offset in range(0, sectorlens[sector], step):
debug.memory_write(
sectoraddrs[sector] + offset, content[offset : offset + step], flash=True
)
if __name__ == "__main__":
main()

@ -1,64 +0,0 @@
#!/usr/bin/env python3
# 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>.
import sys
from trezorlib.debuglink import DebugLink
from trezorlib.transport import enumerate_devices
# usage examples
# read entire bootloader: ./mem_read.py 8000000 8000
# read initial stack pointer: ./mem_read.py 8000000 4
# an entire bootloader can be later disassembled with:
# arm-none-eabi-objdump -D -b binary -m arm -M force-thumb memory.dat
# note that in order for this to work, your trezor device must
# be running a firmware that was built with debug link enabled
def find_debug() -> DebugLink:
for device in enumerate_devices():
try:
debug_transport = device.find_debug()
debug = DebugLink(debug_transport, auto_interact=False)
debug.open()
return debug
except Exception:
continue
else:
print("No suitable Trezor device found")
sys.exit(1)
def main() -> None:
debug = find_debug()
arg1 = int(sys.argv[1], 16)
arg2 = int(sys.argv[2], 16)
step = 0x400 if arg2 >= 0x400 else arg2
f = open("memory.dat", "wb")
for addr in range(arg1, arg1 + arg2, step):
mem = debug.memory_read(addr, step)
f.write(mem)
f.close()
if __name__ == "__main__":
main()

@ -1,45 +0,0 @@
#!/usr/bin/env python3
# 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>.
import sys
from trezorlib.debuglink import DebugLink
from trezorlib.transport import enumerate_devices
def find_debug() -> DebugLink:
for device in enumerate_devices():
try:
debug_transport = device.find_debug()
debug = DebugLink(debug_transport, auto_interact=False)
debug.open()
return debug
except Exception:
continue
else:
print("No suitable Trezor device found")
sys.exit(1)
def main() -> None:
debug = find_debug()
debug.memory_write(int(sys.argv[1], 16), bytes.fromhex(sys.argv[2]), flash=True)
if __name__ == "__main__":
main()

@ -75,13 +75,16 @@ trezor_message_impl! {
DebugLinkMemoryRead => MessageType_DebugLinkMemoryRead,
DebugLinkMemory => MessageType_DebugLinkMemory,
DebugLinkMemoryWrite => MessageType_DebugLinkMemoryWrite,
DebugLinkFlashErase => MessageType_DebugLinkFlashErase,
DebugLinkFlashEraseLegacy => MessageType_DebugLinkFlashEraseLegacy,
DebugLinkLayout => MessageType_DebugLinkLayout,
DebugLinkReseedRandom => MessageType_DebugLinkReseedRandom,
DebugLinkRecordScreen => MessageType_DebugLinkRecordScreen,
DebugLinkEraseSdCard => MessageType_DebugLinkEraseSdCard,
DebugLinkWatchLayout => MessageType_DebugLinkWatchLayout,
DebugLinkResetDebugEvents => MessageType_DebugLinkResetDebugEvents,
DebugLinkFlashRead => MessageType_DebugLinkFlashRead,
DebugLinkFlashWrite => MessageType_DebugLinkFlashWrite,
DebugLinkFlashErase => MessageType_DebugLinkFlashErase,
}
#[cfg(feature = "binance")]

@ -212,8 +212,8 @@ pub enum MessageType {
MessageType_DebugLinkMemory = 111,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkMemoryWrite)
MessageType_DebugLinkMemoryWrite = 112,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkFlashErase)
MessageType_DebugLinkFlashErase = 113,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkFlashEraseLegacy)
MessageType_DebugLinkFlashEraseLegacy = 113,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkLayout)
MessageType_DebugLinkLayout = 9001,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkReseedRandom)
@ -226,6 +226,12 @@ pub enum MessageType {
MessageType_DebugLinkWatchLayout = 9006,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkResetDebugEvents)
MessageType_DebugLinkResetDebugEvents = 9007,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkFlashRead)
MessageType_DebugLinkFlashRead = 9008,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkFlashWrite)
MessageType_DebugLinkFlashWrite = 9009,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_DebugLinkFlashErase)
MessageType_DebugLinkFlashErase = 9010,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EthereumGetPublicKey)
MessageType_EthereumGetPublicKey = 450,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EthereumPublicKey)
@ -617,13 +623,16 @@ impl ::protobuf::Enum for MessageType {
110 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkMemoryRead),
111 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkMemory),
112 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkMemoryWrite),
113 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashErase),
113 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashEraseLegacy),
9001 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkLayout),
9002 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkReseedRandom),
9003 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkRecordScreen),
9005 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkEraseSdCard),
9006 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkWatchLayout),
9007 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkResetDebugEvents),
9008 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashRead),
9009 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashWrite),
9010 => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashErase),
450 => ::std::option::Option::Some(MessageType::MessageType_EthereumGetPublicKey),
451 => ::std::option::Option::Some(MessageType::MessageType_EthereumPublicKey),
56 => ::std::option::Option::Some(MessageType::MessageType_EthereumGetAddress),
@ -866,13 +875,16 @@ impl ::protobuf::Enum for MessageType {
"MessageType_DebugLinkMemoryRead" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkMemoryRead),
"MessageType_DebugLinkMemory" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkMemory),
"MessageType_DebugLinkMemoryWrite" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkMemoryWrite),
"MessageType_DebugLinkFlashErase" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashErase),
"MessageType_DebugLinkFlashEraseLegacy" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashEraseLegacy),
"MessageType_DebugLinkLayout" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkLayout),
"MessageType_DebugLinkReseedRandom" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkReseedRandom),
"MessageType_DebugLinkRecordScreen" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkRecordScreen),
"MessageType_DebugLinkEraseSdCard" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkEraseSdCard),
"MessageType_DebugLinkWatchLayout" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkWatchLayout),
"MessageType_DebugLinkResetDebugEvents" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkResetDebugEvents),
"MessageType_DebugLinkFlashRead" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashRead),
"MessageType_DebugLinkFlashWrite" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashWrite),
"MessageType_DebugLinkFlashErase" => ::std::option::Option::Some(MessageType::MessageType_DebugLinkFlashErase),
"MessageType_EthereumGetPublicKey" => ::std::option::Option::Some(MessageType::MessageType_EthereumGetPublicKey),
"MessageType_EthereumPublicKey" => ::std::option::Option::Some(MessageType::MessageType_EthereumPublicKey),
"MessageType_EthereumGetAddress" => ::std::option::Option::Some(MessageType::MessageType_EthereumGetAddress),
@ -1114,13 +1126,16 @@ impl ::protobuf::Enum for MessageType {
MessageType::MessageType_DebugLinkMemoryRead,
MessageType::MessageType_DebugLinkMemory,
MessageType::MessageType_DebugLinkMemoryWrite,
MessageType::MessageType_DebugLinkFlashErase,
MessageType::MessageType_DebugLinkFlashEraseLegacy,
MessageType::MessageType_DebugLinkLayout,
MessageType::MessageType_DebugLinkReseedRandom,
MessageType::MessageType_DebugLinkRecordScreen,
MessageType::MessageType_DebugLinkEraseSdCard,
MessageType::MessageType_DebugLinkWatchLayout,
MessageType::MessageType_DebugLinkResetDebugEvents,
MessageType::MessageType_DebugLinkFlashRead,
MessageType::MessageType_DebugLinkFlashWrite,
MessageType::MessageType_DebugLinkFlashErase,
MessageType::MessageType_EthereumGetPublicKey,
MessageType::MessageType_EthereumPublicKey,
MessageType::MessageType_EthereumGetAddress,
@ -1368,157 +1383,160 @@ impl ::protobuf::EnumFull for MessageType {
MessageType::MessageType_DebugLinkMemoryRead => 89,
MessageType::MessageType_DebugLinkMemory => 90,
MessageType::MessageType_DebugLinkMemoryWrite => 91,
MessageType::MessageType_DebugLinkFlashErase => 92,
MessageType::MessageType_DebugLinkFlashEraseLegacy => 92,
MessageType::MessageType_DebugLinkLayout => 93,
MessageType::MessageType_DebugLinkReseedRandom => 94,
MessageType::MessageType_DebugLinkRecordScreen => 95,
MessageType::MessageType_DebugLinkEraseSdCard => 96,
MessageType::MessageType_DebugLinkWatchLayout => 97,
MessageType::MessageType_DebugLinkResetDebugEvents => 98,
MessageType::MessageType_EthereumGetPublicKey => 99,
MessageType::MessageType_EthereumPublicKey => 100,
MessageType::MessageType_EthereumGetAddress => 101,
MessageType::MessageType_EthereumAddress => 102,
MessageType::MessageType_EthereumSignTx => 103,
MessageType::MessageType_EthereumSignTxEIP1559 => 104,
MessageType::MessageType_EthereumTxRequest => 105,
MessageType::MessageType_EthereumTxAck => 106,
MessageType::MessageType_EthereumSignMessage => 107,
MessageType::MessageType_EthereumVerifyMessage => 108,
MessageType::MessageType_EthereumMessageSignature => 109,
MessageType::MessageType_EthereumSignTypedData => 110,
MessageType::MessageType_EthereumTypedDataStructRequest => 111,
MessageType::MessageType_EthereumTypedDataStructAck => 112,
MessageType::MessageType_EthereumTypedDataValueRequest => 113,
MessageType::MessageType_EthereumTypedDataValueAck => 114,
MessageType::MessageType_EthereumTypedDataSignature => 115,
MessageType::MessageType_EthereumSignTypedHash => 116,
MessageType::MessageType_NEMGetAddress => 117,
MessageType::MessageType_NEMAddress => 118,
MessageType::MessageType_NEMSignTx => 119,
MessageType::MessageType_NEMSignedTx => 120,
MessageType::MessageType_NEMDecryptMessage => 121,
MessageType::MessageType_NEMDecryptedMessage => 122,
MessageType::MessageType_TezosGetAddress => 123,
MessageType::MessageType_TezosAddress => 124,
MessageType::MessageType_TezosSignTx => 125,
MessageType::MessageType_TezosSignedTx => 126,
MessageType::MessageType_TezosGetPublicKey => 127,
MessageType::MessageType_TezosPublicKey => 128,
MessageType::MessageType_StellarSignTx => 129,
MessageType::MessageType_StellarTxOpRequest => 130,
MessageType::MessageType_StellarGetAddress => 131,
MessageType::MessageType_StellarAddress => 132,
MessageType::MessageType_StellarCreateAccountOp => 133,
MessageType::MessageType_StellarPaymentOp => 134,
MessageType::MessageType_StellarPathPaymentStrictReceiveOp => 135,
MessageType::MessageType_StellarManageSellOfferOp => 136,
MessageType::MessageType_StellarCreatePassiveSellOfferOp => 137,
MessageType::MessageType_StellarSetOptionsOp => 138,
MessageType::MessageType_StellarChangeTrustOp => 139,
MessageType::MessageType_StellarAllowTrustOp => 140,
MessageType::MessageType_StellarAccountMergeOp => 141,
MessageType::MessageType_StellarManageDataOp => 142,
MessageType::MessageType_StellarBumpSequenceOp => 143,
MessageType::MessageType_StellarManageBuyOfferOp => 144,
MessageType::MessageType_StellarPathPaymentStrictSendOp => 145,
MessageType::MessageType_StellarClaimClaimableBalanceOp => 146,
MessageType::MessageType_StellarSignedTx => 147,
MessageType::MessageType_CardanoGetPublicKey => 148,
MessageType::MessageType_CardanoPublicKey => 149,
MessageType::MessageType_CardanoGetAddress => 150,
MessageType::MessageType_CardanoAddress => 151,
MessageType::MessageType_CardanoTxItemAck => 152,
MessageType::MessageType_CardanoTxAuxiliaryDataSupplement => 153,
MessageType::MessageType_CardanoTxWitnessRequest => 154,
MessageType::MessageType_CardanoTxWitnessResponse => 155,
MessageType::MessageType_CardanoTxHostAck => 156,
MessageType::MessageType_CardanoTxBodyHash => 157,
MessageType::MessageType_CardanoSignTxFinished => 158,
MessageType::MessageType_CardanoSignTxInit => 159,
MessageType::MessageType_CardanoTxInput => 160,
MessageType::MessageType_CardanoTxOutput => 161,
MessageType::MessageType_CardanoAssetGroup => 162,
MessageType::MessageType_CardanoToken => 163,
MessageType::MessageType_CardanoTxCertificate => 164,
MessageType::MessageType_CardanoTxWithdrawal => 165,
MessageType::MessageType_CardanoTxAuxiliaryData => 166,
MessageType::MessageType_CardanoPoolOwner => 167,
MessageType::MessageType_CardanoPoolRelayParameters => 168,
MessageType::MessageType_CardanoGetNativeScriptHash => 169,
MessageType::MessageType_CardanoNativeScriptHash => 170,
MessageType::MessageType_CardanoTxMint => 171,
MessageType::MessageType_CardanoTxCollateralInput => 172,
MessageType::MessageType_CardanoTxRequiredSigner => 173,
MessageType::MessageType_CardanoTxInlineDatumChunk => 174,
MessageType::MessageType_CardanoTxReferenceScriptChunk => 175,
MessageType::MessageType_CardanoTxReferenceInput => 176,
MessageType::MessageType_RippleGetAddress => 177,
MessageType::MessageType_RippleAddress => 178,
MessageType::MessageType_RippleSignTx => 179,
MessageType::MessageType_RippleSignedTx => 180,
MessageType::MessageType_MoneroTransactionInitRequest => 181,
MessageType::MessageType_MoneroTransactionInitAck => 182,
MessageType::MessageType_MoneroTransactionSetInputRequest => 183,
MessageType::MessageType_MoneroTransactionSetInputAck => 184,
MessageType::MessageType_MoneroTransactionInputViniRequest => 185,
MessageType::MessageType_MoneroTransactionInputViniAck => 186,
MessageType::MessageType_MoneroTransactionAllInputsSetRequest => 187,
MessageType::MessageType_MoneroTransactionAllInputsSetAck => 188,
MessageType::MessageType_MoneroTransactionSetOutputRequest => 189,
MessageType::MessageType_MoneroTransactionSetOutputAck => 190,
MessageType::MessageType_MoneroTransactionAllOutSetRequest => 191,
MessageType::MessageType_MoneroTransactionAllOutSetAck => 192,
MessageType::MessageType_MoneroTransactionSignInputRequest => 193,
MessageType::MessageType_MoneroTransactionSignInputAck => 194,
MessageType::MessageType_MoneroTransactionFinalRequest => 195,
MessageType::MessageType_MoneroTransactionFinalAck => 196,
MessageType::MessageType_MoneroKeyImageExportInitRequest => 197,
MessageType::MessageType_MoneroKeyImageExportInitAck => 198,
MessageType::MessageType_MoneroKeyImageSyncStepRequest => 199,
MessageType::MessageType_MoneroKeyImageSyncStepAck => 200,
MessageType::MessageType_MoneroKeyImageSyncFinalRequest => 201,
MessageType::MessageType_MoneroKeyImageSyncFinalAck => 202,
MessageType::MessageType_MoneroGetAddress => 203,
MessageType::MessageType_MoneroAddress => 204,
MessageType::MessageType_MoneroGetWatchKey => 205,
MessageType::MessageType_MoneroWatchKey => 206,
MessageType::MessageType_DebugMoneroDiagRequest => 207,
MessageType::MessageType_DebugMoneroDiagAck => 208,
MessageType::MessageType_MoneroGetTxKeyRequest => 209,
MessageType::MessageType_MoneroGetTxKeyAck => 210,
MessageType::MessageType_MoneroLiveRefreshStartRequest => 211,
MessageType::MessageType_MoneroLiveRefreshStartAck => 212,
MessageType::MessageType_MoneroLiveRefreshStepRequest => 213,
MessageType::MessageType_MoneroLiveRefreshStepAck => 214,
MessageType::MessageType_MoneroLiveRefreshFinalRequest => 215,
MessageType::MessageType_MoneroLiveRefreshFinalAck => 216,
MessageType::MessageType_EosGetPublicKey => 217,
MessageType::MessageType_EosPublicKey => 218,
MessageType::MessageType_EosSignTx => 219,
MessageType::MessageType_EosTxActionRequest => 220,
MessageType::MessageType_EosTxActionAck => 221,
MessageType::MessageType_EosSignedTx => 222,
MessageType::MessageType_BinanceGetAddress => 223,
MessageType::MessageType_BinanceAddress => 224,
MessageType::MessageType_BinanceGetPublicKey => 225,
MessageType::MessageType_BinancePublicKey => 226,
MessageType::MessageType_BinanceSignTx => 227,
MessageType::MessageType_BinanceTxRequest => 228,
MessageType::MessageType_BinanceTransferMsg => 229,
MessageType::MessageType_BinanceOrderMsg => 230,
MessageType::MessageType_BinanceCancelMsg => 231,
MessageType::MessageType_BinanceSignedTx => 232,
MessageType::MessageType_WebAuthnListResidentCredentials => 233,
MessageType::MessageType_WebAuthnCredentials => 234,
MessageType::MessageType_WebAuthnAddResidentCredential => 235,
MessageType::MessageType_WebAuthnRemoveResidentCredential => 236,
MessageType::MessageType_SolanaGetPublicKey => 237,
MessageType::MessageType_SolanaPublicKey => 238,
MessageType::MessageType_SolanaGetAddress => 239,
MessageType::MessageType_SolanaAddress => 240,
MessageType::MessageType_SolanaSignTx => 241,
MessageType::MessageType_SolanaTxSignature => 242,
MessageType::MessageType_DebugLinkFlashRead => 99,
MessageType::MessageType_DebugLinkFlashWrite => 100,
MessageType::MessageType_DebugLinkFlashErase => 101,
MessageType::MessageType_EthereumGetPublicKey => 102,
MessageType::MessageType_EthereumPublicKey => 103,
MessageType::MessageType_EthereumGetAddress => 104,
MessageType::MessageType_EthereumAddress => 105,
MessageType::MessageType_EthereumSignTx => 106,
MessageType::MessageType_EthereumSignTxEIP1559 => 107,
MessageType::MessageType_EthereumTxRequest => 108,
MessageType::MessageType_EthereumTxAck => 109,
MessageType::MessageType_EthereumSignMessage => 110,
MessageType::MessageType_EthereumVerifyMessage => 111,
MessageType::MessageType_EthereumMessageSignature => 112,
MessageType::MessageType_EthereumSignTypedData => 113,
MessageType::MessageType_EthereumTypedDataStructRequest => 114,
MessageType::MessageType_EthereumTypedDataStructAck => 115,
MessageType::MessageType_EthereumTypedDataValueRequest => 116,
MessageType::MessageType_EthereumTypedDataValueAck => 117,
MessageType::MessageType_EthereumTypedDataSignature => 118,
MessageType::MessageType_EthereumSignTypedHash => 119,
MessageType::MessageType_NEMGetAddress => 120,
MessageType::MessageType_NEMAddress => 121,
MessageType::MessageType_NEMSignTx => 122,
MessageType::MessageType_NEMSignedTx => 123,
MessageType::MessageType_NEMDecryptMessage => 124,
MessageType::MessageType_NEMDecryptedMessage => 125,
MessageType::MessageType_TezosGetAddress => 126,
MessageType::MessageType_TezosAddress => 127,
MessageType::MessageType_TezosSignTx => 128,
MessageType::MessageType_TezosSignedTx => 129,
MessageType::MessageType_TezosGetPublicKey => 130,
MessageType::MessageType_TezosPublicKey => 131,
MessageType::MessageType_StellarSignTx => 132,
MessageType::MessageType_StellarTxOpRequest => 133,
MessageType::MessageType_StellarGetAddress => 134,
MessageType::MessageType_StellarAddress => 135,
MessageType::MessageType_StellarCreateAccountOp => 136,
MessageType::MessageType_StellarPaymentOp => 137,
MessageType::MessageType_StellarPathPaymentStrictReceiveOp => 138,
MessageType::MessageType_StellarManageSellOfferOp => 139,
MessageType::MessageType_StellarCreatePassiveSellOfferOp => 140,
MessageType::MessageType_StellarSetOptionsOp => 141,
MessageType::MessageType_StellarChangeTrustOp => 142,
MessageType::MessageType_StellarAllowTrustOp => 143,
MessageType::MessageType_StellarAccountMergeOp => 144,
MessageType::MessageType_StellarManageDataOp => 145,
MessageType::MessageType_StellarBumpSequenceOp => 146,
MessageType::MessageType_StellarManageBuyOfferOp => 147,
MessageType::MessageType_StellarPathPaymentStrictSendOp => 148,
MessageType::MessageType_StellarClaimClaimableBalanceOp => 149,
MessageType::MessageType_StellarSignedTx => 150,
MessageType::MessageType_CardanoGetPublicKey => 151,
MessageType::MessageType_CardanoPublicKey => 152,
MessageType::MessageType_CardanoGetAddress => 153,
MessageType::MessageType_CardanoAddress => 154,
MessageType::MessageType_CardanoTxItemAck => 155,
MessageType::MessageType_CardanoTxAuxiliaryDataSupplement => 156,
MessageType::MessageType_CardanoTxWitnessRequest => 157,
MessageType::MessageType_CardanoTxWitnessResponse => 158,
MessageType::MessageType_CardanoTxHostAck => 159,
MessageType::MessageType_CardanoTxBodyHash => 160,
MessageType::MessageType_CardanoSignTxFinished => 161,
MessageType::MessageType_CardanoSignTxInit => 162,
MessageType::MessageType_CardanoTxInput => 163,
MessageType::MessageType_CardanoTxOutput => 164,
MessageType::MessageType_CardanoAssetGroup => 165,
MessageType::MessageType_CardanoToken => 166,
MessageType::MessageType_CardanoTxCertificate => 167,
MessageType::MessageType_CardanoTxWithdrawal => 168,
MessageType::MessageType_CardanoTxAuxiliaryData => 169,
MessageType::MessageType_CardanoPoolOwner => 170,
MessageType::MessageType_CardanoPoolRelayParameters => 171,
MessageType::MessageType_CardanoGetNativeScriptHash => 172,
MessageType::MessageType_CardanoNativeScriptHash => 173,
MessageType::MessageType_CardanoTxMint => 174,
MessageType::MessageType_CardanoTxCollateralInput => 175,
MessageType::MessageType_CardanoTxRequiredSigner => 176,
MessageType::MessageType_CardanoTxInlineDatumChunk => 177,
MessageType::MessageType_CardanoTxReferenceScriptChunk => 178,
MessageType::MessageType_CardanoTxReferenceInput => 179,
MessageType::MessageType_RippleGetAddress => 180,
MessageType::MessageType_RippleAddress => 181,
MessageType::MessageType_RippleSignTx => 182,
MessageType::MessageType_RippleSignedTx => 183,
MessageType::MessageType_MoneroTransactionInitRequest => 184,
MessageType::MessageType_MoneroTransactionInitAck => 185,
MessageType::MessageType_MoneroTransactionSetInputRequest => 186,
MessageType::MessageType_MoneroTransactionSetInputAck => 187,
MessageType::MessageType_MoneroTransactionInputViniRequest => 188,
MessageType::MessageType_MoneroTransactionInputViniAck => 189,
MessageType::MessageType_MoneroTransactionAllInputsSetRequest => 190,
MessageType::MessageType_MoneroTransactionAllInputsSetAck => 191,
MessageType::MessageType_MoneroTransactionSetOutputRequest => 192,
MessageType::MessageType_MoneroTransactionSetOutputAck => 193,
MessageType::MessageType_MoneroTransactionAllOutSetRequest => 194,
MessageType::MessageType_MoneroTransactionAllOutSetAck => 195,
MessageType::MessageType_MoneroTransactionSignInputRequest => 196,
MessageType::MessageType_MoneroTransactionSignInputAck => 197,
MessageType::MessageType_MoneroTransactionFinalRequest => 198,
MessageType::MessageType_MoneroTransactionFinalAck => 199,
MessageType::MessageType_MoneroKeyImageExportInitRequest => 200,
MessageType::MessageType_MoneroKeyImageExportInitAck => 201,
MessageType::MessageType_MoneroKeyImageSyncStepRequest => 202,
MessageType::MessageType_MoneroKeyImageSyncStepAck => 203,
MessageType::MessageType_MoneroKeyImageSyncFinalRequest => 204,
MessageType::MessageType_MoneroKeyImageSyncFinalAck => 205,
MessageType::MessageType_MoneroGetAddress => 206,
MessageType::MessageType_MoneroAddress => 207,
MessageType::MessageType_MoneroGetWatchKey => 208,
MessageType::MessageType_MoneroWatchKey => 209,
MessageType::MessageType_DebugMoneroDiagRequest => 210,
MessageType::MessageType_DebugMoneroDiagAck => 211,
MessageType::MessageType_MoneroGetTxKeyRequest => 212,
MessageType::MessageType_MoneroGetTxKeyAck => 213,
MessageType::MessageType_MoneroLiveRefreshStartRequest => 214,
MessageType::MessageType_MoneroLiveRefreshStartAck => 215,
MessageType::MessageType_MoneroLiveRefreshStepRequest => 216,
MessageType::MessageType_MoneroLiveRefreshStepAck => 217,
MessageType::MessageType_MoneroLiveRefreshFinalRequest => 218,
MessageType::MessageType_MoneroLiveRefreshFinalAck => 219,
MessageType::MessageType_EosGetPublicKey => 220,
MessageType::MessageType_EosPublicKey => 221,
MessageType::MessageType_EosSignTx => 222,
MessageType::MessageType_EosTxActionRequest => 223,
MessageType::MessageType_EosTxActionAck => 224,
MessageType::MessageType_EosSignedTx => 225,
MessageType::MessageType_BinanceGetAddress => 226,
MessageType::MessageType_BinanceAddress => 227,
MessageType::MessageType_BinanceGetPublicKey => 228,
MessageType::MessageType_BinancePublicKey => 229,
MessageType::MessageType_BinanceSignTx => 230,
MessageType::MessageType_BinanceTxRequest => 231,
MessageType::MessageType_BinanceTransferMsg => 232,
MessageType::MessageType_BinanceOrderMsg => 233,
MessageType::MessageType_BinanceCancelMsg => 234,
MessageType::MessageType_BinanceSignedTx => 235,
MessageType::MessageType_WebAuthnListResidentCredentials => 236,
MessageType::MessageType_WebAuthnCredentials => 237,
MessageType::MessageType_WebAuthnAddResidentCredential => 238,
MessageType::MessageType_WebAuthnRemoveResidentCredential => 239,
MessageType::MessageType_SolanaGetPublicKey => 240,
MessageType::MessageType_SolanaPublicKey => 241,
MessageType::MessageType_SolanaGetAddress => 242,
MessageType::MessageType_SolanaAddress => 243,
MessageType::MessageType_SolanaSignTx => 244,
MessageType::MessageType_SolanaTxSignature => 245,
};
Self::enum_descriptor().value_by_index(index)
}
@ -1568,7 +1586,7 @@ pub mod exts {
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\x20google/protobuf/de\
scriptor.proto*\x9aT\n\x0bMessageType\x12(\n\x16MessageType_Initialize\
scriptor.proto*\xb5U\n\x0bMessageType\x12(\n\x16MessageType_Initialize\
\x10\0\x1a\x0c\x80\xa6\x1d\x01\xb0\xb5\x18\x01\x90\xb5\x18\x01\x12\x1e\n\
\x10MessageType_Ping\x10\x01\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12\
%\n\x13MessageType_Success\x10\x02\x1a\x0c\x80\xa6\x1d\x01\xa8\xb5\x18\
@ -1673,27 +1691,31 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x1d\x01\xb0\xb5\x18\x01\xa0\xb5\x18\x01\x12(\n\x1aMessageType_DebugLink\
State\x10f\x1a\x08\x80\xa6\x1d\x01\xa8\xb5\x18\x01\x12'\n\x19MessageType\
_DebugLinkStop\x10g\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12&\n\x18Me\
ssageType_DebugLinkLog\x10h\x1a\x08\x80\xa6\x1d\x01\xa8\xb5\x18\x01\x12-\
\n\x1fMessageType_DebugLinkMemoryRead\x10n\x1a\x08\x80\xa6\x1d\x01\xa0\
\xb5\x18\x01\x12)\n\x1bMessageType_DebugLinkMemory\x10o\x1a\x08\x80\xa6\
\x1d\x01\xa8\xb5\x18\x01\x12.\n\x20MessageType_DebugLinkMemoryWrite\x10p\
\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12-\n\x1fMessageType_DebugLink\
FlashErase\x10q\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12*\n\x1bMessag\
eType_DebugLinkLayout\x10\xa9F\x1a\x08\x80\xa6\x1d\x01\xa8\xb5\x18\x01\
\x120\n!MessageType_DebugLinkReseedRandom\x10\xaaF\x1a\x08\x80\xa6\x1d\
\x01\xa0\xb5\x18\x01\x120\n!MessageType_DebugLinkRecordScreen\x10\xabF\
\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12/\n\x20MessageType_DebugLink\
EraseSdCard\x10\xadF\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12/\n\x20M\
essageType_DebugLinkWatchLayout\x10\xaeF\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\
\x18\x01\x124\n%MessageType_DebugLinkResetDebugEvents\x10\xafF\x1a\x08\
\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12+\n\x20MessageType_EthereumGetPublic\
Key\x10\xc2\x03\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_EthereumPu\
blicKey\x10\xc3\x03\x1a\x04\x98\xb5\x18\x01\x12(\n\x1eMessageType_Ethere\
umGetAddress\x108\x1a\x04\x90\xb5\x18\x01\x12%\n\x1bMessageType_Ethereum\
Address\x109\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EthereumSignT\
x\x10:\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_EthereumSignTxEIP1559\
\x10\xc4\x03\x1a\x04\x90\xb5\x18\x01\x12'\n\x1dMessageType_EthereumTxReq\
uest\x10;\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_EthereumTxAck\
ssageType_DebugLinkLog\x10h\x1a\x08\x80\xa6\x1d\x01\xa8\xb5\x18\x01\x12/\
\n\x1fMessageType_DebugLinkMemoryRead\x10n\x1a\n\x08\x01\x80\xa6\x1d\x01\
\xa0\xb5\x18\x01\x12)\n\x1bMessageType_DebugLinkMemory\x10o\x1a\x08\x80\
\xa6\x1d\x01\xa8\xb5\x18\x01\x120\n\x20MessageType_DebugLinkMemoryWrite\
\x10p\x1a\n\x08\x01\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x125\n%MessageType_D\
ebugLinkFlashEraseLegacy\x10q\x1a\n\x08\x01\x80\xa6\x1d\x01\xa0\xb5\x18\
\x01\x12*\n\x1bMessageType_DebugLinkLayout\x10\xa9F\x1a\x08\x80\xa6\x1d\
\x01\xa8\xb5\x18\x01\x120\n!MessageType_DebugLinkReseedRandom\x10\xaaF\
\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x120\n!MessageType_DebugLinkRec\
ordScreen\x10\xabF\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12/\n\x20Mes\
sageType_DebugLinkEraseSdCard\x10\xadF\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\
\x18\x01\x12/\n\x20MessageType_DebugLinkWatchLayout\x10\xaeF\x1a\x08\x80\
\xa6\x1d\x01\xa0\xb5\x18\x01\x124\n%MessageType_DebugLinkResetDebugEvent\
s\x10\xafF\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12-\n\x1eMessageType\
_DebugLinkFlashRead\x10\xb0F\x1a\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12\
.\n\x1fMessageType_DebugLinkFlashWrite\x10\xb1F\x1a\x08\x80\xa6\x1d\x01\
\xa0\xb5\x18\x01\x12.\n\x1fMessageType_DebugLinkFlashErase\x10\xb2F\x1a\
\x08\x80\xa6\x1d\x01\xa0\xb5\x18\x01\x12+\n\x20MessageType_EthereumGetPu\
blicKey\x10\xc2\x03\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_Ethere\
umPublicKey\x10\xc3\x03\x1a\x04\x98\xb5\x18\x01\x12(\n\x1eMessageType_Et\
hereumGetAddress\x108\x1a\x04\x90\xb5\x18\x01\x12%\n\x1bMessageType_Ethe\
reumAddress\x109\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EthereumS\
ignTx\x10:\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_EthereumSignTxEIP1\
559\x10\xc4\x03\x1a\x04\x90\xb5\x18\x01\x12'\n\x1dMessageType_EthereumTx\
Request\x10;\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_EthereumTxAck\
\x10<\x1a\x04\x90\xb5\x18\x01\x12)\n\x1fMessageType_EthereumSignMessage\
\x10@\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumVerifyMessage\
\x10A\x1a\x04\x90\xb5\x18\x01\x12.\n$MessageType_EthereumMessageSignatur\

File diff suppressed because it is too large Load Diff

@ -17,8 +17,9 @@
from __future__ import annotations
import os
import typing as t
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Generator, Iterator
import pytest
import xdist
@ -27,6 +28,7 @@ from trezorlib import debuglink, log, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.device import apply_settings
from trezorlib.device import wipe as wipe_device
from trezorlib.messages import Capability
from trezorlib.transport import enumerate_devices, get_transport
# register rewrites before importing from local package
@ -37,7 +39,7 @@ from . import translations, ui_tests
from .device_handler import BackgroundDeviceHandler
from .emulators import EmulatorWrapper
if TYPE_CHECKING:
if t.TYPE_CHECKING:
from _pytest.config import Config
from _pytest.config.argparsing import Parser
from _pytest.terminal import TerminalReporter
@ -63,7 +65,7 @@ def _emulator_wrapper_main_args() -> list[str]:
@pytest.fixture
def core_emulator(request: pytest.FixtureRequest) -> Iterator[Emulator]:
def core_emulator(request: pytest.FixtureRequest) -> t.Iterator[Emulator]:
"""Fixture returning default core emulator with possibility of screen recording."""
with EmulatorWrapper("core", main_args=_emulator_wrapper_main_args()) as emu:
# Modifying emu.client to add screen recording (when --ui=test is used)
@ -72,7 +74,7 @@ def core_emulator(request: pytest.FixtureRequest) -> Iterator[Emulator]:
@pytest.fixture(scope="session")
def emulator(request: pytest.FixtureRequest) -> Generator["Emulator", None, None]:
def emulator(request: pytest.FixtureRequest) -> t.Generator["Emulator", None, None]:
"""Fixture for getting emulator connection in case tests should operate it on their own.
Is responsible for starting it at the start of the session and stopping
@ -123,8 +125,28 @@ def emulator(request: pytest.FixtureRequest) -> Generator["Emulator", None, None
yield emu
@dataclass
class SetupParams:
uninitialized: bool = False
mnemonic: str = " ".join(["all"] * 12)
pin: str | None = None
passphrase: bool | str = False
needs_backup: bool = False
no_backup: bool = False
experimental: bool = False
lang: str = "en"
class ClientConnection:
def __init__(self, client: Client):
self.client = client
self.setup_params = SetupParams()
self.language = client.features.language or "en-US"
self.storage_hash = b""
@pytest.fixture(scope="session")
def _raw_client(request: pytest.FixtureRequest) -> Client:
def client_connection(request: pytest.FixtureRequest) -> ClientConnection:
# In case tests run in parallel, each process has its own emulator/client.
# Requesting the emulator fixture only if relevant.
if request.session.config.getoption("control_emulators"):
@ -138,14 +160,7 @@ def _raw_client(request: pytest.FixtureRequest) -> Client:
else:
client = _find_client(request, interact)
# Setting the appropriate language
# Not doing it for T1
if client.model is not models.T1B1:
lang = request.session.config.getoption("lang") or "en"
assert isinstance(lang, str)
translations.set_language(client, lang)
return client
return ClientConnection(client)
def _client_from_path(
@ -173,8 +188,8 @@ def _find_client(request: pytest.FixtureRequest, interact: bool) -> Client:
@pytest.fixture(scope="function")
def client(
request: pytest.FixtureRequest, _raw_client: Client
) -> Generator[Client, None, None]:
request: pytest.FixtureRequest, client_connection: ClientConnection
) -> t.Generator[Client, None, None]:
"""Client fixture.
Every test function that requires a client instance will get it from here.
@ -198,29 +213,19 @@ def client(
@pytest.mark.experimental
"""
if (
request.node.get_closest_marker("skip_t2t1")
and _raw_client.model is models.T2T1
):
client = client_connection.client
if request.node.get_closest_marker("skip_t2t1") and client.model is models.T2T1:
pytest.skip("Test excluded on Trezor T")
if (
request.node.get_closest_marker("skip_t1b1")
and _raw_client.model is models.T1B1
):
if request.node.get_closest_marker("skip_t1b1") and client.model is models.T1B1:
pytest.skip("Test excluded on Trezor 1")
if (
request.node.get_closest_marker("skip_t2b1")
and _raw_client.model is models.T2B1
):
if request.node.get_closest_marker("skip_t2b1") and client.model is models.T2B1:
pytest.skip("Test excluded on Trezor T2B1")
if (
request.node.get_closest_marker("skip_t3t1")
and _raw_client.model is models.T3T1
):
if request.node.get_closest_marker("skip_t3t1") and client.model is models.T3T1:
pytest.skip("Test excluded on Trezor T3T1")
sd_marker = request.node.get_closest_marker("sd_card")
if sd_marker and not _raw_client.features.sd_card_present:
if sd_marker and not client.features.sd_card_present:
raise RuntimeError(
"This test requires SD card.\n"
"To skip all such tests, run:\n"
@ -229,74 +234,77 @@ def client(
test_ui = request.config.getoption("ui")
_raw_client.reset_debug_features()
_raw_client.open()
client.reset_debug_features()
client.open()
try:
_raw_client.init_device()
client.init_device()
except Exception:
request.session.shouldstop = "Failed to communicate with Trezor"
pytest.fail("Failed to communicate with Trezor")
# Resetting all the debug events to not be influenced by previous test
_raw_client.debug.reset_debug_events()
client.debug.reset_debug_events()
if test_ui:
# we need to reseed before the wipe
_raw_client.debug.reseed(0)
client.debug.reseed(0)
if sd_marker:
should_format = sd_marker.kwargs.get("formatted", True)
_raw_client.debug.erase_sd_card(format=should_format)
wipe_device(_raw_client)
# Load language again, as it got erased in wipe
if _raw_client.model is not models.T1B1:
lang = request.session.config.getoption("lang") or "en"
assert isinstance(lang, str)
if lang != "en":
translations.set_language(_raw_client, lang)
setup_params = dict(
uninitialized=False,
mnemonic=" ".join(["all"] * 12),
pin=None,
passphrase=False,
needs_backup=False,
no_backup=False,
)
client.debug.erase_sd_card(format=should_format)
setup_params = SetupParams()
setup_params.experimental = bool(request.node.get_closest_marker("experimental"))
setup_params.lang = t.cast(str, request.session.config.getoption("lang") or "en")
marker = request.node.get_closest_marker("setup_client")
if marker:
setup_params.update(marker.kwargs)
setup_params.__dict__.update(marker.kwargs)
use_passphrase = setup_params["passphrase"] is True or isinstance(
setup_params["passphrase"], str
)
storage_hash = client.debug.storage_hash()
if (
client_connection.storage_hash != storage_hash
or client_connection.setup_params != setup_params
):
# wipe and reconfigure
wipe_device(client)
if not setup_params["uninitialized"]:
debuglink.load_device(
_raw_client,
mnemonic=setup_params["mnemonic"], # type: ignore
pin=setup_params["pin"], # type: ignore
passphrase_protection=use_passphrase,
label="test",
needs_backup=setup_params["needs_backup"], # type: ignore
no_backup=setup_params["no_backup"], # type: ignore
use_passphrase = setup_params.passphrase is True or isinstance(
setup_params.passphrase, str
)
if request.node.get_closest_marker("experimental"):
apply_settings(_raw_client, experimental_features=True)
if (
setup_params.lang != "en"
and Capability.Translations in client.features.capabilities
):
translations.set_language(client, setup_params.lang)
if not setup_params.uninitialized:
debuglink.load_device(
client,
mnemonic=setup_params.mnemonic,
pin=setup_params.pin,
passphrase_protection=use_passphrase,
label="test",
needs_backup=setup_params.needs_backup,
no_backup=setup_params.no_backup,
)
if setup_params.experimental:
apply_settings(client, experimental_features=True)
if use_passphrase and isinstance(setup_params.passphrase, str):
client.use_passphrase(setup_params.passphrase)
if use_passphrase and isinstance(setup_params["passphrase"], str):
_raw_client.use_passphrase(setup_params["passphrase"])
client_connection.setup_params = setup_params
client_connection.storage_hash = client.debug.storage_hash()
_raw_client.clear_session()
client.clear_session()
with ui_tests.screen_recording(_raw_client, request):
yield _raw_client
with ui_tests.screen_recording(client, request):
yield client
_raw_client.close()
client.close()
def _is_main_runner(session_or_request: pytest.Session | pytest.FixtureRequest) -> bool:
@ -436,7 +444,7 @@ def pytest_runtest_setup(item: pytest.Item) -> None:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item: pytest.Item, call) -> Generator:
def pytest_runtest_makereport(item: pytest.Item, call) -> t.Generator:
# Make test results available in fixtures.
# See https://docs.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures
# The device_handler fixture uses this as 'request.node.rep_call.passed' attribute,
@ -447,7 +455,7 @@ def pytest_runtest_makereport(item: pytest.Item, call) -> Generator:
@pytest.fixture
def device_handler(client: Client, request: pytest.FixtureRequest) -> Generator:
def device_handler(client: Client, request: pytest.FixtureRequest) -> t.Generator:
device_handler = BackgroundDeviceHandler(client)
yield device_handler

Loading…
Cancel
Save