1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00
Files
wolfssl/tests/api/test_ed448.c
Tobias Frauenschläger 478847d81e Support device private keys by id or label for Ed25519 and Ed448
RSA, ECC and the PQC signature algorithms can reference a private key
held by a crypto callback device through an id or label
(WOLF_PRIVATE_KEY_ID), both in wolfCrypt and through
wolfSSL_CTX_use_PrivateKey_Id / _Label. Ed25519 and Ed448 already
dispatch sign and verify through crypto callbacks but had no way to
name such a key, so a TLS server with an Ed25519 or Ed448 certificate
could not use a device key: no key object could be created for it and
wolfSSL_CTX_check_private_key failed.

Add wc_ed25519_init_id, wc_ed25519_init_label, wc_ed448_init_id and
wc_ed448_init_label, with the id and label stored at the end of the key
structures and limited to 32 bytes, like ECC. Code outside ed25519.c and
ed448.c tests ED25519_MAX_ID_LEN and ED448_MAX_ID_LEN rather than
WOLF_PRIVATE_KEY_ID, because FIPS v6 builds use pinned ed25519.h and
ed448.h that have neither the fields nor the functions.

wc_ed25519_make_public and wc_ed448_make_public no longer reject a key
named by id or label before asking the device, so a device can derive
the public key of a key it holds. When the device declines, or the key
has no device, they still return ECC_PRIV_KEY_E rather than deriving
from an empty software key.

In the TLS layer, CreateDevPrivateKey and DecodePrivateKey_ex build
Ed25519 and Ed448 device keys for ed25519_sa_algo and ed448_sa_algo.
check_cert_key_dev imports the certificate's public key into the device
key and validates the pair through the Ed25519 or Ed448 check_key
callback. It calls the callback directly rather than wc_ed*_check_key,
whose software fallback would only validate the public key of a device
key, so a device that declines the check fails it. Builds without
Ed25519 or Ed448 key import cannot do that, so they keep failing the
check as before.

A device key named by id or label has no private key in software, so
the check_key callbacks previously reported checkPriv as 0 for it and
a device would only have validated the public key. checkPriv is now
also set when the key carries an id or label.

Tests cover the init argument checks, make_public on a device key, and a
TLS 1.3 test per curve where a callback device holds the server key: the
pair check succeeds for both id and label, fails against a certificate
for another key, with an id longer than the key can hold or when the
device declines the check, and the handshake is signed by the device
after one more pair check when the certificate public key is loaded into
the device key.
2026-10-12 21:36:01 -07:00

2049 lines
78 KiB
C

/* test_ed448.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <tests/unit.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/wolfcrypt/ed448.h>
#include <wolfssl/wolfcrypt/types.h>
#ifdef WOLF_CRYPTO_CB
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
#include <tests/api/api.h>
#include <tests/api/test_ed448.h>
/*
* Testing wc_ed448_make_key().
*/
int test_wc_ed448_make_key(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448)
ed448_key key;
WC_RNG rng;
unsigned char pubkey[ED448_PUB_KEY_SIZE];
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_public(&key, pubkey, sizeof(pubkey)),
WC_NO_ERR_TRACE(ECC_PRIV_KEY_E));
/* MC/DC: wc_ed448_make_public()'s (key == NULL || pubKey == NULL ||
* pubKeySz != ED448_PUB_KEY_SIZE) arg check. The call above (valid key,
* valid pubkey, correct size) is the all-FALSE baseline; each call
* below flips exactly one operand TRUE while holding the other two at
* their baseline (FALSE) value, closing all three operands'
* independence pairs. They also give the (ret == 0) FALSE side of the
* (ret == 0) && (!key->privKeySet) check immediately below it. */
ExpectIntEQ(wc_ed448_make_public(NULL, pubkey, sizeof(pubkey)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_make_public(&key, NULL, sizeof(pubkey)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_make_public(&key, pubkey, sizeof(pubkey) - 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_make_key(NULL, ED448_KEY_SIZE, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE - 1, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE + 1, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_make_key */
/*
* Testing that wc_ed448_make_public() adopts the derived key into the key
* object when the key arrived without a public half.
*/
int test_wc_ed448_make_public_stores_pub(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) && \
defined(HAVE_ED448_KEY_EXPORT) && \
(!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0))
ed448_key key;
ed448_key privOnly;
WC_RNG rng;
byte priv[ED448_KEY_SIZE];
byte pub[ED448_PUB_KEY_SIZE];
byte derived[ED448_PUB_KEY_SIZE];
byte exported[ED448_PRV_KEY_SIZE];
word32 privSz = sizeof(priv);
word32 pubSz = sizeof(pub);
word32 exportedSz = sizeof(exported);
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
ed448_key pubOnly;
byte msg[] = "Everybody gets Friday off.\n";
byte sig[ED448_SIG_SIZE];
word32 sigSz = sizeof(sig);
int verify_ok = 0;
#endif
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&privOnly, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(derived, 0, sizeof(derived));
XMEMSET(exported, 0, sizeof(exported));
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
XMEMSET(&pubOnly, 0, sizeof(ed448_key));
XMEMSET(sig, 0, sizeof(sig));
#endif
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_init(&privOnly), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz), 0);
PRIVATE_KEY_LOCK();
ExpectIntEQ(wc_ed448_export_public(&key, pub, &pubSz), 0);
/* A PKCS#8 v1 PrivateKeyInfo has no public-key field, so this is the
* state a decoded private key arrives in. */
ExpectIntEQ(wc_ed448_import_private_only(priv, privSz, &privOnly), 0);
ExpectIntEQ(wc_ed448_make_public(&privOnly, derived, sizeof(derived)), 0);
ExpectIntEQ(XMEMCMP(derived, pub, ED448_PUB_KEY_SIZE), 0);
/* Setting pubKeySet is not enough: wc_ed448_sign_msg() gates on the flag
* and hashes key->p, so a key left with an empty p signs over zeros. */
ExpectIntEQ(XMEMCMP(privOnly.p, pub, ED448_PUB_KEY_SIZE), 0);
/* wc_ed448_export_private() gates on privKeySet alone and hands back all
* of key->k, so the mirrored public half has to be there too. */
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private(&privOnly, exported, &exportedSz), 0);
PRIVATE_KEY_LOCK();
ExpectIntEQ(exportedSz, ED448_PRV_KEY_SIZE);
ExpectIntEQ(XMEMCMP(exported, priv, ED448_KEY_SIZE), 0);
ExpectIntEQ(XMEMCMP(exported + ED448_KEY_SIZE, pub, ED448_PUB_KEY_SIZE), 0);
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
/* Verify against a key that only ever saw the real public half, so a
* signature made over an empty p cannot verify against itself. */
ExpectIntEQ(wc_ed448_init(&pubOnly), 0);
ExpectIntEQ(wc_ed448_import_public(pub, pubSz, &pubOnly), 0);
ExpectIntEQ(wc_ed448_sign_msg(msg, sizeof(msg), sig, &sigSz, &privOnly,
NULL, 0), 0);
ExpectIntEQ(wc_ed448_verify_msg(sig, sigSz, msg, sizeof(msg), &verify_ok,
&pubOnly, NULL, 0), 0);
ExpectIntEQ(verify_ok, 1);
#endif
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
wc_ed448_free(&privOnly);
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
wc_ed448_free(&pubOnly);
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_make_public_stores_pub */
/*
* Testing wc_ed448_init()
*/
int test_wc_ed448_init(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448)
ed448_key key;
XMEMSET(&key, 0, sizeof(ed448_key));
ExpectIntEQ(wc_ed448_init(&key), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_init(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_init */
/*
* Testing wc_ed448_init_id() and wc_ed448_init_label()
*/
int test_wc_ed448_init_id(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(ED448_MAX_ID_LEN)
ed448_key key;
byte id[ED448_MAX_ID_LEN + 1];
char label[ED448_MAX_LABEL_LEN + 2];
XMEMSET(&key, 0, sizeof(key));
XMEMSET(id, 0x11, sizeof(id));
XMEMSET(label, 'a', sizeof(label) - 1);
label[sizeof(label) - 1] = '\0';
ExpectIntEQ(wc_ed448_init_id(NULL, id, 4, NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_init_id(&key, NULL, 4, NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_init_id(&key, id, -1, NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_ed448_init_id(&key, id, ED448_MAX_ID_LEN + 1, NULL,
INVALID_DEVID), WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_ed448_init_id(&key, NULL, 0, NULL, INVALID_DEVID), 0);
ExpectIntEQ(key.idLen, 0);
wc_ed448_free(&key);
ExpectIntEQ(wc_ed448_init_id(&key, id, ED448_MAX_ID_LEN, NULL,
INVALID_DEVID), 0);
ExpectIntEQ(key.idLen, ED448_MAX_ID_LEN);
ExpectBufEQ(key.id, id, ED448_MAX_ID_LEN);
wc_ed448_free(&key);
ExpectIntEQ(wc_ed448_init_label(NULL, "lbl", NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_init_label(&key, NULL, NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_init_label(&key, "", NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_ed448_init_label(&key, label, NULL, INVALID_DEVID),
WC_NO_ERR_TRACE(BUFFER_E));
label[ED448_MAX_LABEL_LEN] = '\0';
ExpectIntEQ(wc_ed448_init_label(&key, label, NULL, INVALID_DEVID), 0);
ExpectIntEQ(key.labelLen, ED448_MAX_LABEL_LEN);
ExpectBufEQ(key.label, label, ED448_MAX_LABEL_LEN);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_init_id */
/*
* Test wc_ed448_sign_msg() and wc_ed448_verify_msg()
*/
int test_wc_ed448_sign_msg(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN)
ed448_key key;
WC_RNG rng;
byte msg[] = "Everybody gets Friday off.\n";
byte sig[ED448_SIG_SIZE];
word32 msglen = sizeof(msg);
word32 siglen = sizeof(sig);
word32 badSigLen = sizeof(sig) - 1;
#ifdef HAVE_ED448_VERIFY
int verify_ok = 0; /*1 = Verify success.*/
#endif
/* Initialize stack variables. */
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(sig, 0, siglen);
/* Initialize key. */
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, sig, &siglen, &key, NULL, 0), 0);
ExpectIntEQ(siglen, ED448_SIG_SIZE);
/* Test bad args. */
ExpectIntEQ(wc_ed448_sign_msg(NULL, msglen, sig, &siglen, &key, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, NULL, &siglen, &key, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, sig, NULL, &key, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, sig, &siglen, NULL, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, sig, &badSigLen, &key, NULL, 0),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(badSigLen, ED448_SIG_SIZE);
badSigLen--;
#ifdef HAVE_ED448_VERIFY
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen, msg, msglen, &verify_ok, &key,
NULL, 0), 0);
ExpectIntEQ(verify_ok, 1);
/* Test bad args. */
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen - 1, msg, msglen, &verify_ok,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen + 1, msg, msglen, &verify_ok,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg(NULL, siglen, msg, msglen, &verify_ok,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen, NULL, msglen, &verify_ok,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen, msg, msglen, NULL,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen, msg, msglen, &verify_ok,
NULL, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg(sig, badSigLen, msg, msglen, &verify_ok,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif /* Verify. */
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_sign_msg */
/*
* RFC 8032 requires the Ed448 signature scalar S to be canonical (S < L).
* Because L times the base point is the identity, a malleated signature with
* S' = S + L recomputes the same R, so the S-range check is the only guard
* against it. Confirm a signature with S >= L (including the malleability case
* S + L) is rejected with BAD_FUNC_ARG, while an in-range but wrong S fails
* verification with SIG_VERIFY_E.
*/
int test_wc_ed448_verify_sig_S_range(void)
{
EXPECT_DECLS;
/* The S-range rejection may be absent in the frozen ed448.c of older
* FIPS-certified modules, so restrict to non-FIPS or FIPS v7 and later. */
#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && \
defined(HAVE_ED448_VERIFY)
ed448_key key;
WC_RNG rng;
byte msg[] = "Everybody gets Friday off.\n";
byte sig[ED448_SIG_SIZE];
byte badSig[ED448_SIG_SIZE];
word32 msglen = sizeof(msg);
word32 siglen = sizeof(sig);
int verify_ok = 0;
int i;
int carry;
int sum;
/* Ed448 group order L, little-endian, 57 bytes. */
static const byte order[] = {
0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23,
0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21,
0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4,
0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
0x00
};
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(sig, 0, sizeof(sig));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* Produce a valid signature and confirm it verifies. */
ExpectIntEQ(wc_ed448_sign_msg(msg, msglen, sig, &siglen, &key, NULL, 0), 0);
ExpectIntEQ(siglen, ED448_SIG_SIZE);
ExpectIntEQ(wc_ed448_verify_msg(sig, siglen, msg, msglen, &verify_ok, &key,
NULL, 0), 0);
ExpectIntEQ(verify_ok, 1);
/* Malleability: S' = S + L. The same R is recomputed, so only the S-range
* check can reject it. */
XMEMCPY(badSig, sig, ED448_SIG_SIZE);
carry = 0;
for (i = 0; i < (int)sizeof(order); i++) {
sum = (int)badSig[ED448_SIG_SIZE / 2 + i] + (int)order[i] + carry;
badSig[ED448_SIG_SIZE / 2 + i] = (byte)(sum & 0xff);
carry = sum >> 8;
}
verify_ok = 1;
ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen,
&verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_ok, 0);
/* S exactly equal to L. */
XMEMCPY(badSig, sig, ED448_SIG_SIZE);
XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order));
verify_ok = 1;
ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen,
&verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_ok, 0);
/* S greater than L in a high byte. */
XMEMCPY(badSig, sig, ED448_SIG_SIZE);
XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order));
badSig[ED448_SIG_SIZE / 2 + 55] = 0x40;
verify_ok = 1;
ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen,
&verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_ok, 0);
/* S greater than L in a low byte. */
XMEMCPY(badSig, sig, ED448_SIG_SIZE);
XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order));
badSig[ED448_SIG_SIZE / 2 + 0] = 0xf4;
verify_ok = 1;
ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen,
&verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_ok, 0);
/* S below L: passes the range check, fails verification instead. */
XMEMCPY(badSig, sig, ED448_SIG_SIZE);
XMEMCPY(badSig + ED448_SIG_SIZE / 2, order, sizeof(order));
badSig[ED448_SIG_SIZE / 2 + 0] = 0xf2;
verify_ok = 1;
ExpectIntEQ(wc_ed448_verify_msg(badSig, ED448_SIG_SIZE, msg, msglen,
&verify_ok, &key, NULL, 0), WC_NO_ERR_TRACE(SIG_VERIFY_E));
ExpectIntEQ(verify_ok, 0);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_verify_sig_S_range */
/*
* Test that wc_ed448_sign_msg() rejects a public-key-only key object.
* A key with pubKeySet=1 but privKeySet=0 must not silently sign.
*/
int test_wc_ed448_sign_msg_pubonly_fails(void)
{
EXPECT_DECLS;
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && \
defined(HAVE_ED448_KEY_IMPORT) && defined(HAVE_ED448_KEY_EXPORT)
ed448_key fullKey;
ed448_key pubOnlyKey;
WC_RNG rng;
byte pubBuf[ED448_PUB_KEY_SIZE];
word32 pubSz = sizeof(pubBuf);
byte msg[] = "test message for pubonly check";
byte sig[ED448_SIG_SIZE];
word32 sigLen = sizeof(sig);
XMEMSET(&fullKey, 0, sizeof(fullKey));
XMEMSET(&pubOnlyKey, 0, sizeof(pubOnlyKey));
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_ed448_init(&fullKey), 0);
ExpectIntEQ(wc_ed448_init(&pubOnlyKey), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
/* Generate a real key pair and export its public key. */
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &fullKey), 0);
ExpectIntEQ(wc_ed448_export_public(&fullKey, pubBuf, &pubSz), 0);
/* Import only the public key into a fresh key object. */
ExpectIntEQ(wc_ed448_import_public(pubBuf, pubSz, &pubOnlyKey), 0);
/* Signing with a public-key-only object must fail. */
ExpectIntEQ(wc_ed448_sign_msg(msg, sizeof(msg), sig, &sigLen,
&pubOnlyKey, NULL, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&pubOnlyKey);
wc_ed448_free(&fullKey);
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_sign_msg_pubonly_fails */
/*
* Testing wc_ed448_import_public()
*/
int test_wc_ed448_import_public(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
ed448_key pubKey;
WC_RNG rng;
const byte in[] =
"Ed448PublicKeyUnitTest.................................\n";
word32 inlen = sizeof(in);
XMEMSET(&pubKey, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&pubKey), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &pubKey), 0);
ExpectIntEQ(wc_ed448_import_public_ex(in, inlen, &pubKey, 1), 0);
ExpectIntEQ(XMEMCMP(in, pubKey.p, inlen), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_import_public(NULL, inlen, &pubKey),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_public(in, inlen, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_public(in, inlen - 1, &pubKey),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
/* MC/DC: wc_ed448_import_public_ex()'s tri-state length check
* (inLen != PUB_KEY_SIZE && inLen != PUB_KEY_SIZE+1 &&
* inLen != 2*PUB_KEY_SIZE+1) -- close the third operand's FALSE side
* (inLen == 115) by falling through with a 115-byte input below, which
* also exercises the compressed-prefix (in[0] == 0x40 &&
* inLen > PUB_KEY_SIZE) and uncompressed-prefix (in[0] == 0x04 &&
* inLen > 2*PUB_KEY_SIZE) branches that no other test reaches. */
{
byte compressed[ED448_PUB_KEY_SIZE + 1];
byte uncompressed[2 * ED448_PUB_KEY_SIZE + 1];
/* in[0] == 0x40, inLen (58) > PUB_KEY_SIZE (57): compressed-prefix
* branch TRUE side. */
compressed[0] = 0x40;
XMEMCPY(compressed + 1, in, ED448_PUB_KEY_SIZE);
ExpectIntEQ(wc_ed448_import_public_ex(compressed,
(word32)sizeof(compressed), &pubKey, 1), 0);
/* in[0] == 0x40, inLen (57) == PUB_KEY_SIZE: compressed-prefix
* branch's length operand FALSE side -- falls through to the
* "inLen == PUB_KEY_SIZE" plain-copy branch instead. */
ExpectIntEQ(wc_ed448_import_public_ex(compressed,
ED448_PUB_KEY_SIZE, &pubKey, 1), 0);
/* in[0] == 0x04, inLen (115 == 2*PUB_KEY_SIZE+1) > 2*PUB_KEY_SIZE:
* uncompressed-prefix branch TRUE side, and the tri-state length
* OR's third operand FALSE side (with the first two held TRUE).
* ge448_compress_key() does not validate that (x, y) is on the
* curve, so arbitrary x/y bytes exercise the branch safely under
* a trusted import. */
uncompressed[0] = 0x04;
XMEMSET(uncompressed + 1, 0x24, ED448_PUB_KEY_SIZE); /* x */
XMEMCPY(uncompressed + 1 + ED448_PUB_KEY_SIZE, in,
ED448_PUB_KEY_SIZE); /* y */
ExpectIntEQ(wc_ed448_import_public_ex(uncompressed,
(word32)sizeof(uncompressed), &pubKey, 1), 0);
/* in[0] == 0x04, inLen (57) == PUB_KEY_SIZE: uncompressed-prefix
* branch's length operand FALSE side -- also falls through to the
* plain-copy branch (the leading 0x04 becomes part of the
* "compressed" key bytes copied verbatim). */
ExpectIntEQ(wc_ed448_import_public_ex(uncompressed,
ED448_PUB_KEY_SIZE, &pubKey, 1), 0);
}
#endif
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&pubKey);
#endif
return EXPECT_RESULT();
} /* END wc_ed448_import_public */
/*
* Testing wc_ed448_import_private_key()
*/
int test_wc_ed448_import_private_key(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
ed448_key key;
WC_RNG rng;
const byte privKey[] =
"Ed448PrivateKeyUnitTest................................\n";
const byte pubKey[] =
"Ed448PublicKeyUnitTest.................................\n";
word32 privKeySz = sizeof(privKey);
word32 pubKeySz = sizeof(pubKey);
#ifdef HAVE_ED448_KEY_EXPORT
byte bothKeys[sizeof(privKey) + sizeof(pubKey)];
word32 bothKeysSz = sizeof(bothKeys);
#endif
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
ExpectIntEQ(wc_ed448_import_private_key_ex(privKey, privKeySz, pubKey,
pubKeySz, &key, 1), 0);
ExpectIntEQ(XMEMCMP(pubKey, key.p, privKeySz), 0);
ExpectIntEQ(XMEMCMP(privKey, key.k, pubKeySz), 0);
#ifdef HAVE_ED448_KEY_EXPORT
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private(&key, bothKeys, &bothKeysSz), 0);
PRIVATE_KEY_LOCK();
ExpectIntEQ(wc_ed448_import_private_key_ex(bothKeys, bothKeysSz, NULL, 0,
&key, 1), 0);
ExpectIntEQ(XMEMCMP(pubKey, key.p, privKeySz), 0);
ExpectIntEQ(XMEMCMP(privKey, key.k, pubKeySz), 0);
#endif
/* Test bad args. */
ExpectIntEQ(wc_ed448_import_private_key(NULL, privKeySz, pubKey, pubKeySz,
&key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_private_key(privKey, privKeySz, NULL, pubKeySz,
&key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_private_key(privKey, privKeySz, pubKey,
pubKeySz, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_private_key(privKey, privKeySz - 1, pubKey,
pubKeySz, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_private_key(privKey, privKeySz, pubKey,
pubKeySz - 1, &key), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_import_private_key(privKey, privKeySz, NULL, 0, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_import_private_key */
/*
* Testing wc_ed448_export_public() and wc_ed448_export_private_only()
*/
int test_wc_ed448_export(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
ed448_key key;
WC_RNG rng;
byte priv[ED448_PRV_KEY_SIZE];
byte pub[ED448_PUB_KEY_SIZE];
word32 privSz = sizeof(priv);
word32 pubSz = sizeof(pub);
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&key), 0);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
/* Reject export when private key not set. */
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_private(&key, priv, &privSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
PRIVATE_KEY_LOCK();
#endif /* !HAVE_FIPS || FIPS_VERSION3_GE(7,0,0) */
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
ExpectIntEQ(wc_ed448_export_public(&key, pub, &pubSz), 0);
ExpectIntEQ(pubSz, ED448_KEY_SIZE);
ExpectIntEQ(XMEMCMP(key.p, pub, pubSz), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_export_public(NULL, pub, &pubSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_public(&key, NULL, &pubSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_public(&key, pub, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz), 0);
ExpectIntEQ(privSz, ED448_KEY_SIZE);
ExpectIntEQ(XMEMCMP(key.k, priv, privSz), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_export_private_only(NULL, priv, &privSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_private_only(&key, NULL, &privSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
PRIVATE_KEY_LOCK();
/* MC/DC: the (ret == 0) && (*outLen < <size>) BUFFER_E checks in
* wc_ed448_export_public(), wc_ed448_export_private_only() and
* wc_ed448_export_private(). Each pair holds the size operand at a
* fixed too-small value across a NULL-key call (ret == 0 FALSE) and a
* valid-key call (ret == 0 TRUE), closing both operands. */
{
word32 tinyPubLen = ED448_PUB_KEY_SIZE - 1;
ExpectIntEQ(wc_ed448_export_public(NULL, pub, &tinyPubLen),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
tinyPubLen = ED448_PUB_KEY_SIZE - 1;
ExpectIntEQ(wc_ed448_export_public(&key, pub, &tinyPubLen),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(tinyPubLen, ED448_PUB_KEY_SIZE);
}
PRIVATE_KEY_UNLOCK();
{
word32 tinyPrivLen = ED448_KEY_SIZE - 1;
ExpectIntEQ(wc_ed448_export_private_only(NULL, priv, &tinyPrivLen),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
tinyPrivLen = ED448_KEY_SIZE - 1;
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &tinyPrivLen),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(tinyPrivLen, ED448_KEY_SIZE);
}
{
word32 tinyBothLen = ED448_PRV_KEY_SIZE - 1;
ExpectIntEQ(wc_ed448_export_private(NULL, priv, &tinyBothLen),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
tinyBothLen = ED448_PRV_KEY_SIZE - 1;
ExpectIntEQ(wc_ed448_export_private(&key, priv, &tinyBothLen),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(tinyBothLen, ED448_PRV_KEY_SIZE);
}
PRIVATE_KEY_LOCK();
#ifdef HAVE_ED448_KEY_IMPORT
/* Public-only key: re-init and import just the public part; private
* exports must still fail with privKeySet == 0. */
wc_ed448_free(&key);
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public(pub, pubSz, &key), 0);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_private(&key, priv, &privSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
PRIVATE_KEY_LOCK();
#endif /* !HAVE_FIPS || FIPS_VERSION3_GE(7,0,0) */
#endif
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_export */
/*
* Testing wc_ed448_size()
*/
int test_wc_ed448_size(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448)
ed448_key key;
WC_RNG rng;
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
ExpectIntEQ(wc_ed448_size(&key), ED448_KEY_SIZE);
/* Test bad args. */
ExpectIntEQ(wc_ed448_size(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_sig_size(&key), ED448_SIG_SIZE);
/* Test bad args. */
ExpectIntEQ(wc_ed448_sig_size(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_pub_size(&key), ED448_PUB_KEY_SIZE);
/* Test bad args. */
ExpectIntEQ(wc_ed448_pub_size(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_priv_size(&key), ED448_PRV_KEY_SIZE);
/* Test bad args. */
ExpectIntEQ(wc_ed448_priv_size(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_size */
/*
* Testing wc_ed448_export_private() and wc_ed448_export_key()
*/
int test_wc_ed448_exportKey(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)
ed448_key key;
WC_RNG rng;
byte priv[ED448_PRV_KEY_SIZE];
byte pub[ED448_PUB_KEY_SIZE];
byte privOnly[ED448_PRV_KEY_SIZE];
word32 privSz = sizeof(priv);
word32 pubSz = sizeof(pub);
word32 privOnlySz = sizeof(privOnly);
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private(&key, privOnly, &privOnlySz), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_export_private(NULL, privOnly, &privOnlySz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_private(&key, NULL, &privOnlySz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_private(&key, privOnly, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_key(&key, priv, &privSz, pub, &pubSz), 0);
/* Test bad args. */
ExpectIntEQ(wc_ed448_export_key(NULL, priv, &privSz, pub, &pubSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_key(&key, NULL, &privSz, pub, &pubSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_key(&key, priv, NULL, pub, &pubSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_key(&key, priv, &privSz, NULL, &pubSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_export_key(&key, priv, &privSz, pub, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
PRIVATE_KEY_LOCK();
/* Cross check output. */
ExpectIntEQ(XMEMCMP(priv, privOnly, privSz), 0);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_exportKey */
/*
* Testing wc_Ed448PublicKeyToDer
*/
int test_wc_Ed448PublicKeyToDer(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
(defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
ed448_key key;
byte derBuf[1024];
WC_RNG rng;
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(&key, 0, sizeof(ed448_key));
/* Test bad args */
ExpectIntEQ(wc_Ed448PublicKeyToDer(NULL, NULL, 0, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_init(&key), 0);
#if defined(HAVE_FIPS) && FIPS_VERSION3_LT(7,0,0)
if (EXPECT_SUCCESS()) {
int ret = wc_Ed448PublicKeyToDer(&key, derBuf, 0, 0);
ExpectTrue((ret == WC_NO_ERR_TRACE(BUFFER_E)) ||
(ret == WC_NO_ERR_TRACE(PUBLIC_KEY_E)));
}
#else
ExpectIntEQ(wc_Ed448PublicKeyToDer(&key, derBuf, 0, 0),
WC_NO_ERR_TRACE(PUBLIC_KEY_E));
#endif
wc_ed448_free(&key);
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
ExpectIntEQ(wc_Ed448PublicKeyToDer(&key, derBuf, 0, 0),
WC_NO_ERR_TRACE(BUFFER_E));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
/* Test good args */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* length only */
ExpectIntGT(wc_Ed448PublicKeyToDer(&key, NULL, 0, 0), 0);
ExpectIntGT(wc_Ed448PublicKeyToDer(&key, NULL, 0, 1), 0);
ExpectIntGT(wc_Ed448PublicKeyToDer(&key, derBuf,
(word32)sizeof(derBuf), 1), 0);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
}
#endif
return EXPECT_RESULT();
} /* END testing wc_Ed448PublicKeyToDer */
/*
* Testing wc_Ed448KeyToDer
*/
int test_wc_Ed448KeyToDer(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
(defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
byte output[ONEK_BUF];
ed448_key ed448Key;
WC_RNG rng;
word32 inLen;
XMEMSET(&ed448Key, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&ed448Key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &ed448Key), 0);
inLen = (word32)sizeof(output);
/* Bad Cases */
ExpectIntEQ(wc_Ed448KeyToDer(NULL, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Ed448KeyToDer(NULL, output, inLen),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Ed448KeyToDer(&ed448Key, output, 0),
WC_NO_ERR_TRACE(BUFFER_E));
/* Good Cases */
/* length only */
ExpectIntGT(wc_Ed448KeyToDer(&ed448Key, NULL, 0), 0);
ExpectIntGT(wc_Ed448KeyToDer(&ed448Key, output, inLen), 0);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&ed448Key);
#endif
return EXPECT_RESULT();
} /* End test_wc_Ed448KeyToDer */
/*
* Testing wc_Ed448PrivateKeyToDer
*/
int test_wc_Ed448PrivateKeyToDer(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
(defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
byte output[ONEK_BUF];
ed448_key ed448PrivKey;
WC_RNG rng;
word32 inLen;
XMEMSET(&ed448PrivKey, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_ed448_init(&ed448PrivKey), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &ed448PrivKey),
0);
inLen = (word32)sizeof(output);
/* Bad Cases */
ExpectIntEQ(wc_Ed448PrivateKeyToDer(NULL, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Ed448PrivateKeyToDer(NULL, output, inLen),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Ed448PrivateKeyToDer(&ed448PrivKey, output, 0),
WC_NO_ERR_TRACE(BUFFER_E));
/* Good cases */
/* length only */
ExpectIntGT(wc_Ed448PrivateKeyToDer(&ed448PrivKey, NULL, 0), 0);
ExpectIntGT(wc_Ed448PrivateKeyToDer(&ed448PrivKey, output, inLen), 0);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&ed448PrivKey);
#endif
return EXPECT_RESULT();
} /* End test_wc_Ed448PrivateKeyToDer */
/*
* RFC 5958: version=v2 (1) when pub key is bundled, v1 (0) for private only. */
int test_wc_Ed448KeyToDer_oneasymkey_version(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
defined(HAVE_ED448_KEY_IMPORT) && defined(WOLFSSL_KEY_GEN)
ed448_key key;
ed448_key key2;
WC_RNG rng;
byte ref[512]; /* reference DER (bundled, then private only) */
byte rt[512]; /* re-export target for memcmp */
int refSz = 0;
int rtSz = 0;
word32 idx;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&key2, 0, sizeof(key2));
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_init(&key2), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* Bundled (v=1) */
ExpectIntGT(refSz = wc_Ed448KeyToDer(&key, ref, (word32)sizeof(ref)), 0);
ExpectIntEQ(test_pkcs8_get_version_byte(ref, (word32)refSz), 1);
idx = 0;
ExpectIntEQ(wc_Ed448PrivateKeyDecode(ref, &idx, &key2, (word32)refSz), 0);
ExpectIntEQ(rtSz = wc_Ed448KeyToDer(&key2, rt, (word32)sizeof(rt)), refSz);
ExpectIntEQ(XMEMCMP(ref, rt, (size_t)refSz), 0);
/* Private only (v=0) */
ExpectIntGT(refSz = wc_Ed448PrivateKeyToDer(&key, ref,
(word32)sizeof(ref)), 0);
ExpectIntEQ(test_pkcs8_get_version_byte(ref, (word32)refSz), 0);
wc_ed448_free(&key);
wc_ed448_free(&key2);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
/* The trusted flag controls whether a public key bundled in the DER is
* checked against the private key during decode. */
int test_wc_Ed448PrivateKeyDecode_ex(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
defined(HAVE_ED448_KEY_IMPORT)
ed448_key key;
ed448_key key2;
WC_RNG rng;
byte der[512];
int derSz = 0;
word32 idx;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&key2, 0, sizeof(key2));
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_init(&key2), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* Bundled private+public DER; public key is the trailing
* ED448_PUB_KEY_SIZE bytes. */
ExpectIntGT(derSz = wc_Ed448KeyToDer(&key, der, (word32)sizeof(der)), 0);
/* Intact DER decodes with either trust setting. */
idx = 0;
ExpectIntEQ(wc_Ed448PrivateKeyDecode_ex(der, &idx, &key2,
(word32)derSz, 0), 0);
idx = 0;
ExpectIntEQ(wc_Ed448PrivateKeyDecode_ex(der, &idx, &key2,
(word32)derSz, 1), 0);
/* Corrupt the bundled public key. */
if (derSz > 0) {
der[derSz - 1] ^= 0x01;
}
/* Untrusted decode checks the public key and must reject it, as must
* the non-ex decode. */
idx = 0;
ExpectIntEQ(wc_Ed448PrivateKeyDecode_ex(der, &idx, &key2,
(word32)derSz, 0), WC_NO_ERR_TRACE(PUBLIC_KEY_E));
idx = 0;
ExpectIntEQ(wc_Ed448PrivateKeyDecode(der, &idx, &key2, (word32)derSz),
WC_NO_ERR_TRACE(PUBLIC_KEY_E));
/* Trusted decode skips the check. */
idx = 0;
ExpectIntEQ(wc_Ed448PrivateKeyDecode_ex(der, &idx, &key2,
(word32)derSz, 1), 0);
wc_ed448_free(&key);
wc_ed448_free(&key2);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
/* Ed448 identity and small-order public keys must be rejected.
* Edwards448 has cofactor 4, so the small-order subgroup contains the
* identity, an order-2 point, and two order-4 points. With any of these
* as the public key, h*A is the neutral element and forged signatures
* verify for arbitrary messages. Gated on FIPS_VERSION3_GE(7,0,0)
* because older FIPS-certified modules do not have this check in their
* frozen copy of ed448.c. */
int test_wc_ed448_reject_small_order_keys(void)
{
EXPECT_DECLS;
#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
/* Two regressions are guarded here. Both sign-bit variants of each
* y are listed so weakening the "clear all of byte 56" mask in
* ed448_is_small_order() would be caught. The non-canonical rows
* (y = p, y = p + 1) guard against dropping the canonical-form
* coverage: fe448_from_bytes reads bytes 0-55 modulo p with no
* canonical-form check, so y = p decodes to 0 and y = p + 1
* decodes to 1, both of which are small order. */
static const byte small_order_keys[][ED448_PUB_KEY_SIZE] = {
/* identity (y = 1), sign 0 */
{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00},
/* identity (y = 1), sign bit set */
{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80},
/* order 4: y = 0, x-sign 0 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00},
/* order 4: y = 0, x-sign 1 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80},
/* order 2: y = p - 1, x = 0, sign 0 */
{0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00},
/* order 2: y = p - 1, sign bit set */
{0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x80},
/* non-canonical y = p (decodes to y = 0), sign 0 */
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00},
/* non-canonical y = p, sign bit set */
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x80},
/* non-canonical y = p + 1 (decodes to y = 1), sign 0 */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00},
/* non-canonical y = p + 1, sign bit set */
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x80},
};
#ifndef NO_ED448_VERIFY
/* Arbitrary signature bytes: S = 1 (must be below the Ed448 group
* order or wc_ed448_verify_msg() returns BAD_FUNC_ARG before the
* small-order check has a chance to fire). The R bytes do not need
* to encode a valid curve point for this test - the small-order
* defence in ed448_verify_msg_final_with_sha() rejects the public
* key before the R/S verification math runs. */
static const byte forged_sig[ED448_SIG_SIZE] = {
/* R: 57 bytes of arbitrary data (last byte 0 to satisfy the
* spec-mandated zero of byte 56 bits 0-6; sign bit doesn't
* matter here). */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,
/* S = 1 */
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};
#endif
ed448_key key;
word32 i;
word32 num_keys = (word32)(sizeof(small_order_keys) / ED448_PUB_KEY_SIZE);
/* (1) Untrusted wc_ed448_import_public must reject every small-order
* encoding (it runs wc_ed448_check_key as part of the import). */
for (i = 0; i < num_keys; i++) {
int rc;
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
rc = wc_ed448_import_public(small_order_keys[i],
ED448_PUB_KEY_SIZE, &key);
if (rc != WC_NO_ERR_TRACE(PUBLIC_KEY_E)) {
fprintf(stderr, "small_order_keys[%u]: import_public returned %d, "
"expected PUBLIC_KEY_E\n", (unsigned)i, rc);
}
ExpectIntEQ(rc, WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&key);
}
/* (2) wc_ed448_check_key called directly must also reject. Guards
* against a refactor that moves the small-order check out of
* check_key and into the import path: (1) would still pass, but the
* documented check_key contract would silently regress. */
for (i = 0; i < num_keys; i++) {
int rc;
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
/* trusted = 1 bypasses the import-time check_key call so the
* direct check_key below is what's under test. */
ExpectIntEQ(wc_ed448_import_public_ex(small_order_keys[i],
ED448_PUB_KEY_SIZE, &key, 1), 0);
rc = wc_ed448_check_key(&key);
if (rc != WC_NO_ERR_TRACE(PUBLIC_KEY_E)) {
fprintf(stderr, "small_order_keys[%u]: check_key returned %d, "
"expected PUBLIC_KEY_E\n", (unsigned)i, rc);
}
ExpectIntEQ(rc, WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&key);
}
#ifndef NO_ED448_VERIFY
/* (3) Even a "trusted" import (which bypasses wc_ed448_check_key)
* must not let wc_ed448_verify_msg accept a forged signature against
* an identity public key. Test both the canonical encoding (y = 1,
* small_order_keys[0]) and the non-canonical encoding (y = p + 1,
* small_order_keys[8]) so the verify-side check is exercised against
* the canonical-form bypass route, not just the byte-for-byte
* identity. */
{
static const word32 identity_indices[] = { 0, 8 };
const char* msg = "forged message";
word32 j;
for (j = 0;
j < sizeof(identity_indices)/sizeof(identity_indices[0]);
j++) {
word32 idx = identity_indices[j];
int verify_result = 1;
int rc;
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public_ex(small_order_keys[idx],
ED448_PUB_KEY_SIZE, &key, 1), 0);
rc = wc_ed448_verify_msg(forged_sig, sizeof(forged_sig),
(const byte*)msg, (word32)XSTRLEN(msg), &verify_result,
&key, NULL, 0);
if (rc != WC_NO_ERR_TRACE(BAD_FUNC_ARG) || verify_result != 0) {
fprintf(stderr, "verify_msg with identity-equiv "
"small_order_keys[%u]: rc=%d verify_result=%d "
"(expected BAD_FUNC_ARG and 0)\n",
(unsigned)idx, rc, verify_result);
}
ExpectIntEQ(rc, WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_result, 0);
wc_ed448_free(&key);
}
}
#endif
#endif
return EXPECT_RESULT();
}
/* Ed448 public keys whose y-coordinate is not in [0, p - 1] must be rejected
* (RFC 8032 5.2.3: "If the resulting value is >= p, decoding fails").
* fe448_from_bytes() reads bytes 0-55 modulo p and ignores bits 0-6 of byte
* 56, so without the range test in wc_ed448_check_key() every such encoding
* decodes to the same point as a canonical one and is accepted. */
int test_wc_ed448_reject_noncanonical_y(void)
{
EXPECT_DECLS;
#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \
defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
/* RFC 8032 section 7.4 "Blank" public key: y < p, x-sign bit set. */
static const byte canonical_key[ED448_PUB_KEY_SIZE] = {
0x5f,0xd7,0x44,0x9b,0x59,0xb4,0x61,0xfd,
0x2c,0xe7,0x87,0xec,0x61,0x6a,0xd4,0x6a,
0x1d,0xa1,0x34,0x24,0x85,0xa7,0x0e,0x1f,
0x8a,0x0e,0xa7,0x5d,0x80,0xe9,0x67,0x78,
0xed,0xf1,0x24,0x76,0x9b,0x46,0xc7,0x06,
0x1b,0xd6,0x78,0x3d,0xf1,0xe5,0x0f,0x6c,
0xd1,0xfa,0x1a,0xbe,0xaf,0xe8,0x25,0x61,
0x80
};
/* y = 3 is on the curve; its canonical encoding is the control. */
static const byte y3_key[ED448_PUB_KEY_SIZE] = {
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};
/* y = 3 + p: same point as y3_key but y >= p. Bytes 29-55 are all 0xff
* and byte 28 is 0xff > 0xfe, so the range test must reject it before
* decompression; p = 2^448 - 2^224 - 1. */
static const byte y3_plus_p_key[ED448_PUB_KEY_SIZE] = {
0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0x00
};
byte bad[ED448_PUB_KEY_SIZE];
ed448_key key;
word32 i;
int rc;
/* Controls: canonical encodings import. */
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public(canonical_key, ED448_PUB_KEY_SIZE,
&key), 0);
wc_ed448_free(&key);
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public(y3_key, ED448_PUB_KEY_SIZE, &key), 0);
wc_ed448_free(&key);
/* y + p encoding: rejected by untrusted import and by a direct
* wc_ed448_check_key() after a trusted import. */
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public(y3_plus_p_key, ED448_PUB_KEY_SIZE,
&key), WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&key);
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public_ex(y3_plus_p_key, ED448_PUB_KEY_SIZE,
&key, 1), 0);
ExpectIntEQ(wc_ed448_check_key(&key), WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&key);
/* Bits 448-454 (byte 56 bits 0-6) are part of y and must be zero. Set
* each one in turn on an otherwise valid key: y >= 2^448 > p. */
for (i = 0; i < 7; i++) {
XMEMCPY(bad, canonical_key, sizeof(bad));
bad[ED448_PUB_KEY_SIZE - 1] |= (byte)(1U << i);
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
rc = wc_ed448_import_public(bad, ED448_PUB_KEY_SIZE, &key);
if (rc != WC_NO_ERR_TRACE(PUBLIC_KEY_E)) {
fprintf(stderr, "byte 56 bit %u set: import_public returned %d, "
"expected PUBLIC_KEY_E\n", (unsigned)i, rc);
}
ExpectIntEQ(rc, WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&key);
}
#ifndef NO_ED448_VERIFY
/* A trusted import bypasses wc_ed448_check_key(); wc_ed448_verify_msg()
* must still refuse to verify under a y >= p key. Signature bytes are
* arbitrary with S = 1 (below the group order) so the key check is what
* decides. */
{
static const byte sig[ED448_SIG_SIZE] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00
};
const char* msg = "non-canonical key";
int verify_result = 1;
XMEMCPY(bad, canonical_key, sizeof(bad));
bad[ED448_PUB_KEY_SIZE - 1] |= 0x7f;
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public_ex(bad, ED448_PUB_KEY_SIZE, &key,
1), 0);
ExpectIntEQ(wc_ed448_verify_msg(sig, sizeof(sig), (const byte*)msg,
(word32)XSTRLEN(msg), &verify_result, &key, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_result, 0);
wc_ed448_free(&key);
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_import_public_ex(y3_plus_p_key,
ED448_PUB_KEY_SIZE, &key, 1), 0);
ExpectIntEQ(wc_ed448_verify_msg(sig, sizeof(sig), (const byte*)msg,
(word32)XSTRLEN(msg), &verify_result, &key, NULL, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(verify_result, 0);
wc_ed448_free(&key);
}
#endif
#endif
return EXPECT_RESULT();
}
/*
* MC/DC decision coverage for wolfcrypt/src/ed448.c decisions the pre-existing
* ed448 API tests never drive: the sign/verify (context == NULL && contextLen
* != 0) compound and its "context != NULL" hash-update branches, the explicit
* wc_ed448_sign_msg_ex/verify_msg_ex type path, and the Ed448ph (prehash)
* sign/verify branches including the (type == Ed448ph && inLen !=
* ED448_PREHASH_SIZE) length check.
*/
int test_wc_Ed448DecisionCoverage(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
ed448_key key;
ed448_key key2;
WC_RNG rng;
byte msg[] = "ed448 decision coverage message";
byte ctx[] = "ed448-context";
byte sig[ED448_SIG_SIZE];
byte hash[ED448_PREHASH_SIZE];
byte badhash[ED448_PREHASH_SIZE - 1];
word32 sigLen = sizeof(sig);
word32 msgLen = sizeof(msg);
byte ctxLen = (byte)(sizeof(ctx) - 1);
int verify = 0;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&key2, 0, sizeof(key2));
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(sig, 0, sizeof(sig));
XMEMSET(hash, 0x5a, sizeof(hash));
XMEMSET(badhash, 0x5a, sizeof(badhash));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* MC/DC: the (ret == 0) && (context != NULL) hash-update guards in
* wc_ed448_sign_msg_ex() (both the nonce and the R/S hash phases share
* the same `ret` chain). A freshly-initialized key (pubKeySet == 0)
* with a non-NULL context makes the (ret == 0) operand FALSE while
* holding "context != NULL" at the same TRUE value used by the
* successful sign-with-context call below, closing that operand's
* independence pair without needing to force an internal hash
* failure. */
ExpectIntEQ(wc_ed448_init(&key2), 0);
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448_sign_msg(msg, msgLen, sig, &sigLen, &key2, ctx,
ctxLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wc_ed448_free(&key2);
/* Sign/verify with a non-NULL context: exercises the "context != NULL"
* side of the (context == NULL && contextLen != 0) compound plus the
* "context != NULL" hash-update branches in both sign and verify. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448_sign_msg(msg, msgLen, sig, &sigLen, &key, ctx, ctxLen),
0);
ExpectIntEQ(wc_ed448_verify_msg(sig, sigLen, msg, msgLen, &verify, &key,
ctx, ctxLen), 0);
ExpectIntEQ(verify, 1);
/* context == NULL && contextLen != 0: compound TRUE -> BAD_FUNC_ARG, in
* both the sign and verify sanity checks. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448_sign_msg(msg, msgLen, sig, &sigLen, &key, NULL, 5),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
verify = 0;
ExpectIntEQ(wc_ed448_verify_msg(sig, sizeof(sig), msg, msgLen, &verify,
&key, NULL, 5), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Explicit wc_ed448_sign_msg_ex/verify_msg_ex with type == Ed448. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448_sign_msg_ex(msg, msgLen, sig, &sigLen, &key,
(byte)Ed448, ctx, ctxLen), 0);
verify = 0;
ExpectIntEQ(wc_ed448_verify_msg_ex(sig, sigLen, msg, msgLen, &verify, &key,
(byte)Ed448, ctx, ctxLen), 0);
ExpectIntEQ(verify, 1);
/* Ed448ph: type == Ed448ph path through sign_msg_ex (prehash then sign)
* and the matching verify, without and with a context. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448ph_sign_msg(msg, msgLen, sig, &sigLen, &key, NULL, 0),
0);
verify = 0;
ExpectIntEQ(wc_ed448ph_verify_msg(sig, sigLen, msg, msgLen, &verify, &key,
NULL, 0), 0);
ExpectIntEQ(verify, 1);
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448ph_sign_msg(msg, msgLen, sig, &sigLen, &key, ctx,
ctxLen), 0);
verify = 0;
ExpectIntEQ(wc_ed448ph_verify_msg(sig, sigLen, msg, msgLen, &verify, &key,
ctx, ctxLen), 0);
ExpectIntEQ(verify, 1);
/* Ed448ph prehash sign/verify with a correctly sized hash. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448ph_sign_hash(hash, sizeof(hash), sig, &sigLen, &key,
NULL, 0), 0);
verify = 0;
ExpectIntEQ(wc_ed448ph_verify_hash(sig, sigLen, hash, sizeof(hash), &verify,
&key, NULL, 0), 0);
ExpectIntEQ(verify, 1);
#if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)
/* type == Ed448ph && inLen != ED448_PREHASH_SIZE -> BAD_LENGTH_E
* (sign_hash forwards hashLen as inLen with type Ed448ph). */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448ph_sign_hash(badhash, sizeof(badhash), sig, &sigLen,
&key, NULL, 0), WC_NO_ERR_TRACE(BAD_LENGTH_E));
/* MC/DC: wc_ed448_verify_msg_ex()'s (type == Ed448ph &&
* msgLen != ED448_PREHASH_SIZE) check, verify side. Paired with the
* regular (non-ph) verify calls above (type == Ed448ph FALSE, msgLen
* != PREHASH_SIZE TRUE) for the type operand, and with the
* correctly-sized Ed448ph verify_hash call above (type == Ed448ph
* TRUE, msgLen != PREHASH_SIZE FALSE) for the length operand. */
ExpectIntEQ(wc_ed448ph_verify_hash(sig, sigLen, badhash, sizeof(badhash),
&verify, &key, NULL, 0), WC_NO_ERR_TRACE(BAD_LENGTH_E));
#endif
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_Ed448DecisionCoverage */
/*
* Feature coverage for the ed448 streaming verify API
* (wc_ed448_verify_msg_init/update/final): positive multi-chunk verification
* (loop true-sides) without and with a context, plus the update NULL-segment
* and init/final NULL argument guards. Guarded identically to the streaming
* verify code under test so it auto-skips where the feature is compiled out.
*/
int test_wc_Ed448FeatureCoverage(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && \
defined(HAVE_ED448_VERIFY) && defined(WOLFSSL_ED448_STREAMING_VERIFY)
ed448_key key;
WC_RNG rng;
byte msg[] = "streaming multi-chunk ed448 verify message body";
byte ctx[] = "stream-ctx";
byte sig[ED448_SIG_SIZE];
word32 sigLen = sizeof(sig);
word32 msgLen = sizeof(msg);
byte ctxLen = (byte)(sizeof(ctx) - 1);
int verify = 0;
word32 off;
word32 chunk = 7;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(sig, 0, sizeof(sig));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
/* Sign the whole message (no context), then verify it through the
* streaming init/update(x N)/final API a few bytes at a time. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448_sign_msg(msg, msgLen, sig, &sigLen, &key, NULL, 0), 0);
ExpectIntEQ(wc_ed448_verify_msg_init(sig, sigLen, &key, (byte)Ed448, NULL,
0), 0);
for (off = 0; off < msgLen; off += chunk) {
word32 n = (msgLen - off < chunk) ? (msgLen - off) : chunk;
ExpectIntEQ(wc_ed448_verify_msg_update(msg + off, n, &key), 0);
}
ExpectIntEQ(wc_ed448_verify_msg_final(sig, sigLen, &verify, &key), 0);
ExpectIntEQ(verify, 1);
/* Same, but with a non-NULL context supplied at init. */
sigLen = sizeof(sig);
ExpectIntEQ(wc_ed448_sign_msg(msg, msgLen, sig, &sigLen, &key, ctx, ctxLen),
0);
ExpectIntEQ(wc_ed448_verify_msg_init(sig, sigLen, &key, (byte)Ed448, ctx,
ctxLen), 0);
for (off = 0; off < msgLen; off += chunk) {
word32 n = (msgLen - off < chunk) ? (msgLen - off) : chunk;
ExpectIntEQ(wc_ed448_verify_msg_update(msg + off, n, &key), 0);
}
verify = 0;
ExpectIntEQ(wc_ed448_verify_msg_final(sig, sigLen, &verify, &key), 0);
ExpectIntEQ(verify, 1);
/* Negative decisions in the streaming path: init NULL sig, update NULL
* segment (ed448_verify_msg_update_with_sha's msgSegment == NULL guard),
* final NULL res. */
ExpectIntEQ(wc_ed448_verify_msg_init(NULL, sigLen, &key, (byte)Ed448, NULL,
0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg_init(sig, sigLen, &key, (byte)Ed448, NULL,
0), 0);
ExpectIntEQ(wc_ed448_verify_msg_update(NULL, msgLen, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg_update(msg, msgLen, &key), 0);
/* MC/DC: ed448_verify_msg_final_with_sha()'s sig == NULL operand
* (reachable only through the streaming final() API, since
* wc_ed448_verify_msg_ex() always calls the init step -- which itself
* rejects a NULL sig -- before ever reaching the final step). */
ExpectIntEQ(wc_ed448_verify_msg_final(NULL, sigLen, &verify, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ed448_verify_msg_final(sig, sigLen, NULL, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_Ed448FeatureCoverage */
/*
* MC/DC decision coverage for wolfcrypt/src/ed448.c's
* wc_ed448_import_private_only(): the (priv == NULL || key == NULL) arg
* check, the (ret == 0 && privSz != ED448_KEY_SIZE) length check, the
* (ret == 0 && key->pubKeySet) validate-against-public-key branch, and the
* (ret != 0 && key != NULL) error-cleanup guard. No existing test called
* this function at all before this addition.
*/
int test_wc_ed448_import_private_only(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) && \
defined(HAVE_ED448_KEY_EXPORT)
ed448_key key;
ed448_key key2;
WC_RNG rng;
byte priv[ED448_KEY_SIZE];
byte privOnly[ED448_KEY_SIZE];
word32 privOnlySz = sizeof(privOnly);
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&key2, 0, sizeof(key2));
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(priv, 0x11, sizeof(priv));
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_init(&key2), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private_only(&key, privOnly, &privOnlySz), 0);
PRIVATE_KEY_LOCK();
/* Baseline: key2 has neither key set. Valid priv + correct size ->
* success. Gives (ret == 0) TRUE with (privSz != SIZE) FALSE, and
* (key->pubKeySet) FALSE with (ret == 0) TRUE. */
ExpectIntEQ(wc_ed448_import_private_only(priv, ED448_KEY_SIZE, &key2), 0);
/* (ret == 0) && (privSz != ED448_KEY_SIZE): TRUE side, holding the
* arg-NULL operands FALSE (priv/key both valid). */
ExpectIntEQ(wc_ed448_import_private_only(priv, ED448_KEY_SIZE - 1, &key2),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* priv == NULL, with the same too-small privSz held constant across
* the pair: (ret == 0) FALSE here (short-circuited by the arg check)
* vs TRUE above -> closes the (ret == 0) operand of the privSz check.
* Also priv == NULL with key != NULL (held valid across this call and
* the baseline) closes the arg-check OR's priv-operand. */
ExpectIntEQ(wc_ed448_import_private_only(NULL, ED448_KEY_SIZE - 1, &key2),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* key == NULL, with priv held valid/non-NULL across this call and the
* baseline: closes the arg-check OR's key-operand. Also gives
* (ret != 0) && (key == NULL) for the error-cleanup guard below, which
* must not dereference key. */
ExpectIntEQ(wc_ed448_import_private_only(priv, ED448_KEY_SIZE, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* (ret == 0) && key->pubKeySet: TRUE side. `key` already has
* pubKeySet == 1 from wc_ed448_make_key() above; re-importing its own
* exported private key recomputes a matching public key, so
* wc_ed448_check_key() succeeds and ret stays 0. */
ExpectIntEQ(wc_ed448_import_private_only(privOnly, ED448_KEY_SIZE, &key),
0);
/* (ret == 0) FALSE with key->pubKeySet held TRUE (same `key`, still
* pubKeySet == 1): a bad privSz trips the length check first, so the
* pubKeySet branch is never reached with ret == 0 -- closes that
* operand's independence pair. This call's (ret != 0) && (key != NULL)
* also closes the error-cleanup guard's independence pairs alongside
* the baseline (ret == 0) and key == NULL (above) calls. */
ExpectIntEQ(wc_ed448_import_private_only(priv, ED448_KEY_SIZE - 1, &key),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
wc_ed448_free(&key2);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_import_private_only */
/*
* MC/DC decision coverage for wolfcrypt/src/ed448.c's wc_ed448_check_key():
* the (ret == 0 && !key->pubKeySet) "have a public key" gate, the
* (ret == 0) operand of the (ret == 0 && ed448_is_small_order(...)) defence
* (the is_small_order VALUE operand's independence is already shown by
* test_wc_ed448_reject_small_order_keys()), the (ret == 0 &&
* XMEMCMP(...) != 0) recomputed-vs-stored public key mismatch check in the
* have-private-key branch, and both decisions of the Y-range walk: the
* top-byte loop and the 0xFE compare that follows it.
*/
int test_wc_ed448_check_key_decisions(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)
ed448_key key;
ed448_key freshKey;
WC_RNG rng;
byte near_p[ED448_PUB_KEY_SIZE];
int rc;
XMEMSET(&key, 0, sizeof(key));
XMEMSET(&freshKey, 0, sizeof(freshKey));
XMEMSET(&rng, 0, sizeof(rng));
/* key == NULL: (ret == 0) FALSE side (short-circuited before any key
* dereference). */
ExpectIntEQ(wc_ed448_check_key(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Freshly-initialized key: key != NULL (ret == 0 TRUE) but pubKeySet
* == 0 -> PUBLIC_KEY_E. Closes the pubKeySet operand's TRUE side and,
* paired against the NULL call above, the (ret == 0) operand of this
* same decision. Also gives the (ret == 0) FALSE side of the
* small-order check below it (ret is already PUBLIC_KEY_E by the time
* that line runs, so it short-circuits without touching key->p). */
ExpectIntEQ(wc_ed448_init(&freshKey), 0);
ExpectIntEQ(wc_ed448_check_key(&freshKey), WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&freshKey);
/* Real key pair: pubKeySet == 1 (closes the pubKeySet operand's FALSE
* side), not small order, private key matches public key -> success.
* Gives the (ret == 0) TRUE side of the small-order check (paired
* against the fresh-key call above) and the FALSE side of the
* recomputed-public-key-mismatch compare below. */
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
ExpectIntEQ(wc_ed448_check_key(&key), 0);
/* Tamper with the stored public key while keeping the private key:
* wc_ed448_make_public() recomputes the real public key from key->k,
* which will now differ from the corrupted key->p -> XMEMCMP(...) != 0
* TRUE -> PUBLIC_KEY_E. Closes the mismatch operand's TRUE side. */
key.p[0] = (byte)(key.p[0] ^ 0xff);
ExpectIntEQ(wc_ed448_check_key(&key), WC_NO_ERR_TRACE(PUBLIC_KEY_E));
/* Restore so wc_ed448_free()'s zeroize-check doesn't care either way.*/
key.p[0] = (byte)(key.p[0] ^ 0xff);
/* Deep Y-range check: a Y value that is not one of
* ed448_is_small_order()'s tabulated points but still runs the top-byte
* loop to exhaustion (every byte above the 0xFE position is 0xff), so
* the loop's index operand goes false and the 0xFE compare below it is
* reached and taken. Only reachable via a trusted import, which skips
* wc_ed448_check_key() at import time so the crafted (curve-invalid)
* point can be handed to a *direct* wc_ed448_check_key() call below --
* same technique as test_wc_ed448_reject_small_order_keys(). Whatever
* the later curve-decode step decides is fine; the range-check decision
* itself is what's targeted here. */
XMEMSET(near_p, 0xff, sizeof(near_p));
near_p[28] = 0xfe;
near_p[0] = 0x00;
ExpectIntEQ(wc_ed448_init(&freshKey), 0);
ExpectIntEQ(wc_ed448_import_public_ex(near_p, ED448_PUB_KEY_SIZE,
&freshKey, 1), 0);
rc = wc_ed448_check_key(&freshKey);
ExpectTrue((rc == 0) || (rc == WC_NO_ERR_TRACE(PUBLIC_KEY_E)));
wc_ed448_free(&freshKey);
/* Same construction with a byte inside the walked range cleared, so the
* loop breaks with ret == 0 instead of running out: closes the byte
* compare's TRUE side and the FALSE side of the public-key-error guard
* that follows it. */
near_p[29] = 0x00;
ExpectIntEQ(wc_ed448_init(&freshKey), 0);
ExpectIntEQ(wc_ed448_import_public_ex(near_p, ED448_PUB_KEY_SIZE,
&freshKey, 1), 0);
rc = wc_ed448_check_key(&freshKey);
ExpectTrue((rc == 0) || (rc == WC_NO_ERR_TRACE(PUBLIC_KEY_E)));
wc_ed448_free(&freshKey);
/* Every byte 0xff, including the 0xFE position: not a tabulated
* small-order encoding, the walk finds no byte below 0xff and the 0xFE
* compare is false, so the Y value is out of range. Closes that
* compare's FALSE side. */
XMEMSET(near_p, 0xff, sizeof(near_p));
ExpectIntEQ(wc_ed448_init(&freshKey), 0);
ExpectIntEQ(wc_ed448_import_public_ex(near_p, ED448_PUB_KEY_SIZE,
&freshKey, 1), 0);
ExpectIntEQ(wc_ed448_check_key(&freshKey),
WC_NO_ERR_TRACE(PUBLIC_KEY_E));
wc_ed448_free(&freshKey);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_check_key_decisions */
/* Test Ed448 sign/verify routed through a crypto callback (CryptoCb) device. */
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_ED448) && \
defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY) && \
!defined(WC_NO_RNG)
typedef struct ed448SpyCtx {
int signSeen;
int verifySeen;
} ed448SpyCtx;
/* Spy device: services Ed448 sign/verify in software (devId cleared) and counts
* each; declines everything else so make_key runs in software. */
static int ed448_test_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
ed448SpyCtx* spy = (ed448SpyCtx*)ctx;
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
(void)devIdArg;
if (info == NULL || spy == NULL) {
return BAD_FUNC_ARG;
}
if (info->algo_type == WC_ALGO_TYPE_PK) {
#ifdef HAVE_ED448_SIGN
if (info->pk.type == WC_PK_TYPE_ED448) {
int save = info->pk.ed448sign.key->devId;
info->pk.ed448sign.key->devId = INVALID_DEVID;
ret = wc_ed448_sign_msg_ex(
info->pk.ed448sign.in, info->pk.ed448sign.inLen,
info->pk.ed448sign.out, info->pk.ed448sign.outLen,
info->pk.ed448sign.key, info->pk.ed448sign.type,
info->pk.ed448sign.context, info->pk.ed448sign.contextLen);
info->pk.ed448sign.key->devId = save;
spy->signSeen++;
}
#endif
#ifdef HAVE_ED448_VERIFY
if (info->pk.type == WC_PK_TYPE_ED448_VERIFY) {
int save = info->pk.ed448verify.key->devId;
info->pk.ed448verify.key->devId = INVALID_DEVID;
ret = wc_ed448_verify_msg_ex(
info->pk.ed448verify.sig, info->pk.ed448verify.sigLen,
info->pk.ed448verify.msg, info->pk.ed448verify.msgLen,
info->pk.ed448verify.res, info->pk.ed448verify.key,
info->pk.ed448verify.type, info->pk.ed448verify.context,
info->pk.ed448verify.contextLen);
info->pk.ed448verify.key->devId = save;
spy->verifySeen++;
}
#endif
}
return ret;
}
#endif
int test_wc_ed448_cryptocb(void)
{
EXPECT_DECLS;
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_ED448) && \
defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY) && \
!defined(WC_NO_RNG)
int devId = 4448;
ed448SpyCtx spy;
WC_RNG rng;
byte msg[32];
word32 sigLen = ED448_SIG_SIZE;
int verify = 0;
WC_DECLARE_VAR(key, ed448_key, 1, HEAP_HINT);
WC_DECLARE_VAR(sig, byte, ED448_SIG_SIZE, HEAP_HINT);
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&spy, 0, sizeof(spy));
XMEMSET(msg, 0x5a, sizeof(msg));
WC_ALLOC_VAR(key, ed448_key, 1, HEAP_HINT);
WC_ALLOC_VAR(sig, byte, ED448_SIG_SIZE, HEAP_HINT);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
ExpectNotNull(key);
ExpectNotNull(sig);
#endif
if (WC_VAR_OK(sig)) {
XMEMSET(sig, 0, ED448_SIG_SIZE);
}
ExpectIntEQ(wc_CryptoCb_RegisterDevice(devId, ed448_test_crypto_cb, &spy),
0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_init_ex(key, HEAP_HINT, devId), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, key), 0);
/* Sign routes through the device callback. */
ExpectIntEQ(wc_ed448_sign_msg(msg, (word32)sizeof(msg), sig, &sigLen, key,
NULL, 0), 0);
ExpectIntGE(spy.signSeen, 1);
/* Verify routes through the device callback. */
ExpectIntEQ(wc_ed448_verify_msg(sig, sigLen, msg, (word32)sizeof(msg),
&verify, key, NULL, 0), 0);
ExpectIntGE(spy.verifySeen, 1);
ExpectIntEQ(verify, 1);
/* Negative: corrupt the signature. Ed448 reports a bad signature as
* SIG_VERIFY_E, exercising the device verify error path (verify == 0). */
if (WC_VAR_OK(sig)) {
sig[0] ^= 0xFF;
}
verify = 1;
ExpectIntEQ(wc_ed448_verify_msg(sig, sigLen, msg, (word32)sizeof(msg),
&verify, key, NULL, 0),
WC_NO_ERR_TRACE(SIG_VERIFY_E));
ExpectIntGE(spy.verifySeen, 2);
ExpectIntEQ(verify, 0);
wc_ed448_free(key);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_CryptoCb_UnRegisterDevice(devId);
WC_FREE_VAR(sig, HEAP_HINT);
WC_FREE_VAR(key, HEAP_HINT);
#endif
return EXPECT_RESULT();
}
#if defined(HAVE_ED448) && defined(WOLF_CRYPTO_CB) && \
defined(ED448_MAX_ID_LEN)
typedef struct ed448DevPubCtx {
int decline;
int calls;
} ed448DevPubCtx;
/* Device that knows the public key of the key it holds by reference. */
static int ed448_dev_pub_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
ed448DevPubCtx* dev = (ed448DevPubCtx*)ctx;
(void)devIdArg;
if ((info->algo_type != WC_ALGO_TYPE_PK) ||
(info->pk.type != WC_PK_TYPE_ED448_MAKE_PUB)) {
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
}
dev->calls++;
if (dev->decline) {
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
}
XMEMSET(info->pk.ed448makepub.pubOut, 0x5a,
info->pk.ed448makepub.pubOutSz);
return 0;
}
#endif
/*
* Testing wc_ed448_make_public() on a key held by a device.
*/
int test_wc_ed448_make_public_dev_key(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(WOLF_CRYPTO_CB) && \
defined(ED448_MAX_ID_LEN)
int devId = 4480;
ed448DevPubCtx dev;
ed448_key key;
static const byte id[] = { 0x01, 0x02, 0x03, 0x04 };
byte pub[ED448_PUB_KEY_SIZE];
byte expPub[ED448_PUB_KEY_SIZE];
XMEMSET(&dev, 0, sizeof(dev));
XMEMSET(&key, 0, sizeof(key));
XMEMSET(expPub, 0x5a, sizeof(expPub));
ExpectIntEQ(wc_CryptoCb_RegisterDevice(devId, ed448_dev_pub_cb, &dev), 0);
ExpectIntEQ(wc_ed448_init_id(&key, id, (int)sizeof(id), NULL, devId), 0);
ExpectIntEQ(wc_ed448_make_public(&key, pub, (word32)sizeof(pub)), 0);
ExpectIntEQ(dev.calls, 1);
ExpectBufEQ(pub, expPub, sizeof(pub));
ExpectIntEQ(key.pubKeySet, 1);
ExpectBufEQ(key.p, expPub, sizeof(expPub));
wc_ed448_free(&key);
/* Declined by the device, there is no private key to derive from. */
dev.decline = 1;
ExpectIntEQ(wc_ed448_init_label(&key, "dev-key", NULL, devId), 0);
ExpectIntEQ(wc_ed448_make_public(&key, pub, (word32)sizeof(pub)),
WC_NO_ERR_TRACE(ECC_PRIV_KEY_E));
ExpectIntEQ(dev.calls, 2);
ExpectIntEQ(key.pubKeySet, 0);
wc_ed448_free(&key);
ExpectIntEQ(wc_ed448_init_id(&key, id, (int)sizeof(id), NULL,
INVALID_DEVID), 0);
ExpectIntEQ(wc_ed448_make_public(&key, pub, (word32)sizeof(pub)),
WC_NO_ERR_TRACE(ECC_PRIV_KEY_E));
ExpectIntEQ(dev.calls, 2);
wc_ed448_free(&key);
wc_CryptoCb_UnRegisterDevice(devId);
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_make_public_dev_key */