1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-04 21:48:17 +00:00

Compare commits

...

12 Commits

Author SHA1 Message Date
Ioan Bizău
8a189b5313
Merge 3bf8f12cd5 into ef02c4de5d 2024-12-03 11:17:29 +01:00
matejcik
ef02c4de5d feat(core): introduce storage insecure mode
reduces the number of PIN iterations and avoids erasing the other
storage bank -- if a test ever overruns, it will probably RSOD out, but
that's unlikely to happen
2024-12-03 11:02:17 +01:00
matejcik
835f7087c6 build(core): correctly propagate DISABLE_OPTIGA to kernel 2024-12-03 11:02:17 +01:00
matejcik
331e07b1e0 feat(core): disable animations in debug firmware by default
This makes it possible to run HW tests on the T3T1 where animations mess
things up. It also speeds up HW tests on other models slightly.

export TREZOR_DISABLE_ANIMATION=0 to build a debug firmware with
animations enabled
2024-12-03 11:02:17 +01:00
Ioan Bizău
3bf8f12cd5 fixup! fixup! feat(core): add libtropic to unix build 2024-11-27 16:19:12 +01:00
Ioan Bizău
14a5770703 fixup! feat(core): add libtropic to unix build 2024-11-27 16:18:42 +01:00
Ioan Bizău
21d26d60df chore(core/tropic): update libtropic. 2024-11-27 15:49:56 +01:00
Ioan Bizău
9567cca9d0 fixup! chore(core/tests): add smoke test for libtropic 2024-11-27 15:49:56 +01:00
Ioan Bizău
ff3f1deac1 fixup! feat(core): add libtropic to unix build 2024-11-27 15:49:56 +01:00
Ioan Bizău
ce62dc6e2a chore(core): add ability for emu launcher to launch tropic model 2024-11-27 15:49:56 +01:00
Ioan Bizău
45891cb799 chore(core/tests): add smoke test for libtropic 2024-11-27 15:49:56 +01:00
Ioan Bizău
d316d88c0f feat(core): add libtropic to unix build 2024-11-27 15:49:52 +01:00
25 changed files with 471 additions and 11 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ __pycache__/
proto.gv*
.DS_Store
crypto/tests/libtrezor-crypto.so.dSYM/
tropic-model/

4
.gitmodules vendored
View File

@ -27,7 +27,9 @@
[submodule "vendor/cmsis_5"]
path = vendor/cmsis_5
url = https://github.com/ARM-software/CMSIS_5.git
[submodule "vendor/stm32u5xx_hal_driver"]
path = vendor/stm32u5xx_hal_driver
url = https://github.com/trezor/stm32u5xx_hal_driver.git
[submodule "vendor/libtropic"]
path = vendor/libtropic
url = https://github.com/tropicsquare/libtropic.git

View File

@ -31,6 +31,7 @@ PYOPT ?= 1
BITCOIN_ONLY ?= 0
BOOTLOADER_QA ?= 0
BOOTLOADER_DEVEL ?= 0
DISABLE_OPTIGA ?= 0
TREZOR_MODEL ?= T
TREZOR_MEMPERF ?= 0
ADDRESS_SANITIZER ?= 0
@ -41,6 +42,8 @@ THP ?= 0
BENCHMARK ?= 0
TREZOR_EMULATOR_DEBUGGABLE ?= 0
QUIET_MODE ?= 0
TREZOR_DISABLE_ANIMATION ?= $(if $(filter 0,$(PYOPT)),1,0)
STORAGE_INSECURE_TESTING_MODE ?= 0
# OpenOCD interface default. Alternative: ftdi/olimex-arm-usb-tiny-h
OPENOCD_INTERFACE ?= stlink
@ -142,7 +145,9 @@ SCONS_VARS = \
PRODUCTION="$(PRODUCTION)" \
PYOPT="$(PYOPT)" \
QUIET_MODE="$(QUIET_MODE)" \
STORAGE_INSECURE_TESTING_MODE="$(STORAGE_INSECURE_TESTING_MODE)" \
THP="$(THP)" \
TREZOR_DISABLE_ANIMATION="$(TREZOR_DISABLE_ANIMATION)" \
TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \
TREZOR_EMULATOR_DEBUGGABLE=$(TREZOR_EMULATOR_DEBUGGABLE) \
TREZOR_MEMPERF="$(TREZOR_MEMPERF)" \

View File

@ -18,6 +18,14 @@ HW_REVISION = ARGUMENTS.get('HW_REVISION', None)
THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol
MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL)
BENCHMARK = ARGUMENTS.get('BENCHMARK', '0') == '1'
DISABLE_ANIMATION = ARGUMENTS.get('TREZOR_DISABLE_ANIMATION', '0') == '1'
STORAGE_INSECURE_TESTING_MODE = ARGUMENTS.get('STORAGE_INSECURE_TESTING_MODE', '0') == '1'
if STORAGE_INSECURE_TESTING_MODE and PRODUCTION:
raise RuntimeError("STORAGE_INSECURE_TESTING_MODE cannot be used in production")
if STORAGE_INSECURE_TESTING_MODE:
DISABLE_OPTIGA = True
PYOPT = "0"
if BENCHMARK and PYOPT != '0':
print("BENCHMARK=1 works only with PYOPT=0.")
@ -30,7 +38,9 @@ FEATURE_FLAGS = {
}
FEATURES_WANTED = ["input", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"]
if DISABLE_OPTIGA and PYOPT == '0':
if DISABLE_OPTIGA:
if PYOPT != '0':
raise RuntimeError("DISABLE_OPTIGA requires PYOPT=0")
FEATURES_WANTED.remove("optiga")
CCFLAGS_MOD = ''
@ -69,6 +79,7 @@ CPPDEFINES_MOD += [
('USE_CARDANO', '1' if EVERYTHING else '0'),
('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL == "T") else '0'),
('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL == "T") else '0'),
('DISABLE_ANIMATION', '1' if DISABLE_ANIMATION else '0'),
]
SOURCE_MOD += [
'embed/upymod/trezorobj.c',
@ -367,6 +378,9 @@ if THP:
'vendor/trezor-crypto/elligator2.c',
]
if STORAGE_INSECURE_TESTING_MODE:
CPPDEFINES_MOD += ['STORAGE_INSECURE_TESTING_MODE']
ui.init_ui(TREZOR_MODEL, "firmware", CPPDEFINES_MOD, SOURCE_MOD, RUST_UI_FEATURES)
SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED
@ -681,6 +695,7 @@ if FROZEN:
use_button='button' in FEATURES_AVAILABLE,
use_touch='touch' in FEATURES_AVAILABLE,
ui_layout=ui.get_ui_layout(TREZOR_MODEL),
tropic='tropic' in FEATURES_AVAILABLE,
thp=THP,
)
@ -873,6 +888,14 @@ elif 'STM32U5G9xx' in CPPDEFINES_HAL or 'STM32U585xx' in CPPDEFINES_HAL:
else:
raise Exception("Unknown MCU")
if STORAGE_INSECURE_TESTING_MODE:
INSECURE_TESTING_MODE_STR = """
#########################################################
# STORAGE_INSECURE_TESTING_MODE enabled, DO NOT USE #
#########################################################
"""
action_bin.append(INSECURE_TESTING_MODE_STR)
program_bin = env.Command(
target='firmware.bin',
source=program_elf,

View File

@ -16,6 +16,13 @@ DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1'
HW_REVISION = ARGUMENTS.get('HW_REVISION', None)
THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol
STORAGE_INSECURE_TESTING_MODE = ARGUMENTS.get('STORAGE_INSECURE_TESTING_MODE', '0') == '1'
if STORAGE_INSECURE_TESTING_MODE and PRODUCTION:
raise RuntimeError("STORAGE_INSECURE_TESTING_MODE cannot be used in production")
if STORAGE_INSECURE_TESTING_MODE:
DISABLE_OPTIGA = True
PYOPT = "0"
FEATURE_FLAGS = {
"RDI": True,
"SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot)
@ -24,7 +31,10 @@ FEATURE_FLAGS = {
}
FEATURES_WANTED = ["input", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"]
if DISABLE_OPTIGA and PYOPT == '0':
if DISABLE_OPTIGA:
# TODO use PYOPT instead of PRODUCTION, same as in firmware, blocked on #4253
if PRODUCTION:
raise RuntimeError("DISABLE_OPTIGA requires non-production build")
FEATURES_WANTED.remove("optiga")
CCFLAGS_MOD = ''
@ -235,6 +245,8 @@ if THP:
'vendor/trezor-crypto/elligator2.c',
]
if STORAGE_INSECURE_TESTING_MODE:
CPPDEFINES_MOD += ['STORAGE_INSECURE_TESTING_MODE']
env = Environment(
ENV=os.environ,
@ -411,6 +423,14 @@ action_bin=[
'$CP $TARGET ' + BINARY_NAME,
]
if STORAGE_INSECURE_TESTING_MODE:
INSECURE_TESTING_MODE_STR = """
#########################################################
# STORAGE_INSECURE_TESTING_MODE enabled, DO NOT USE #
#########################################################
"""
action_bin.append(INSECURE_TESTING_MODE_STR)
program_bin = env.Command(
target='kernel.bin',
source=program_elf,

View File

@ -21,7 +21,7 @@ if BENCHMARK and PYOPT != '0':
print("BENCHMARK=1 works only with PYOPT=0.")
exit(1)
FEATURES_WANTED = ["input", "sd_card", "dma2d", "optiga"]
FEATURES_WANTED = ["input", "sd_card", "dma2d", "optiga", "tropic"]
if not models.has_emulator(TREZOR_MODEL):
# skip unix build
@ -48,6 +48,7 @@ SOURCE_MOD = [
'vendor/micropython/extmod/vfs_posix_file.c',
]
SOURCE_MOD_CRYPTO = []
SOURCE_MOD_TROPIC = []
RUST_UI_FEATURES = []
# modtrezorconfig
@ -251,6 +252,14 @@ SOURCE_MOD += [
'embed/upymod/modutime.c',
]
SOURCE_MOD_TROPIC += [
'vendor/libtropic/src/libtropic.c',
]
CPPDEFINES_MOD += ['USE_TREZOR_CRYPTO']
CPPPATH_MOD += ['vendor/libtropic/src/', 'vendor/libtropic/include/']
SOURCE_MICROPYTHON = [
'vendor/micropython/extmod/modubinascii.c',
'vendor/micropython/extmod/moductypes.c',
@ -752,6 +761,7 @@ if FROZEN:
bitcoin_only=BITCOIN_ONLY,
backlight='backlight' in FEATURES_AVAILABLE,
optiga='optiga' in FEATURES_AVAILABLE,
tropic='tropic' in FEATURES_AVAILABLE,
use_button='button' in FEATURES_AVAILABLE,
use_touch='touch' in FEATURES_AVAILABLE,
ui_layout=ui.get_ui_layout(TREZOR_MODEL),
@ -769,7 +779,7 @@ if FROZEN:
#
obj_program = []
source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_MICROPYTHON + SOURCE_UNIX
source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_MOD_TROPIC + SOURCE_MICROPYTHON + SOURCE_UNIX
obj_program.extend(env.Object(source=SOURCE_MOD))
obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero'))
if FEATURE_FLAGS["SECP256K1_ZKP"]:

View File

@ -40,6 +40,7 @@ rgb_led = []
backlight = []
usb = []
optiga = []
tropic = []
translations = ["crypto"]
test = [
"backlight",

View File

@ -0,0 +1,234 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* 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.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if USE_TROPIC
// Default initial Tropic handshake keys
#define PKEY_INDEX_BYTE PAIRING_KEY_SLOT_INDEX_0
#define SHiPRIV_BYTES \
{0xf0, 0xc4, 0xaa, 0x04, 0x8f, 0x00, 0x13, 0xa0, 0x96, 0x84, 0xdf, \
0x05, 0xe8, 0xa2, 0x2e, 0xf7, 0x21, 0x38, 0x98, 0x28, 0x2b, 0xa9, \
0x43, 0x12, 0xf3, 0x13, 0xdf, 0x2d, 0xce, 0x8d, 0x41, 0x64};
#define SHiPUB_BYTES \
{0x84, 0x2f, 0xe3, 0x21, 0xa8, 0x24, 0x74, 0x08, 0x37, 0x37, 0xff, \
0x2b, 0x9b, 0x88, 0xa2, 0xaf, 0x42, 0x44, 0x2d, 0xb0, 0xd8, 0xaa, \
0xcc, 0x6d, 0xc6, 0x9e, 0x99, 0x53, 0x33, 0x44, 0xb2, 0x46};
#include "libtropic.h"
/// package: trezorcrypto.tropic
/// class TropicError(Exception):
/// """Error returned by the Tropic Square chip."""
MP_DEFINE_EXCEPTION(TropicError, Exception)
#define PING_MSG_MAX_LEN 64
#define ECC_SLOT_COUNT 32
#define SIG_SIZE 64
STATIC bool lt_handle_initialized = false;
STATIC lt_handle_t lt_handle = {0};
STATIC void tropic_init(lt_handle_t *handle) {
lt_ret_t ret = LT_FAIL;
ret = lt_init(handle);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_init failed.");
}
uint8_t X509_cert[LT_L2_GET_INFO_REQ_CERT_SIZE] = {0};
ret = lt_get_info_cert(handle, X509_cert, LT_L2_GET_INFO_REQ_CERT_SIZE);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_get_info_cert failed.");
}
uint8_t stpub[32] = {0};
ret = lt_cert_verify_and_parse(X509_cert, 512, stpub);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_cert_verify_and_parse failed.");
}
uint8_t pkey_index = PKEY_INDEX_BYTE;
uint8_t shipriv[] = SHiPRIV_BYTES;
uint8_t shipub[] = SHiPUB_BYTES;
ret = lt_session_start(handle, stpub, pkey_index, shipriv, shipub);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_session_start failed.");
}
}
/// def ping(message: str) -> str:
/// """
/// Test the session by pinging the chip.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_ping(mp_obj_t message) {
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
uint8_t msg_in[PING_MSG_MAX_LEN] = {0};
mp_buffer_info_t message_b = {0};
mp_get_buffer_raise(message, &message_b, MP_BUFFER_READ);
if (message_b.len > 0) {
ret = lt_ping(&lt_handle, (uint8_t *)message_b.buf, (uint8_t *)msg_in,
message_b.len);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_ping failed.");
}
} else {
return mp_const_none;
}
vstr_t result = {0};
vstr_init_len(&result, message_b.len);
memcpy(result.buf, msg_in, message_b.len);
result.len = strlen(result.buf);
return mp_obj_new_str_from_vstr(&mp_type_str, &result);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_tropic_ping_obj,
mod_trezorcrypto_tropic_ping);
/// def get_certificate() -> bytes:
/// """
/// Return the chip's certificate.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_get_certificate() {
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
uint8_t X509_cert[512] = {0};
ret = lt_get_info_cert(&lt_handle, X509_cert, 512);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_get_info_cert failed.");
}
vstr_t vstr = {0};
vstr_init_len(&vstr, 512);
memcpy(vstr.buf, X509_cert, 512);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_tropic_get_certificate_obj,
mod_trezorcrypto_tropic_get_certificate);
/// def key_generate(
/// key_index: int,
/// ) -> None:
/// """
/// Generate ECC key in the device's ECC key slot.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_key_generate(mp_obj_t key_index) {
mp_int_t idx = mp_obj_get_int(key_index);
if (idx < 0 || idx >= ECC_SLOT_COUNT) {
mp_raise_ValueError("Invalid index.");
}
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
ret = lt_ecc_key_generate(&lt_handle, idx, CURVE_ED25519);
if (ret != LT_OK) {
mp_raise_msg(&mp_type_TropicError, "lt_ecc_key_generate failed.");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_tropic_key_generate_obj,
mod_trezorcrypto_tropic_key_generate);
/// def sign(
/// key_index: int,
/// digest: bytes,
/// ) -> bytes:
/// """
/// Uses the private key at key_index to produce a signature of the digest.
/// """
STATIC mp_obj_t mod_trezorcrypto_tropic_sign(mp_obj_t key_index,
mp_obj_t digest) {
mp_int_t idx = mp_obj_get_int(key_index);
if (idx < 0 || idx >= ECC_SLOT_COUNT) {
mp_raise_ValueError("Invalid index.");
}
mp_buffer_info_t dig = {0};
mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (dig.len != 32) {
mp_raise_ValueError("Invalid length of digest.");
}
lt_ret_t ret = LT_FAIL;
if (!lt_handle_initialized) {
tropic_init(&lt_handle);
lt_handle_initialized = true;
}
vstr_t sig = {0};
vstr_init_len(&sig, SIG_SIZE);
ret = lt_ecc_eddsa_sign(&lt_handle, idx, (const uint8_t *)dig.buf, dig.len,
((uint8_t *)sig.buf), SIG_SIZE);
if (ret != LT_OK) {
vstr_clear(&sig);
mp_raise_msg(&mp_type_TropicError, "lt_ecc_eddsa_sign failed.");
}
sig.len = SIG_SIZE;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_tropic_sign_obj,
mod_trezorcrypto_tropic_sign);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_tropic_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_tropic)},
{MP_ROM_QSTR(MP_QSTR_ping), MP_ROM_PTR(&mod_trezorcrypto_tropic_ping_obj)},
{MP_ROM_QSTR(MP_QSTR_get_certificate),
MP_ROM_PTR(&mod_trezorcrypto_tropic_get_certificate_obj)},
{MP_ROM_QSTR(MP_QSTR_key_generate),
MP_ROM_PTR(&mod_trezorcrypto_tropic_key_generate_obj)},
{MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_tropic_sign_obj)},
{MP_ROM_QSTR(MP_QSTR_TropicError), MP_ROM_PTR(&mp_type_TropicError)}};
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_tropic_globals,
mod_trezorcrypto_tropic_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_tropic_module = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_tropic_globals,
};
#endif

View File

@ -69,6 +69,9 @@ static void wrapped_ui_wait_callback(uint32_t current, uint32_t total) {
#ifdef USE_OPTIGA
#include "modtrezorcrypto-optiga.h"
#endif
#ifdef USE_TROPIC
#include "modtrezorcrypto-tropic.h"
#endif
#if !BITCOIN_ONLY
#include "modtrezorcrypto-cardano.h"
#include "modtrezorcrypto-monero.h"
@ -135,6 +138,9 @@ STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = {
#if USE_OPTIGA
{MP_ROM_QSTR(MP_QSTR_optiga), MP_ROM_PTR(&mod_trezorcrypto_optiga_module)},
#endif
#if USE_TROPIC
{MP_ROM_QSTR(MP_QSTR_tropic), MP_ROM_PTR(&mod_trezorcrypto_tropic_module)},
#endif
};
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorcrypto_globals,
mp_module_trezorcrypto_globals_table);

View File

@ -388,6 +388,8 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = {
/// """Whether the hardware supports haptic feedback."""
/// USE_OPTIGA: bool
/// """Whether the hardware supports Optiga secure element."""
/// USE_TROPIC: bool
/// """Whether the hardware supports Tropic Square secure element."""
/// USE_TOUCH: bool
/// """Whether the hardware supports touch screen."""
/// USE_BUTTON: bool
@ -410,6 +412,9 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = {
/// """UI layout identifier ("tt" for model T, "tr" for models One and R)."""
/// USE_THP: bool
/// """Whether the firmware supports Trezor-Host Protocol (version 2)."""
/// if __debug__:
/// DISABLE_ANIMATION: bool
/// """Whether the firmware should disable animations."""
STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorutils)},
@ -458,6 +463,11 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else
{MP_ROM_QSTR(MP_QSTR_USE_OPTIGA), mp_const_false},
#endif
#ifdef USE_TROPIC
{MP_ROM_QSTR(MP_QSTR_USE_TROPIC), mp_const_true},
#else
{MP_ROM_QSTR(MP_QSTR_USE_TROPIC), mp_const_false},
#endif
#ifdef USE_TOUCH
{MP_ROM_QSTR(MP_QSTR_USE_TOUCH), mp_const_true},
#else
@ -502,6 +512,13 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else
#error Unknown layout
#endif
#if !PYOPT
#if DISABLE_ANIMATION
{MP_ROM_QSTR(MP_QSTR_DISABLE_ANIMATION), mp_const_true},
#else
{MP_ROM_QSTR(MP_QSTR_DISABLE_ANIMATION), mp_const_false},
#endif // TREZOR_DISABLE_ANIMATION
#endif // PYOPT
};
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorutils_globals,

View File

@ -112,6 +112,7 @@ def _from_env(name: str) -> bool:
@click.option("-G", "--alloc-profiling/--no-alloc-profiling", default=_from_env("TREZOR_MEMPERF"), help="Profile memory allocation (requires special micropython build)")
@click.option("-h", "--headless", is_flag=True, help="Headless mode (no display, disables animation)")
@click.option("--heap-size", metavar="SIZE", default="20M", help="Configure heap size")
@click.option("-m", "--tropic-model", is_flag=True, help="Start the Tropic Square model, needed for running the Tropic tests. Needs to be installed first.")
@click.option("--main", help="Path to python main file")
@click.option("--mnemonic", "mnemonics", multiple=True, help="Initialize device with given mnemonic. Specify multiple times for Shamir shares.")
@click.option("--log-memory/--no-log-memory", default=_from_env("TREZOR_LOG_MEMORY"), help="Print memory usage after workflows")
@ -139,6 +140,7 @@ def cli(
alloc_profiling: bool,
headless: bool,
heap_size: str,
tropic_model: bool,
main: str,
mnemonics: list[str],
log_memory: bool,
@ -177,7 +179,7 @@ def cli(
if command and not run_command:
raise click.ClickException("Extra arguments found. Did you mean to use -c?")
if watch and (command or debugger):
if watch and (command or debugger or tropic_model):
raise click.ClickException("Cannot use -w together with -c or -D")
if watch and inotify is None:
@ -297,6 +299,10 @@ def cli(
emulator.client, record_dir, report_func=print
)
if tropic_model:
run_command = True
command = "./tropic-model.sh"
if run_command:
ret = run_command_with_emulator(emulator, command)
elif watch:

View File

@ -0,0 +1,31 @@
from typing import *
# upymod/modtrezorcrypto/modtrezorcrypto-tropic.h
class TropicError(Exception):
"""Error returned by the Tropic Square chip."""
def ping(message: str) -> str:
"""
Test the session by pinging the chip.
"""
def get_certificate() -> bytes:
"""
Return the chip's certificate.
"""
def key_generate(
key_index: int,
) -> None:
"""
Generate ECC key in the device's ECC key slot.
"""
def sign(
key_index: int,
digest: bytes,
) -> bytes:
"""
Uses the private key at key_index to produce a signature of the digest.
"""

View File

@ -130,6 +130,8 @@ USE_HAPTIC: bool
"""Whether the hardware supports haptic feedback."""
USE_OPTIGA: bool
"""Whether the hardware supports Optiga secure element."""
USE_TROPIC: bool
"""Whether the hardware supports Tropic Square secure element."""
USE_TOUCH: bool
"""Whether the hardware supports touch screen."""
USE_BUTTON: bool
@ -152,3 +154,6 @@ UI_LAYOUT: str
"""UI layout identifier ("tt" for model T, "tr" for models One and R)."""
USE_THP: bool
"""Whether the firmware supports Trezor-Host Protocol (version 2)."""
if __debug__:
DISABLE_ANIMATION: bool
"""Whether the firmware should disable animations."""

View File

@ -55,6 +55,27 @@ def configure(
features_available.append("optiga")
defines += [("USE_OPTIGA", "1")]
if "tropic" in features_wanted:
sources += [
"vendor/libtropic/src/libtropic.c",
"vendor/libtropic/src/lt_crc16.c",
"vendor/libtropic/src/lt_hkdf.c",
"vendor/libtropic/src/lt_l1.c",
"vendor/libtropic/src/lt_l1_port_wrap.c",
"vendor/libtropic/src/lt_l2.c",
"vendor/libtropic/src/lt_l2_frame_check.c",
"vendor/libtropic/src/lt_l3.c",
"vendor/libtropic/src/lt_random.c",
"vendor/libtropic/hal/port/unix/lt_port_unix.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_aesgcm.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_ed25519.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_sha256.c",
"vendor/libtropic/hal/crypto/trezor_crypto/lt_crypto_trezor_x25519.c",
]
defines += ["USE_TREZOR_CRYPTO"]
features_available.append("tropic")
defines += ["USE_TROPIC=1"]
if "input" in features_wanted:
sources += ["embed/io/touch/unix/touch.c"]
paths += ["embed/io/touch/inc"]

View File

@ -44,6 +44,7 @@ def generate(env):
btc_only = env["bitcoin_only"] == "1"
backlight = env["backlight"]
optiga = env["optiga"]
tropic = env["tropic"]
layout_tt = env["ui_layout"] == "UI_LAYOUT_TT"
layout_tr = env["ui_layout"] == "UI_LAYOUT_TR"
touch = env["use_touch"]
@ -55,6 +56,7 @@ def generate(env):
rf"-e 's/utils\.BITCOIN_ONLY/{btc_only}/g'",
rf"-e 's/utils\.USE_BACKLIGHT/{backlight}/g'",
rf"-e 's/utils\.USE_OPTIGA/{optiga}/g'",
rf"-e 's/utils\.USE_TROPIC/{tropic}/g'",
rf"-e 's/utils\.UI_LAYOUT == \"TT\"/{layout_tt}/g'",
rf"-e 's/utils\.UI_LAYOUT == \"TR\"/{layout_tr}/g'",
rf"-e 's/utils\.UI_LAYOUT == \"MERCURY\"/{layout_mercury}/g'",

View File

@ -22,5 +22,8 @@ if not utils.BITCOIN_ONLY:
if utils.USE_OPTIGA:
from trezorcrypto import optiga # noqa: F401
if utils.USE_TROPIC:
from trezorcrypto import tropic # noqa: F401
if utils.USE_THP:
from trezorcrypto import elligator2 # noqa: F401

View File

@ -24,7 +24,7 @@ else:
if __debug__:
trezorui2.disable_animation(bool(utils.DISABLE_ANIMATION))
trezorui2.disable_animation(utils.DISABLE_ANIMATION)
# all rendering is done through a singleton of `Display`

View File

@ -14,6 +14,7 @@ from trezorutils import ( # noqa: F401
USE_BUTTON,
USE_HAPTIC,
USE_OPTIGA,
USE_TROPIC,
USE_SD_CARD,
USE_THP,
USE_TOUCH,
@ -33,17 +34,20 @@ from trezorutils import ( # noqa: F401
)
from typing import TYPE_CHECKING
DISABLE_ANIMATION = 0
if __debug__:
if EMULATOR:
import uos
DISABLE_ANIMATION = int(uos.getenv("TREZOR_DISABLE_ANIMATION") or "0")
LOG_MEMORY = int(uos.getenv("TREZOR_LOG_MEMORY") or "0")
DISABLE_ANIMATION = uos.getenv("TREZOR_DISABLE_ANIMATION") == "1"
LOG_MEMORY = uos.getenv("TREZOR_LOG_MEMORY") == "1"
else:
from trezorutils import DISABLE_ANIMATION # noqa: F401
LOG_MEMORY = 0
else:
DISABLE_ANIMATION = False
if TYPE_CHECKING:
from typing import Any, Iterator, Protocol, Sequence, TypeVar

View File

@ -0,0 +1,27 @@
from common import * # isort:skip
from slip39_vectors import vectors
from trezor.crypto import tropic
class TestCryptoTropic(unittest.TestCase):
def test_ping(self):
self.assertEqual(tropic.ping("HeLlO!"), "HeLlO!")
def test_get_certificate(self):
self.assertEqual(len(tropic.get_certificate()), 512)
def test_sign(self):
try:
tropic.sign(0, "ASD")
assert False
except ValueError as e:
self.assertIn("invalid length", str(e).lower())
tropic.key_generate(0)
# signing should work now that we have a key
self.assertEqual(len(tropic.sign(0, "a" * 32)), 64)
if __name__ == "__main__":
unittest.main()

20
core/tropic-model.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
if [ ! -d "tropic-model" ]; then
echo "================================================="
echo "Please install the Tropic model to the tropic-model/ directory first, using the steps below!"
echo "1. mkdir tropic-model && python3 -mvenv tropic-model/venv && source tropic-model/venv/bin/activate"
echo "2. Follow instructions here: https://github.com/tropicsquare/ts-tvl/tree/master?tab=readme-ov-file#installing"
echo " (basically, download the tvl-XXX.whl and pip install it under the venv created above - which should be already activated)"
echo "3. Get config files for the model from https://github.com/tropicsquare/ts-tvl/tree/master/tvl/server/model_config"
echo " i. model_config.yml"
echo " ii. tropic01_ese_certificate_1.pem"
echo " iii.tropic01_ese_private_key_1.pem"
echo " iv. tropic01_ese_public_key_1.pem"
echo "================================================="
exit 1
fi
cd tropic-model
source venv/bin/activate
model_server tcp -vv -c model_config.yml

1
core/vendor/libtropic vendored Symbolic link
View File

@ -0,0 +1 @@
../../vendor/libtropic/

View File

@ -165,6 +165,7 @@ CFLAGS += -I../vendor/nanopb -Iprotob -DPB_FIELD_16BIT=1 -DPB_ENCODE_ARRAYS_UNPA
CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"'
CFLAGS += -DUSE_MONERO=0
CFLAGS += -DUSE_OPTIGA=0
CFLAGS += -DUSE_TROPIC=0
ifneq ($(BITCOIN_ONLY),1)
CFLAGS += -DUSE_ETHEREUM=1
CFLAGS += -DUSE_NEM=1

View File

@ -284,11 +284,15 @@ void norcow_wipe(void) {
// Erase the active sector first, because it contains sensitive data.
erase_sector(norcow_active_sector, sectrue);
#if STORAGE_INSECURE_TESTING_MODE && !PRODUCTION
// skip erasing inactive sectors
#else
for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) {
if (i != norcow_active_sector) {
erase_sector(i, secfalse);
}
}
#endif
norcow_active_version = NORCOW_VERSION;
norcow_write_sector = norcow_active_sector;
norcow_free_offset = NORCOW_STORAGE_START;

View File

@ -86,8 +86,12 @@ const uint32_t V0_PIN_EMPTY = 1;
// up constant storage space.
#define MAX_WIPE_CODE_LEN 50
#if STORAGE_INSECURE_TESTING_MODE && !PRODUCTION
#define PIN_ITER_COUNT 1
#else
// The total number of iterations to use in PBKDF2.
#define PIN_ITER_COUNT 20000
#endif
// The minimum number of milliseconds between progress updates.
#define MIN_PROGRESS_UPDATE_MS 100

View File

@ -2,3 +2,15 @@
#include <stdint.h>
uint32_t hamming_weight(uint32_t value);
#ifndef STORAGE_INSECURE_TESTING_MODE
#define STORAGE_INSECURE_TESTING_MODE 0
#endif
#if STORAGE_INSECURE_TESTING_MODE
#if PRODUCTION
#error "STORAGE_INSECURE_TESTING_MODE can't be used in production"
#else
#pragma message("STORAGE IS INSECURE DO NOT USE THIS IN PRODUCTION")
#endif
#endif