diff --git a/.gitmodules b/.gitmodules index 94ecc04554..c04fee7ad6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 6f6f59a8fb..31c91531c8 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -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( diff --git a/core/SConscript.prodtest_emu b/core/SConscript.prodtest_emu index d7d037625b..b5790ac379 100644 --- a/core/SConscript.prodtest_emu +++ b/core/SConscript.prodtest_emu @@ -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', diff --git a/core/embed/models/T3W1/secret_layout.h b/core/embed/models/T3W1/secret_layout.h index 601a7a6b43..0fedd8abab 100644 --- a/core/embed/models/T3W1/secret_layout.h +++ b/core/embed/models/T3W1/secret_layout.h @@ -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 diff --git a/core/embed/projects/prodtest/cmd/common.c b/core/embed/projects/prodtest/cmd/common.c index ed7727083c..a8d533f7ef 100644 --- a/core/embed/projects/prodtest/cmd/common.c +++ b/core/embed/projects/prodtest/cmd/common.c @@ -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; } diff --git a/core/embed/projects/prodtest/cmd/prodtest_secrets.c b/core/embed/projects/prodtest/cmd/prodtest_secrets.c index b13777b440..e929ebe7d3 100644 --- a/core/embed/projects/prodtest/cmd/prodtest_secrets.c +++ b/core/embed/projects/prodtest/cmd/prodtest_secrets.c @@ -38,6 +38,8 @@ #include #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 diff --git a/core/embed/rtl/inc/rtl/cli.h b/core/embed/rtl/inc/rtl/cli.h index 6c36d1d613..ebea207ee1 100644 --- a/core/embed/rtl/inc/rtl/cli.h +++ b/core/embed/rtl/inc/rtl/cli.h @@ -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 diff --git a/core/embed/sec/secret/inc/sec/secret_keys.h b/core/embed/sec/secret/inc/sec/secret_keys.h index dafed935f8..cf13ad0db7 100644 --- a/core/embed/sec/secret/inc/sec/secret_keys.h +++ b/core/embed/sec/secret/inc/sec/secret_keys.h @@ -27,9 +27,9 @@ #define SECRET_KEY_MASKING -#include +#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 diff --git a/core/embed/sec/secret/stm32u5/secret_keys.c b/core/embed/sec/secret/stm32u5/secret_keys.c index 6924151e02..41b448aa3d 100644 --- a/core/embed/sec/secret/stm32u5/secret_keys.c +++ b/core/embed/sec/secret/stm32u5/secret_keys.c @@ -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)); diff --git a/core/embed/sec/secret/unix/secret_keys.c b/core/embed/sec/secret/unix/secret_keys.c index 660401d164..145f082ec8 100644 --- a/core/embed/sec/secret/unix/secret_keys.c +++ b/core/embed/sec/secret/unix/secret_keys.c @@ -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; } diff --git a/core/vendor/mldsa-native b/core/vendor/mldsa-native new file mode 120000 index 0000000000..a4189375bc --- /dev/null +++ b/core/vendor/mldsa-native @@ -0,0 +1 @@ +../../vendor/mldsa-native/ \ No newline at end of file diff --git a/vendor/mldsa-native b/vendor/mldsa-native new file mode 160000 index 0000000000..6a9e7f315d --- /dev/null +++ b/vendor/mldsa-native @@ -0,0 +1 @@ +Subproject commit 6a9e7f315d664c4dce260c0fe3842fdcfc233f2b