lms: drop the aliasing memset in create_merkle_internal_value

0xiviel's review found that the memset added to
create_merkle_internal_value() breaks LMS verification: in
mbedtls_lms_verify(), Tc_candidate_root_node is passed as out while
simultaneously being left_node or right_node as the Merkle path is
walked bottom-up -- the memset wipes the running candidate before
psa_hash_update() reads it as an input, on 100 of 4192 calls in
test_suite_lms at this head, failing 9 of 25 tests closed
(MBEDTLS_ERR_LMS_VERIFY_FAILED, no forgery route, per 0xiviel's
analysis).

None of the three functions touched in lmots.c alias this way:  all
three are static, and at every one of their seven call sites (verified
by 0xiviel, and independently here) the destination is a distinct
object from every input. Those three keep their memset. Only
create_merkle_leaf_value's original memset (from 9b3051fb10, pre-dating
this PR) and create_merkle_internal_value's new one were ever in
question; create_merkle_leaf_value does not alias (pub_key and out are
always distinct per RFC8554 Algorithm 1 step 2's tree construction) and
also keeps its memset.

Verified: tests/test_suite_lms back to PASSED (25 / 25), both with a
plain build and with -fsanitize=address,undefined (no diagnostics
either way). tests/test_suite_lmots unaffected, PASSED (17 / 17, 1
skipped) throughout.

Signed-off-by: Johnson Ajibi <ajibijohnson@gmail.com>
This commit is contained in:
Johnson Ajibi 2026-10-21 20:24:11 +01:00
parent c03b3f188a
commit d327b904b3

View File

@ -178,9 +178,6 @@ static int create_merkle_internal_value(const mbedtls_lms_parameters_t *params,
size_t output_hash_len;
unsigned char r_node_idx_bytes[4];
/* Always zeroize the output buffer because it may contain data from the previous invocation */
memset(out, 0, MBEDTLS_LMS_M_NODE_BYTES(params->type));
op = psa_hash_operation_init();
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {