Skip to content

Commit ad989b9

Browse files
committed
feat(core/prodtest): implement tropic prodtest properly
1 parent fb8b400 commit ad989b9

File tree

13 files changed

+1647
-120
lines changed

13 files changed

+1647
-120
lines changed

core/embed/projects/prodtest/README.md

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,135 @@ tropic-get-chip-id
947947
OK 00000001000000000000000000000000000000000000000000000000000000000000000001000000054400000000FFFFFFFFFFFF01F00F000544545354303103001300000B54524F50494330312D4553FFFFFFFF000100000000FFFF000100000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13000300
948948
```
949949

950+
### tropic-certtropic-read
951+
952+
Reads the X.509 certificate issued by Tropic Square for the Tropic chip.
953+
954+
Example:
955+
```
956+
tropic-certtropic-read
957+
OK 308201CB30820151A00302010202100200110308861906100F32000000045B300A06082A8648CE3D0403033047310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3119301706035504030C1054524F50494330312D54204341207631301E170D3235303730313130353533325A170D3435303730313130353533325A30173115301306035504030C0C54524F504943303120655345302A300506032B656E032100F582E78C4ECCB186D72A29B6B54E8CAD931C765DBA0C3EDE9405602CB1065246A37E307C300C0603551D130101FF04023000300E0603551D0F0101FF040403020308301F0603551D2304183016801433C711060CE80513B5677B019650644E3B43FAE7303B0603551D1F043430323030A02EA02C862A687474703A2F2F706B692E74726F7069637371756172652E636F6D2F6C332F7430312D5476312E63726C300A06082A8648CE3D0403030368003065023100C46E44F9D1FE26A4DC8AC659D1B6A9A82CEEBE9D283726633053FE410FF665073B7FB6ECE235FD8AB7F87336DDBCF96202300F919622C0A1CF6D00CF43CE4229AC44548055030566E8E03CA98B15D6B29B04DF231B9BF7006A9E28C15E88B07141893082025E308201E4A00302010202027531300A06082A8648CE3D0403033045310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3117301506035504030C0E54524F50494330312043412076313020170D3235303333313132303833305A180F32303630303333313132303833305A3047310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3119301706035504030C1054524F50494330312D542043412076313076301006072A8648CE3D020106052B8104002203620004A70C3273AE3227DC767EF0293D95CC106691E5BC9AA6C0282BAA8FD4B37CFAC30FEE0D879C32D8D9CE9B0BD7924B5C10097B8C4A5E7ED68D690185E3D128161256C01033C0293DE39A7188A72CFF9EEAF5B3B5DEE898F954C4F226C2ADE70BC6A381A230819F301D0603551D0E0416041433C711060CE80513B5677B019650644E3B43FAE730120603551D130101FF040830060101FF020100300E0603551D0F0101FF040403020106301F0603551D2304183016801443BAB7BDA7CDE728945CF142CBD2F9CD5588A93F30390603551D1F04323030302EA02CA02A8628687474703A2F2F706B692E74726F7069637371756172652E636F6D2F6C322F74303176312E63726C300A06082A8648CE3D0403030368003065023014AEC525E5E8311B5D6312CF0EBB2286700552EEBA32D641672C20F02A612B77E9FC3709C9657CEC6D82D6CDBDDE57C4023100BB9B77CCBBD9DE11086481D4BA9772C38743591E722B9E4D08A89940D879DA2447A55C15F84175C479946326E0F482AF3082028B308201ECA00302010202020BB9300A06082A8648CE3D040304304F310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3121301F06035504030C1854726F7069632053717561726520526F6F742043412076313020170D3235303333313132303832395A180F32303635303333313132303832395A3045310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3117301506035504030C0E54524F50494330312043412076313076301006072A8648CE3D020106052B81040022036200042301BE5B6ED9A858153F57C6BEBC9F37B858BC2874DDC90C1041BE6D04E7BBF24A7968F2E51173D0ACAC892E65E4FC03EA5BC4381A60154D7CD7CC6DF94591650F5FDC008919157314FC1F8D8295F1A10571DD1573E868BFECA96C92CCBB816FA381A230819F301D0603551D0E0416041443BAB7BDA7CDE728945CF142CBD2F9CD5588A93F30120603551D130101FF040830060101FF020101300E0603551D0F0101FF040403020106301F0603551D230418301680143C18AF711A6699B37914E363963FE25CF304B3BF30390603551D1F04323030302EA02CA02A8628687474703A2F2F706B692E74726F7069637371756172652E636F6D2F6C312F74737276312E63726C300A06082A8648CE3D04030403818C00308188024200BCD02D464329F3FC7DC81723B0C26437E35C2B49782BAE97432789F508B5A220240E6E3E4D12C15C3BDB15A8D3F90CDD19071E2227C4898220B2BEF584B2C20F8F024201EB854F05F9A2C5B466D798FE627C539B98703531735F7AB49546FE5CFB9DF0BF3B6985D700EFBC36DF3FF01692F0ECE98BB8DB2FBB9BF40913EA87EA121A7AD2E730820258308201BBA0030201020202012D300A06082A8648CE3D040304304F310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3121301F06035504030C1854726F7069632053717561726520526F6F742043412076313020170D3235303333313132303832355A180F32303735303333313132303832355A304F310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3121301F06035504030C1854726F7069632053717561726520526F6F7420434120763130819B301006072A8648CE3D020106052B8104002303818600040187CCEA62837E23092D8A7135789FCC6FBC3D35E79FC01F4F498FC5C2C409CE772F901340090403E8BA4D97E13F1E7594AC6D2F51FD2239F8D457769F378440A18000712BF16A48EA2025837BEFD0502A562FD93941D52CC40ED9553CA79B145BA585F32492BFD792EB96D949D31676CD099F19CE8848697B8C3430AF016FED985E1EB4A3423040301D0603551D0E041604143C18AF711A6699B37914E363963FE25CF304B3BF300F0603551D130101FF040530030101FF300E0603551D0F0101FF040403020106300A06082A8648CE3D04030403818A0030818602416841837339337C182A4EE896CBFD5DA5925F0026E7A6FA3DEE61F49A46B5D9856858D3D86501BE64B0F2F33B05D856DE96F57B947F49E720E875090B30C337791802412FDDB68D166510451FE4C62DBAE0CCD952DC34E03AE6617818CCD0EA28A9DFF045AA13A248A5F066B51139C9BEF471DD004DAC4F78DB56CF7B3E8D6F8F87D048D2
958+
```
959+
960+
### tropic-pair
961+
962+
Pairs the MCU with the Tropic chip. This command is idempotent, meaning it can be called multiple times without changing the state of the device. This command is irreversible and cannot be undone. The command `secrets-init` must be executed before calling this command.
963+
964+
Example:
965+
```
966+
tropic-pair
967+
OK
968+
```
969+
970+
### tropic-get-access-credential
971+
972+
Returns a cryptogram that encrypts and authenticates the Tropic pairing private key and authenticates the Tropic public key. The commands `secrets-init` and `secure-channel-handshake-2` must be executed before calling this command.
973+
974+
Example:
975+
```
976+
tropic-get-access-credential
977+
OK 03ca0e9d74ef59fa80a06161f3d2fceeb3e0c5e2db8182526d337aac78bad2d2ce4cacf05cdcd879843bcc43ed330199
978+
```
979+
980+
### tropic-get-fido-masking-key
981+
982+
Returns a cryptogram that encrypts and authenticates the FIDO masking key for the Tropic chip. The commands `secrets-init` and `secure-channel-handshake-2` must be executed before calling this command.
983+
984+
Example:
985+
```
986+
tropic-get-fido-masking-key
987+
OK dc106118a32feeef8d9211f54b9c8e9d571abe4cb104dc4ab087531cfee4574283ccf9c6f45e68be712f630d72d4999c
988+
```
989+
990+
### tropic-handshake
991+
992+
Establishes a secure channel with the Tropic chip. Expects handshake a request as input, returns a handshake response.
993+
994+
```
995+
tropic-handshake 648724356a6bb22b258557927287af52133a27b7317d3c919db23395cae03d853422af
996+
OK 09ad6ec70806318313c903094ae8fb63698051210dfa540ea7c7f7e588601dac478eee30432063964574879dee93250d8a5049
997+
```
998+
999+
### tropic-send-command
1000+
1001+
Sends a command to the Tropic chip and returns the response. The command `tropic-handshake` must be executed before calling this command.
1002+
1003+
Example:
1004+
```
1005+
tropic-send-command <hexadecimal string>
1006+
OK <hexadecimal string>
1007+
```
1008+
1009+
### tropic-certdev-read
1010+
1011+
Retrieves the X.509 certificate issued by the Trezor Company for the device.
1012+
1013+
Example:
1014+
```
1015+
tropic-certdev-read
1016+
OK <hexadecimal string>
1017+
```
1018+
1019+
### tropic-certdev-write
1020+
1021+
Writes the X.509 certificate issued by the Trezor Company for the device.
1022+
1023+
Example:
1024+
```
1025+
tropic-certdev-write <hexadecimal string>
1026+
OK <hexadecimal string>
1027+
```
1028+
1029+
### tropic-certfido-read
1030+
1031+
Retrieves the X.509 certificate issued by the Trezor Company for the FIDO attestation key.
1032+
1033+
Example:
1034+
```
1035+
tropic-certfido-read
1036+
OK <hexadecimal string>
1037+
```
1038+
1039+
### tropic-certfido-write
1040+
1041+
Writes the X.509 certificate issued by the Trezor Company for the FIDO attestation key.
1042+
1043+
Example:
1044+
```
1045+
tropic-certfido-write <hexadecimal string>
1046+
OK <hexadecimal string>
1047+
```
1048+
1049+
### tropic-lock
1050+
1051+
Configures the Tropic chip. This command is idempotent, meaning it can be called multiple times without changing the state of the device. This command is irreversible and cannot be undone. The command `tropic-pair` must be executed before calling this command.
1052+
1053+
Example:
1054+
```
1055+
tropic-lock
1056+
OK <hexadecimal string>
1057+
```
1058+
1059+
### secure-channel-handshake-1
1060+
1061+
Returns the first handshake message for establishing a secure channel with the device.
1062+
1063+
Example:
1064+
```
1065+
secure-channel-handshake-1
1066+
OK 1e85285cbf805d0418be1f502a325806f68fa07c78fd63b7b960b2d0416f8b49
1067+
```
1068+
1069+
### secure-channel-handshake-2
1070+
1071+
Establishes a secure channel with the device. Expects the second handshake message as input. The command `secure-channel-handshake-1` must be executed before calling this command.
1072+
1073+
Example:
1074+
```
1075+
secure-channel-handshake-2 e08e84b91413ad8f7b07853c8ce4c1b5547a12d9dd65f30e3adaa1e2398e0359bd7ba0e9fb2c64130c25d56abb811f72
1076+
OK
1077+
```
1078+
9501079
### wpc-info
9511080
Retrieves detailed information from the wireless power receiver, including chip identification, firmware version, configuration settings, and error status.
9521081

@@ -1087,6 +1216,3 @@ Example:
10871216
rtc-get
10881217
OK 2025 07 03 14 23 00 4
10891218
```
1090-
1091-
1092-

core/embed/projects/prodtest/cmd/common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ static const uint8_t SUBJECT_COMMON_NAME[] = {
5151
#ifdef TREZOR_MODEL_T3T1
5252
'T', '3', 'T', '1', ' ', 'T', 'r', 'e', 'z', 'o', 'r', ' ', 'S', 'a', 'f', 'e', ' ', '5',
5353
#endif
54+
#ifdef TREZOR_MODEL_T3W1
55+
'T', '3', 'W', '1', ' ', 'T', 'r', 'e', 'z', 'o', 'r', ' ', 'S', 'a', 'f', 'e', ' ', '7',
56+
#endif
5457
};
5558
// clang-format on
5659

core/embed/projects/prodtest/cmd/prodtest_secrets.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "memzero.h"
3232
#include "rand.h"
3333
#include "secbool.h"
34+
#include "secure_channel.h"
3435

3536
secbool generate_random_secret(uint8_t* secret, size_t length) {
3637
random_buffer(secret, length);
@@ -128,6 +129,71 @@ static void prodtest_secrets_init(cli_t* cli) {
128129
cli_ok(cli, "");
129130
}
130131

132+
static void prodtest_secrets_get_mcu_device_key(cli_t* cli) {
133+
if (cli_arg_count(cli) > 0) {
134+
cli_error_arg_count(cli);
135+
return;
136+
}
137+
138+
curve25519_key mcu_private = {0};
139+
if (secret_key_mcu_device_auth(mcu_private) != sectrue) {
140+
cli_error(cli, CLI_ERROR, "`secret_key_mcu_device_auth()` failed.");
141+
return;
142+
}
143+
curve25519_key mcu_public = {0};
144+
curve25519_scalarmult_basepoint(mcu_public, mcu_private);
145+
146+
uint8_t output[sizeof(curve25519_key) + NOISE_TAG_SIZE] = {0};
147+
if (!secure_channel_encrypt(NULL, 0, mcu_public, sizeof(curve25519_key),
148+
output + NOISE_TAG_SIZE)) {
149+
// `secure_channel_handshake_2()` might not have been called
150+
cli_error(cli, CLI_ERROR, "`secure_channel_encrypt()` failed.");
151+
goto cleanup;
152+
}
153+
154+
cli_ok_hexdata(cli, output, sizeof(output));
155+
156+
cleanup:
157+
memzero(mcu_private, sizeof(mcu_private));
158+
}
159+
160+
static void prodtest_secrets_certdev_write(cli_t* cli) {
161+
if (cli_arg_count(cli) > 0) {
162+
cli_error_arg_count(cli);
163+
return;
164+
}
165+
166+
size_t certificate_length = 0;
167+
uint8_t certificate[512] = {0};
168+
if (!cli_arg_hex(cli, "hex-data", certificate, sizeof(certificate),
169+
&certificate_length)) {
170+
if (certificate_length == sizeof(certificate)) {
171+
cli_error(cli, CLI_ERROR, "Certificate too long.");
172+
} else {
173+
cli_error(cli, CLI_ERROR, "Hexadecimal decoding error.");
174+
}
175+
return;
176+
}
177+
178+
// TODO: Write the certificate to the flash.
179+
180+
cli_ok(cli, "");
181+
}
182+
183+
static void prodtest_secrets_certdev_read(cli_t* cli) {
184+
if (cli_arg_count(cli) > 0) {
185+
cli_error_arg_count(cli);
186+
return;
187+
}
188+
189+
uint8_t certificate[512] = {0};
190+
size_t certificate_length = 0;
191+
192+
// TODO: Read the certificate from the flash.
193+
194+
cli_ok_hexdata(cli, certificate, certificate_length);
195+
}
196+
131197
// clang-format off
132198

133199
PRODTEST_CLI_CMD(
@@ -136,3 +202,24 @@ PRODTEST_CLI_CMD(
136202
.info = "Generate and write secrets to flash",
137203
.args = ""
138204
);
205+
206+
PRODTEST_CLI_CMD(
207+
.name = "secrets-get-mcu-device_key",
208+
.func = prodtest_secrets_get_mcu_device_key,
209+
.info = "Get MCU device key",
210+
.args = ""
211+
);
212+
213+
PRODTEST_CLI_CMD(
214+
.name = "secrets-certdev-write",
215+
.func = prodtest_secrets_certdev_write,
216+
.info = "Write the device's X.509 certificate to flash",
217+
.args = "<hex-data>"
218+
);
219+
220+
PRODTEST_CLI_CMD(
221+
.name = "secrets-certdev-read",
222+
.func = prodtest_secrets_certdev_read,
223+
.info = "Read the device's X.509 certificate from flash",
224+
.args = ""
225+
);

core/embed/projects/prodtest/cmd/prodtest_secure_channel.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ static void prodtest_secure_channel_handshake_2(cli_t* cli) {
5959
}
6060

6161
if (!secure_channel_handshake_2(input)) {
62-
// TODO: Consider distinguishing between cryptography error and state error
63-
cli_error(cli, CLI_ERROR,
64-
"You have to call `secure-channel-handshake-1` first.");
62+
// Either `secure_channel_handshake_1()` has not been called or the keys do
63+
// not match.
64+
cli_error(cli, CLI_ERROR, "`secure_channel_handshake_2()` failed.");
6565
}
6666

6767
cli_ok(cli, "");

0 commit comments

Comments
 (0)