Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions mldsa/mldsa_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ int MLD_API_NAMESPACE(signature_internal)(
* @param[in] m Pointer to message to be signed.
* @param mlen Length of message.
* @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.
* @param ctxlen Length of context string. Should be <= 255.
* @param ctxlen Length of context string. Must be <= 255.
* @param[in] sk Bit-packed secret key.
* @param context Application context. Only present when
* MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
Expand Down Expand Up @@ -437,8 +437,8 @@ int MLD_API_NAMESPACE(signature_extmu)(
* @param[out] smlen Pointer to output length of signed message.
* @param[in] m Pointer to message to be signed.
* @param mlen Length of message.
* @param[in] ctx Pointer to context string.
* @param ctxlen Length of context string.
* @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.
* @param ctxlen Length of context string. Must be <= 255.
* @param[in] sk Bit-packed secret key.
* @param context Application context. Only present when
* MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
Expand Down Expand Up @@ -835,8 +835,8 @@ int MLD_API_NAMESPACE(verify_pre_hash_shake256)(
* @param[in] ph Pointer to pre-hashed message (ignored for pure
* ML-DSA).
* @param phlen Length of pre-hashed message (ignored for pure ML-DSA).
* @param[in] ctx Pointer to context string (may be NULL).
* @param ctxlen Length of context string.
* @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.
* @param ctxlen Length of context string. Must be <= 255.
* @param hashalg Hash algorithm constant (MLD_PREHASH_NONE for pure
* ML-DSA, or MLD_PREHASH_* for HashML-DSA).
*
Expand Down
36 changes: 34 additions & 2 deletions mldsa/src/sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,7 @@ int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
uint8_t *rho, *tr, *key, *mu, *rhoprime;
uint16_t nonce = 0;
const uint16_t nonce_limit = mld_get_max_signing_attempts();

MLD_ALLOC(seedbuf, uint8_t,
2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context);
MLD_ALLOC(mat, mld_polymat, 1, context);
Expand All @@ -929,6 +930,12 @@ int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
goto cleanup;
}

if (externalmu && mlen != MLDSA_CRHBYTES)
{
ret = MLD_ERR_FAIL;
goto cleanup;
}

rho = seedbuf;
tr = rho + MLDSA_SEEDBYTES;
key = tr + MLDSA_TRBYTES;
Expand Down Expand Up @@ -1052,6 +1059,7 @@ int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
{
size_t pre_len;
int ret;

MLD_ALLOC(pre, uint8_t, MLD_DOMAIN_SEPARATION_MAX_BYTES, context);
MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context);
Comment on lines +1062 to 1064

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check must happen after the allocations for strict C90 compliance. Which has the benefit that we can reuse the cleanup section.


Expand All @@ -1061,6 +1069,12 @@ int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
goto cleanup;
}

if (ctxlen > 255 || (ctx == NULL && ctxlen != 0))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the ctx == NULL check throughout.
We are not checking for NULL pointers anywhere else in the code.
I'll separately open a PR to document the convention to not check for NULL.

{
ret = MLD_ERR_FAIL;
goto cleanup;
}

/* Prepare domain separation prefix for pure ML-DSA */
pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen,
MLD_PREHASH_NONE);
Expand Down Expand Up @@ -1204,7 +1218,7 @@ int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
goto cleanup;
}

if (siglen != MLDSA_CRYPTO_BYTES)
if (siglen != MLDSA_CRYPTO_BYTES || (externalmu && mlen != MLDSA_CRHBYTES))
{
ret = MLD_ERR_FAIL;
goto cleanup;
Expand Down Expand Up @@ -1320,6 +1334,12 @@ int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m,
size_t pre_len;
int ret;

if (ctxlen > 255 || (ctx == NULL && ctxlen != 0))
{
ret = MLD_ERR_FAIL;
goto cleanup;
}

pre_len = mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen,
MLD_PREHASH_NONE);
if (pre_len == 0)
Expand Down Expand Up @@ -1411,6 +1431,12 @@ int mld_sign_signature_pre_hash_internal(
size_t pre_len;
int ret;

if (ctxlen > 255 || (ctx == NULL && ctxlen != 0))
{
ret = MLD_ERR_FAIL;
goto cleanup;
}

pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen,
hashalg);
if (pre_len == 0)
Expand Down Expand Up @@ -1453,6 +1479,12 @@ int mld_sign_verify_pre_hash_internal(
size_t pre_len;
int ret;

if (ctxlen > 255 || (ctx == NULL && ctxlen != 0))
{
ret = MLD_ERR_FAIL;
goto cleanup;
}

pre_len = mld_prepare_domain_separation_prefix(pre, ph, phlen, ctx, ctxlen,
hashalg);
if (pre_len == 0)
Expand Down Expand Up @@ -1607,7 +1639,7 @@ size_t mld_prepare_domain_separation_prefix(
uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph,
size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg)
{
if (ctxlen > 255)
if (ctxlen > 255 || (ctx == NULL && ctxlen != 0))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer input validation to happen at the top-level API, even if it means a bit of code-duplication.

{
return 0;
}
Expand Down
12 changes: 6 additions & 6 deletions mldsa/src/sign.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ __contract__(
* @param[in] m Pointer to message to be signed.
* @param mlen Length of message.
* @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.
* @param ctxlen Length of context string. Should be <= 255.
* @param ctxlen Length of context string. Must be <= 255.
* @param[in] sk Bit-packed secret key.
* @param context Application context. Only present when
* MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
Expand Down Expand Up @@ -343,8 +343,8 @@ __contract__(
* @param[out] smlen Pointer to output length of signed message.
* @param[in] m Pointer to message to be signed.
* @param mlen Length of message.
* @param[in] ctx Pointer to context string.
* @param ctxlen Length of context string.
* @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.
* @param ctxlen Length of context string. Must be <= 255.
* @param[in] sk Bit-packed secret key.
* @param context Application context. Only present when
* MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
Expand All @@ -371,7 +371,7 @@ __contract__(
requires(memory_no_alias(smlen, sizeof(size_t)))
requires(m == sm || memory_no_alias(m, mlen))
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(ctx, ctxlen))
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if this needed. My understanding was that memory_no_alias() does permit NULL if the length is zero bytes.
@hanno-becker?

requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen))
assigns(object_whole(smlen))
Expand Down Expand Up @@ -787,8 +787,8 @@ __contract__(
* @param[in] ph Pointer to pre-hashed message (ignored for pure
* ML-DSA).
* @param phlen Length of pre-hashed message (ignored for pure ML-DSA).
* @param[in] ctx Pointer to context string (may be NULL).
* @param ctxlen Length of context string.
* @param[in] ctx Pointer to context string. May be NULL if ctxlen == 0.
* @param ctxlen Length of context string. Must be <= 255.
* @param hashalg Hash algorithm constant (MLD_PREHASH_NONE for pure
* ML-DSA, or MLD_PREHASH_* for HashML-DSA).
*
Expand Down
4 changes: 2 additions & 2 deletions test/src/test_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,16 +517,16 @@ int main(void)
r |= test_pk_from_sk_alloc_failure(&ctx);
#endif

/* Sign tests */
#if !defined(MLD_CONFIG_NO_SIGN_API)
/* Sign tests */
r |= test_sign_alloc_failure(&ctx);
r |= test_sign_combined_alloc_failure(&ctx);
r |= test_signature_extmu_alloc_failure(&ctx);
r |= test_signature_pre_hash_shake256_alloc_failure(&ctx);
#endif /* !MLD_CONFIG_NO_SIGN_API */

/* Verify tests */
#if !defined(MLD_CONFIG_NO_VERIFY_API)
/* Verify tests */
r |= test_verify_alloc_failure(&ctx);
r |= test_verify_extmu_alloc_failure(&ctx);
r |= test_verify_pre_hash_shake256_alloc_failure(&ctx);
Expand Down
46 changes: 46 additions & 0 deletions test/src/test_mldsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

/* Additional SUPERCOP-style macros for functions not in the standard set */
#define crypto_sign_keypair_internal MLD_API_NAMESPACE(keypair_internal)
#define crypto_sign_signature_internal MLD_API_NAMESPACE(signature_internal)
#define crypto_sign_verify_internal MLD_API_NAMESPACE(verify_internal)
#define crypto_sign_signature_extmu MLD_API_NAMESPACE(signature_extmu)
#define crypto_sign_verify_extmu MLD_API_NAMESPACE(verify_extmu)
#define crypto_sign_signature_pre_hash_shake256 \
Expand Down Expand Up @@ -134,6 +136,49 @@ static int test_sign_unaligned(void)
return test_sign_core(pk + 1, sk + 1, sm + 1, m + 1, m2 + 1, ctx + 1);
}

static int test_invalid_inputs_rejected(void)
{
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
uint8_t sig[CRYPTO_BYTES];
uint8_t m[MLEN];
uint8_t mu[MLDSA_CRHBYTES];
uint8_t rnd[MLDSA_RNDBYTES];
size_t siglen = CRYPTO_BYTES;
int rc;

CHECK(crypto_sign_keypair(pk, sk) == 0);
CHECK(randombytes(m, sizeof(m)) == 0);
MLD_CT_TESTING_SECRET(m, sizeof(m));
CHECK(randombytes(mu, sizeof(mu)) == 0);
MLD_CT_TESTING_SECRET(mu, sizeof(mu));
CHECK(randombytes(rnd, sizeof(rnd)) == 0);
MLD_CT_TESTING_SECRET(rnd, sizeof(rnd));
CHECK(randombytes(sig, sizeof(sig)) == 0);
MLD_CT_TESTING_SECRET(sig, sizeof(sig));

rc = crypto_sign_signature(sig, &siglen, m, sizeof(m), NULL, 1, sk);
CHECK(rc == MLD_ERR_FAIL);
CHECK(siglen == 0);

siglen = CRYPTO_BYTES;
rc = crypto_sign_signature_internal(sig, &siglen, mu, MLDSA_CRHBYTES - 1,
NULL, 0, rnd, sk, 1);
CHECK(rc == MLD_ERR_FAIL);
CHECK(siglen == 0);

rc = crypto_sign_verify(sig, CRYPTO_BYTES, m, sizeof(m), NULL, 1, pk);
CHECK(rc == MLD_ERR_FAIL);
rc = crypto_sign_verify_internal(sig, CRYPTO_BYTES - 1, mu, sizeof(mu), NULL,
0, pk, 1);
CHECK(rc == MLD_ERR_FAIL);
rc = crypto_sign_verify_internal(sig, CRYPTO_BYTES, mu, MLDSA_CRHBYTES - 1,
NULL, 0, pk, 1);
CHECK(rc == MLD_ERR_FAIL);

return 0;
}

static int test_sign_extmu(void)
{
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
Expand Down Expand Up @@ -509,6 +554,7 @@ int main(void)
!defined(MLD_CONFIG_NO_VERIFY_API)
r |= test_sign();
r |= test_sign_unaligned();
r |= test_invalid_inputs_rejected();
r |= test_wrong_pk();
r |= test_wrong_sig();
r |= test_wrong_ctx();
Expand Down