Properly reject Ed448 identity public key

Reported by: Nicholas Carlini <npc@anthropic.com>
This commit is contained in:
Tobias Frauenschläger
2026-04-01 15:48:55 +02:00
parent cece804621
commit 2237297cea
2 changed files with 66 additions and 3 deletions
+37
View File
@@ -34758,6 +34758,42 @@ static int test_DhAgree_rejects_p_minus_1(void)
return EXPECT_RESULT();
}
/* Test: Ed448 must reject identity public key (0,1) */
static int test_ed448_rejects_identity_key(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && !defined(HAVE_SELFTEST) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0))
ed448_key key;
byte identity[ED448_PUB_KEY_SIZE];
byte forged_sig[ED448_SIG_SIZE];
const byte msg[] = "test message";
int res = 0;
XMEMSET(identity, 0, sizeof(identity));
identity[0] = 0x01; /* identity (0,1) encoding */
XMEMSET(forged_sig, 0, sizeof(forged_sig));
forged_sig[0] = 0x01; /* R = identity, S = 0 */
ExpectIntEQ(wc_ed448_init(&key), 0);
/* The identity public key must be rejected at import time. */
ExpectIntNE(wc_ed448_import_public(identity, sizeof(identity), &key), 0);
/* If import somehow succeeded, verify must also reject the forgery. */
if (EXPECT_SUCCESS() && key.pubKeySet) {
int verifyRet = wc_ed448_verify_msg(forged_sig, sizeof(forged_sig),
msg, sizeof(msg) - 1,
&res, &key, NULL, 0);
ExpectTrue(verifyRet != 0 || res == 0);
}
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
}
TEST_CASE testCases[] = {
TEST_DECL(test_fileAccess),
@@ -35573,6 +35609,7 @@ TEST_CASE testCases[] = {
TEST_TLS_DECLS,
TEST_DECL(test_wc_DhSetNamedKey),
TEST_DECL(test_DhAgree_rejects_p_minus_1),
TEST_DECL(test_ed448_rejects_identity_key),
#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
TEST_DECL(test_sniffer_chain_input_overflow),
+29 -3
View File
@@ -711,6 +711,18 @@ static int ed448_verify_msg_final_with_sha(const byte* sig, word32 sigLen,
if (i == -1)
return BAD_FUNC_ARG;
/* Reject identity public key (0,1): 0x01 followed by 56 zero bytes. */
{
int isIdentity = (key->p[0] == 0x01);
int j;
for (j = 1; j < ED448_PUB_KEY_SIZE && isIdentity; j++) {
if (key->p[j] != 0x00)
isIdentity = 0;
}
if (isIdentity)
return BAD_FUNC_ARG;
}
/* uncompress A (public key), test if valid, and negate it */
if (ge448_from_bytes_negate_vartime(&A, key->p) != 0)
return BAD_FUNC_ARG;
@@ -1335,14 +1347,28 @@ int wc_ed448_check_key(ed448_key* key)
}
/* No private key, check Y is valid. */
else if ((ret == 0) && (!key->privKeySet)) {
/* Verify that Q is not identity element 0.
* 0 has no representation for Ed448. */
/* Reject the identity element (0, 1).
* Encoding: 0x01 followed by 56 zero bytes. */
{
int isIdentity = 1;
int i;
if (key->p[0] != 0x01)
isIdentity = 0;
for (i = 1; i < ED448_PUB_KEY_SIZE && isIdentity; i++) {
if (key->p[i] != 0x00)
isIdentity = 0;
}
if (isIdentity) {
WOLFSSL_MSG("Ed448 public key is the identity element");
ret = PUBLIC_KEY_E;
}
}
/* Verify that xQ and yQ are integers in the interval [0, p - 1].
* Only have yQ so check that ordinate.
* p = 2^448-2^224-1 = 0xff..fe..ff
*/
{
if (ret == 0) {
int i;
ret = PUBLIC_KEY_E;