diff --git a/CHANGELOG.md b/CHANGELOG.md index e96ba6d64..5bfb921a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [4.0.0] + +### Changed +- `lt_ecc_ecdsa_sign` now expects a 32-byte hash instead of an arbitrary message - provided data are not hashed anymore. +Select a hash function (e.g., SHA256) which outputs 32 bytes (or pad/truncate the output accordingly). + +### Added + +### Fixed + +### Removed + ## [3.2.0] ### Changed diff --git a/include/libtropic.h b/include/libtropic.h index 84668dd1d..4870013b0 100644 --- a/include/libtropic.h +++ b/include/libtropic.h @@ -549,21 +549,22 @@ lt_ret_t lt_ecc_key_read(lt_handle_t *h, const lt_ecc_slot_t ecc_slot, uint8_t * lt_ret_t lt_ecc_key_erase(lt_handle_t *h, const lt_ecc_slot_t ecc_slot); /** - * @brief Performs ECDSA sign of a message with a private ECC key stored in TROPIC01 + * @brief Calculates ECDSA signature of a message hash (32 bytes) with a private ECC key stored in + * TROPIC01. * - * @param h Handle for communication with TROPIC01 - * @param ecc_slot Slot containing a private key, TR01_ECC_SLOT_0 - TR01_ECC_SLOT_31 - * @param msg Buffer containing a message - * @param msg_len Length of the message - * @param rs Buffer for storing a signature in a form of R and S bytes (should always have - * length 64B) + * @param h Handle for communication with TROPIC01. + * @param ecc_slot Slot containing a private key, TR01_ECC_SLOT_0 - TR01_ECC_SLOT_31. + * @param msg_hash Buffer containing a 32-byte hash of the message to sign. + * @param msg_hash_len Length of the hash. + * @param rs Buffer for storing a signature in a form of R and S bytes (should always have + * length 64B). * - * @retval LT_OK Function executed successfully - * @retval other Function did not execute successully, you might use lt_ret_verbose() to get - * verbose encoding of returned value + * @retval LT_OK Function executed successfully. + * @retval other Function did not execute successully, you might use lt_ret_verbose() to + * get verbose encoding of returned value. */ -lt_ret_t lt_ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t ecc_slot, const uint8_t *msg, - const uint32_t msg_len, uint8_t *rs); +lt_ret_t lt_ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t ecc_slot, const uint8_t *msg_hash, + const uint32_t msg_hash_len, uint8_t *rs); /** * @brief Performs EdDSA sign of a message with a private ECC key stored in TROPIC01 diff --git a/include/libtropic_l3.h b/include/libtropic_l3.h index 160552e94..769a2796c 100644 --- a/include/libtropic_l3.h +++ b/include/libtropic_l3.h @@ -462,14 +462,14 @@ lt_ret_t lt_in__ecc_key_erase(lt_handle_t *h); * @note Used for separate L3 communication, for more information read info * at the top of this file. * - * @param h Handle for communication with TROPIC01 - * @param slot ECC key slot to use for signing - * @param msg Message to sign - * @param msg_len Length of the message - * @return LT_OK if success, otherwise returns other error code. - */ -lt_ret_t lt_out__ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t slot, const uint8_t *msg, - const uint32_t msg_len); + * @param h Handle for communication with TROPIC01. + * @param slot ECC key slot to use for signing. + * @param msg_hash Buffer containing a 32-byte hash of the message to sign. + * @param msg_hash_len Length of the hash. + * @return LT_OK if success, otherwise returns other error code. + */ +lt_ret_t lt_out__ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t slot, const uint8_t *msg_hash, + const uint32_t msg_hash_len); /** * @brief Decodes ECDSA_Sign result payload. diff --git a/src/libtropic.c b/src/libtropic.c index 3743928fa..73770dd2c 100644 --- a/src/libtropic.c +++ b/src/libtropic.c @@ -1337,17 +1337,19 @@ lt_ret_t lt_ecc_key_erase(lt_handle_t *h, const lt_ecc_slot_t ecc_slot) return lt_in__ecc_key_erase(h); } -lt_ret_t lt_ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t ecc_slot, const uint8_t *msg, - const uint32_t msg_len, uint8_t *rs) +lt_ret_t lt_ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t ecc_slot, const uint8_t *msg_hash, + const uint32_t msg_hash_len, uint8_t *rs) { - if (!h || !msg || !rs || (ecc_slot > TR01_ECC_SLOT_31)) { + if (!h || !msg_hash || !rs || (ecc_slot > TR01_ECC_SLOT_31) || + msg_hash_len != TR01_L3_ECDSA_SIGN_CMD_MSG_HASH_LEN) { return LT_PARAM_ERR; } + if (h->l3.session_status != LT_SECURE_SESSION_ON) { return LT_HOST_NO_SESSION; } - lt_ret_t ret = lt_out__ecc_ecdsa_sign(h, ecc_slot, msg, msg_len); + lt_ret_t ret = lt_out__ecc_ecdsa_sign(h, ecc_slot, msg_hash, msg_hash_len); if (ret != LT_OK) { return ret; } diff --git a/src/libtropic_l3.c b/src/libtropic_l3.c index 33ca4d830..cd1368780 100644 --- a/src/libtropic_l3.c +++ b/src/libtropic_l3.c @@ -1202,39 +1202,17 @@ lt_ret_t lt_in__ecc_key_erase(lt_handle_t *h) return LT_OK; } -lt_ret_t lt_out__ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t slot, const uint8_t *msg, - const uint32_t msg_len) +lt_ret_t lt_out__ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t slot, const uint8_t *msg_hash, + const uint32_t msg_hash_len) { - if (!h || (slot > TR01_ECC_SLOT_31) || !msg) { + if (!h || (slot > TR01_ECC_SLOT_31) || !msg_hash || + msg_hash_len != TR01_L3_ECDSA_SIGN_CMD_MSG_HASH_LEN) { return LT_PARAM_ERR; } if (h->l3.session_status != LT_SECURE_SESSION_ON) { return LT_HOST_NO_SESSION; } - // Prepare hash of a message - uint8_t msg_hash[32] = {0}; - lt_ret_t ret; - lt_ret_t ret_unused; - - // Initialize SHA-256 context. - ret = lt_sha256_init(h->l3.crypto_ctx); - if (ret != LT_OK) { - return ret; - } - ret = lt_sha256_start(h->l3.crypto_ctx); - if (ret != LT_OK) { - goto sha256_cleanup; - } - ret = lt_sha256_update(h->l3.crypto_ctx, (uint8_t *)msg, msg_len); - if (ret != LT_OK) { - goto sha256_cleanup; - } - ret = lt_sha256_finish(h->l3.crypto_ctx, msg_hash); - if (ret != LT_OK) { - goto sha256_cleanup; - } - // Pointer to access l3 buffer when it contains command data struct lt_l3_ecdsa_sign_cmd_t *p_l3_cmd = (struct lt_l3_ecdsa_sign_cmd_t *)h->l3.buff; @@ -1244,14 +1222,7 @@ lt_ret_t lt_out__ecc_ecdsa_sign(lt_handle_t *h, const lt_ecc_slot_t slot, const p_l3_cmd->slot = slot; memcpy(p_l3_cmd->msg_hash, msg_hash, sizeof(p_l3_cmd->msg_hash)); - ret = lt_l3_encrypt_request(&h->l3); - -sha256_cleanup: - ret_unused = lt_sha256_deinit(h->l3.crypto_ctx); - lt_secure_memzero(msg_hash, sizeof(msg_hash)); - LT_UNUSED(ret_unused); - - return ret; + return lt_l3_encrypt_request(&h->l3); } lt_ret_t lt_in__ecc_ecdsa_sign(lt_handle_t *h, uint8_t *rs) diff --git a/src/lt_l3_api_structs.h b/src/lt_l3_api_structs.h index c82f4398f..61ec929ef 100644 --- a/src/lt_l3_api_structs.h +++ b/src/lt_l3_api_structs.h @@ -1202,6 +1202,8 @@ LT_STATIC_ASSERT( #define TR01_L3_ECDSA_SIGN_CMD_ID 0x70 /** @brief Command length (fields: CMD_ID + CMD_DATA) */ #define TR01_L3_ECDSA_SIGN_CMD_SIZE 48u +/** @brief Length of the msg_hash field */ +#define TR01_L3_ECDSA_SIGN_CMD_MSG_HASH_LEN 32u /** @brief Result length (fields: RESULT + RES_DATA) */ #define TR01_L3_ECDSA_SIGN_RES_SIZE 80u @@ -1230,7 +1232,7 @@ struct lt_l3_ecdsa_sign_cmd_t { * @brief * The hash of the message to sign (max size of 32 bytes). */ - uint8_t msg_hash[32]; /**< Hash of the Message to sign. */ + uint8_t msg_hash[TR01_L3_ECDSA_SIGN_CMD_MSG_HASH_LEN]; /**< Hash of the Message to sign. */ } __attribute__((packed)); // clang-format off diff --git a/tests/functional/src/libtropic_functional_tests.h b/tests/functional/src/libtropic_functional_tests.h index ae57d5c39..d1104a6a1 100644 --- a/tests/functional/src/libtropic_functional_tests.h +++ b/tests/functional/src/libtropic_functional_tests.h @@ -48,14 +48,15 @@ void lt_test_rev_eddsa_sign(lt_handle_t *h); * Test steps: * 1. Start Secure Session with pairing key slot 0. * 2. Generate random message with random size for signing. - * 3. Sign message with each empty slot and check for fail. - * 4. Store pre-generated private key to each slot. - * 5. Read the public key from each slot. - * 6. Sign the message with each slot. - * 7. Verify the signature. - * 8. Erase each slot. - * 9. Sign message with each erased slot and check for fail. - * 10. Do steps 2-9, but instead of storing the key, generate it. + * 3. Calculate a hash of the message. + * 4. Sign message hash with each empty slot and check for fail. + * 5. Store pre-generated private key to each slot. + * 6. Read the public key from each slot. + * 7. Sign the message hash with each slot. + * 8. Verify the signature. + * 9. Erase each slot. + * 10. Sign message hash with each erased slot and check for fail. + * 11. Do steps 2-9, but instead of storing the key, generate it. * * @param h Handle for communication with TROPIC01 */ diff --git a/tests/functional/src/lt_test_rev_ecdsa_sign.c b/tests/functional/src/lt_test_rev_ecdsa_sign.c index 8c9cd4a6b..0d058fade 100644 --- a/tests/functional/src/lt_test_rev_ecdsa_sign.c +++ b/tests/functional/src/lt_test_rev_ecdsa_sign.c @@ -122,8 +122,15 @@ void lt_test_rev_ecdsa_sign(lt_handle_t *h) msg_to_sign_len); LT_TEST_ASSERT(LT_OK, lt_random_bytes(h, msg_to_sign, msg_to_sign_len)); - LT_LOG_INFO("Signing message with empty slot (should fail)..."); - LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_to_sign, msg_to_sign_len, rs)); + LT_LOG_INFO("Calculating hash of the message..."); + LT_TEST_ASSERT(LT_OK, lt_sha256_init(h->l3.crypto_ctx)); + LT_TEST_ASSERT(LT_OK, lt_sha256_start(h->l3.crypto_ctx)); + LT_TEST_ASSERT(LT_OK, lt_sha256_update(h->l3.crypto_ctx, msg_to_sign, msg_to_sign_len)); + LT_TEST_ASSERT(LT_OK, lt_sha256_finish(h->l3.crypto_ctx, msg_hash)); + LT_TEST_ASSERT(LT_OK, lt_sha256_deinit(h->l3.crypto_ctx)); + + LT_LOG_INFO("Signing message hash with empty slot (should fail)..."); + LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_hash, sizeof(msg_hash), rs)); LT_LOG_INFO("Storing private key pre-generated using P256 curve..."); LT_TEST_ASSERT(LT_OK, lt_ecc_key_store(h, i, TR01_CURVE_P256, priv_test_key)); @@ -132,15 +139,8 @@ void lt_test_rev_ecdsa_sign(lt_handle_t *h) LT_TEST_ASSERT(LT_OK, lt_ecc_key_read(h, i, read_pub_key, sizeof(read_pub_key), &curve, &origin)); - LT_LOG_INFO("Signing message..."); - LT_TEST_ASSERT(LT_OK, lt_ecc_ecdsa_sign(h, i, msg_to_sign, msg_to_sign_len, rs)); - - LT_LOG_INFO("Calculating hash of the message before verifying the signature..."); - LT_TEST_ASSERT(LT_OK, lt_sha256_init(h->l3.crypto_ctx)); - LT_TEST_ASSERT(LT_OK, lt_sha256_start(h->l3.crypto_ctx)); - LT_TEST_ASSERT(LT_OK, lt_sha256_update(h->l3.crypto_ctx, msg_to_sign, msg_to_sign_len)); - LT_TEST_ASSERT(LT_OK, lt_sha256_finish(h->l3.crypto_ctx, msg_hash)); - LT_TEST_ASSERT(LT_OK, lt_sha256_deinit(h->l3.crypto_ctx)); + LT_LOG_INFO("Signing message hash..."); + LT_TEST_ASSERT(LT_OK, lt_ecc_ecdsa_sign(h, i, msg_hash, sizeof(msg_hash), rs)); LT_LOG_INFO("Verifying signature..."); LT_TEST_ASSERT(1, uECC_verify(read_pub_key, msg_hash, sizeof(msg_hash), rs, uECC_secp256r1())); @@ -148,8 +148,8 @@ void lt_test_rev_ecdsa_sign(lt_handle_t *h) LT_LOG_INFO("Erasing the slot..."); LT_TEST_ASSERT(LT_OK, lt_ecc_key_erase(h, i)); - LT_LOG_INFO("Signing message with erased slot (should fail)..."); - LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_to_sign, msg_to_sign_len, rs)); + LT_LOG_INFO("Signing message hash with erased slot (should fail)..."); + LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_hash, sizeof(msg_hash), rs)); } LT_LOG_LINE(); @@ -166,8 +166,15 @@ void lt_test_rev_ecdsa_sign(lt_handle_t *h) msg_to_sign_len); LT_TEST_ASSERT(LT_OK, lt_random_bytes(h, msg_to_sign, msg_to_sign_len)); - LT_LOG_INFO("Signing message with empty slot (should fail)..."); - LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_to_sign, msg_to_sign_len, rs)); + LT_LOG_INFO("Calculating hash of the message..."); + LT_TEST_ASSERT(LT_OK, lt_sha256_init(h->l3.crypto_ctx)); + LT_TEST_ASSERT(LT_OK, lt_sha256_start(h->l3.crypto_ctx)); + LT_TEST_ASSERT(LT_OK, lt_sha256_update(h->l3.crypto_ctx, msg_to_sign, msg_to_sign_len)); + LT_TEST_ASSERT(LT_OK, lt_sha256_finish(h->l3.crypto_ctx, msg_hash)); + LT_TEST_ASSERT(LT_OK, lt_sha256_deinit(h->l3.crypto_ctx)); + + LT_LOG_INFO("Signing message hash with empty slot (should fail)..."); + LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_hash, sizeof(msg_hash), rs)); LT_LOG_INFO("Generating private key using P256 curve..."); LT_TEST_ASSERT(LT_OK, lt_ecc_key_generate(h, i, TR01_CURVE_P256)); @@ -176,15 +183,8 @@ void lt_test_rev_ecdsa_sign(lt_handle_t *h) LT_TEST_ASSERT(LT_OK, lt_ecc_key_read(h, i, read_pub_key, sizeof(read_pub_key), &curve, &origin)); - LT_LOG_INFO("Signing message..."); - LT_TEST_ASSERT(LT_OK, lt_ecc_ecdsa_sign(h, i, msg_to_sign, msg_to_sign_len, rs)); - - LT_LOG_INFO("Calculating hash of the message before verifying the signature..."); - LT_TEST_ASSERT(LT_OK, lt_sha256_init(h->l3.crypto_ctx)); - LT_TEST_ASSERT(LT_OK, lt_sha256_start(h->l3.crypto_ctx)); - LT_TEST_ASSERT(LT_OK, lt_sha256_update(h->l3.crypto_ctx, msg_to_sign, msg_to_sign_len)); - LT_TEST_ASSERT(LT_OK, lt_sha256_finish(h->l3.crypto_ctx, msg_hash)); - LT_TEST_ASSERT(LT_OK, lt_sha256_deinit(h->l3.crypto_ctx)); + LT_LOG_INFO("Signing message hash..."); + LT_TEST_ASSERT(LT_OK, lt_ecc_ecdsa_sign(h, i, msg_hash, sizeof(msg_hash), rs)); LT_LOG_INFO("Verifying signature..."); LT_TEST_ASSERT(1, uECC_verify(read_pub_key, msg_hash, sizeof(msg_hash), rs, uECC_secp256r1())); @@ -192,8 +192,8 @@ void lt_test_rev_ecdsa_sign(lt_handle_t *h) LT_LOG_INFO("Erasing the slot..."); LT_TEST_ASSERT(LT_OK, lt_ecc_key_erase(h, i)); - LT_LOG_INFO("Signing message with erased slot (should fail)..."); - LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_to_sign, msg_to_sign_len, rs)); + LT_LOG_INFO("Signing message hash with erased slot (should fail)..."); + LT_TEST_ASSERT(LT_L3_INVALID_KEY, lt_ecc_ecdsa_sign(h, i, msg_hash, sizeof(msg_hash), rs)); } LT_LOG_LINE();