mirror of
https://github.com/trezor/trezor-firmware.git
synced 2026-02-19 16:22:44 +01:00
feat(core): Use ML-DSA-44 for MCU device attestation key.
[no changelog]
This commit is contained in:
committed by
Andrew Kozlik
parent
58245dd51d
commit
ba51fa46d3
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -41,3 +41,7 @@
|
||||
path = vendor/sphincsplus
|
||||
url = https://github.com/sphincs/sphincsplus/
|
||||
branch = consistent-basew
|
||||
[submodule "vendor/mldsa-native"]
|
||||
path = vendor/mldsa-native
|
||||
url = https://github.com/pq-code-package/mldsa-native.git
|
||||
ignore = untracked
|
||||
|
||||
@@ -144,6 +144,17 @@ if 'boot_ucb' in FEATURES_AVAILABLE:
|
||||
'vendor/sphincsplus/ref/wots.c',
|
||||
]
|
||||
|
||||
SOURCE_MLDSA = [
|
||||
'vendor/mldsa-native/mldsa/fips202/fips202.c',
|
||||
'vendor/mldsa-native/mldsa/fips202/fips202x4.c',
|
||||
'vendor/mldsa-native/mldsa/fips202/keccakf1600.c',
|
||||
'vendor/mldsa-native/mldsa/ntt.c',
|
||||
'vendor/mldsa-native/mldsa/packing.c',
|
||||
'vendor/mldsa-native/mldsa/poly.c',
|
||||
'vendor/mldsa-native/mldsa/polyvec.c',
|
||||
'vendor/mldsa-native/mldsa/sign.c',
|
||||
]
|
||||
|
||||
# modtrezorui
|
||||
CPPPATH_MOD += [
|
||||
'vendor/micropython/lib/uzlib'
|
||||
@@ -303,6 +314,7 @@ obj_program.extend(env.Object(source=SOURCE_MOD))
|
||||
obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero'))
|
||||
obj_program.extend(env.Object(source=SOURCE_PRODTEST))
|
||||
obj_program.extend(env.Object(source=SOURCE_HAL))
|
||||
obj_program.extend(env.Object(source=SOURCE_MLDSA))
|
||||
|
||||
if 'boot_ucb' in FEATURES_AVAILABLE:
|
||||
obj_program += env.Object(
|
||||
|
||||
@@ -106,6 +106,16 @@ if FEATURE_FLAGS["AES_GCM"]:
|
||||
'vendor/trezor-crypto/aes/aesgcm.c',
|
||||
]
|
||||
|
||||
SOURCE_MLDSA = [
|
||||
'vendor/mldsa-native/mldsa/fips202/fips202.c',
|
||||
'vendor/mldsa-native/mldsa/fips202/fips202x4.c',
|
||||
'vendor/mldsa-native/mldsa/fips202/keccakf1600.c',
|
||||
'vendor/mldsa-native/mldsa/ntt.c',
|
||||
'vendor/mldsa-native/mldsa/packing.c',
|
||||
'vendor/mldsa-native/mldsa/poly.c',
|
||||
'vendor/mldsa-native/mldsa/polyvec.c',
|
||||
'vendor/mldsa-native/mldsa/sign.c',
|
||||
]
|
||||
|
||||
# modtrezorui
|
||||
CPPPATH_MOD += [
|
||||
@@ -287,6 +297,7 @@ obj_program += env.Object(source=SOURCE_MOD)
|
||||
obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero')
|
||||
obj_program += env.Object(source=SOURCE_PRODTEST)
|
||||
obj_program += env.Object(source=SOURCE_HAL)
|
||||
obj_program += env.Object(source=SOURCE_MLDSA)
|
||||
|
||||
program_elf = env.Command(
|
||||
target='prodtest.elf',
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define SECRET_KEY_SLOT_2_PUBLIC 1
|
||||
|
||||
#define SECRET_MCU_DEVICE_CERT_OFFSET 0x870
|
||||
#define SECRET_MCU_DEVICE_CERT_SIZE 0x400
|
||||
#define SECRET_MCU_DEVICE_CERT_SIZE 0x1000
|
||||
|
||||
#define SECRET_LOCK_SLOT_OFFSET 0x1FF0
|
||||
#define SECRET_LOCK_SLOT_LEN 0x10
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "sha2.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <../vendor/mldsa-native/mldsa/sign.h>
|
||||
|
||||
// Identifier of context-specific constructed tag 3, which is used for
|
||||
// extensions in X.509.
|
||||
#define DER_X509_EXTENSIONS 0xa3
|
||||
@@ -59,6 +61,12 @@ static const uint8_t EDDSA_25519[] = {
|
||||
0x2b, 0x65, 0x70, // corresponds to EdDSA 25519 in X.509
|
||||
};
|
||||
|
||||
static const uint8_t MLDSA44[] = {
|
||||
0x30, 0x0b, // a sequence of 11 bytes
|
||||
0x06, 0x09, // an OID of 9 bytes
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11, // corresponds to id-ml-dsa-44 in X.509
|
||||
};
|
||||
|
||||
static const uint8_t OID_COMMON_NAME[] = {
|
||||
0x06, 0x03, // an OID of 3 bytes
|
||||
0x55, 0x04, 0x03, // corresponds to commonName in X.509
|
||||
@@ -87,7 +95,11 @@ static const uint8_t SUBJECT_COMMON_NAME[] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
typedef enum { ALG_ID_ECDSA_P256_WITH_SHA256, ALG_ID_EDDSA_25519 } alg_id_t;
|
||||
typedef enum {
|
||||
ALG_ID_ECDSA_P256_WITH_SHA256,
|
||||
ALG_ID_EDDSA_25519,
|
||||
ALG_ID_MLDSA44
|
||||
} alg_id_t;
|
||||
|
||||
static bool get_algorithm(DER_ITEM* alg, alg_id_t* alg_id) {
|
||||
if (alg->buf.size == sizeof(ECDSA_P256_WITH_SHA256) &&
|
||||
@@ -103,6 +115,12 @@ static bool get_algorithm(DER_ITEM* alg, alg_id_t* alg_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (alg->buf.size == sizeof(MLDSA44) &&
|
||||
memcmp(alg->buf.data, MLDSA44, sizeof(MLDSA44)) == 0) {
|
||||
*alg_id = ALG_ID_MLDSA44;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -275,6 +293,19 @@ static bool verify_signature(alg_id_t alg_id, const uint8_t* pub_key,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (alg_id == ALG_ID_MLDSA44) {
|
||||
if (pub_key_size != CRYPTO_PUBLICKEYBYTES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (crypto_sign_verify(sig, sig_size, msg, msg_size, (const uint8_t*)"", 0,
|
||||
pub_key) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <trezor_model.h>
|
||||
#endif
|
||||
|
||||
#include <../vendor/mldsa-native/mldsa/sign.h>
|
||||
|
||||
secbool generate_random_secret(uint8_t* secret, size_t length) {
|
||||
random_buffer(secret, length);
|
||||
|
||||
@@ -141,15 +143,20 @@ static void prodtest_secrets_get_mcu_device_key(cli_t* cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
ed25519_secret_key mcu_private = {0};
|
||||
if (secret_key_mcu_device_auth(mcu_private) != sectrue) {
|
||||
uint8_t seed[MLDSA_SEEDBYTES] = {0};
|
||||
if (secret_key_mcu_device_auth(seed) != sectrue) {
|
||||
cli_error(cli, CLI_ERROR, "`secret_key_mcu_device_auth()` failed.");
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
ed25519_public_key mcu_public = {0};
|
||||
ed25519_publickey(mcu_private, mcu_public);
|
||||
|
||||
uint8_t output[sizeof(ed25519_public_key) + NOISE_TAG_SIZE] = {0};
|
||||
uint8_t mcu_public[CRYPTO_PUBLICKEYBYTES] = {0};
|
||||
uint8_t mcu_private[CRYPTO_SECRETKEYBYTES] = {0};
|
||||
if (crypto_sign_keypair_internal(mcu_public, mcu_private, seed) != 0) {
|
||||
cli_error(cli, CLI_ERROR, "`crypto_sign_keypair_internal()` failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint8_t output[sizeof(mcu_public) + NOISE_TAG_SIZE] = {0};
|
||||
if (!secure_channel_encrypt(mcu_public, sizeof(mcu_public), NULL, 0,
|
||||
output)) {
|
||||
// `secure_channel_handshake_2()` might not have been called
|
||||
@@ -160,31 +167,56 @@ static void prodtest_secrets_get_mcu_device_key(cli_t* cli) {
|
||||
cli_ok_hexdata(cli, output, sizeof(output));
|
||||
|
||||
cleanup:
|
||||
memzero(seed, sizeof(seed));
|
||||
memzero(mcu_private, sizeof(mcu_private));
|
||||
}
|
||||
|
||||
#ifndef TREZOR_EMULATOR
|
||||
static bool check_device_cert_chain(cli_t* cli, const uint8_t* chain,
|
||||
size_t chain_size) {
|
||||
ed25519_secret_key mcu_private = {0};
|
||||
if (secret_key_mcu_device_auth(mcu_private) != sectrue) {
|
||||
bool ret = false;
|
||||
|
||||
uint8_t seed[MLDSA_SEEDBYTES] = {0};
|
||||
if (secret_key_mcu_device_auth(seed) != sectrue) {
|
||||
cli_error(cli, CLI_ERROR, "`secret_key_mcu_device_auth()` failed.");
|
||||
return false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint8_t mcu_public[CRYPTO_PUBLICKEYBYTES] = {0};
|
||||
uint8_t mcu_private[CRYPTO_SECRETKEYBYTES] = {0};
|
||||
if (crypto_sign_keypair_internal(mcu_public, mcu_private, seed) != 0) {
|
||||
cli_error(cli, CLI_ERROR, "`crypto_sign_keypair_internal()` failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint8_t rnd[MLDSA_RNDBYTES] = {0};
|
||||
random_buffer(rnd, sizeof(rnd));
|
||||
|
||||
// The challenge is intentionally constant zero.
|
||||
const uint8_t ENCODED_EMPTY_CONTEXT_STRING[] = {0, 0};
|
||||
uint8_t challenge[CHALLENGE_SIZE] = {0};
|
||||
ed25519_signature signature = {0};
|
||||
ed25519_sign(challenge, sizeof(challenge), mcu_private, signature);
|
||||
memzero(mcu_private, sizeof(mcu_private));
|
||||
|
||||
if (!check_cert_chain(cli, chain, chain_size, signature, sizeof(signature),
|
||||
challenge)) {
|
||||
// Error returned by check_cert_chain().
|
||||
return false;
|
||||
uint8_t signature[CRYPTO_BYTES] = {0};
|
||||
size_t siglen = 0;
|
||||
if (crypto_sign_signature_internal(
|
||||
signature, &siglen, challenge, sizeof(challenge),
|
||||
ENCODED_EMPTY_CONTEXT_STRING, sizeof(ENCODED_EMPTY_CONTEXT_STRING),
|
||||
rnd, mcu_private, 0) != 0) {
|
||||
cli_error(cli, CLI_ERROR, "`crypto_sign_signature()` failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!check_cert_chain(cli, chain, chain_size, signature, siglen, challenge)) {
|
||||
// Error returned by check_cert_chain().
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
||||
cleanup:
|
||||
memzero(seed, sizeof(seed));
|
||||
memzero(mcu_private, sizeof(mcu_private));
|
||||
memzero(rnd, sizeof(rnd));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
typedef struct cli cli_t;
|
||||
|
||||
// Maximum length of command line input (including command, arguments)
|
||||
#define CLI_LINE_BUFFER_SIZE 4096
|
||||
#define CLI_LINE_BUFFER_SIZE 8192
|
||||
// Maximum number of command arguments + 1
|
||||
#define CLI_MAX_ARGS 64
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
#define SECRET_KEY_MASKING
|
||||
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
#include <../vendor/mldsa-native/mldsa/params.h>
|
||||
|
||||
secbool secret_key_mcu_device_auth(ed25519_secret_key dest);
|
||||
secbool secret_key_mcu_device_auth(uint8_t dest[MLDSA_SEEDBYTES]);
|
||||
|
||||
#endif // SECRET_MASTER_KEY_SLOT_SIZE
|
||||
|
||||
|
||||
@@ -71,17 +71,6 @@ cleanup:
|
||||
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]) {
|
||||
@@ -114,9 +103,10 @@ cleanup:
|
||||
}
|
||||
#endif
|
||||
|
||||
secbool secret_key_mcu_device_auth(ed25519_secret_key dest) {
|
||||
return secret_key_derive_curve25519(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
|
||||
KEY_INDEX_MCU_DEVICE_AUTH, dest);
|
||||
secbool secret_key_mcu_device_auth(uint8_t dest[MLDSA_SEEDBYTES]) {
|
||||
_Static_assert(MLDSA_SEEDBYTES == SHA256_DIGEST_LENGTH);
|
||||
return secret_key_derive_sym(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
|
||||
KEY_INDEX_MCU_DEVICE_AUTH, 0, dest);
|
||||
}
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
@@ -133,6 +123,17 @@ secbool secret_key_optiga_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
|
||||
#endif // USE_OPTIGA
|
||||
|
||||
#ifdef USE_TROPIC
|
||||
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;
|
||||
}
|
||||
|
||||
secbool secret_key_tropic_public(curve25519_key dest) {
|
||||
return secret_key_get(SECRET_TROPIC_TROPIC_PUBKEY_SLOT, dest,
|
||||
sizeof(curve25519_key));
|
||||
|
||||
@@ -44,8 +44,9 @@ _Static_assert(sizeof(SECRET_TROPIC_PAIRING_BYTES) == sizeof(curve25519_key),
|
||||
_Static_assert(sizeof(SECRET_TROPIC_PUBKEY_BYTES) == sizeof(curve25519_key),
|
||||
"Invalid size of Tropic public key");
|
||||
|
||||
secbool secret_key_mcu_device_auth(ed25519_secret_key dest) {
|
||||
memset(dest, 3, sizeof(ed25519_secret_key));
|
||||
secbool secret_key_mcu_device_auth(uint8_t dest[MLDSA_SEEDBYTES]) {
|
||||
_Static_assert(MLDSA_SEEDBYTES == SHA256_DIGEST_LENGTH);
|
||||
memset(dest, 3, SHA256_DIGEST_LENGTH);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
|
||||
1
core/vendor/mldsa-native
vendored
Symbolic link
1
core/vendor/mldsa-native
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../../vendor/mldsa-native/
|
||||
1
vendor/mldsa-native
vendored
Submodule
1
vendor/mldsa-native
vendored
Submodule
Submodule vendor/mldsa-native added at 6a9e7f315d
Reference in New Issue
Block a user