diff --git a/core/embed/projects/prodtest/.changelog.d/5281.added.2 b/core/embed/projects/prodtest/.changelog.d/5281.added.2 new file mode 100644 index 0000000000..3772e48257 --- /dev/null +++ b/core/embed/projects/prodtest/.changelog.d/5281.added.2 @@ -0,0 +1 @@ +Add the `optiga-pair` command to pair the Optiga with the MCU. diff --git a/core/embed/projects/prodtest/README.md b/core/embed/projects/prodtest/README.md index 1c758f64df..1da7b74bd8 100644 --- a/core/embed/projects/prodtest/README.md +++ b/core/embed/projects/prodtest/README.md @@ -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. diff --git a/core/embed/projects/prodtest/cmd/prodtest_optiga.c b/core/embed/projects/prodtest/cmd/prodtest_optiga.c index e34643df2b..4b30126843 100644 --- a/core/embed/projects/prodtest/cmd/prodtest_optiga.c +++ b/core/embed/projects/prodtest/cmd/prodtest_optiga.c @@ -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, diff --git a/core/embed/projects/prodtest/cmd/prodtest_optiga.h b/core/embed/projects/prodtest/cmd/prodtest_optiga.h index a1b5ea8072..30cf591beb 100644 --- a/core/embed/projects/prodtest/cmd/prodtest_optiga.h +++ b/core/embed/projects/prodtest/cmd/prodtest_optiga.h @@ -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); diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c index 3447c64fbe..4557b3bdcb 100644 --- a/core/embed/projects/prodtest/main.c +++ b/core/embed/projects/prodtest/main.c @@ -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