1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-22 14:38:27 +00:00

feat(core/prodtest): add optiga-pair command

This commit is contained in:
Ondřej Vejpustek 2025-06-29 21:48:32 +02:00
parent c8bf5be9b8
commit 9f606ec922
5 changed files with 35 additions and 56 deletions

View File

@ -0,0 +1 @@
Add the `optiga-pair` command to pair the Optiga with the MCU.

View File

@ -624,6 +624,15 @@ secrets-init
OK
```
### optiga-pair
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.
Example:
```
optiga-pair
OK
```
### optiga-id-read
Retrieves the coprocessor UID of the Optiga chip as a 27 byte hexadecimal string.

View File

@ -50,16 +50,6 @@
#define OID_KEY_PAIRING OPTIGA_OID_PTFBIND_SECRET
#define OID_TRUST_ANCHOR (OPTIGA_OID_CA_CERT + 0)
typedef enum {
OPTIGA_PAIRING_UNPAIRED = 0,
OPTIGA_PAIRING_PAIRED,
OPTIGA_PAIRING_ERR_READ_FLASH,
OPTIGA_PAIRING_ERR_WRITE_OPTIGA,
OPTIGA_PAIRING_ERR_HANDSHAKE,
} optiga_pairing;
static optiga_pairing optiga_pairing_state = OPTIGA_PAIRING_UNPAIRED;
// Data object access conditions.
static const optiga_metadata_item ACCESS_PAIRED =
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_CONF, OID_KEY_PAIRING);
@ -68,29 +58,6 @@ static const optiga_metadata_item KEY_USE_SIGN =
static const optiga_metadata_item TYPE_PTFBIND =
OPTIGA_META_VALUE(OPTIGA_DATA_TYPE_PTFBIND);
static bool optiga_paired(cli_t* cli) {
const char* details = "";
switch (optiga_pairing_state) {
case OPTIGA_PAIRING_PAIRED:
return true;
case OPTIGA_PAIRING_ERR_READ_FLASH:
details = "failed to read pairing secret from flash";
break;
case OPTIGA_PAIRING_ERR_WRITE_OPTIGA:
details = "failed to write pairing secret to Optiga";
break;
case OPTIGA_PAIRING_ERR_HANDSHAKE:
details = "failed optiga_sec_chan_handshake";
break;
default:
break;
}
cli_error(cli, CLI_ERROR, "Optiga not paired (%s).", details);
return false;
}
static bool set_metadata(cli_t* cli, uint16_t oid,
const optiga_metadata* metadata, bool report_error) {
uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
@ -136,16 +103,23 @@ static bool set_metadata(cli_t* cli, uint16_t oid,
return true;
}
void pair_optiga(cli_t* cli) {
void prodtest_optiga_pair(cli_t* cli) {
if (cli_arg_count(cli) > 0) {
cli_error_arg_count(cli);
return;
}
uint8_t pairing_secret[OPTIGA_PAIRING_SECRET_SIZE] = {0};
// Load the pairing secret from the flash memory.
if (sectrue != secret_key_optiga_pairing(pairing_secret)) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_READ_FLASH;
cli_error(cli, CLI_ERROR,
"`secret_key_optiga_pairing` failed. You have to call "
"`secrets_write` first.");
goto cleanup;
}
// Execute the handshake to verify that the secret is stored in Optiga.
// Execute the handshake to verify whether the secret is stored in Optiga.
if (OPTIGA_SUCCESS !=
optiga_sec_chan_handshake(pairing_secret, sizeof(pairing_secret))) {
// Enable writing the pairing secret to OPTIGA.
@ -160,19 +134,19 @@ void pair_optiga(cli_t* cli) {
if (OPTIGA_SUCCESS != optiga_set_data_object(OID_KEY_PAIRING, false,
pairing_secret,
sizeof(pairing_secret))) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_OPTIGA;
cli_error(cli, CLI_ERROR, "`optiga_set_data_object` failed.");
goto cleanup;
}
// Execute the handshake to verify that the secret is stored in Optiga.
if (OPTIGA_SUCCESS !=
optiga_sec_chan_handshake(pairing_secret, sizeof(pairing_secret))) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE;
cli_error(cli, CLI_ERROR, "`optiga_sec_chan_handshake` failed.");
goto cleanup;
}
}
optiga_pairing_state = OPTIGA_PAIRING_PAIRED;
cli_ok(cli, "");
cleanup:
memzero(pairing_secret, sizeof(pairing_secret));
@ -192,7 +166,10 @@ static void prodtest_optiga_lock(cli_t* cli) {
return;
}
if (!optiga_paired(cli)) return;
// TODO: For every slot that is going to be locked, we might want to verify
// that the slot has already been written to. This check can be performed here
// or within a separate command, depending on who we want to be responsible
// for not locking a partially provisioned optiga.
// Delete trust anchor.
optiga_result ret =
@ -263,8 +240,6 @@ static void prodtest_optiga_lock(cli_t* cli) {
}
optiga_locked_status get_optiga_locked_status(cli_t* cli) {
if (!optiga_paired(cli)) return OPTIGA_LOCKED_ERROR;
const uint16_t oids[] = {OID_CERT_DEV, OID_CERT_FIDO, OID_KEY_DEV,
OID_KEY_FIDO, OID_KEY_PAIRING};
@ -323,8 +298,6 @@ static void prodtest_optiga_id_read(cli_t* cli) {
return;
}
if (!optiga_paired(cli)) return;
uint8_t optiga_id[27] = {0};
size_t optiga_id_size = 0;
@ -346,8 +319,6 @@ static void cert_read(cli_t* cli, uint16_t oid) {
return;
}
if (!optiga_paired(cli)) return;
static uint8_t cert[OPTIGA_MAX_CERT_SIZE] = {0};
size_t cert_size = 0;
optiga_result ret =
@ -416,8 +387,6 @@ static bool check_device_cert_chain(cli_t* cli, const uint8_t* chain,
}
static void cert_write(cli_t* cli, uint16_t oid) {
if (!optiga_paired(cli)) return;
// Enable writing to the certificate slot.
optiga_metadata metadata = {0};
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
@ -472,8 +441,6 @@ static void pubkey_read(cli_t* cli, uint16_t oid,
return;
}
if (!optiga_paired(cli)) return;
// Enable key agreement usage.
optiga_metadata metadata = {0};
@ -530,8 +497,6 @@ static void pubkey_read(cli_t* cli, uint16_t oid,
}
static void prodtest_optiga_keyfido_write(cli_t* cli) {
if (!optiga_paired(cli)) return;
const size_t EPH_PUB_KEY_SIZE = 33;
const size_t PAYLOAD_SIZE = 32;
const size_t CIPHERTEXT_OFFSET = EPH_PUB_KEY_SIZE;
@ -670,8 +635,6 @@ static void prodtest_optiga_counter_read(cli_t* cli) {
return;
}
if (!optiga_paired(cli)) return;
uint8_t sec = 0;
size_t size = 0;
@ -729,6 +692,13 @@ PRODTEST_CLI_CMD(
.args = ""
);
PRODTEST_CLI_CMD(
.name = "optiga-pair",
.func = prodtest_optiga_pair,
.info = "Write the pairing secret to Optiga",
.args = ""
);
PRODTEST_CLI_CMD(
.name = "optiga-certinf-read",
.func = prodtest_optiga_certinf_read,

View File

@ -27,5 +27,5 @@ typedef enum {
OPTIGA_LOCKED_ERROR,
} optiga_locked_status;
void pair_optiga(cli_t* cli);
void prodtest_optiga_pair(cli_t* cli);
optiga_locked_status get_optiga_locked_status(cli_t* cli);

View File

@ -288,7 +288,6 @@ int prodtest_main(void) {
#ifdef USE_OPTIGA
optiga_init();
optiga_open_application();
pair_optiga(&g_cli);
#endif
#if defined USE_BUTTON && defined USE_POWER_MANAGER