@@ -11669,6 +11669,55 @@ int wc_MlDsaKey_ImportPubRaw(wc_MlDsaKey* key, const byte* in, word32 inLen)
1166911669
1167011670#ifdef WOLFSSL_MLDSA_PRIVATE_KEY
1167111671
11672+ /* Check the s1 and s2 vectors of a private key are in range [-eta, eta].
11673+ *
11674+ * FIPS 204, Algorithm 25 skDecode: s1 and s2 are BitPack encodings of
11675+ * (eta - coeff), so each packed value must be no greater than 2*eta. Reject
11676+ * a private key with any value outside this range rather than silently
11677+ * accepting a non-conforming key.
11678+ *
11679+ * @param [in] p Encoded s1 followed by s2.
11680+ * @param [in] eta Coefficient range specifier (2 or 4).
11681+ * @param [in] len Number of encoded bytes covering s1 and s2.
11682+ * @return 0 when all values are in range.
11683+ * @return PUBLIC_KEY_E when at least one value is out of range.
11684+ */
11685+ static int mldsa_check_eta_range (const byte * p , byte eta , word32 len )
11686+ {
11687+ int ret = 0 ;
11688+ word32 i ;
11689+ word32 j ;
11690+ word32 bits ;
11691+ byte max = (byte )(2 * eta );
11692+
11693+ if (eta == MLDSA_ETA_4 ) {
11694+ /* 4 bits per coefficient, two coefficients per byte. */
11695+ for (i = 0 ; i < len ; i ++ ) {
11696+ if (((p [i ] & 0xf ) > max ) || ((p [i ] >> 4 ) > max )) {
11697+ ret = PUBLIC_KEY_E ;
11698+ break ;
11699+ }
11700+ }
11701+ }
11702+ else {
11703+ /* 3 bits per coefficient, eight coefficients per three bytes. len
11704+ * (s1EncSz + s2EncSz) is always a multiple of 3, so no trailing
11705+ * partial group is skipped. */
11706+ for (i = 0 ; (ret == 0 ) && (i + 3 <= len ); i += 3 ) {
11707+ bits = (word32 )p [i ] | ((word32 )p [i + 1 ] << 8 ) |
11708+ ((word32 )p [i + 2 ] << 16 );
11709+ for (j = 0 ; j < 8 ; j ++ ) {
11710+ if (((bits >> (3 * j )) & 0x7 ) > max ) {
11711+ ret = PUBLIC_KEY_E ;
11712+ break ;
11713+ }
11714+ }
11715+ }
11716+ }
11717+
11718+ return ret ;
11719+ }
11720+
1167211721/* Set the private key data into key.
1167311722 *
1167411723 * @param [in] priv Private key data.
@@ -11677,6 +11726,7 @@ int wc_MlDsaKey_ImportPubRaw(wc_MlDsaKey* key, const byte* in, word32 inLen)
1167711726 * @return 0 on success.
1167811727 * @return BAD_FUNC_ARG when private key size is invalid.
1167911728 * @return MEMORY_E when dynamic memory allocation fails.
11729+ * @return PUBLIC_KEY_E when an s1 or s2 coefficient is out of range.
1168011730 * @return Other negative on hash error.
1168111731 */
1168211732static int mldsa_set_priv_key (const byte * priv , word32 privSz ,
@@ -11706,6 +11756,15 @@ static int mldsa_set_priv_key(const byte* priv, word32 privSz,
1170611756 }
1170711757#endif
1170811758
11759+ if (ret == 0 ) {
11760+ /* Reject a private key whose s1 or s2 coefficients are out of range
11761+ * before copying it in, so a failed import never overwrites an
11762+ * existing key or leaves the object in an inconsistent state. */
11763+ const byte * s1p = priv + MLDSA_PUB_SEED_SZ + MLDSA_K_SZ + MLDSA_TR_SZ ;
11764+ ret = mldsa_check_eta_range (s1p , key -> params -> eta ,
11765+ (word32 )key -> params -> s1EncSz + key -> params -> s2EncSz );
11766+ }
11767+
1170911768 if (ret == 0 ) {
1171011769 /* Copy the private key data in or copy pointer. */
1171111770 #ifdef WOLFSSL_MLDSA_ASSIGN_KEY
0 commit comments