decoded value of t0 matches the calculated value of t0.
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26681)
PACKET pkt;
/* When loading from an explicit key, drop the seed. */
- OPENSSL_free(key->seed);
+ OPENSSL_clear_free(key->seed, ML_DSA_SEED_BYTES);
key->seed = NULL;
/* Allow the key encoding to be already set to the provided pointer */
for (i = 0; i < l; ++i)
if (!decode_fn(key->s1.poly + i, &pkt))
- return 0;
+ goto err;
for (i = 0; i < k; ++i)
if (!decode_fn(key->s2.poly + i, &pkt))
- return 0;
+ goto err;
for (i = 0; i < k; ++i)
if (!poly_decode_signed_two_to_power_12(key->t0.poly + i, &pkt))
- return 0;
+ goto err;
if (PACKET_remaining(&pkt) != 0)
- return 0;
+ goto err;
if (key->priv_encoding == NULL
&& (key->priv_encoding = OPENSSL_memdup(in, in_len)) == NULL)
- return 0;
+ goto err;
/*
* Computing the public key also computes its hash, which must be equal to
* the |tr| value in the private key, else the key was corrupted.
*/
- if (ossl_ml_dsa_key_public_from_private(key) != 0
- && memcmp(input_tr, key->tr, sizeof(input_tr)) == 0)
- return 1;
+ if (!ossl_ml_dsa_key_public_from_private(key)
+ || memcmp(input_tr, key->tr, sizeof(input_tr)) != 0)
+ goto err;
- /* On error, reset the key back to uninitialised. */
- ossl_ml_dsa_key_reset(key);
+ return 1;
+ err:
return 0;
}
if (!vector_alloc(&t0, key->params->k)) /* t0 is already in the private key */
return 0;
- if (!ossl_ml_dsa_key_pub_alloc(key)) /* allocate space for t1 */
- return 0;
-
- md_ctx = EVP_MD_CTX_new();
- if (md_ctx == NULL)
- goto err;
-
- ret = public_from_private(key, md_ctx, &key->t1, &t0)
+ ret = ((md_ctx = EVP_MD_CTX_new())!= NULL)
+ && ossl_ml_dsa_key_pub_alloc(key) /* allocate space for t1 */
+ && public_from_private(key, md_ctx, &key->t1, &t0)
+ && vector_equal(&t0, &key->t0) /* compare the generated t0 to the expected */
&& ossl_ml_dsa_pk_encode(key)
&& shake_xof(md_ctx, key->shake256_md,
key->pub_encoding, key->params->pk_len,
key->tr, sizeof(key->tr));
-err:
vector_free(&t0);
EVP_MD_CTX_free(md_ctx);
return ret;
return ret;
}
+static int ml_dsa_priv_pub_bad_t0_test(void)
+{
+ int ret = 0;
+ EVP_PKEY *key = NULL;
+ ML_DSA_SIG_GEN_TEST_DATA *td = &ml_dsa_siggen_testdata[0];
+ uint8_t *priv = OPENSSL_memdup(td->priv, td->priv_len);
+
+ if (!TEST_ptr(priv))
+ goto err;
+ memcpy(priv, td->priv, td->priv_len);
+ /*
+ * t0 is at the end of the encoding so corrupt it.
+ * This offset is the start of t0 (which is the last 416 * k bytes))
+ */
+ priv[td->priv_len - 6 * 416] ^= 1;
+ if (!TEST_true(ml_dsa_create_keypair(&key, td->alg,
+ priv, td->priv_len, NULL, 0, 0)))
+ goto err;
+
+ priv[td->priv_len - 6 * 416] ^= 1;
+ if (!TEST_true(ml_dsa_create_keypair(&key, td->alg,
+ priv, td->priv_len, NULL, 0, 1)))
+ goto err;
+ ret = 1;
+ err:
+ OPENSSL_free(priv);
+ EVP_PKEY_free(key);
+ return ret;
+}
+
const OPTIONS *test_get_options(void)
{
static const OPTIONS options[] = {
ADD_TEST(from_data_invalid_public_test);
ADD_TEST(from_data_bad_input_test);
ADD_TEST(ml_dsa_digest_sign_verify_test);
+ ADD_TEST(ml_dsa_priv_pub_bad_t0_test);
return 1;
}