Skip to content

Commit e29ef7b

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

File tree

13 files changed

+1698
-130
lines changed

13 files changed

+1698
-130
lines changed

core/embed/projects/prodtest/README.md

Lines changed: 173 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,33 @@ secrets-init
648648
OK
649649
```
650650

651+
### secrets-get-mcu-device-key
652+
Returns the device attestation key stored in MCU.
653+
654+
Example:
655+
```
656+
secrets-get-mcu-device-key
657+
OK 638c8a83ddc8fd84cddf5a0a4fa3d9615146cd341685dca942bab1132c2bc99b
658+
```
659+
660+
### secrets-certdev-write
661+
Writes the X.509 device attestation certificate issued by the Trezor Company for the attestation key stored in MCU.
662+
663+
Example:
664+
```
665+
secrets-certdev-write
666+
OK <hexadecimal string>
667+
```
668+
669+
### secrets-certdev-read
670+
Retrieves the X.509 device attestation certificate issued by the Trezor Company for the attestation key stored in MCU.
671+
672+
Example:
673+
```
674+
secrets-certdev-read
675+
OK <hexadecimal string>
676+
```
677+
651678
### optiga-pair
652679
Writes the pairing secret to the Optiga chip to pair it with the MCU. The command `secrets-init` must be executed before calling this command.
653680

@@ -675,17 +702,17 @@ optiga-certinf-read
675702
OK <hexadecimal string>
676703
```
677704

678-
### optiga-certinf-write
679-
Writes the X.509 certificate issued by the Trezor Company for the device.
705+
### optiga-certdev-write
706+
Writes the X.509 certificate issued by the Trezor Company for the device attestation key stored in Optiga.
680707

681708
Example:
682709
```
683-
optiga-certinf-write <hexadecimal string>
710+
optiga-certdev-write <hexadecimal string>
684711
OK
685712
```
686713

687-
### optiga-certdev-red
688-
Retrieves the X.509 certificate issued by the Trezor Company for the device.
714+
### optiga-certdev-read
715+
Retrieves the X.509 certificate issued by the Trezor Company for the device attestation key stored in Optiga.
689716

690717
Example:
691718
```
@@ -694,7 +721,7 @@ OK <hexadecimal string>
694721
```
695722

696723
### optiga-certfido-write
697-
Writes the X.509 certificate issued by the Trezor Company for the FIDO attestation key.
724+
Writes the X.509 certificate issued by the Trezor Company for the FIDO attestation key stored in Optiga.
698725

699726
Example:
700727
```
@@ -703,7 +730,7 @@ OK
703730
```
704731

705732
### optiga-certfido-read
706-
Retrieves the X.509 certificate issued by the Trezor Company for the FIDO attestation key.
733+
Retrieves the X.509 certificate issued by the Trezor Company for the FIDO attestation key stored in Optiga.
707734

708735
Example:
709736
```
@@ -947,6 +974,145 @@ tropic-get-chip-id
947974
OK 00000001000000000000000000000000000000000000000000000000000000000000000001000000054400000000FFFFFFFFFFFF01F00F000544545354303103001300000B54524F50494330312D4553FFFFFFFF000100000000FFFF000100000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13000300
948975
```
949976

977+
### tropic-certtropic-read
978+
979+
Reads the X.509 certificate issued by Tropic Square for the Tropic chip.
980+
981+
Example:
982+
```
983+
tropic-certtropic-read
984+
OK 308201CB30820151A00302010202100200110308861906100F32000000045B300A06082A8648CE3D0403033047310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3119301706035504030C1054524F50494330312D54204341207631301E170D3235303730313130353533325A170D3435303730313130353533325A30173115301306035504030C0C54524F504943303120655345302A300506032B656E032100F582E78C4ECCB186D72A29B6B54E8CAD931C765DBA0C3EDE9405602CB1065246A37E307C300C0603551D130101FF04023000300E0603551D0F0101FF040403020308301F0603551D2304183016801433C711060CE80513B5677B019650644E3B43FAE7303B0603551D1F043430323030A02EA02C862A687474703A2F2F706B692E74726F7069637371756172652E636F6D2F6C332F7430312D5476312E63726C300A06082A8648CE3D0403030368003065023100C46E44F9D1FE26A4DC8AC659D1B6A9A82CEEBE9D283726633053FE410FF665073B7FB6ECE235FD8AB7F87336DDBCF96202300F919622C0A1CF6D00CF43CE4229AC44548055030566E8E03CA98B15D6B29B04DF231B9BF7006A9E28C15E88B07141893082025E308201E4A00302010202027531300A06082A8648CE3D0403033045310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3117301506035504030C0E54524F50494330312043412076313020170D3235303333313132303833305A180F32303630303333313132303833305A3047310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3119301706035504030C1054524F50494330312D542043412076313076301006072A8648CE3D020106052B8104002203620004A70C3273AE3227DC767EF0293D95CC106691E5BC9AA6C0282BAA8FD4B37CFAC30FEE0D879C32D8D9CE9B0BD7924B5C10097B8C4A5E7ED68D690185E3D128161256C01033C0293DE39A7188A72CFF9EEAF5B3B5DEE898F954C4F226C2ADE70BC6A381A230819F301D0603551D0E0416041433C711060CE80513B5677B019650644E3B43FAE730120603551D130101FF040830060101FF020100300E0603551D0F0101FF040403020106301F0603551D2304183016801443BAB7BDA7CDE728945CF142CBD2F9CD5588A93F30390603551D1F04323030302EA02CA02A8628687474703A2F2F706B692E74726F7069637371756172652E636F6D2F6C322F74303176312E63726C300A06082A8648CE3D0403030368003065023014AEC525E5E8311B5D6312CF0EBB2286700552EEBA32D641672C20F02A612B77E9FC3709C9657CEC6D82D6CDBDDE57C4023100BB9B77CCBBD9DE11086481D4BA9772C38743591E722B9E4D08A89940D879DA2447A55C15F84175C479946326E0F482AF3082028B308201ECA00302010202020BB9300A06082A8648CE3D040304304F310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3121301F06035504030C1854726F7069632053717561726520526F6F742043412076313020170D3235303333313132303832395A180F32303635303333313132303832395A3045310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3117301506035504030C0E54524F50494330312043412076313076301006072A8648CE3D020106052B81040022036200042301BE5B6ED9A858153F57C6BEBC9F37B858BC2874DDC90C1041BE6D04E7BBF24A7968F2E51173D0ACAC892E65E4FC03EA5BC4381A60154D7CD7CC6DF94591650F5FDC008919157314FC1F8D8295F1A10571DD1573E868BFECA96C92CCBB816FA381A230819F301D0603551D0E0416041443BAB7BDA7CDE728945CF142CBD2F9CD5588A93F30120603551D130101FF040830060101FF020101300E0603551D0F0101FF040403020106301F0603551D230418301680143C18AF711A6699B37914E363963FE25CF304B3BF30390603551D1F04323030302EA02CA02A8628687474703A2F2F706B692E74726F7069637371756172652E636F6D2F6C312F74737276312E63726C300A06082A8648CE3D04030403818C00308188024200BCD02D464329F3FC7DC81723B0C26437E35C2B49782BAE97432789F508B5A220240E6E3E4D12C15C3BDB15A8D3F90CDD19071E2227C4898220B2BEF584B2C20F8F024201EB854F05F9A2C5B466D798FE627C539B98703531735F7AB49546FE5CFB9DF0BF3B6985D700EFBC36DF3FF01692F0ECE98BB8DB2FBB9BF40913EA87EA121A7AD2E730820258308201BBA0030201020202012D300A06082A8648CE3D040304304F310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3121301F06035504030C1854726F7069632053717561726520526F6F742043412076313020170D3235303333313132303832355A180F32303735303333313132303832355A304F310B300906035504061302435A311D301B060355040A0C1454726F7069632053717561726520732E722E6F2E3121301F06035504030C1854726F7069632053717561726520526F6F7420434120763130819B301006072A8648CE3D020106052B8104002303818600040187CCEA62837E23092D8A7135789FCC6FBC3D35E79FC01F4F498FC5C2C409CE772F901340090403E8BA4D97E13F1E7594AC6D2F51FD2239F8D457769F378440A18000712BF16A48EA2025837BEFD0502A562FD93941D52CC40ED9553CA79B145BA585F32492BFD792EB96D949D31676CD099F19CE8848697B8C3430AF016FED985E1EB4A3423040301D0603551D0E041604143C18AF711A6699B37914E363963FE25CF304B3BF300F0603551D130101FF040530030101FF300E0603551D0F0101FF040403020106300A06082A8648CE3D04030403818A0030818602416841837339337C182A4EE896CBFD5DA5925F0026E7A6FA3DEE61F49A46B5D9856858D3D86501BE64B0F2F33B05D856DE96F57B947F49E720E875090B30C337791802412FDDB68D166510451FE4C62DBAE0CCD952DC34E03AE6617818CCD0EA28A9DFF045AA13A248A5F066B51139C9BEF471DD004DAC4F78DB56CF7B3E8D6F8F87D048D2
985+
```
986+
987+
### tropic-lock-check
988+
989+
Returns 'YES' if the Tropic chip has been locked, otherwise returns 'NO'.
990+
991+
Example:
992+
```
993+
tropic-lock-check
994+
OK YES
995+
```
996+
997+
### tropic-pair
998+
999+
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.
1000+
1001+
Example:
1002+
```
1003+
tropic-pair
1004+
OK
1005+
```
1006+
1007+
### tropic-get-access-credential
1008+
1009+
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.
1010+
1011+
Example:
1012+
```
1013+
tropic-get-access-credential
1014+
OK 03ca0e9d74ef59fa80a06161f3d2fceeb3e0c5e2db8182526d337aac78bad2d2ce4cacf05cdcd879843bcc43ed330199
1015+
```
1016+
1017+
### tropic-get-fido-masking-key
1018+
1019+
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.
1020+
1021+
Example:
1022+
```
1023+
tropic-get-fido-masking-key
1024+
OK dc106118a32feeef8d9211f54b9c8e9d571abe4cb104dc4ab087531cfee4574283ccf9c6f45e68be712f630d72d4999c
1025+
```
1026+
1027+
### tropic-handshake
1028+
1029+
Establishes a secure channel with the Tropic chip. Expects handshake a request as input, returns a handshake response.
1030+
1031+
```
1032+
tropic-handshake 648724356a6bb22b258557927287af52133a27b7317d3c919db23395cae03d853422af
1033+
OK 09ad6ec70806318313c903094ae8fb63698051210dfa540ea7c7f7e588601dac478eee30432063964574879dee93250d8a5049
1034+
```
1035+
1036+
### tropic-send-command
1037+
1038+
Sends a command to the Tropic chip and returns the response. The command `tropic-handshake` must be executed before calling this command.
1039+
1040+
Example:
1041+
```
1042+
tropic-send-command <hexadecimal string>
1043+
OK <hexadecimal string>
1044+
```
1045+
1046+
### tropic-certdev-read
1047+
1048+
Retrieves the X.509 certificate issued by the Trezor Company for the device attestation key stored in Tropic.
1049+
1050+
Example:
1051+
```
1052+
tropic-certdev-read
1053+
OK <hexadecimal string>
1054+
```
1055+
1056+
### tropic-certdev-write
1057+
1058+
Writes the X.509 certificate issued by the Trezor Company for the device attestation key stored in Tropic.
1059+
1060+
Example:
1061+
```
1062+
tropic-certdev-write <hexadecimal string>
1063+
OK <hexadecimal string>
1064+
```
1065+
1066+
### tropic-certfido-read
1067+
1068+
Retrieves the X.509 certificate issued by the Trezor Company for the FIDO attestation key stored in Tropic.
1069+
1070+
Example:
1071+
```
1072+
tropic-certfido-read
1073+
OK <hexadecimal string>
1074+
```
1075+
1076+
### tropic-certfido-write
1077+
1078+
Writes the X.509 certificate issued by the Trezor Company for the FIDO attestation key stored in Tropic.
1079+
1080+
Example:
1081+
```
1082+
tropic-certfido-write <hexadecimal string>
1083+
OK <hexadecimal string>
1084+
```
1085+
1086+
### tropic-lock
1087+
1088+
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.
1089+
1090+
Example:
1091+
```
1092+
tropic-lock
1093+
OK <hexadecimal string>
1094+
```
1095+
1096+
### secure-channel-handshake-1
1097+
1098+
Returns the first handshake message for establishing a secure channel with the device.
1099+
1100+
Example:
1101+
```
1102+
secure-channel-handshake-1
1103+
OK 1e85285cbf805d0418be1f502a325806f68fa07c78fd63b7b960b2d0416f8b49
1104+
```
1105+
1106+
### secure-channel-handshake-2
1107+
1108+
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.
1109+
1110+
Example:
1111+
```
1112+
secure-channel-handshake-2 e08e84b91413ad8f7b07853c8ce4c1b5547a12d9dd65f30e3adaa1e2398e0359bd7ba0e9fb2c64130c25d56abb811f72
1113+
OK
1114+
```
1115+
9501116
### wpc-info
9511117
Retrieves detailed information from the wireless power receiver, including chip identification, firmware version, configuration settings, and error status.
9521118

@@ -1087,6 +1253,3 @@ Example:
10871253
rtc-get
10881254
OK 2025 07 03 14 23 00 4
10891255
```
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: 91 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,73 @@ static void prodtest_secrets_init(cli_t* cli) {
128129
cli_ok(cli, "");
129130
}
130131

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

133201
PRODTEST_CLI_CMD(
@@ -136,3 +204,26 @@ PRODTEST_CLI_CMD(
136204
.info = "Generate and write secrets to flash",
137205
.args = ""
138206
);
207+
208+
#ifdef SECRET_MASTER_KEY_SLOT_SIZE
209+
PRODTEST_CLI_CMD(
210+
.name = "secrets-get-mcu-device_key",
211+
.func = prodtest_secrets_get_mcu_device_key,
212+
.info = "Get MCU device key",
213+
.args = ""
214+
);
215+
216+
PRODTEST_CLI_CMD(
217+
.name = "secrets-certdev-write",
218+
.func = prodtest_secrets_certdev_write,
219+
.info = "Write the device's X.509 certificate to flash",
220+
.args = "<hex-data>"
221+
);
222+
223+
PRODTEST_CLI_CMD(
224+
.name = "secrets-certdev-read",
225+
.func = prodtest_secrets_certdev_read,
226+
.info = "Read the device's X.509 certificate from flash",
227+
.args = ""
228+
);
229+
#endif

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)