@@ -187,6 +187,56 @@ static int ed448_hash(ed448_key* key, const byte* in, word32 inLen,
187187 return ret ;
188188}
189189
190+ #if FIPS_VERSION3_GE (6 ,0 ,0 )
191+ /* Performs a Pairwise Consistency Test on an Ed448 key pair.
192+ *
193+ * @param [in] key Ed448 key to test.
194+ * @param [in] rng Random number generator to use to create random digest.
195+ * @return 0 on success.
196+ * @return ECC_PCT_E when signing or verification fail.
197+ * @return Other -ve when random number generation fails.
198+ */
199+ static int ed448_pairwise_consistency_test (ed448_key * key , WC_RNG * rng )
200+ {
201+ int err = 0 ;
202+ byte digest [WC_SHA256_DIGEST_SIZE ];
203+ word32 digestLen = WC_SHA256_DIGEST_SIZE ;
204+ byte sig [ED448_SIG_SIZE ];
205+ word32 sigLen = ED448_SIG_SIZE ;
206+ int res = 0 ;
207+
208+ /* Generate a random digest to sign. */
209+ err = wc_RNG_GenerateBlock (rng , digest , digestLen );
210+ if (err == 0 ) {
211+ /* Sign digest without context. */
212+ err = wc_ed448_sign_msg_ex (digest , digestLen , sig , & sigLen , key , Ed448 ,
213+ NULL , 0 );
214+ if (err != 0 ) {
215+ /* Any sign failure means test failed. */
216+ err = ECC_PCT_E ;
217+ }
218+ }
219+ if (err == 0 ) {
220+ /* Verify digest without context. */
221+ err = wc_ed448_verify_msg_ex (sig , sigLen , digest , digestLen , & res , key ,
222+ Ed448 , NULL , 0 );
223+ if (err != 0 ) {
224+ /* Any verification operation failure means test failed. */
225+ err = ECC_PCT_E ;
226+ }
227+ /* Check whether the signature verified. */
228+ else if (res == 0 ) {
229+ /* Test failed. */
230+ err = ECC_PCT_E ;
231+ }
232+ }
233+
234+ ForceZero (sig , sigLen );
235+
236+ return err ;
237+ }
238+ #endif
239+
190240/* Derive the public key for the private key.
191241 *
192242 * key [in] Ed448 key object.
@@ -272,6 +322,13 @@ int wc_ed448_make_key(WC_RNG* rng, int keySz, ed448_key* key)
272322 if (ret == 0 ) {
273323 /* put public key after private key, on the same buffer */
274324 XMEMMOVE (key -> k + ED448_KEY_SIZE , key -> p , ED448_PUB_KEY_SIZE );
325+
326+ #if FIPS_VERSION3_GE (6 ,0 ,0 )
327+ ret = wc_ed448_check_key (key );
328+ if (ret == 0 ) {
329+ ret = ed448_pairwise_consistency_test (key , rng );
330+ }
331+ #endif
275332 }
276333
277334 return ret ;
@@ -966,7 +1023,7 @@ int wc_ed448_import_public_ex(const byte* in, word32 inLen, ed448_key* key,
9661023 ret = BAD_FUNC_ARG ;
9671024 }
9681025
969- if (inLen != ED448_PUB_KEY_SIZE ) {
1026+ if (( inLen != ED448_PUB_KEY_SIZE ) && ( inLen != ED448_PUB_KEY_SIZE + 1 ) ) {
9701027 ret = BAD_FUNC_ARG ;
9711028 }
9721029
@@ -995,7 +1052,7 @@ int wc_ed448_import_public_ex(const byte* in, word32 inLen, ed448_key* key,
9951052
9961053 if (ret == 0 ) {
9971054 key -> pubKeySet = 1 ;
998- if (key -> privKeySet && ( !trusted ) ) {
1055+ if (!trusted ) {
9991056 /* Check untrusted public key data matches private key. */
10001057 ret = wc_ed448_check_key (key );
10011058 }
@@ -1243,31 +1300,90 @@ int wc_ed448_export_key(ed448_key* key, byte* priv, word32 *privSz,
12431300
12441301#endif /* HAVE_ED448_KEY_EXPORT */
12451302
1246- /* Check the public key of the ed448 key matches the private key .
1303+ /* Check the public key is valid .
12471304 *
1248- * key [in] Ed448 private/public key.
1249- * returns BAD_FUNC_ARG when key is NULL,
1250- * PUBLIC_KEY_E when the public key is not set or doesn't match,
1251- * other -ve value on hash failure,
1252- * 0 otherwise.
1305+ * When private key available, check the calculated public key matches.
1306+ * When no private key, check Y is in range and an X is able to be calculated.
1307+ *
1308+ * @param [in] key Ed448 private/public key.
1309+ * @return 0 otherwise.
1310+ * @return BAD_FUNC_ARG when key is NULL.
1311+ * @return PUBLIC_KEY_E when the public key is not set, doesn't match or is
1312+ * invalid.
1313+ * @return other -ve value on hash failure.
12531314 */
12541315int wc_ed448_check_key (ed448_key * key )
12551316{
12561317 int ret = 0 ;
12571318 unsigned char pubKey [ED448_PUB_KEY_SIZE ];
12581319
1320+ /* Validate parameter. */
12591321 if (key == NULL ) {
12601322 ret = BAD_FUNC_ARG ;
12611323 }
12621324
1325+ /* Check we have a public key to check. */
12631326 if (ret == 0 && !key -> pubKeySet ) {
12641327 ret = PUBLIC_KEY_E ;
12651328 }
1266- if (ret == 0 ) {
1329+
1330+ /* If we have a private key just make the public key and compare. */
1331+ if ((ret == 0 ) && key -> privKeySet ) {
12671332 ret = wc_ed448_make_public (key , pubKey , sizeof (pubKey ));
1333+ if ((ret == 0 ) && (XMEMCMP (pubKey , key -> p , ED448_PUB_KEY_SIZE ) != 0 )) {
1334+ ret = PUBLIC_KEY_E ;
1335+ }
12681336 }
1269- if ((ret == 0 ) && (XMEMCMP (pubKey , key -> p , ED448_PUB_KEY_SIZE ) != 0 )) {
1270- ret = PUBLIC_KEY_E ;
1337+ /* No private key, check Y is valid. */
1338+ else if ((ret == 0 ) && (!key -> privKeySet )) {
1339+ /* Verify that Q is not identity element 0.
1340+ * 0 has no representation for Ed448. */
1341+
1342+ /* Verify that xQ and yQ are integers in the interval [0, p - 1].
1343+ * Only have yQ so check that ordinate.
1344+ * p = 2^448-2^224-1 = 0xff..fe..ff
1345+ */
1346+ {
1347+ int i ;
1348+ ret = PUBLIC_KEY_E ;
1349+
1350+ /* Check top part before 0xFE. */
1351+ for (i = ED448_PUB_KEY_SIZE - 1 ; i > ED448_PUB_KEY_SIZE /2 ; i -- ) {
1352+ if (key -> p [i ] < 0xff ) {
1353+ ret = 0 ;
1354+ break ;
1355+ }
1356+ }
1357+ if (ret == PUBLIC_KEY_E ) {
1358+ /* Check against 0xFE. */
1359+ if (key -> p [ED448_PUB_KEY_SIZE /2 ] < 0xfe ) {
1360+ ret = 0 ;
1361+ }
1362+ else if (key -> p [ED448_PUB_KEY_SIZE /2 ] == 0xfe ) {
1363+ /* Check bottom part before last byte. */
1364+ for (i = ED448_PUB_KEY_SIZE /2 - 1 ; i > 0 ; i -- ) {
1365+ if (key -> p [i ] != 0xff ) {
1366+ ret = 0 ;
1367+ break ;
1368+ }
1369+ }
1370+ /* Check last byte. */
1371+ if ((ret == PUBLIC_KEY_E ) && (key -> p [0 ] < 0xff )) {
1372+ ret = 0 ;
1373+ }
1374+ }
1375+ }
1376+ }
1377+
1378+ if (ret == 0 ) {
1379+ /* Verify that Q is on the curve.
1380+ * Uncompressing the public key will validate yQ. */
1381+ ge448_p2 A ;
1382+
1383+ if (ge448_from_bytes_negate_vartime (& A , key -> p ) != 0 ) {
1384+ ret = PUBLIC_KEY_E ;
1385+ }
1386+ }
12711387 }
12721388
12731389 return ret ;
0 commit comments