mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-21 14:08:13 +00:00
feat(core/prodtest): add secrets-write command
This commit is contained in:
parent
34921907b0
commit
c8bf5be9b8
@ -178,6 +178,7 @@ SOURCE_PRODTEST = [
|
||||
'embed/projects/prodtest/cmd/prodtest_reboot.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_rgbled.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_sdcard.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_secrets.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_tamper.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_sbu.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_touch.c',
|
||||
|
@ -165,6 +165,7 @@ SOURCE_PRODTEST = [
|
||||
'embed/projects/prodtest/cmd/prodtest_reboot.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_rgbled.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_sdcard.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_secrets.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_tamper.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_sbu.c',
|
||||
'embed/projects/prodtest/cmd/prodtest_touch.c',
|
||||
|
1
core/embed/projects/prodtest/.changelog.d/5281.added.1
Normal file
1
core/embed/projects/prodtest/.changelog.d/5281.added.1
Normal file
@ -0,0 +1 @@
|
||||
Add the `secrets-init` command to generate and write secrets to flash.
|
@ -615,6 +615,15 @@ prodtest-homescreen
|
||||
OK
|
||||
```
|
||||
|
||||
### secrets-init
|
||||
Generates random secrets and stores them in the protected storage.
|
||||
|
||||
Example:
|
||||
```
|
||||
secrets-init
|
||||
OK
|
||||
```
|
||||
|
||||
### optiga-id-read
|
||||
Retrieves the coprocessor UID of the Optiga chip as a 27 byte hexadecimal string.
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <rtl/cli.h>
|
||||
#include <sec/optiga_commands.h>
|
||||
#include <sec/optiga_transport.h>
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
|
||||
#include "aes/aes.h"
|
||||
@ -54,9 +53,7 @@
|
||||
typedef enum {
|
||||
OPTIGA_PAIRING_UNPAIRED = 0,
|
||||
OPTIGA_PAIRING_PAIRED,
|
||||
OPTIGA_PAIRING_ERR_RNG,
|
||||
OPTIGA_PAIRING_ERR_READ_FLASH,
|
||||
OPTIGA_PAIRING_ERR_WRITE_FLASH,
|
||||
OPTIGA_PAIRING_ERR_WRITE_OPTIGA,
|
||||
OPTIGA_PAIRING_ERR_HANDSHAKE,
|
||||
} optiga_pairing;
|
||||
@ -77,15 +74,9 @@ static bool optiga_paired(cli_t* cli) {
|
||||
switch (optiga_pairing_state) {
|
||||
case OPTIGA_PAIRING_PAIRED:
|
||||
return true;
|
||||
case OPTIGA_PAIRING_ERR_RNG:
|
||||
details = "optiga_get_random error";
|
||||
break;
|
||||
case OPTIGA_PAIRING_ERR_READ_FLASH:
|
||||
details = "failed to read pairing secret from flash";
|
||||
break;
|
||||
case OPTIGA_PAIRING_ERR_WRITE_FLASH:
|
||||
details = "failed to write pairing secret to flash";
|
||||
break;
|
||||
case OPTIGA_PAIRING_ERR_WRITE_OPTIGA:
|
||||
details = "failed to write pairing secret to Optiga";
|
||||
break;
|
||||
@ -145,56 +136,13 @@ static bool set_metadata(cli_t* cli, uint16_t oid,
|
||||
return true;
|
||||
}
|
||||
|
||||
static secbool initialize_secrets(void) {
|
||||
#ifdef SECRET_PRIVILEGED_MASTER_KEY_SLOT
|
||||
uint8_t secret[2 * SECRET_MASTER_KEY_SLOT_SIZE] = {0};
|
||||
#else
|
||||
uint8_t secret[OPTIGA_PAIRING_SECRET_SIZE] = {0};
|
||||
#endif
|
||||
|
||||
// Generate the pairing secret or master keys.
|
||||
if (OPTIGA_SUCCESS != optiga_get_random(secret, sizeof(secret))) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG;
|
||||
return secfalse;
|
||||
}
|
||||
random_xor(secret, sizeof(secret));
|
||||
|
||||
#ifdef SECRET_PRIVILEGED_MASTER_KEY_SLOT
|
||||
// Store the master keys in the flash memory.
|
||||
secbool ret = secret_key_set(SECRET_PRIVILEGED_MASTER_KEY_SLOT, secret,
|
||||
SECRET_MASTER_KEY_SLOT_SIZE);
|
||||
if (sectrue == ret) {
|
||||
ret = secret_key_set(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
|
||||
&secret[SECRET_MASTER_KEY_SLOT_SIZE],
|
||||
SECRET_MASTER_KEY_SLOT_SIZE);
|
||||
}
|
||||
#else
|
||||
// Store the pairing secret in the flash memory.
|
||||
secbool ret =
|
||||
secret_key_set(SECRET_OPTIGA_SLOT, secret, OPTIGA_PAIRING_SECRET_SIZE);
|
||||
#endif
|
||||
memzero(secret, sizeof(secret));
|
||||
if (sectrue != ret) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_FLASH;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pair_optiga(cli_t* cli) {
|
||||
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)) {
|
||||
if (sectrue != initialize_secrets()) {
|
||||
// optiga_pairing_state set by initialize_secrets().
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Load the pairing secret from the flash memory.
|
||||
if (sectrue != secret_key_optiga_pairing(pairing_secret)) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_READ_FLASH;
|
||||
goto cleanup;
|
||||
}
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_READ_FLASH;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Execute the handshake to verify that the secret is stored in Optiga.
|
||||
|
136
core/embed/projects/prodtest/cmd/prodtest_secrets.c
Normal file
136
core/embed/projects/prodtest/cmd/prodtest_secrets.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <trezor_model.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <rtl/cli.h>
|
||||
#ifdef USE_OPTIGA
|
||||
#include <sec/optiga_commands.h>
|
||||
#endif
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
|
||||
#include "memzero.h"
|
||||
#include "rand.h"
|
||||
#include "secbool.h"
|
||||
|
||||
secbool generate_random_secret(uint8_t* secret, size_t length) {
|
||||
random_buffer(secret, length);
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
uint8_t optiga_secret[length];
|
||||
if (OPTIGA_SUCCESS != optiga_get_random(optiga_secret, length)) {
|
||||
return secfalse;
|
||||
}
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
secret[i] ^= optiga_secret[i];
|
||||
}
|
||||
memzero(optiga_secret, sizeof(optiga_secret));
|
||||
#endif
|
||||
|
||||
#ifdef USE_TROPIC
|
||||
// TODO: Generate randomness using tropic and xor it with `secret`.
|
||||
#endif
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool set_random_secret(uint8_t slot, size_t length) {
|
||||
uint8_t secret[length];
|
||||
uint8_t secret_read[length];
|
||||
|
||||
secbool ret = secfalse;
|
||||
|
||||
if (secret_key_writable(slot) != sectrue) {
|
||||
if (generate_random_secret(secret, sizeof(secret)) != sectrue) {
|
||||
ret = secfalse;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (secret_key_set(slot, secret, sizeof(secret)) != sectrue) {
|
||||
ret = secfalse;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (secret_key_get(slot, secret_read, sizeof(secret_read)) != sectrue) {
|
||||
ret = secfalse;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (memcmp(secret, secret_read, sizeof(secret)) != 0) {
|
||||
ret = secfalse;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
ret = sectrue;
|
||||
|
||||
cleanup:
|
||||
memzero(secret, sizeof(secret));
|
||||
memzero(secret_read, sizeof(secret_read));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void prodtest_secrets_init(cli_t* cli) {
|
||||
if (cli_arg_count(cli) > 0) {
|
||||
cli_error_arg_count(cli);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SECRET_PRIVILEGED_MASTER_KEY_SLOT
|
||||
if (set_random_secret(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
|
||||
SECRET_MASTER_KEY_SLOT_SIZE) != sectrue) {
|
||||
cli_error(cli, CLI_ERROR,
|
||||
"`set_random_secret` failed for privileged master key.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SECRET_UNPRIVILEGED_MASTER_KEY_SLOT
|
||||
if (set_random_secret(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
|
||||
SECRET_MASTER_KEY_SLOT_SIZE) != sectrue) {
|
||||
cli_error(cli, CLI_ERROR,
|
||||
"`set_random_secret` failed for unprivileged master key.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
#ifdef SECRET_OPTIGA_SLOT
|
||||
if (set_random_secret(SECRET_OPTIGA_SLOT, OPTIGA_PAIRING_SECRET_SIZE) !=
|
||||
sectrue) {
|
||||
cli_error(cli, CLI_ERROR,
|
||||
"`set_random_secret` failed for optiga pairing secret.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
cli_ok(cli, "");
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
PRODTEST_CLI_CMD(
|
||||
.name = "secrets-init",
|
||||
.func = prodtest_secrets_init,
|
||||
.info = "Generate and write secrets to flash",
|
||||
.args = ""
|
||||
);
|
Loading…
Reference in New Issue
Block a user