diff --git a/mldsa/mldsa_native.h b/mldsa/mldsa_native.h index 4310f2aae8..2a0dd60856 100644 --- a/mldsa/mldsa_native.h +++ b/mldsa/mldsa_native.h @@ -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 @@ -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 @@ -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). * diff --git a/mldsa/src/sign.c b/mldsa/src/sign.c index 276c5a5f57..4f52cbaade 100644 --- a/mldsa/src/sign.c +++ b/mldsa/src/sign.c @@ -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); @@ -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; @@ -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); @@ -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)) + { + 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); @@ -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; @@ -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) @@ -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) @@ -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) @@ -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)) { return 0; } diff --git a/mldsa/src/sign.h b/mldsa/src/sign.h index cc2ddc6dcc..e4d27b2fee 100644 --- a/mldsa/src/sign.h +++ b/mldsa/src/sign.h @@ -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 @@ -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 @@ -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)) requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES)) assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen)) assigns(object_whole(smlen)) @@ -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). * diff --git a/test/src/test_alloc.c b/test/src/test_alloc.c index fc39536056..71bb44d4eb 100644 --- a/test/src/test_alloc.c +++ b/test/src/test_alloc.c @@ -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); diff --git a/test/src/test_mldsa.c b/test/src/test_mldsa.c index 63a18d62a5..89ba042fcb 100644 --- a/test/src/test_mldsa.c +++ b/test/src/test_mldsa.c @@ -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 \ @@ -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]; @@ -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();