1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-08-01 19:38:33 +00:00

feat(core): Implement derivation from master key in secret API.

[no changelog]
This commit is contained in:
Andrew Kozlik 2025-06-26 19:51:46 +02:00 committed by Andrew Kozlik
parent 32c4d9f105
commit d933598df4
6 changed files with 160 additions and 18 deletions

View File

@ -21,12 +21,14 @@
#define SECRET_NUM_KEY_SLOTS 3
#define SECRET_MASTER_KEY_SLOT_SIZE 0x20
// first page: static
#define SECRET_HEADER_OFFSET 0x00
#define SECRET_HEADER_LEN 0x10
#define SECRET_KEY_SLOT_0_OFFSET 0x10
#define SECRET_KEY_SLOT_0_LEN 0x20
#define SECRET_KEY_SLOT_0_LEN SECRET_MASTER_KEY_SLOT_SIZE
#define SECRET_MONOTONIC_COUNTER_0_OFFSET 0x30
#define SECRET_MONOTONIC_COUNTER_0_LEN 0x400
@ -35,7 +37,8 @@
#define SECRET_MONOTONIC_COUNTER_1_LEN 0x400
#define SECRET_KEY_SLOT_1_OFFSET 0x830
#define SECRET_KEY_SLOT_1_LEN 0x20
#define SECRET_KEY_SLOT_1_LEN SECRET_MASTER_KEY_SLOT_SIZE
#define SECRET_KEY_SLOT_1_PUBLIC 1
#define SECRET_KEY_SLOT_2_OFFSET 0x850
#define SECRET_KEY_SLOT_2_LEN 0x20
@ -46,6 +49,6 @@
#define SECRET_BHK_LEN 0x20
// slot assignments
#define SECRET_OPTIGA_SLOT 0
#define SECRET_TROPIC_TREZOR_PRIVKEY_SLOT 1
#define SECRET_PRIVILEGED_MASTER_KEY_SLOT 0
#define SECRET_UNPRIVILEGED_MASTER_KEY_SLOT 1
#define SECRET_TROPIC_TROPIC_PUBKEY_SLOT 2

View File

@ -23,20 +23,35 @@
#ifdef SECURE_MODE
#ifdef SECRET_MASTER_KEY_SLOT
#include <ed25519-donna/ed25519.h>
secbool secret_key_mcu_device_auth(curve25519_key dest);
#endif // SECRET_MASTER_KEY_SLOT
#ifdef USE_OPTIGA
#include <ecdsa.h>
#define OPTIGA_PAIRING_SECRET_SIZE 32
secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]);
secbool secret_key_optiga_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
#endif
#endif // USE_OPTIGA
#ifdef USE_TROPIC
#include <ecdsa.h>
#include <ed25519-donna/ed25519.h>
secbool secret_key_tropic_public(curve25519_key dest);
secbool secret_key_tropic_pairing(curve25519_key dest);
#endif
secbool secret_key_tropic_pairing_unprivileged(curve25519_key dest);
secbool secret_key_tropic_pairing_privileged(curve25519_key dest);
secbool secret_key_tropic_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
#endif
#endif // USE_TROPIC
#endif // SECURE_MODE

View File

@ -26,22 +26,143 @@
#include <sec/secret.h>
#include <sec/secret_keys.h>
#ifdef USE_OPTIGA
secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) {
return secret_key_get(SECRET_OPTIGA_SLOT, dest, OPTIGA_PAIRING_SECRET_SIZE);
#ifdef SECRET_PRIVILEGED_MASTER_KEY_SLOT
#include "hmac.h"
#include "memzero.h"
#include "nist256p1.h"
// Key derivation indices
#define KEY_INDEX_MCU_DEVICE_AUTH 0
#define KEY_INDEX_OPTIGA_PAIRING 1
#define KEY_INDEX_OPTIGA_MASKING 2
#define KEY_INDEX_TROPIC_PAIRING_UNPRIVILEGED 3
#define KEY_INDEX_TROPIC_PAIRING_PRIVILEGED 4
#define KEY_INDEX_TROPIC_MASKING 5
static secbool secret_key_derive_sym(uint8_t slot, uint16_t index,
uint16_t subindex,
uint8_t dest[SHA256_DIGEST_LENGTH]) {
secbool ret = sectrue;
// The diversifier consists of:
// - the key derivation index (2 bytes big-endian), which identifies the
// purpose of the key,
// - the subindex (2 bytes big-endian), which is incremented until the derived
// key meets required criteria, and
// - the block index (1 byte), which can be used to produce outputs that are
// longer than 32 bytes.
uint8_t diversifier[] = {index >> 8, index & 0xff, subindex >> 8,
subindex & 0xff, 0};
uint8_t master_key[32] = {0};
ret = secret_key_get(slot, master_key, sizeof(master_key));
if (ret != sectrue) {
goto cleanup;
}
hmac_sha256(master_key, sizeof(master_key), diversifier, sizeof(diversifier),
dest);
cleanup:
memzero(master_key, sizeof(master_key));
return ret;
}
static secbool secret_key_derive_curve25519(uint8_t slot, uint16_t index,
curve25519_key dest) {
_Static_assert(sizeof(curve25519_key) == SHA256_DIGEST_LENGTH);
secbool ret = secret_key_derive_sym(slot, index, 0, dest);
dest[0] &= 248;
dest[31] &= 127;
dest[31] |= 64;
return ret;
}
#if defined(USE_OPTIGA) || defined(USE_TROPIC)
static secbool secret_key_derive_nist256p1(
uint8_t slot, uint16_t index, uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
_Static_assert(ECDSA_PRIVATE_KEY_SIZE == SHA256_DIGEST_LENGTH);
secbool ret = sectrue;
bignum256 s = {0};
for (uint16_t i = 0; i < 10000; i++) {
ret = secret_key_derive_sym(slot, index, i, dest);
if (ret != sectrue) {
goto cleanup;
}
bn_read_be(dest, &s);
if (!bn_is_zero(&s) && bn_is_less(&s, &nist256p1.order)) {
// Valid private key, we are done.
ret = sectrue;
goto cleanup;
}
// Invalid private key, we generate the next key in line.
}
// Loop exhausted all attempts without producing a valid private key.
ret = secfalse;
cleanup:
memzero(&s, sizeof(s));
return ret;
}
#endif
secbool secret_key_mcu_device_auth(curve25519_key dest) {
return secret_key_derive_curve25519(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
KEY_INDEX_MCU_DEVICE_AUTH, dest);
}
#ifdef USE_OPTIGA
secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) {
_Static_assert(OPTIGA_PAIRING_SECRET_SIZE == SHA256_DIGEST_LENGTH);
return secret_key_derive_sym(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
KEY_INDEX_OPTIGA_PAIRING, 0, dest);
}
secbool secret_key_optiga_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
return secret_key_derive_nist256p1(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
KEY_INDEX_OPTIGA_MASKING, dest);
}
#endif // USE_OPTIGA
#ifdef USE_TROPIC
secbool secret_key_tropic_public(curve25519_key dest) {
return secret_key_get(SECRET_TROPIC_TROPIC_PUBKEY_SLOT, dest,
sizeof(curve25519_key));
}
secbool secret_key_tropic_pairing(curve25519_key dest) {
return secret_key_get(SECRET_TROPIC_TREZOR_PRIVKEY_SLOT, dest,
sizeof(curve25519_key));
secbool secret_key_tropic_pairing_unprivileged(curve25519_key dest) {
return secret_key_derive_curve25519(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
KEY_INDEX_TROPIC_PAIRING_UNPRIVILEGED,
dest);
}
#endif
#endif
secbool secret_key_tropic_pairing_privileged(curve25519_key dest) {
return secret_key_derive_curve25519(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
KEY_INDEX_TROPIC_PAIRING_PRIVILEGED,
dest);
}
secbool secret_key_tropic_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
return secret_key_derive_nist256p1(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
KEY_INDEX_TROPIC_MASKING, dest);
}
#endif // USE_TROPIC
#else // SECRET_PRIVILEGED_MASTER_KEY_SLOT
#ifdef USE_OPTIGA
secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) {
return secret_key_get(SECRET_OPTIGA_SLOT, dest, OPTIGA_PAIRING_SECRET_SIZE);
}
#endif // USE_OPTIGA
#endif // SECRET_PRIVILEGED_MASTER_KEY_SLOT
#endif // SECURE_MODE

View File

@ -49,7 +49,7 @@ secbool secret_key_tropic_public(curve25519_key dest) {
return sectrue;
}
secbool secret_key_tropic_pairing(curve25519_key dest) {
secbool secret_key_tropic_pairing_privileged(curve25519_key dest) {
memcpy(dest, SECRET_TROPIC_PAIRING_BYTES, sizeof(curve25519_key));
return sectrue;
}

View File

@ -61,7 +61,8 @@ bool tropic_init(void) {
}
secbool pubkey_ok = secret_key_tropic_public(tropic_secret_tropic_pubkey);
secbool privkey_ok = secret_key_tropic_pairing(tropic_secret_trezor_privkey);
secbool privkey_ok =
secret_key_tropic_pairing_privileged(tropic_secret_trezor_privkey);
if (pubkey_ok == sectrue && privkey_ok == sectrue) {
uint8_t trezor_pubkey[32] = {0};

View File

@ -61,6 +61,8 @@ typedef struct {
// (4 + 32 + 1 + 4 [checksum]) * 8 / log2(58) plus NUL.
#define MAX_WIF_SIZE (57)
#define ECDSA_PRIVATE_KEY_SIZE 32
void point_copy(const curve_point *cp1, curve_point *cp2);
void point_add(const ecdsa_curve *curve, const curve_point *cp1,
curve_point *cp2);