mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-22 22:48:20 +00:00
feat(core/prodtest): add optiga-pair command
This commit is contained in:
parent
c8bf5be9b8
commit
9f606ec922
1
core/embed/projects/prodtest/.changelog.d/5281.added.2
Normal file
1
core/embed/projects/prodtest/.changelog.d/5281.added.2
Normal file
@ -0,0 +1 @@
|
|||||||
|
Add the `optiga-pair` command to pair the Optiga with the MCU.
|
@ -624,6 +624,15 @@ secrets-init
|
|||||||
OK
|
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
|
### optiga-id-read
|
||||||
Retrieves the coprocessor UID of the Optiga chip as a 27 byte hexadecimal string.
|
Retrieves the coprocessor UID of the Optiga chip as a 27 byte hexadecimal string.
|
||||||
|
|
||||||
|
@ -50,16 +50,6 @@
|
|||||||
#define OID_KEY_PAIRING OPTIGA_OID_PTFBIND_SECRET
|
#define OID_KEY_PAIRING OPTIGA_OID_PTFBIND_SECRET
|
||||||
#define OID_TRUST_ANCHOR (OPTIGA_OID_CA_CERT + 0)
|
#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.
|
// Data object access conditions.
|
||||||
static const optiga_metadata_item ACCESS_PAIRED =
|
static const optiga_metadata_item ACCESS_PAIRED =
|
||||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_CONF, OID_KEY_PAIRING);
|
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 =
|
static const optiga_metadata_item TYPE_PTFBIND =
|
||||||
OPTIGA_META_VALUE(OPTIGA_DATA_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,
|
static bool set_metadata(cli_t* cli, uint16_t oid,
|
||||||
const optiga_metadata* metadata, bool report_error) {
|
const optiga_metadata* metadata, bool report_error) {
|
||||||
uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
|
uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
|
||||||
@ -136,16 +103,23 @@ static bool set_metadata(cli_t* cli, uint16_t oid,
|
|||||||
return true;
|
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};
|
uint8_t pairing_secret[OPTIGA_PAIRING_SECRET_SIZE] = {0};
|
||||||
|
|
||||||
// Load the pairing secret from the flash memory.
|
// Load the pairing secret from the flash memory.
|
||||||
if (sectrue != secret_key_optiga_pairing(pairing_secret)) {
|
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;
|
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 !=
|
if (OPTIGA_SUCCESS !=
|
||||||
optiga_sec_chan_handshake(pairing_secret, sizeof(pairing_secret))) {
|
optiga_sec_chan_handshake(pairing_secret, sizeof(pairing_secret))) {
|
||||||
// Enable writing the pairing secret to OPTIGA.
|
// 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,
|
if (OPTIGA_SUCCESS != optiga_set_data_object(OID_KEY_PAIRING, false,
|
||||||
pairing_secret,
|
pairing_secret,
|
||||||
sizeof(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;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the handshake to verify that the secret is stored in Optiga.
|
// Execute the handshake to verify that the secret is stored in Optiga.
|
||||||
if (OPTIGA_SUCCESS !=
|
if (OPTIGA_SUCCESS !=
|
||||||
optiga_sec_chan_handshake(pairing_secret, sizeof(pairing_secret))) {
|
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;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optiga_pairing_state = OPTIGA_PAIRING_PAIRED;
|
cli_ok(cli, "");
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
memzero(pairing_secret, sizeof(pairing_secret));
|
memzero(pairing_secret, sizeof(pairing_secret));
|
||||||
@ -192,7 +166,10 @@ static void prodtest_optiga_lock(cli_t* cli) {
|
|||||||
return;
|
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.
|
// Delete trust anchor.
|
||||||
optiga_result ret =
|
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) {
|
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,
|
const uint16_t oids[] = {OID_CERT_DEV, OID_CERT_FIDO, OID_KEY_DEV,
|
||||||
OID_KEY_FIDO, OID_KEY_PAIRING};
|
OID_KEY_FIDO, OID_KEY_PAIRING};
|
||||||
|
|
||||||
@ -323,8 +298,6 @@ static void prodtest_optiga_id_read(cli_t* cli) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optiga_paired(cli)) return;
|
|
||||||
|
|
||||||
uint8_t optiga_id[27] = {0};
|
uint8_t optiga_id[27] = {0};
|
||||||
size_t optiga_id_size = 0;
|
size_t optiga_id_size = 0;
|
||||||
|
|
||||||
@ -346,8 +319,6 @@ static void cert_read(cli_t* cli, uint16_t oid) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optiga_paired(cli)) return;
|
|
||||||
|
|
||||||
static uint8_t cert[OPTIGA_MAX_CERT_SIZE] = {0};
|
static uint8_t cert[OPTIGA_MAX_CERT_SIZE] = {0};
|
||||||
size_t cert_size = 0;
|
size_t cert_size = 0;
|
||||||
optiga_result ret =
|
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) {
|
static void cert_write(cli_t* cli, uint16_t oid) {
|
||||||
if (!optiga_paired(cli)) return;
|
|
||||||
|
|
||||||
// Enable writing to the certificate slot.
|
// Enable writing to the certificate slot.
|
||||||
optiga_metadata metadata = {0};
|
optiga_metadata metadata = {0};
|
||||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
@ -472,8 +441,6 @@ static void pubkey_read(cli_t* cli, uint16_t oid,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optiga_paired(cli)) return;
|
|
||||||
|
|
||||||
// Enable key agreement usage.
|
// Enable key agreement usage.
|
||||||
|
|
||||||
optiga_metadata metadata = {0};
|
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) {
|
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 EPH_PUB_KEY_SIZE = 33;
|
||||||
const size_t PAYLOAD_SIZE = 32;
|
const size_t PAYLOAD_SIZE = 32;
|
||||||
const size_t CIPHERTEXT_OFFSET = EPH_PUB_KEY_SIZE;
|
const size_t CIPHERTEXT_OFFSET = EPH_PUB_KEY_SIZE;
|
||||||
@ -670,8 +635,6 @@ static void prodtest_optiga_counter_read(cli_t* cli) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optiga_paired(cli)) return;
|
|
||||||
|
|
||||||
uint8_t sec = 0;
|
uint8_t sec = 0;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
@ -729,6 +692,13 @@ PRODTEST_CLI_CMD(
|
|||||||
.args = ""
|
.args = ""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
PRODTEST_CLI_CMD(
|
||||||
|
.name = "optiga-pair",
|
||||||
|
.func = prodtest_optiga_pair,
|
||||||
|
.info = "Write the pairing secret to Optiga",
|
||||||
|
.args = ""
|
||||||
|
);
|
||||||
|
|
||||||
PRODTEST_CLI_CMD(
|
PRODTEST_CLI_CMD(
|
||||||
.name = "optiga-certinf-read",
|
.name = "optiga-certinf-read",
|
||||||
.func = prodtest_optiga_certinf_read,
|
.func = prodtest_optiga_certinf_read,
|
||||||
|
@ -27,5 +27,5 @@ typedef enum {
|
|||||||
OPTIGA_LOCKED_ERROR,
|
OPTIGA_LOCKED_ERROR,
|
||||||
} optiga_locked_status;
|
} 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);
|
optiga_locked_status get_optiga_locked_status(cli_t* cli);
|
||||||
|
@ -288,7 +288,6 @@ int prodtest_main(void) {
|
|||||||
#ifdef USE_OPTIGA
|
#ifdef USE_OPTIGA
|
||||||
optiga_init();
|
optiga_init();
|
||||||
optiga_open_application();
|
optiga_open_application();
|
||||||
pair_optiga(&g_cli);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined USE_BUTTON && defined USE_POWER_MANAGER
|
#if defined USE_BUTTON && defined USE_POWER_MANAGER
|
||||||
|
Loading…
Reference in New Issue
Block a user