chore(core): add testing tropic attestation key and certificate
What changed, and why it matters
This commit updates Trezor's internal test-only files that simulate a TROPIC01 secure chip. It replaces old self-signed test certificates with a new four-level test certificate chain and embeds keys directly into config files instead of referencing separate PEM files. The change is labeled as a testing chore, touches only test/development artifacts, and does not alter production firmware code. The most notable security-relevant detail is that a hardcoded X25519 private key is included in test data, but it is explicitly a test key already present in the public source tree and used only for the emulator/unix test build.
No immediate action required for production security. Reviewers should confirm the hardcoded test key is not referenced by production builds and that the new `base_config.yml` values are only used in test/emulator contexts. If the repository is scanned for secrets, these test-only keys should be allow-listed to avoid false positives.
Security signals we found
Hardcoded cryptographic private key material in test fixtures (l3.key / X25519 seed)
Addition of certificate chain generation script for test model
Removal of older self-signed test certificates
Refactoring of test-only configuration generator; no production firmware code changed
Commit message explicitly marks change as testing-related and skips changelog
Evidence from the diff
The patch refactors core/tools/generate_tropic_model_config.py to stop generating an Ed25519 signing key/certificate chain on the fly and instead read a pre-generated cert_store.der plus an l3.key from tests/tropic_model/tropic_cert_chain/. It adds base_config.yml containing pre-baked r_user_data slots 3-5 (device certificate chain for Trezor’s authenticity check) and r_ecc_keys slot 0. It removes old standalone PEM files (root_cert.pem, root_key.pem, tropic_cert.pem, tropic_key.pem, tropic01_ese_*) and adds a new generate_test_chain.py script that creates a 4-level EC/X25519 cert chain. The leaf l3.key is derived from the well-known hex seed b04280...e367, which the code comments identify as SECRET_TROPIC_PUBKEY_BYTES from the unix secret_keys file. The upgrade test is adjusted because certificate/key values are now embedded as binary blobs rather than file paths.
Changed components
tests/tropic_model/ (Tropic model test fixtures)core/tools/generate_tropic_model_config.py (test config generator)tests/upgrade_tests/test_tropic_config_set.py (upgrade test)tests/tropic_model/tropic_cert_chain/ (new test certificate chain)Inspect captured patch +560 / −210
diff --git a/core/tools/generate_tropic_model_config.py b/core/tools/generate_tropic_model_config.py
index a3a0d400..eddc3660 100755
--- a/core/tools/generate_tropic_model_config.py
+++ b/core/tools/generate_tropic_model_config.py
@@ -1,14 +1,18 @@
#!/usr/bin/env python3
-import hashlib
import json
import os
from pathlib import Path
import click
import yaml
-from cryptography import x509
-from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.serialization import (
+ Encoding,
+ NoEncryption,
+ PrivateFormat,
+ PublicFormat,
+ load_pem_private_key,
+)
HERE = Path(__file__).parent
ROOT = HERE.parent.parent.resolve()
@@ -18,21 +22,9 @@ CFG_SPEC_PATH = (
ROOT / "core" / "embed" / "sec" / "tropic" / "config" / "tropic_configs.json"
)
-# private key used by the Tropic model to sign
-TROPIC_KEY = CONFIG_DIR / "tropic_key.pem"
-
-# certificate of the Tropic model - signed by the root authority
-TROPIC_CERT = CONFIG_DIR / "tropic_cert.pem"
-
-# certificate of the root authority
-ROOT_CERT = CONFIG_DIR / "root_cert.pem"
-
-VENDOR_CONFIG_DIR = ROOT / "vendor" / "ts-tvl" / "model_configs" / "example_config"
-EXTRA_FILES = [
- VENDOR_CONFIG_DIR / "tropic01_ese_certificate_1.pem",
- VENDOR_CONFIG_DIR / "tropic01_ese_private_key_1.pem",
- VENDOR_CONFIG_DIR / "tropic01_ese_public_key_1.pem",
-]
+BASE_CONFIG = CONFIG_DIR / "base_config.yml"
+CERT_CHAIN_DIR = CONFIG_DIR / "tropic_cert_chain"
+CERT_STORE_PATH = CERT_CHAIN_DIR / "cert_store.der"
HEADER = f"""# This file is auto-generated by `{Path(__file__).relative_to(ROOT)}`.
# Do not edit this file directly. Instead, run `make gen` or
@@ -92,84 +84,24 @@ def get_tropic_configuration(path: Path) -> dict:
@click.command()
@click.option("--check", is_flag=True)
def generate_config(check: bool) -> None:
- tropic_key = serialization.load_pem_private_key(
- TROPIC_KEY.read_bytes(), password=None
- )
-
- tropic_a = tropic_key.public_key().public_bytes(
- encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
- )
-
- tropic_private_key_bytes = tropic_key.private_bytes(
- encoding=serialization.Encoding.Raw,
- format=serialization.PrivateFormat.Raw,
- encryption_algorithm=serialization.NoEncryption(),
+ device_private_key = load_pem_private_key(
+ (CERT_CHAIN_DIR / "l3.key").read_bytes(), None
)
+ cert_store = CERT_STORE_PATH.read_bytes()
- # perform clamping
- # https://www.jcraige.com/an-explainer-on-ed25519-clamping
- h = hashlib.sha512(tropic_private_key_bytes).digest()
- tropic_s = bytearray(h[:32])
- tropic_s[0] &= 248
- tropic_s[31] &= 63
- tropic_s[31] |= 64
- tropic_s = bytes(tropic_s)
-
- tropic_prefix = hashlib.sha512(tropic_s).digest()[:32]
-
- tropic_cert = x509.load_pem_x509_certificate(TROPIC_CERT.read_bytes())
- tropic_cert_der_bytes = tropic_cert.public_bytes(serialization.Encoding.DER)
-
- root_cert = x509.load_pem_x509_certificate(ROOT_CERT.read_bytes())
- root_cert_der_bytes = root_cert.public_bytes(serialization.Encoding.DER)
-
- # certificate chain with the length prefix
- all_cert_bytes = (
- (len(tropic_cert_der_bytes) + len(root_cert_der_bytes)).to_bytes(2, "big")
- + tropic_cert_der_bytes
- + root_cert_der_bytes
- )
-
- SLOT_LEN = 444
-
- # make sure they fit in 3 slots, which is what we have available
- assert len(all_cert_bytes) < SLOT_LEN * 3
-
- # split the data in 3 slots
- slot_1_bytes = all_cert_bytes[:SLOT_LEN]
- slot_2_bytes = all_cert_bytes[SLOT_LEN : SLOT_LEN * 2]
- slot_3_bytes = all_cert_bytes[SLOT_LEN * 2 : SLOT_LEN * 3]
-
- # save the data starting at slot 3
- # see https://github.com/trezor/trezor-firmware/blob/main/core/embed/sec/tropic/inc/sec/tropic.h#L31
- TROPIC_DEVICE_CERT_FIRST_SLOT = 3
- TROPIC_CONFIG_DISTRIBUTION_VERSION_SLOT = 6
- user_data = {}
- for i, data in enumerate([slot_1_bytes, slot_2_bytes, slot_3_bytes]):
- if len(data) != 0:
- if len(data) < SLOT_LEN: # pad last slot
- data += b"\x00" * (SLOT_LEN - len(data))
- user_data[TROPIC_DEVICE_CERT_FIRST_SLOT + i] = {"value": data}
- user_data[TROPIC_CONFIG_DISTRIBUTION_VERSION_SLOT] = {
- "value": (0).to_bytes(4, "big")
- }
chip_id = bytes.fromhex("0" * 192 + "19071f0a04" + "0" * 54)
tropic_cfg = get_tropic_configuration(CFG_SPEC_PATH)
+
config_dict = {
- "s_t_priv": "tropic01_ese_private_key_1.pem",
- "s_t_pub": "tropic01_ese_public_key_1.pem",
- "x509_certificate": "tropic01_ese_certificate_1.pem",
+ "s_t_priv": device_private_key.private_bytes(
+ Encoding.Raw, PrivateFormat.Raw, NoEncryption()
+ ),
+ "s_t_pub": device_private_key.public_key().public_bytes(
+ Encoding.Raw, PublicFormat.Raw
+ ),
+ "x509_certificate": cert_store,
"debug_random_value": b"\x00\xc0\xff\xee",
- "r_user_data": user_data, # certificate chain
"chip_id": chip_id,
- "r_ecc_keys": { # signing key at index 0
- 0: {
- "a": tropic_a,
- "s": tropic_s,
- "prefix": tropic_prefix,
- "origin": 2, # imported key
- }
- },
"riscv_fw_version": "1.0.0", # Version of the RISCV Firmware (also know as Application FW) used in TS7 devices
"spect_fw_version": "1.0.0",
"r_config": tropic_cfg["r_config"],
@@ -196,55 +128,55 @@ def generate_config(check: bool) -> None:
},
}
- config = yaml.dump(config_dict)
+ base_config = yaml.safe_load(BASE_CONFIG.read_text())
+ # r_user_data slots 3-5 (the device certificate chain used in Trezor's
+ # authenticity check) come from base_config; slot 6 is generated here.
+ # See https://github.com/trezor/trezor-firmware/blob/main/core/embed/sec/tropic/inc/sec/tropic.h#L31
+ TROPIC_CONFIG_DISTRIBUTION_VERSION_SLOT = 6
+ base_config["r_user_data"][TROPIC_CONFIG_DISTRIBUTION_VERSION_SLOT] = {
+ "value": (0).to_bytes(4, "big")
+ }
+
+ overlap = config_dict.keys() & base_config.keys()
+ if overlap:
+ raise click.ClickException(
+ f"Key collision between base_config and generated config: {overlap}"
+ )
+ config = HEADER + yaml.dump({**base_config, **config_dict})
if check:
if not DEST_PATH.exists():
print(f"{DEST_PATH} missing")
raise click.ClickException("Config file is missing")
- elif (HEADER + config) != DEST_PATH.read_text():
+ elif config != DEST_PATH.read_text():
raise click.ClickException("Config file is out of date")
- for extra_file in EXTRA_FILES:
- extra_file_dest = CONFIG_DIR / extra_file.name
- if not extra_file_dest.exists():
- print(f"{extra_file_dest} missing")
- raise click.ClickException("Extra config file missing")
- elif extra_file.read_bytes() != extra_file_dest.read_bytes():
- print(f"{extra_file_dest} is out of date")
- raise click.ClickException("Extra config file is out of date")
+ if not CERT_STORE_PATH.exists():
+ print(f"{CERT_STORE_PATH} missing")
+ raise click.ClickException("Cert store file is missing")
else:
- tropic_key_stat = TROPIC_KEY.stat()
- tropic_cert_stat = TROPIC_CERT.stat()
- root_cert_stat = ROOT_CERT.stat()
- tropic_config_stat = CFG_SPEC_PATH.stat()
- DEST_PATH.write_text(HEADER + config)
+ base_config_stat = BASE_CONFIG.stat()
+ cfg_spec_stat = CFG_SPEC_PATH.stat()
+ cert_store_stat = CERT_STORE_PATH.stat()
+ device_key_stat = (CERT_CHAIN_DIR / "l3.key").stat()
+ DEST_PATH.write_text(config)
os.utime(
DEST_PATH,
ns=(
max(
- tropic_key_stat.st_atime_ns,
- tropic_cert_stat.st_atime_ns,
- root_cert_stat.st_atime_ns,
- tropic_config_stat.st_atime_ns,
+ base_config_stat.st_atime_ns,
+ cfg_spec_stat.st_atime_ns,
+ cert_store_stat.st_atime_ns,
+ device_key_stat.st_atime_ns,
),
max(
- tropic_key_stat.st_mtime_ns,
- tropic_cert_stat.st_mtime_ns,
- root_cert_stat.st_mtime_ns,
- tropic_config_stat.st_mtime_ns,
+ base_config_stat.st_mtime_ns,
+ cfg_spec_stat.st_mtime_ns,
+ cert_store_stat.st_mtime_ns,
+ device_key_stat.st_mtime_ns,
),
),
)
- for extra_file in EXTRA_FILES:
- extra_file_dest = CONFIG_DIR / extra_file.name
- extra_file_dest.write_bytes(extra_file.read_bytes())
- extra_file_stat = extra_file.stat()
- os.utime(
- extra_file_dest,
- ns=(extra_file_stat.st_atime_ns, extra_file_stat.st_mtime_ns),
- )
-
if __name__ == "__main__":
generate_config()
diff --git a/tests/tropic_model/README.md b/tests/tropic_model/README.md
index f5c20cce..85c10037 100644
--- a/tests/tropic_model/README.md
+++ b/tests/tropic_model/README.md
@@ -1,32 +1,8 @@
This directory contains files needed to launch the "Tropic model" - [ts-tvl](https://github.com/tropicsquare/ts-tvl/) - which is used to simulate the presence of the TROPIC01 chip during tests.
The Tropic model requires:
- * (I) a keypair and a certificate it will use to communicate to the host (`tropic01_ese_*`) - these are simply copied from [example_config](https://github.com/tropicsquare/ts-tvl/tree/master/model_configs/example_config)
- * (II) a certificate chain and a keypair that will be used during Trezor's authenticity check
-
-The root key, certificate chain and keypair are generated using these commands:
-
-```
-# generate root keypair
-openssl genpkey -algorithm Ed25519 -out root_key.pem
-openssl pkey -in root_key.pem -pubout -out root_pubkey.pem
-
-# see the root pubkey - to be used in test
-openssl pkey -in root_pubkey.pem -pubin -outform DER | tail -c 32 | xxd -p -c 256
-
-# generate root certificate (signed by the root key)
-openssl req -new -x509 -key root_key.pem -out root_cert.pem -days 36500
-
-# generate device key pair
-openssl genpkey -algorithm Ed25519 -out tropic_key.pem
-openssl pkey -in tropic_key.pem -pubout -out tropic_pubkey.pem
-
-# generate certificate signing request
-openssl req -new -key tropic_key.pem -out tropic.csr -subj "/CN=T3W1"
-
-# use the signing request to generate a device certificate signed by the authority
-openssl x509 -req -in tropic.csr -CA root_cert.pem -CAkey root_key.pem -CAcreateserial -out tropic_cert.pem -days 36500
-```
+ * (I) a keypair and a certificate it will use to communicate to the host - these are generated by running `tropic_cert_chain/generate_test_chain.py` from within that directory.
+ * (II) a certificate chain and a keypair that will be used during Trezor's authenticity check - these were generated by provisioning a prodtest emulator using a customized HSM that uses `70e57b9267ecfe8bd48ff367e3fa2d27052760c0f7fc7456436875abc31a227b` as the root ed25519 private key, and then copying the Tropic model's saved config.
`ts-tvl` then uses a YAML config file to load the above keys and certificates.
* (I) go into: `s_t_priv`, `s_t_pub` and `x509_certificate` as required by [`ts-tvl`](https://github.com/tropicsquare/ts-tvl/blob/master/model_configs/example_config/example_config.yml)
diff --git a/tests/tropic_model/base_config.yml b/tests/tropic_model/base_config.yml
new file mode 100644
index 00000000..5be218fb
--- /dev/null
+++ b/tests/tropic_model/base_config.yml
@@ -0,0 +1,43 @@
+r_ecc_keys:
+ 0:
+ a: !!binary |
+ NO1FnxTZhbCto5o/wW32Vri5do/X7Y5p7MDuheV3oV4=
+ origin: 1
+ prefix: !!binary |
+ mPLEpBTIRX85mkGjhjMnqmcJXyeNMU/cLgtRRtfVXfs=
+ s: !!binary |
+ gt1Ziv3lkQN0BNo4ArnT8xQBjAbIc4KZVpcsC+DCSwc=
+r_user_data:
+ 3:
+ free: false
+ value: !!binary |
+ A1gwggGPMIIBQaADAgECAghqGYl8vU/fZTAFBgMrZXAwTzELMAkGA1UEBhMCQ1oxHjAcBgNVBAoM
+ FVRyZXpvciBDb21wYW55IHMuci5vLjEgMB4GA1UEAwwXVHJlem9yIE1hbnVmYWN0dXJpbmcgQ0Ew
+ IBcNMjYwNTI5MTI0MTM0WhgPMjA1NjA1MjkxMjQxMzRaMEcxGzAZBgNVBAMMElQzVzEgVHJlem9y
+ IFNhZmUgNzEXMBUGA1UEBRMOMTIzNDU2Nzg5MDEyMzQxDzANBgNVBC4TBlRyb3BpYzAqMAUGAytl
+ cAMhADTtRZ8U2YWwraOaP8Ft9la4uXaP1+2OaezA7oXld6Feo0EwPzAOBgNVHQ8BAf8EBAMCAIAw
+ DAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQlrTb4rxo0D5Q4r67kLb0dWh8GfjAFBgMrZXADQQBY
+ UvSq/qeCetgLo2BVCVtTzNYQZ/h1/ywbr7nUQoVgtu4AmNylPAf0wU3/Nh1kIpmPOChftCxk3o3N
+ EC4FaxkBMIIBwTCCAXOgAwIBAgIIahmJfAChFPswBQYDK2VwMFQxCzAJBgNV
+ 4:
+ free: false
+ value: !!binary |
+ BAYTAkNaMR4wHAYDVQQKDBVUcmV6b3IgQ29tcGFueSBzLnIuby4xJTAjBgNVBAMMHFRyZXpvciBN
+ YW51ZmFjdHVyaW5nIFJvb3QgQ0EwIBcNMjYwNTI5MTI0MTM0WhgPMjA1NjA1MjkxMjQxMzRaME8x
+ CzAJBgNVBAYTAkNaMR4wHAYDVQQKDBVUcmV6b3IgQ29tcGFueSBzLnIuby4xIDAeBgNVBAMMF1Ry
+ ZXpvciBNYW51ZmFjdHVyaW5nIENBMCowBQYDK2VwAyEAIqu/Tw0FdXfZM6insNm/pYTxCaglF0l1
+ qEo7FJVm4eGjZjBkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
+ BBQlrTb4rxo0D5Q4r67kLb0dWh8GfjAfBgNVHSMEGDAWgBTVNlLs4s+6GW64HN3F3UH2GuDYMTAF
+ BgMrZXADQQBwsfMsZ0SWMLi2f/nYVrraInCvvBGPR9oPbweuB1/nVqEDGM4aaa7DVnTW95mfq0PF
+ XHeEL692nN8SdN+goaYNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ 5:
+ free: false
+ value: !!binary |
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
diff --git a/tests/tropic_model/config.yml b/tests/tropic_model/config.yml
index 81c68367..ead9edcf 100644
--- a/tests/tropic_model/config.yml
+++ b/tests/tropic_model/config.yml
@@ -80,27 +80,40 @@ r_config:
r_ecc_keys:
0:
a: !!binary |
- /znnOD2vDW1Znx2ymKbAur+8R+x3vj8uL/e5VUqnH38=
- origin: 2
+ NO1FnxTZhbCto5o/wW32Vri5do/X7Y5p7MDuheV3oV4=
+ origin: 1
prefix: !!binary |
- a2BLVJLG4DGBZBPl5ipLvlLOj8zovqvCgejgJtWKGw8=
+ mPLEpBTIRX85mkGjhjMnqmcJXyeNMU/cLgtRRtfVXfs=
s: !!binary |
- 2JitRIPXXNvDPBcYOyKAWEEGn1k97MfNKx+z4/kNQEk=
+ gt1Ziv3lkQN0BNo4ArnT8xQBjAbIc4KZVpcsC+DCSwc=
r_user_data:
3:
+ free: false
value: !!binary |
- AhwwgeUwgZgCFAYbogFv5WvsoMxMwanH3uF4NejHMAUGAytlcDANMQswCQYDVQQGEwJDWjAgFw0y
- NTEwMDExNTU5MjBaGA8yMTI1MDkwNzE1NTkyMFowHDELMAkGA1UEBhMCQ1oxDTALBgNVBAMMBFQz
- VzEwKjAFBgMrZXADIQD/Oec4Pa8NbVmfHbKYpsC6v7xH7He+Py4v97lVSqcffzAFBgMrZXADQQC/
- Sg/OI9Oa4IcjAGkqswmsZY782uzrHqqOdb8C9QHMQEJFKggXH39rxtXRU2kmj+ryTkYNA4vUhIKm
- +zvKUGkEMIIBMDCB46ADAgECAhRMR5WXXWH8xNquZfZtCCchQO757TAFBgMrZXAwDTELMAkGA1UE
- BhMCQ1owIBcNMjUxMDAxMTUzMzA2WhgPMjEyNTA5MDcxNTMzMDZaMA0xCzAJBgNVBAYTAkNaMCow
- BQYDK2VwAyEAGrHF8S9FcODeXBao2f7qOB9TyNgT/usOsvt/OT8ra1+jUzBRMB0GA1UdDgQWBBSY
- DtrUTbT8JI4eHR/OIHl787VZ1zAfBgNVHSMEGDAWgBSYDtrUTbT8JI4eHR/O
+ A1gwggGPMIIBQaADAgECAghqGYl8vU/fZTAFBgMrZXAwTzELMAkGA1UEBhMCQ1oxHjAcBgNVBAoM
+ FVRyZXpvciBDb21wYW55IHMuci5vLjEgMB4GA1UEAwwXVHJlem9yIE1hbnVmYWN0dXJpbmcgQ0Ew
+ IBcNMjYwNTI5MTI0MTM0WhgPMjA1NjA1MjkxMjQxMzRaMEcxGzAZBgNVBAMMElQzVzEgVHJlem9y
+ IFNhZmUgNzEXMBUGA1UEBRMOMTIzNDU2Nzg5MDEyMzQxDzANBgNVBC4TBlRyb3BpYzAqMAUGAytl
+ cAMhADTtRZ8U2YWwraOaP8Ft9la4uXaP1+2OaezA7oXld6Feo0EwPzAOBgNVHQ8BAf8EBAMCAIAw
+ DAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQlrTb4rxo0D5Q4r67kLb0dWh8GfjAFBgMrZXADQQBY
+ UvSq/qeCetgLo2BVCVtTzNYQZ/h1/ywbr7nUQoVgtu4AmNylPAf0wU3/Nh1kIpmPOChftCxk3o3N
+ EC4FaxkBMIIBwTCCAXOgAwIBAgIIahmJfAChFPswBQYDK2VwMFQxCzAJBgNV
4:
+ free: false
value: !!binary |
- IHl787VZ1zAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAD2wmHseXqtUk2QJuwRUpdoestUlhKGR
- xrD1yhY8fxCvCzU+b4qZffXCyyk4qgDiTgdNHMz04zL6nKcNhT+geAQAAAAAAAAAAAAAAAAAAAAA
+ BAYTAkNaMR4wHAYDVQQKDBVUcmV6b3IgQ29tcGFueSBzLnIuby4xJTAjBgNVBAMMHFRyZXpvciBN
+ YW51ZmFjdHVyaW5nIFJvb3QgQ0EwIBcNMjYwNTI5MTI0MTM0WhgPMjA1NjA1MjkxMjQxMzRaME8x
+ CzAJBgNVBAYTAkNaMR4wHAYDVQQKDBVUcmV6b3IgQ29tcGFueSBzLnIuby4xIDAeBgNVBAMMF1Ry
+ ZXpvciBNYW51ZmFjdHVyaW5nIENBMCowBQYDK2VwAyEAIqu/Tw0FdXfZM6insNm/pYTxCaglF0l1
+ qEo7FJVm4eGjZjBkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
+ BBQlrTb4rxo0D5Q4r67kLb0dWh8GfjAfBgNVHSMEGDAWgBTVNlLs4s+6GW64HN3F3UH2GuDYMTAF
+ BgMrZXADQQBwsfMsZ0SWMLi2f/nYVrraInCvvBGPR9oPbweuB1/nVqEDGM4aaa7DVnTW95mfq0PF
+ XHeEL692nN8SdN+goaYNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ 5:
+ free: false
+ value: !!binary |
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@@ -111,7 +124,51 @@ r_user_data:
value: !!binary |
AAAAAA==
riscv_fw_version: 1.0.0
-s_t_priv: tropic01_ese_private_key_1.pem
-s_t_pub: tropic01_ese_public_key_1.pem
+s_t_priv: !!binary |
+ sEKAf+kv+HXfRScPbVWqKt9814O+VloX1Gbu1UW+42c=
+s_t_pub: !!binary |
+ MekK8VBFEO5O/XkTM0FIFYmiiVzF+7E+1XEcHpuBmHI=
spect_fw_version: 1.0.0
-x509_certificate: tropic01_ese_certificate_1.pem
+x509_certificate: !!binary |
+ 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
+ GwYDVQQKDBRUcm9waWMgU3F1YXJlIHMuci5vLjEmMCQGA1UEAwwdVHJvcGljIFNxdWFyZSBURVNU
+ IFJvb3QgQ0EgdjEwIBcNMjYwNTE4MTQxNjA5WhgPMjA3NjA1MTcxNDE2MDlaMFQxCzAJBgNVBAYT
+ AkNaMR0wGwYDVQQKDBRUcm9waWMgU3F1YXJlIHMuci5vLjEmMCQGA1UEAwwdVHJvcGljIFNxdWFy
+ ZSBURVNUIFJvb3QgQ0EgdjEwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAF2kR6+e8uAVCZbDLzX
+ aQTrYoh6tvi94vkJlbhEWMqAYCfioae9ZEh1wMK5kFCQ7UlO/1wjO3lT4NbfYTUmYFgW+wGkDOA6
+ siTLfpqDZV/Czta7dtYaVGXrV9MlaiUih9qggl35dy/297dTDOU/wwg29Bze46Ft2eHhPKB84A5X
+ JNi/NaNCMEAwHQYDVR0OBBYEFDrSXHRUqqjR0Ql5YApJ5sl+G3FJMA8GA1UdEwEB/wQFMAMBAf8w
+ DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMEA4GLADCBhwJCAJcZyplLgFyFcJQvuns22FEP/0LX
+ uwl3oK0Yr6UyMIEYEEJYS6oPw4qqVz5359+p+ueUulKXcTZ1mcYk45/OgQvFAkEQhKqUl8NhPkeX
+ HItERgqDxhJUTf995gZF/v1TOzJSix62Ykn7pd0p7gXYQVTWVDhLHSxUepPe7NxuD5UUJJtpUQ==
diff --git a/tests/tropic_model/config_old.yml b/tests/tropic_model/config_old.yml
index c9d1a1a1..3e32b5c7 100644
--- a/tests/tropic_model/config_old.yml
+++ b/tests/tropic_model/config_old.yml
@@ -32,6 +32,16 @@ r_user_data:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
riscv_fw_version: !!binary |
AAAAAQ==
-s_t_priv: tropic01_ese_private_key_1.pem
-s_t_pub: tropic01_ese_public_key_1.pem
-x509_certificate: tropic01_ese_certificate_1.pem
+s_t_priv: !!binary |
+ sEKAf+kv+HXfRScPbVWqKt9814O+VloX1Gbu1UW+42c=
+s_t_pub: !!binary |
+ MekK8VBFEO5O/XkTM0FIFYmiiVzF+7E+1XEcHpuBmHI=
+x509_certificate: !!binary |
+ MIIBkDCCARegAwIBAgIBATAKBggqhkjOPQQDAzBZMQswCQYDVQQGEwJDWjEPMA0GA1UEBwwGUHJh
+ Z3VlMRYwFAYDVQQKDA1Ucm9waWMgU3F1YXJlMSEwHwYDVQQDDBhUcm9waWMgU3F1YXJlIFJvb3Qg
+ Q0EgdjEwHhcNMjQwNjA0MDc0MDMxWhcNMjUwNjA0MDc0MDMxWjAXMRUwEwYDVQQDDAxUUk9QSUMw
+ MSBlU0UwKjAFBgMrZW4DIQAx6QrxUEUQ7k79eRMzQUgViaKJXMX7sT7VcRwem4GYcqNBMD8wDAYD
+ VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCAwgwHwYDVR0jBBgwFoAUipzvY3hE2wO8KSaA0eZVB9Xe
+ j0cwCgYIKoZIzj0EAwMDZwAwZAIwDLRviNFPbY+5UWmuEBY2/3aSuTQf9iKXUZmrDh9o3mZS13ju
+ BhHV58yAg0vbqzD1AjBRNE490wx/su6TSuGMj9ZX37WugegiBI/r3TQoeL/T/JgO+JReqwIJopvp
+ b2Trhg4=
diff --git a/tests/tropic_model/root_cert.pem b/tests/tropic_model/root_cert.pem
deleted file mode 100644
index fe460ee4..00000000
--- a/tests/tropic_model/root_cert.pem
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBMDCB46ADAgECAhRMR5WXXWH8xNquZfZtCCchQO757TAFBgMrZXAwDTELMAkG
-A1UEBhMCQ1owIBcNMjUxMDAxMTUzMzA2WhgPMjEyNTA5MDcxNTMzMDZaMA0xCzAJ
-BgNVBAYTAkNaMCowBQYDK2VwAyEAGrHF8S9FcODeXBao2f7qOB9TyNgT/usOsvt/
-OT8ra1+jUzBRMB0GA1UdDgQWBBSYDtrUTbT8JI4eHR/OIHl787VZ1zAfBgNVHSME
-GDAWgBSYDtrUTbT8JI4eHR/OIHl787VZ1zAPBgNVHRMBAf8EBTADAQH/MAUGAytl
-cANBAD2wmHseXqtUk2QJuwRUpdoestUlhKGRxrD1yhY8fxCvCzU+b4qZffXCyyk4
-qgDiTgdNHMz04zL6nKcNhT+geAQ=
------END CERTIFICATE-----
diff --git a/tests/tropic_model/root_key.pem b/tests/tropic_model/root_key.pem
deleted file mode 100644
index 0274cea9..00000000
--- a/tests/tropic_model/root_key.pem
+++ /dev/null
@@ -1,3 +0,0 @@
------BEGIN PRIVATE KEY-----
-MC4CAQAwBQYDK2VwBCIEIFia80j5qUKXL7JjYDHMKeubqMyC5aljqbu4fhO1FDJV
------END PRIVATE KEY-----
diff --git a/tests/tropic_model/tropic01_ese_certificate_1.pem b/tests/tropic_model/tropic01_ese_certificate_1.pem
deleted file mode 100644
index 9d2f4bba..00000000
--- a/tests/tropic_model/tropic01_ese_certificate_1.pem
+++ /dev/null
@@ -1,11 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBkDCCARegAwIBAgIBATAKBggqhkjOPQQDAzBZMQswCQYDVQQGEwJDWjEPMA0G
-A1UEBwwGUHJhZ3VlMRYwFAYDVQQKDA1Ucm9waWMgU3F1YXJlMSEwHwYDVQQDDBhU
-cm9waWMgU3F1YXJlIFJvb3QgQ0EgdjEwHhcNMjQwNjA0MDc0MDMxWhcNMjUwNjA0
-MDc0MDMxWjAXMRUwEwYDVQQDDAxUUk9QSUMwMSBlU0UwKjAFBgMrZW4DIQAx6Qrx
-UEUQ7k79eRMzQUgViaKJXMX7sT7VcRwem4GYcqNBMD8wDAYDVR0TAQH/BAIwADAO
-BgNVHQ8BAf8EBAMCAwgwHwYDVR0jBBgwFoAUipzvY3hE2wO8KSaA0eZVB9Xej0cw
-CgYIKoZIzj0EAwMDZwAwZAIwDLRviNFPbY+5UWmuEBY2/3aSuTQf9iKXUZmrDh9o
-3mZS13juBhHV58yAg0vbqzD1AjBRNE490wx/su6TSuGMj9ZX37WugegiBI/r3TQo
-eL/T/JgO+JReqwIJopvpb2Trhg4=
------END CERTIFICATE-----
diff --git a/tests/tropic_model/tropic01_ese_private_key_1.pem b/tests/tropic_model/tropic01_ese_private_key_1.pem
deleted file mode 100644
index 2b0b1e72..00000000
--- a/tests/tropic_model/tropic01_ese_private_key_1.pem
+++ /dev/null
@@ -1,3 +0,0 @@
------BEGIN PRIVATE KEY-----
-MC4CAQAwBQYDK2VuBCIEILBCgH/pL/h130UnD21VqirffNeDvlZaF9Rm7tVFvuNn
------END PRIVATE KEY-----
diff --git a/tests/tropic_model/tropic01_ese_public_key_1.pem b/tests/tropic_model/tropic01_ese_public_key_1.pem
deleted file mode 100644
index 4b371872..00000000
--- a/tests/tropic_model/tropic01_ese_public_key_1.pem
+++ /dev/null
@@ -1,3 +0,0 @@
------BEGIN PUBLIC KEY-----
-MCowBQYDK2VuAyEAMekK8VBFEO5O/XkTM0FIFYmiiVzF+7E+1XEcHpuBmHI=
------END PUBLIC KEY-----
diff --git a/tests/tropic_model/tropic_cert.pem b/tests/tropic_model/tropic_cert.pem
deleted file mode 100644
index 9867509d..00000000
--- a/tests/tropic_model/tropic_cert.pem
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN CERTIFICATE-----
-MIHlMIGYAhQGG6IBb+Vr7KDMTMGpx97heDXoxzAFBgMrZXAwDTELMAkGA1UEBhMC
-Q1owIBcNMjUxMDAxMTU1OTIwWhgPMjEyNTA5MDcxNTU5MjBaMBwxCzAJBgNVBAYT
-AkNaMQ0wCwYDVQQDDARUM1cxMCowBQYDK2VwAyEA/znnOD2vDW1Znx2ymKbAur+8
-R+x3vj8uL/e5VUqnH38wBQYDK2VwA0EAv0oPziPTmuCHIwBpKrMJrGWO/Nrs6x6q
-jnW/AvUBzEBCRSoIFx9/a8bV0VNpJo/q8k5GDQOL1ISCpvs7ylBpBA==
------END CERTIFICATE-----
diff --git a/tests/tropic_model/tropic_cert_chain/cert_store.der b/tests/tropic_model/tropic_cert_chain/cert_store.der
new file mode 100644
index 00000000..c45b365e
Binary files /dev/null and b/tests/tropic_model/tropic_cert_chain/cert_store.der differ
diff --git a/tests/tropic_model/tropic_cert_chain/generate_test_chain.py b/tests/tropic_model/tropic_cert_chain/generate_test_chain.py
new file mode 100755
index 00000000..0e3bbc64
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/generate_test_chain.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python3
+
+import datetime
+from pathlib import Path
+
+from cryptography import x509
+from cryptography.hazmat.primitives import hashes, serialization
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.primitives.asymmetric.x25519 import (
+ X25519PrivateKey,
+ X25519PublicKey,
+)
+from cryptography.x509.oid import NameOID
+
+HERE = Path(__file__).parent
+CERT_STORE_PATH = HERE / "cert_store.der"
+CERT_STORE_VERSION = b"\x01"
+
+
+def issue_cert(
+ subject: x509.Name,
+ public_key: ec.EllipticCurvePublicKey | X25519PublicKey,
+ issuer_cert: x509.Certificate | None,
+ issuer_key: ec.EllipticCurvePrivateKey,
+ hash_algorithm: hashes.SHA384 | hashes.SHA512,
+ serial: int,
+ days: int,
+ extensions: list[tuple[x509.ExtensionType, bool]],
+) -> x509.Certificate:
+ now = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
+ builder = (
+ x509.CertificateBuilder()
+ .subject_name(subject)
+ .issuer_name(issuer_cert.subject if issuer_cert else subject)
+ .public_key(public_key)
+ .serial_number(serial)
+ .not_valid_before(now)
+ .not_valid_after(now + datetime.timedelta(days=days))
+ )
+ for ext, critical in extensions:
+ builder = builder.add_extension(ext, critical=critical)
+ return builder.sign(issuer_key, hash_algorithm)
+
+
+def write_key(
+ key: ec.EllipticCurvePrivateKey | X25519PrivateKey, filename: str
+) -> None:
+ (HERE / filename).write_bytes(
+ key.private_bytes(
+ serialization.Encoding.PEM,
+ serialization.PrivateFormat.PKCS8,
+ serialization.NoEncryption(),
+ )
+ )
+
+
+def write_cert(cert: x509.Certificate, filename: str) -> None:
+ (HERE / filename).write_bytes(cert.public_bytes(serialization.Encoding.PEM))
+
+
+def build_cert_store(certs: list[bytes]) -> bytes:
+ header = CERT_STORE_VERSION + len(certs).to_bytes(1, "big")
+ body = b""
+ for der in certs:
+ header += len(der).to_bytes(2, "big")
+ body += der
+ return header + body
+
+
+l0_key = ec.generate_private_key(ec.SECP521R1())
+l1_key = ec.generate_private_key(ec.SECP384R1())
+l2_key = ec.generate_private_key(ec.SECP384R1())
+# This corresponds to `SECRET_TROPIC_PUBKEY_BYTES` from `core/embed/sec/secret_keys/unix/secret_keys.c`
+l3_key = X25519PrivateKey.from_private_bytes(
+ bytes.fromhex("b042807fe92ff875df45270f6d55aa2adf7cd783be565a17d466eed545bee367")
+)
+
+write_key(l0_key, "l0.key")
+write_key(l1_key, "l1.key")
+write_key(l2_key, "l2.key")
+write_key(l3_key, "l3.key")
+
+l0_cert = issue_cert(
+ subject=x509.Name(
+ [
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "CZ"),
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Tropic Square s.r.o."),
+ x509.NameAttribute(NameOID.COMMON_NAME, "Tropic Square TEST Root CA v1"),
+ ]
+ ),
+ public_key=l0_key.public_key(),
+ issuer_cert=None,
+ issuer_key=l0_key,
+ hash_algorithm=hashes.SHA512(),
+ serial=101,
+ days=18262,
+ extensions=[
+ (x509.SubjectKeyIdentifier.from_public_key(l0_key.public_key()), False),
+ (x509.BasicConstraints(ca=True, path_length=None), True),
+ (
+ x509.KeyUsage(
+ key_cert_sign=True,
+ crl_sign=True,
+ digital_signature=False,
+ content_commitment=False,
+ key_encipherment=False,
+ data_encipherment=False,
+ key_agreement=False,
+ encipher_only=False,
+ decipher_only=False,
+ ),
+ True,
+ ),
+ ],
+)
+
+l1_cert = issue_cert(
+ subject=x509.Name(
+ [
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "CZ"),
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Tropic Square s.r.o."),
+ x509.NameAttribute(NameOID.COMMON_NAME, "TROPIC01 TEST CA v1"),
+ ]
+ ),
+ public_key=l1_key.public_key(),
+ issuer_cert=l0_cert,
+ issuer_key=l0_key,
+ hash_algorithm=hashes.SHA512(),
+ serial=1001,
+ days=14610,
+ extensions=[
+ (x509.SubjectKeyIdentifier.from_public_key(l1_key.public_key()), False),
+ (x509.BasicConstraints(ca=True, path_length=1), True),
+ (
+ x509.KeyUsage(
+ key_cert_sign=True,
+ crl_sign=True,
+ digital_signature=False,
+ content_commitment=False,
+ key_encipherment=False,
+ data_encipherment=False,
+ key_agreement=False,
+ encipher_only=False,
+ decipher_only=False,
+ ),
+ True,
+ ),
+ (
+ x509.AuthorityKeyIdentifier.from_issuer_public_key(l0_key.public_key()),
+ False,
+ ),
+ (
+ x509.CRLDistributionPoints(
+ [
+ x509.DistributionPoint(
+ full_name=[
+ x509.UniformResourceIdentifier(
+ "http://pki.tropicsquare.com/l1/tsrv1.crl"
+ )
+ ],
+ relative_name=None,
+ reasons=None,
+ crl_issuer=None,
+ )
+ ]
+ ),
+ False,
+ ),
+ ],
+)
+
+l2_cert = issue_cert(
+ subject=x509.Name(
+ [
+ x509.NameAttribute(NameOID.COUNTRY_NAME, "CZ"),
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Tropic Square s.r.o."),
+ x509.NameAttribute(NameOID.COMMON_NAME, "TROPIC01-X TEST CA v1"),
+ ]
+ ),
+ public_key=l2_key.public_key(),
+ issuer_cert=l1_cert,
+ issuer_key=l1_key,
+ hash_algorithm=hashes.SHA384(),
+ serial=10001,
+ days=12784,
+ extensions=[
+ (x509.SubjectKeyIdentifier.from_public_key(l2_key.public_key()), False),
+ (x509.BasicConstraints(ca=True, path_length=0), True),
+ (
+ x509.KeyUsage(
+ key_cert_sign=True,
+ crl_sign=True,
+ digital_signature=False,
+ content_commitment=False,
+ key_encipherment=False,
+ data_encipherment=False,
+ key_agreement=False,
+ encipher_only=False,
+ decipher_only=False,
+ ),
+ True,
+ ),
+ (
+ x509.AuthorityKeyIdentifier.from_issuer_public_key(l1_key.public_key()),
+ False,
+ ),
+ (
+ x509.CRLDistributionPoints(
+ [
+ x509.DistributionPoint(
+ full_name=[
+ x509.UniformResourceIdentifier(
+ "http://pki.tropicsquare.com/l2/t01v1.crl"
+ )
+ ],
+ relative_name=None,
+ reasons=None,
+ crl_issuer=None,
+ )
+ ]
+ ),
+ False,
+ ),
+ ],
+)
+
+l3_cert = issue_cert(
+ subject=x509.Name(
+ [
+ x509.NameAttribute(NameOID.COMMON_NAME, '"TROPIC01 eSE TEST CA v1"'),
+ ]
+ ),
+ public_key=l3_key.public_key(),
+ issuer_cert=l2_cert,
+ issuer_key=l2_key,
+ hash_algorithm=hashes.SHA384(),
+ serial=0x02F0000508341904090C0700000305A5,
+ days=7305,
+ extensions=[
+ (x509.BasicConstraints(ca=False, path_length=None), True),
+ (
+ x509.KeyUsage(
+ key_agreement=True,
+ digital_signature=False,
+ content_commitment=False,
+ key_encipherment=False,
+ data_encipherment=False,
+ key_cert_sign=False,
+ crl_sign=False,
+ encipher_only=False,
+ decipher_only=False,
+ ),
+ True,
+ ),
+ (
+ x509.AuthorityKeyIdentifier.from_issuer_public_key(l2_key.public_key()),
+ False,
+ ),
+ (
+ x509.CRLDistributionPoints(
+ [
+ x509.DistributionPoint(
+ full_name=[
+ x509.UniformResourceIdentifier(
+ "http://pki.tropicsquare.com/l3/t01-Tv1.crl"
+ )
+ ],
+ relative_name=None,
+ reasons=None,
+ crl_issuer=None,
+ )
+ ]
+ ),
+ True,
+ ),
+ ],
+)
+
+write_cert(l0_cert, "l0.pem")
+write_cert(l1_cert, "l1.pem")
+write_cert(l2_cert, "l2.pem")
+write_cert(l3_cert, "l3.pem")
+
+CERT_STORE_PATH.write_bytes(
+ build_cert_store(
+ [
+ l3_cert.public_bytes(serialization.Encoding.DER),
+ l2_cert.public_bytes(serialization.Encoding.DER),
+ l1_cert.public_bytes(serialization.Encoding.DER),
+ l0_cert.public_bytes(serialization.Encoding.DER),
+ ]
+ )
+)
diff --git a/tests/tropic_model/tropic_cert_chain/l0.key b/tests/tropic_model/tropic_cert_chain/l0.key
new file mode 100644
index 00000000..e4be0c38
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l0.key
@@ -0,0 +1,8 @@
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAUJ/XZXBoiqlsgPBf
+V6ppK9JqHGJij8jTD2cCUhSndZfg0XrmPzcN0s5THjA0Z5GumHPVijIWMJZrukc5
+K3DBwxqhgYkDgYYABAF2kR6+e8uAVCZbDLzXaQTrYoh6tvi94vkJlbhEWMqAYCfi
+oae9ZEh1wMK5kFCQ7UlO/1wjO3lT4NbfYTUmYFgW+wGkDOA6siTLfpqDZV/Czta7
+dtYaVGXrV9MlaiUih9qggl35dy/297dTDOU/wwg29Bze46Ft2eHhPKB84A5XJNi/
+NQ==
+-----END PRIVATE KEY-----
diff --git a/tests/tropic_model/tropic_cert_chain/l0.pem b/tests/tropic_model/tropic_cert_chain/l0.pem
new file mode 100644
index 00000000..d67d4f6b
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l0.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICYjCCAcSgAwIBAgIBZTAKBggqhkjOPQQDBDBUMQswCQYDVQQGEwJDWjEdMBsG
+A1UECgwUVHJvcGljIFNxdWFyZSBzLnIuby4xJjAkBgNVBAMMHVRyb3BpYyBTcXVh
+cmUgVEVTVCBSb290IENBIHYxMCAXDTI2MDUxODE0MTYwOVoYDzIwNzYwNTE3MTQx
+NjA5WjBUMQswCQYDVQQGEwJDWjEdMBsGA1UECgwUVHJvcGljIFNxdWFyZSBzLnIu
+by4xJjAkBgNVBAMMHVRyb3BpYyBTcXVhcmUgVEVTVCBSb290IENBIHYxMIGbMBAG
+ByqGSM49AgEGBSuBBAAjA4GGAAQBdpEevnvLgFQmWwy812kE62KIerb4veL5CZW4
+RFjKgGAn4qGnvWRIdcDCuZBQkO1JTv9cIzt5U+DW32E1JmBYFvsBpAzgOrIky36a
+g2Vfws7Wu3bWGlRl61fTJWolIofaoIJd+Xcv9ve3UwzlP8MINvQc3uOhbdnh4Tyg
+fOAOVyTYvzWjQjBAMB0GA1UdDgQWBBQ60lx0VKqo0dEJeWAKSebJfhtxSTAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDBAOBiwAwgYcC
+QgCXGcqZS4BchXCUL7p7NthRD/9C17sJd6CtGK+lMjCBGBBCWEuqD8OKqlc+d+ff
+qfrnlLpSl3E2dZnGJOOfzoELxQJBEISqlJfDYT5HlxyLREYKg8YSVE3/feYGRf79
+UzsyUosetmJJ+6XdKe4F2EFU1lQ4Sx0sVHqT3uzcbg+VFCSbaVE=
+-----END CERTIFICATE-----
diff --git a/tests/tropic_model/tropic_cert_chain/l1.key b/tests/tropic_model/tropic_cert_chain/l1.key
new file mode 100644
index 00000000..d5a90f31
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l1.key
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDATFFJvVvSE1q60Sndq
+aJlN48vFKu/uv/UahZmIvo81745DW9GyNw1V005RHhJVeQqhZANiAARRb9dbM9dt
+UDnbziO2HuoahFOlC1+cg855sSdUaFuzOOcKePcgYpl0Mq0LiqIrYUFVQx1xzqBi
+G+Zqxykavqjiu/UFzAVol3ZNF8ws4PIVp4lc5oyjOMswbDUExMenV+0=
+-----END PRIVATE KEY-----
diff --git a/tests/tropic_model/tropic_cert_chain/l1.pem b/tests/tropic_model/tropic_cert_chain/l1.pem
new file mode 100644
index 00000000..294e680b
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIClDCCAfagAwIBAgICA+kwCgYIKoZIzj0EAwQwVDELMAkGA1UEBhMCQ1oxHTAb
+BgNVBAoMFFRyb3BpYyBTcXVhcmUgcy5yLm8uMSYwJAYDVQQDDB1Ucm9waWMgU3F1
+YXJlIFRFU1QgUm9vdCBDQSB2MTAgFw0yNjA1MTgxNDE2MDlaGA8yMDY2MDUxODE0
+MTYwOVowSjELMAkGA1UEBhMCQ1oxHTAbBgNVBAoMFFRyb3BpYyBTcXVhcmUgcy5y
+Lm8uMRwwGgYDVQQDDBNUUk9QSUMwMSBURVNUIENBIHYxMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAEUW/XWzPXbVA5284jth7qGoRTpQtfnIPOebEnVGhbszjnCnj3IGKZ
+dDKtC4qiK2FBVUMdcc6gYhvmascpGr6o4rv1BcwFaJd2TRfMLODyFaeJXOaMozjL
+MGw1BMTHp1fto4GiMIGfMB0GA1UdDgQWBBSjRiAE8oSBPa9wItFsH1jCEN9QejAS
+BgNVHRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQ6
+0lx0VKqo0dEJeWAKSebJfhtxSTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vcGtp
+LnRyb3BpY3NxdWFyZS5jb20vbDEvdHNydjEuY3JsMAoGCCqGSM49BAMEA4GLADCB
+hwJCAUnK+o1VjmXlDZ7jCKXKRSckk1SJ24/g3DHfYJZKiEuZK+ZbVwmzIIUb/SVp
+0cTlBxbGx75kaTxxWsj1KdU1q3bHAkEhE9zumGLOgiAdTmwjqkU+4asd6SP9lsXV
+VCAZqR4FO6ZZLNIQoKQJ3q5VDqwEeac670rYkQUQPXUc7PEyPqqYQg==
+-----END CERTIFICATE-----
diff --git a/tests/tropic_model/tropic_cert_chain/l2.key b/tests/tropic_model/tropic_cert_chain/l2.key
new file mode 100644
index 00000000..a7bc830e
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l2.key
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCSi1VqziO+cikHFCfs
+KK2C3oNQitrmC/F84zLvp2xsilMkA2bbKTqkdsUTrauh12ShZANiAAQGN/ELdeRd
+yVvu+uKr8guUYEs0VH82zQyFaWwMyRcvVJkeZMNt7VCEExnry0A5itifyfQf+Oi1
+QJ05UMELHa16VJdzQr/ovQYl7MUQkcgyWOjbPDgmfWtVEmpRLq0iAXo=
+-----END PRIVATE KEY-----
diff --git a/tests/tropic_model/tropic_cert_chain/l2.pem b/tests/tropic_model/tropic_cert_chain/l2.pem
new file mode 100644
index 00000000..356e1cce
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l2.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICZzCCAe6gAwIBAgICJxEwCgYIKoZIzj0EAwMwSjELMAkGA1UEBhMCQ1oxHTAb
+BgNVBAoMFFRyb3BpYyBTcXVhcmUgcy5yLm8uMRwwGgYDVQQDDBNUUk9QSUMwMSBU
+RVNUIENBIHYxMCAXDTI2MDUxODE0MTYwOVoYDzIwNjEwNTE4MTQxNjA5WjBMMQsw
+CQYDVQQGEwJDWjEdMBsGA1UECgwUVHJvcGljIFNxdWFyZSBzLnIuby4xHjAcBgNV
+BAMMFVRST1BJQzAxLVggVEVTVCBDQSB2MTB2MBAGByqGSM49AgEGBSuBBAAiA2IA
+BAY38Qt15F3JW+764qvyC5RgSzRUfzbNDIVpbAzJFy9UmR5kw23tUIQTGevLQDmK
+2J/J9B/46LVAnTlQwQsdrXpUl3NCv+i9BiXsxRCRyDJY6Ns8OCZ9a1USalEurSIB
+eqOBojCBnzAdBgNVHQ4EFgQUGQ6JRLAIR+LopUQRkZD1H33+z2cwEgYDVR0TAQH/
+BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUo0YgBPKEgT2v
+cCLRbB9YwhDfUHowOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL3BraS50cm9waWNz
+cXVhcmUuY29tL2wyL3QwMXYxLmNybDAKBggqhkjOPQQDAwNnADBkAjAJxfRR923A
+TeXG6DKOP0E/QiBXMT5jAirMDfj8CjHk8aOq9GAdqLwYyVCuYcb2XzQCMDeGx85y
+bI34C3DcEIbmAXm6rgM6iJV3GlQTp41XicHD+qoaUreDKMfF7YZjkpXWqg==
+-----END CERTIFICATE-----
diff --git a/tests/tropic_model/tropic_cert_chain/l3.key b/tests/tropic_model/tropic_cert_chain/l3.key
new file mode 100644
index 00000000..2b0b1e72
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l3.key
@@ -0,0 +1,3 @@
+-----BEGIN PRIVATE KEY-----
+MC4CAQAwBQYDK2VuBCIEILBCgH/pL/h130UnD21VqirffNeDvlZaF9Rm7tVFvuNn
+-----END PRIVATE KEY-----
diff --git a/tests/tropic_model/tropic_cert_chain/l3.pem b/tests/tropic_model/tropic_cert_chain/l3.pem
new file mode 100644
index 00000000..6a546b7d
--- /dev/null
+++ b/tests/tropic_model/tropic_cert_chain/l3.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAWegAwIBAgIQAvAABQg0GQQJDAcAAAMFpTAKBggqhkjOPQQDAzBMMQsw
+CQYDVQQGEwJDWjEdMBsGA1UECgwUVHJvcGljIFNxdWFyZSBzLnIuby4xHjAcBgNV
+BAMMFVRST1BJQzAxLVggVEVTVCBDQSB2MTAeFw0yNjA1MTgxNDE2MDlaFw00NjA1
+MTgxNDE2MDlaMCQxIjAgBgNVBAMMGSJUUk9QSUMwMSBlU0UgVEVTVCBDQSB2MSIw
+KjAFBgMrZW4DIQAx6QrxUEUQ7k79eRMzQUgViaKJXMX7sT7VcRwem4GYcqOBgTB/
+MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgMIMB8GA1UdIwQYMBaAFBkOiUSw
+CEfi6KVEEZGQ9R99/s9nMD4GA1UdHwEB/wQ0MDIwMKAuoCyGKmh0dHA6Ly9wa2ku
+dHJvcGljc3F1YXJlLmNvbS9sMy90MDEtVHYxLmNybDAKBggqhkjOPQQDAwNoADBl
+AjEAp0tLcUjGyZnHCjZiZ00rrHG+BpCEK7CJmCSvN4wRQdPdqwBvCC/cG2UBX2Sh
+JpeAAjB1Xa6VE+xvYKfNm31wskc03xRimotrMvD8278v7KIaZPe6epmg3YB8F+p9
+Hk21/RM=
+-----END CERTIFICATE-----
diff --git a/tests/tropic_model/tropic_key.pem b/tests/tropic_model/tropic_key.pem
deleted file mode 100644
index 49e6a8f7..00000000
--- a/tests/tropic_model/tropic_key.pem
+++ /dev/null
@@ -1,3 +0,0 @@
------BEGIN PRIVATE KEY-----
-MC4CAQAwBQYDK2VwBCIEIKhBm/4pWnrgnqyx/uqbGD7iSaPoWIGGwQmjLz3baBrr
------END PRIVATE KEY-----
diff --git a/tests/upgrade_tests/test_tropic_config_set.py b/tests/upgrade_tests/test_tropic_config_set.py
index 3bb6f180..ee144800 100644
--- a/tests/upgrade_tests/test_tropic_config_set.py
+++ b/tests/upgrade_tests/test_tropic_config_set.py
@@ -38,7 +38,6 @@ from . import model_only
TROPIC_CONFIGS_JSON = (
ROOT / "core" / "embed" / "sec" / "tropic" / "config" / "tropic_configs.json"
)
-TROPIC_MODEL_DIR = TROPIC_MODEL_CONFIGFILE.parent
TROPIC_CONFIG_DISTRIBUTION_VERSION_SLOT = 6
TROPIC_CONFIG_BACKUP_DISTRIBUTION_VERSION_SLOT = 7
CHIP_ID_BATCH_ID_OFFSET = 96
@@ -299,9 +298,6 @@ def _build_tropic_model_config(scenario: TropicBootScenario) -> dict:
_set_slot(
config, TROPIC_CONFIG_BACKUP_DISTRIBUTION_VERSION_SLOT, scenario.backup_slot
)
- config["s_t_priv"] = str(TROPIC_MODEL_DIR / config["s_t_priv"])
- config["s_t_pub"] = str(TROPIC_MODEL_DIR / config["s_t_pub"])
- config["x509_certificate"] = str(TROPIC_MODEL_DIR / config["x509_certificate"])
return config
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.