Files
wolfssl/tests/api/test_eccsi.c
T
Daniele Lacamera e799f180af tests: fix eccsi ValidateEccsiPair error code under WOLFSSL_SP_MATH
wc_ValidateEccsiPair() reports an off-curve PVT via wc_ecc_is_point(), whose
error code is backend-dependent: the mp-based check (classic / SP_MATH_ALL /
fast-math) returns IS_POINT_E, but the minimal WOLFSSL_SP_MATH backend routes
through sp_ecc_is_point_*(), which returns MP_VAL for a point not on the curve
(and eccsi.c only remaps -1 -> IS_POINT_E, not MP_VAL). Select the expected
code per backend so the all-pq-sp-math CI config (--enable-sp-math) passes.

Verified: full unit.test --api under --enable-all --enable-sp-math --enable-sp-asm
reports 0 failures.
2026-07-31 12:56:52 +02:00

863 lines
39 KiB
C

/* test_eccsi.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/eccsi.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/types.h>
#include <tests/api/api.h>
#include <tests/api/test_eccsi.h>
/*
* MC/DC: argument/bounds/state-validation decisions in
* wolfcrypt/src/eccsi.c's public (WOLFSSL_API) functions. All curve
* work uses NIST P-256 (key size 32 bytes), matching wolfcrypt/test's
* eccsi_test().
*
* Two persistent EccsiKey objects are used through most of this test to
* reach the "ECC_PRIVATEKEY" and "ECC_PUBLICKEY" halves of the repeated
* (key->ecc.type != ECC_PRIVATEKEY) && (key->ecc.type != ECC_PUBLICKEY)
* state-validation pattern:
* keyPriv - wc_InitEccsiKey() + wc_MakeEccsiKey() -> type ECC_PRIVATEKEY
* keyPub - wc_InitEccsiKey() + wc_ImportEccsiPublicKey() -> ECC_PUBLICKEY
* A third, keyState0, is only wc_InitEccsiKey()'d (type left at 0 by the
* XMEMSET in Init) so it is neither, isolating the state check's true
* (BAD_STATE_E) leg.
*
* Two decisions are structurally unreachable through the public API and
* are not exercised here (see the closing notes in the assistant's
* report rather than forced/whiteboxed):
* - wc_HashEccsiId()'s "curveSz < 0" leg (eccsi.c ~line 1645): dp->id
* is always a curve that wc_ecc_get_curve_size_from_id() accepts
* once wc_ecc_set_curve() has succeeded.
* - wc_ValidateEccsiPair()'s and wc_VerifyEccsiHash()'s trailing
* "if (valid/verified != NULL)" (eccsi.c ~lines 1547, 2303): both
* functions already return early via a prior "== NULL" check on the
* same out-param, so by the time these lines run the pointer is
* always non-NULL.
*/
int test_wc_Eccsi_DecisionCoverage(void)
{
EXPECT_DECLS;
#ifdef WOLFCRYPT_HAVE_ECCSI
EccsiKey keyPriv;
EccsiKey keyPub;
EccsiKey keyState0;
EccsiKey keyScratch;
WC_RNG rng;
mp_int ssk;
mp_int decSsk;
ecc_point* pvt = NULL;
ecc_point* badPvt = NULL;
ecc_point* decPvt = NULL;
char mail[] = "test@wolfssl.com";
byte* id = (byte*)mail;
word32 idSz;
byte data[256];
word32 sz;
byte keyBuf[32 * 3];
word32 keyBufSz;
byte privBuf[32];
word32 privBufSz;
byte pubKeyData[32 * 2];
word32 pubKeySz;
byte dataRaw[32 * 2];
word32 szRaw;
byte dataDesc[32 * 2 + 1];
word32 szDesc;
byte sigLike[32 * 4 + 1];
byte hashBuf[WC_MAX_DIGEST_SIZE];
byte hBSz;
byte msg[1] = { 0x00 };
word32 msgSz = (word32)sizeof(msg);
byte sigBuf[32 * 4 + 1];
word32 realSigSz;
int valid = 0;
int verified = 0;
XMEMSET(&keyPriv, 0, sizeof(keyPriv));
XMEMSET(&keyPub, 0, sizeof(keyPub));
XMEMSET(&keyState0, 0, sizeof(keyState0));
XMEMSET(&keyScratch, 0, sizeof(keyScratch));
XMEMSET(data, 0, sizeof(data));
XMEMSET(keyBuf, 0, sizeof(keyBuf));
XMEMSET(privBuf, 0, sizeof(privBuf));
XMEMSET(pubKeyData, 0, sizeof(pubKeyData));
XMEMSET(dataRaw, 0, sizeof(dataRaw));
XMEMSET(dataDesc, 0, sizeof(dataDesc));
XMEMSET(sigLike, 0, sizeof(sigLike));
XMEMSET(hashBuf, 0, sizeof(hashBuf));
XMEMSET(sigBuf, 0, sizeof(sigBuf));
idSz = (word32)XSTRLEN(mail);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectNotNull(pvt = wc_ecc_new_point());
ExpectNotNull(badPvt = wc_ecc_new_point());
ExpectNotNull(decPvt = wc_ecc_new_point());
ExpectIntEQ(mp_init(&ssk), MP_OKAY);
ExpectIntEQ(mp_init(&decSsk), MP_OKAY);
/* --- wc_InitEccsiKey_ex() / wc_InitEccsiKey() / wc_FreeEccsiKey() ---
* eccsi.c ~line 65: if (key == NULL) err = BAD_FUNC_ARG;
* eccsi.c ~line 137: if (key != NULL) { ...free... }
*/
ExpectIntEQ(wc_InitEccsiKey_ex(NULL, 32, ECC_SECP256R1, HEAP_HINT,
INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_InitEccsiKey(NULL, HEAP_HINT, INVALID_DEVID),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_InitEccsiKey_ex(&keyScratch, 32, ECC_SECP256R1, HEAP_HINT,
INVALID_DEVID), 0);
wc_FreeEccsiKey(NULL); /* key == NULL: false branch, no-op */
wc_FreeEccsiKey(&keyScratch); /* key != NULL: true branch, frees it */
ExpectIntEQ(wc_InitEccsiKey(&keyPriv, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_InitEccsiKey(&keyState0, HEAP_HINT, INVALID_DEVID), 0);
/* keyPub must be initialized (sets the ECC curve, so key->ecc.dp is
* non-NULL) before wc_ImportEccsiPublicKey() reads key->ecc.dp->size. */
ExpectIntEQ(wc_InitEccsiKey(&keyPub, HEAP_HINT, INVALID_DEVID), 0);
/* --- wc_MakeEccsiKey() (KMS): (key==NULL) || (rng==NULL) --- */
ExpectIntEQ(wc_MakeEccsiKey(NULL, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_MakeEccsiKey(&keyPriv, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Baseline: all valid -- keyPriv becomes type ECC_PRIVATEKEY. */
ExpectIntEQ(wc_MakeEccsiKey(&keyPriv, &rng), 0);
/* --- wc_ExportEccsiKey() / wc_ImportEccsiKey() (KMS) ---
* eccsi.c ~line 627: (key==NULL) || (sz==NULL)
* eccsi.c ~line 631: (err==0) && (key->ecc.type != ECC_PRIVATEKEY)
* eccsi.c ~line 636: data==NULL -> LENGTH_ONLY_E; else *sz < needed
* -> BUFFER_E; else success.
* eccsi.c ~line 706 (Import): (key==NULL) || (data==NULL)
* eccsi.c ~line 709 (Import): sz != key->ecc.dp->size * 3
*/
ExpectIntEQ(wc_ExportEccsiKey(NULL, data, &sz), WC_NO_ERR_TRACE(
BAD_FUNC_ARG));
ExpectIntEQ(wc_ExportEccsiKey(&keyPriv, data, NULL), WC_NO_ERR_TRACE(
BAD_FUNC_ARG));
/* State check: keyState0 has not been wc_MakeEccsiKey()'d. */
sz = sizeof(data);
ExpectIntEQ(wc_ExportEccsiKey(&keyState0, data, &sz),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* data == NULL -> LENGTH_ONLY_E, size query. */
ExpectIntEQ(wc_ExportEccsiKey(&keyPriv, NULL, &sz),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sz, (word32)(32 * 3));
/* *sz too small -> BUFFER_E. */
sz = 32 * 3 - 1;
ExpectIntEQ(wc_ExportEccsiKey(&keyPriv, keyBuf, &sz),
WC_NO_ERR_TRACE(BUFFER_E));
/* Success. */
keyBufSz = sizeof(keyBuf);
ExpectIntEQ(wc_ExportEccsiKey(&keyPriv, keyBuf, &keyBufSz), 0);
ExpectIntEQ(keyBufSz, (word32)(32 * 3));
ExpectIntEQ(wc_ImportEccsiKey(NULL, keyBuf, keyBufSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ImportEccsiKey(&keyPriv, NULL, keyBufSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ImportEccsiKey(&keyPriv, keyBuf, keyBufSz - 1),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_ImportEccsiKey(&keyPriv, keyBuf, keyBufSz), 0);
/* --- wc_ExportEccsiPrivateKey() / wc_ImportEccsiPrivateKey() (KMS) ---
* Same shape as wc_Export/ImportEccsiKey() above, size == key size.
*/
ExpectIntEQ(wc_ExportEccsiPrivateKey(NULL, data, &sz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ExportEccsiPrivateKey(&keyPriv, data, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
sz = sizeof(data);
ExpectIntEQ(wc_ExportEccsiPrivateKey(&keyState0, data, &sz),
WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(wc_ExportEccsiPrivateKey(&keyPriv, NULL, &sz),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sz, (word32)32);
sz = 31;
ExpectIntEQ(wc_ExportEccsiPrivateKey(&keyPriv, privBuf, &sz),
WC_NO_ERR_TRACE(BUFFER_E));
privBufSz = sizeof(privBuf);
ExpectIntEQ(wc_ExportEccsiPrivateKey(&keyPriv, privBuf, &privBufSz), 0);
ExpectIntEQ(privBufSz, (word32)32);
ExpectIntEQ(wc_ImportEccsiPrivateKey(NULL, privBuf, privBufSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ImportEccsiPrivateKey(&keyPriv, NULL, privBufSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ImportEccsiPrivateKey(&keyPriv, privBuf, privBufSz - 1),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_ImportEccsiPrivateKey(&keyPriv, privBuf, privBufSz), 0);
/* --- wc_ExportEccsiPublicKey() (KMS) ---
* eccsi.c ~line 835: (key==NULL) || (sz==NULL)
* eccsi.c ~line 838: (err==0) && (type!=PRIVATEKEY) && (type!=PUBLICKEY)
* eccsi.c ~line 843: (err==0) && (data != NULL)
* (delegates to eccsi_encode_point(): data==NULL -> LENGTH_ONLY_E;
* *sz < needed -> BUFFER_E)
*/
ExpectIntEQ(wc_ExportEccsiPublicKey(NULL, data, &sz, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ExportEccsiPublicKey(&keyPriv, data, NULL, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyState0 is neither PRIVATEKEY nor PUBLICKEY -> BAD_STATE_E */
sz = sizeof(data);
ExpectIntEQ(wc_ExportEccsiPublicKey(&keyState0, data, &sz, 1),
WC_NO_ERR_TRACE(BAD_STATE_E));
/* State: keyPriv is PRIVATEKEY (first term false) -> valid. */
ExpectIntEQ(wc_ExportEccsiPublicKey(&keyPriv, NULL, &sz, 1),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sz, (word32)(32 * 2));
/* data != NULL branch + *sz too small -> BUFFER_E. */
sz = 32 * 2 - 1;
ExpectIntEQ(wc_ExportEccsiPublicKey(&keyPriv, pubKeyData, &sz, 1),
WC_NO_ERR_TRACE(BUFFER_E));
/* Success (raw == 1, no descriptor byte). */
pubKeySz = sizeof(pubKeyData);
ExpectIntEQ(wc_ExportEccsiPublicKey(&keyPriv, pubKeyData, &pubKeySz, 1),
0);
ExpectIntEQ(pubKeySz, (word32)(32 * 2));
/* --- wc_ImportEccsiPublicKey() (CLIENT) ---
* eccsi.c ~line 1301: (key==NULL) || (data==NULL)
* eccsi.c ~line 1315: (err==0) && (!trusted)
*/
ExpectIntEQ(wc_ImportEccsiPublicKey(NULL, pubKeyData, pubKeySz, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ImportEccsiPublicKey(&keyPub, NULL, pubKeySz, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* trusted == 1: !trusted false, wc_ecc_check_key() skipped. */
ExpectIntEQ(wc_ImportEccsiPublicKey(&keyPub, pubKeyData, pubKeySz, 1),
0);
/* trusted == 0: !trusted true, wc_ecc_check_key() run (valid point). */
ExpectIntEQ(wc_ImportEccsiPublicKey(&keyPub, pubKeyData, pubKeySz, 0),
0);
/* keyPub is now type ECC_PUBLICKEY: complete the state-check triple
* deferred from wc_ExportEccsiPublicKey() above (second term false). */
sz = sizeof(data);
ExpectIntEQ(wc_ExportEccsiPublicKey(&keyPub, data, &sz, 1), 0);
/* --- wc_MakeEccsiPair() (KMS) ---
* eccsi.c ~line 954: (key==NULL)||(rng==NULL)||(id==NULL)||(ssk==NULL)
* ||(pvt==NULL) [5-operand OR]
* eccsi.c ~line 958: (err==0) && (key->ecc.type != ECC_PRIVATEKEY)
*/
ExpectIntEQ(wc_MakeEccsiPair(NULL, &rng, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_MakeEccsiPair(&keyPriv, NULL, WC_HASH_TYPE_SHA256, id,
idSz, &ssk, pvt), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_MakeEccsiPair(&keyPriv, &rng, WC_HASH_TYPE_SHA256, NULL,
idSz, &ssk, pvt), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_MakeEccsiPair(&keyPriv, &rng, WC_HASH_TYPE_SHA256, id,
idSz, NULL, pvt), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_MakeEccsiPair(&keyPriv, &rng, WC_HASH_TYPE_SHA256, id,
idSz, &ssk, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyState0 not wc_MakeEccsiKey()'d -> BAD_STATE_E. */
ExpectIntEQ(wc_MakeEccsiPair(&keyState0, &rng, WC_HASH_TYPE_SHA256, id,
idSz, &ssk, pvt), WC_NO_ERR_TRACE(BAD_STATE_E));
/* Baseline: all valid, state PRIVATEKEY -> success; generates the
* real (ssk, pvt) pair reused for the rest of this test. */
ExpectIntEQ(wc_MakeEccsiPair(&keyPriv, &rng, WC_HASH_TYPE_SHA256, id,
idSz, &ssk, pvt), 0);
/* --- wc_EncodeEccsiPair() (KMS) ---
* eccsi.c ~line 993: (key==NULL)||(ssk==NULL)||(pvt==NULL)||(sz==NULL)
* eccsi.c ~line 997: (err==0) && (data==NULL) -> LENGTH_ONLY_E
* eccsi.c ~line 1001: (err==0) && (*sz < needed) -> BUFFER_E
*/
sz = sizeof(data);
ExpectIntEQ(wc_EncodeEccsiPair(NULL, &ssk, pvt, data, &sz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPair(&keyPriv, NULL, pvt, data, &sz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPair(&keyPriv, &ssk, NULL, data, &sz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPair(&keyPriv, &ssk, pvt, data, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPair(&keyPriv, &ssk, pvt, NULL, &sz),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sz, (word32)(32 * 3));
sz = 32 * 3 - 1;
ExpectIntEQ(wc_EncodeEccsiPair(&keyPriv, &ssk, pvt, keyBuf, &sz),
WC_NO_ERR_TRACE(BUFFER_E));
keyBufSz = sizeof(keyBuf);
ExpectIntEQ(wc_EncodeEccsiPair(&keyPriv, &ssk, pvt, keyBuf, &keyBufSz),
0);
ExpectIntEQ(keyBufSz, (word32)(32 * 3));
/* --- wc_DecodeEccsiPair() (CLIENT) ---
* eccsi.c ~line 1173: (key==NULL)||(data==NULL)||(ssk==NULL)||(pvt==NULL)
* eccsi.c ~line 1176: (err==0) && (sz != key size * 3)
*/
ExpectIntEQ(wc_DecodeEccsiPair(NULL, keyBuf, keyBufSz, &decSsk, decPvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPair(&keyPriv, NULL, keyBufSz, &decSsk, decPvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPair(&keyPriv, keyBuf, keyBufSz, NULL, decPvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPair(&keyPriv, keyBuf, keyBufSz, &decSsk, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPair(&keyPriv, keyBuf, keyBufSz - 1, &decSsk,
decPvt), WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_DecodeEccsiPair(&keyPriv, keyBuf, keyBufSz, &decSsk,
decPvt), 0);
ExpectIntEQ(mp_cmp(&ssk, &decSsk), MP_EQ);
ExpectIntEQ(wc_ecc_cmp_point(pvt, decPvt), MP_EQ);
/* --- wc_EncodeEccsiSsk() (KMS) ---
* eccsi.c ~line 1049: (key==NULL)||(ssk==NULL)||(sz==NULL)
* eccsi.c ~line 1053: (err==0) && (type != ECC_PRIVATEKEY)
* eccsi.c ~line 1057: data==NULL -> LENGTH_ONLY_E; *sz<needed -> BUFFER_E
*/
sz = sizeof(data);
ExpectIntEQ(wc_EncodeEccsiSsk(NULL, &ssk, data, &sz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiSsk(&keyPriv, NULL, data, &sz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiSsk(&keyPriv, &ssk, data, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiSsk(&keyState0, &ssk, data, &sz),
WC_NO_ERR_TRACE(BAD_STATE_E));
ExpectIntEQ(wc_EncodeEccsiSsk(&keyPriv, &ssk, NULL, &sz),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sz, (word32)32);
sz = 31;
ExpectIntEQ(wc_EncodeEccsiSsk(&keyPriv, &ssk, privBuf, &sz),
WC_NO_ERR_TRACE(BUFFER_E));
privBufSz = sizeof(privBuf);
ExpectIntEQ(wc_EncodeEccsiSsk(&keyPriv, &ssk, privBuf, &privBufSz), 0);
ExpectIntEQ(privBufSz, (word32)32);
/* --- wc_DecodeEccsiSsk() (KMS) ---
* eccsi.c ~line 1097: (key==NULL)||(data==NULL)||(ssk==NULL)
* eccsi.c ~line 1100: (err==0) && (sz != key size)
*/
ExpectIntEQ(wc_DecodeEccsiSsk(NULL, privBuf, privBufSz, &decSsk),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiSsk(&keyPriv, NULL, privBufSz, &decSsk),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiSsk(&keyPriv, privBuf, privBufSz, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiSsk(&keyPriv, privBuf, privBufSz - 1, &decSsk),
WC_NO_ERR_TRACE(BUFFER_E));
ExpectIntEQ(wc_DecodeEccsiSsk(&keyPriv, privBuf, privBufSz, &decSsk), 0);
ExpectIntEQ(mp_cmp(&ssk, &decSsk), MP_EQ);
/* --- wc_EncodeEccsiPvt() (KMS) ---
* eccsi.c ~line 1138: (key==NULL)||(pvt==NULL)||(sz==NULL)
* (delegates to eccsi_encode_point(): data==NULL -> LENGTH_ONLY_E;
* *sz<needed -> BUFFER_E; raw selects the descriptor byte)
*/
sz = sizeof(data);
ExpectIntEQ(wc_EncodeEccsiPvt(NULL, pvt, data, &sz, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPvt(&keyPriv, NULL, data, &sz, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPvt(&keyPriv, pvt, data, NULL, 1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_EncodeEccsiPvt(&keyPriv, pvt, NULL, &sz, 1),
WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sz, (word32)(32 * 2));
sz = 32 * 2 - 1;
ExpectIntEQ(wc_EncodeEccsiPvt(&keyPriv, pvt, dataRaw, &sz, 1),
WC_NO_ERR_TRACE(BUFFER_E));
/* raw == 1: success, no descriptor byte. */
szRaw = sizeof(dataRaw);
ExpectIntEQ(wc_EncodeEccsiPvt(&keyPriv, pvt, dataRaw, &szRaw, 1), 0);
ExpectIntEQ(szRaw, (word32)(32 * 2));
/* raw == 0: success, descriptor byte 0x04 prepended. */
szDesc = sizeof(dataDesc);
ExpectIntEQ(wc_EncodeEccsiPvt(&keyPriv, pvt, dataDesc, &szDesc, 0), 0);
ExpectIntEQ(szDesc, (word32)(32 * 2 + 1));
ExpectIntEQ(dataDesc[0], 0x04);
/* --- wc_DecodeEccsiPvt() (CLIENT) ---
* eccsi.c ~line 1225: (key==NULL)||(data==NULL)||(pvt==NULL)
* (delegates to eccsi_decode_point():
* ~line 547: (sz != size*2) && (sz != size*2+1) -> BUFFER_E
* ~line 551: (err==0) && (sz & 1) -> descriptor byte
* ~line 552: data[0] != 0x04 -> ASN_PARSE_E)
*/
ExpectIntEQ(wc_DecodeEccsiPvt(NULL, dataRaw, szRaw, decPvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPvt(&keyPriv, NULL, szRaw, decPvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPvt(&keyPriv, dataRaw, szRaw, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* sz == size*2 (even, no descriptor): first term false -> success. */
ExpectIntEQ(wc_DecodeEccsiPvt(&keyPriv, dataRaw, szRaw, decPvt), 0);
ExpectIntEQ(wc_ecc_cmp_point(pvt, decPvt), MP_EQ);
/* sz == size*2+1 (odd, valid 0x04 descriptor): both terms false for
* the BUFFER_E check; sz&1 true -> descriptor path; data[0]==0x04. */
ExpectIntEQ(wc_DecodeEccsiPvt(&keyPriv, dataDesc, szDesc, decPvt), 0);
ExpectIntEQ(wc_ecc_cmp_point(pvt, decPvt), MP_EQ);
/* sz neither size*2 nor size*2+1: both terms true -> BUFFER_E. */
ExpectIntEQ(wc_DecodeEccsiPvt(&keyPriv, dataDesc, szDesc + 4, decPvt),
WC_NO_ERR_TRACE(BUFFER_E));
/* sz == size*2+1 but bad descriptor byte -> ASN_PARSE_E. */
dataDesc[0] = 0xFF;
ExpectIntEQ(wc_DecodeEccsiPvt(&keyPriv, dataDesc, szDesc, decPvt),
WC_NO_ERR_TRACE(ASN_PARSE_E));
dataDesc[0] = 0x04; /* restore for later reuse below */
/* --- wc_DecodeEccsiPvtFromSig() (CLIENT) ---
* eccsi.c ~line 1261: (key==NULL)||(sig==NULL)||(pvt==NULL)
*/
XMEMSET(sigLike, 0, sizeof(sigLike));
XMEMCPY(sigLike + 32 * 2, dataDesc, sizeof(dataDesc));
ExpectIntEQ(wc_DecodeEccsiPvtFromSig(NULL, sigLike, sizeof(sigLike),
decPvt), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPvtFromSig(&keyPriv, NULL, sizeof(sigLike),
decPvt), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPvtFromSig(&keyPriv, sigLike, sizeof(sigLike),
NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_DecodeEccsiPvtFromSig(&keyPriv, sigLike, sizeof(sigLike),
decPvt), 0);
ExpectIntEQ(wc_ecc_cmp_point(pvt, decPvt), MP_EQ);
/* --- wc_ValidateEccsiPair() (CLIENT) ---
* eccsi.c ~line 1489: (key==NULL)||(id==NULL)||(ssk==NULL)||(pvt==NULL)
* ||(valid==NULL) [5-operand OR]
* eccsi.c ~line 1494: (err==0) && (type!=PRIVATEKEY) && (type!=PUBLICKEY)
* eccsi.c ~line 1518: err == -1 (from wc_ecc_is_point()) -> IS_POINT_E
*/
ExpectIntEQ(wc_ValidateEccsiPair(NULL, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt, &valid), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, NULL, idSz,
&ssk, pvt, &valid), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, id, idSz,
NULL, pvt, &valid), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, NULL, &valid), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyState0 is neither -> BAD_STATE_E. */
ExpectIntEQ(wc_ValidateEccsiPair(&keyState0, WC_HASH_TYPE_SHA256, id,
idSz, &ssk, pvt, &valid), WC_NO_ERR_TRACE(BAD_STATE_E));
/* State: keyPub is PUBLICKEY (second term false) -> success. */
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt, &valid), 0);
ExpectIntEQ(valid, 1);
/* State: keyPriv is PRIVATEKEY (first term false) -> success. */
ExpectIntEQ(wc_ValidateEccsiPair(&keyPriv, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt, &valid), 0);
ExpectIntEQ(valid, 1);
/* PVT not on the curve -> wc_ecc_is_point() fails. The error code is
* backend-dependent: the mp-based check (classic / WOLFSSL_SP_MATH_ALL /
* fast-math) returns IS_POINT_E, while the minimal WOLFSSL_SP_MATH backend
* routes through sp_ecc_is_point_*(), which reports MP_VAL for a point not
* on the curve. */
ExpectIntEQ(mp_set(badPvt->x, 1), MP_OKAY);
ExpectIntEQ(mp_set(badPvt->y, 1), MP_OKAY);
ExpectIntEQ(mp_set(badPvt->z, 1), MP_OKAY);
#if defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL)
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, badPvt, &valid), WC_NO_ERR_TRACE(MP_VAL));
#else
ExpectIntEQ(wc_ValidateEccsiPair(&keyPub, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, badPvt, &valid), WC_NO_ERR_TRACE(IS_POINT_E));
#endif
/* --- wc_ValidateEccsiPvt() (CLIENT) ---
* eccsi.c ~line 1579: (key==NULL) | (pvt==NULL) || (valid==NULL)
* (first two operands are combined with a bitwise '|', not '&&'/'||',
* so both are always evaluated; MC/DC's baseline+single-flip pattern
* still applies since the result is the same 0/1 boolean algebra.)
*/
ExpectIntEQ(wc_ValidateEccsiPvt(NULL, pvt, &valid),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPvt(&keyPub, NULL, &valid),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPvt(&keyPub, pvt, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ValidateEccsiPvt(&keyPub, pvt, &valid), 0);
ExpectIntEQ(valid, 1);
/* --- wc_HashEccsiId() (CLIENT) ---
* eccsi.c ~line 1628: (key==NULL)||(id==NULL)||(pvt==NULL)||(hash==NULL)
* ||(hashSz==NULL) [5-operand OR]
* eccsi.c ~line 1632: (err==0) && (type!=PRIVATEKEY) && (type!=PUBLICKEY)
* eccsi.c ~line 1639: dgstSz < 0 (invalid hashType)
* eccsi.c ~line 1649: (err==0) && (dgstSz != curveSz)
* (the "curveSz < 0" leg at ~line 1645 is not reachable via the public
* API once wc_ecc_set_curve() has succeeded -- see file header note)
*/
ExpectIntEQ(wc_HashEccsiId(NULL, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashBuf, &hBSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_SHA256, NULL, idSz, pvt,
hashBuf, &hBSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_SHA256, id, idSz, NULL,
hashBuf, &hBSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_SHA256, id, idSz, pvt,
NULL, &hBSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashBuf, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyState0 is neither -> BAD_STATE_E. */
ExpectIntEQ(wc_HashEccsiId(&keyState0, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashBuf, &hBSz), WC_NO_ERR_TRACE(BAD_STATE_E));
/* Invalid hashType: wc_HashGetDigestSize() returns BAD_FUNC_ARG < 0. */
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_NONE, id, idSz, pvt,
hashBuf, &hBSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef WOLFSSL_SHA384
/* Digest size (48, SHA-384) != curve size (32, P-256) -> BAD_FUNC_ARG. */
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_SHA384, id, idSz, pvt,
hashBuf, &hBSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
/* State: keyPub is PUBLICKEY (second term false) + matching digest
* size (32 == 32) -> success. */
ExpectIntEQ(wc_HashEccsiId(&keyPub, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashBuf, &hBSz), 0);
ExpectIntEQ(hBSz, (byte)32);
/* State: keyPriv is PRIVATEKEY (first term false) -> success; this is
* the hash reused below for signing/verifying. */
ExpectIntEQ(wc_HashEccsiId(&keyPriv, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashBuf, &hBSz), 0);
ExpectIntEQ(hBSz, (byte)32);
/* --- wc_SetEccsiHash() (CLIENT) ---
* eccsi.c ~line 1681: (key==NULL)||(hash==NULL)||(hashSz>WC_MAX_DIGEST_SIZE)
*/
ExpectIntEQ(wc_SetEccsiHash(NULL, hashBuf, hBSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetEccsiHash(&keyPriv, NULL, hBSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetEccsiHash(&keyPriv, hashBuf,
(byte)(WC_MAX_DIGEST_SIZE + 1)), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Baseline: all valid, hashSz well within bound -> success. Leaves
* keyPriv's idHash set for wc_SignEccsiHash() below. */
ExpectIntEQ(wc_SetEccsiHash(&keyPriv, hashBuf, hBSz), 0);
/* --- wc_SetEccsiPair() (CLIENT) ---
* eccsi.c ~line 1706: (key==NULL)||(ssk==NULL)||(pvt==NULL)
*/
ExpectIntEQ(wc_SetEccsiPair(NULL, &ssk, pvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetEccsiPair(&keyPriv, NULL, pvt),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetEccsiPair(&keyPriv, &ssk, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetEccsiPair(&keyPriv, &ssk, pvt), 0);
/* --- wc_SignEccsiHash() (CLIENT) ---
* eccsi.c ~line 1964: (key==NULL)||(rng==NULL)||(msg==NULL)||(sigSz==NULL)
* eccsi.c ~line 1967: (err==0) && (type!=PUBLICKEY) && (type!=PRIVATEKEY)
* eccsi.c ~line 1971: (err==0) && (sig!=NULL) && (idHashSz==0)
* eccsi.c ~line 1977: sig==NULL -> LENGTH_ONLY_E
* eccsi.c ~line 1982: (err==0) && (*sigSz < needed)
*/
ExpectIntEQ(wc_SignEccsiHash(NULL, &rng, WC_HASH_TYPE_SHA256, msg, msgSz,
sigBuf, &realSigSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SignEccsiHash(&keyPriv, NULL, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, &realSigSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SignEccsiHash(&keyPriv, &rng, WC_HASH_TYPE_SHA256, NULL,
msgSz, sigBuf, &realSigSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SignEccsiHash(&keyPriv, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyState0 is neither -> BAD_STATE_E (sig==NULL here too, but
* the state check runs first and short-circuits before it matters). */
realSigSz = sizeof(sigBuf);
ExpectIntEQ(wc_SignEccsiHash(&keyState0, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, NULL, &realSigSz), WC_NO_ERR_TRACE(BAD_STATE_E));
/* State: keyPub is PUBLICKEY (first term false); sig==NULL keeps the
* idHashSz-check's "sig!=NULL" term false -> LENGTH_ONLY_E. */
ExpectIntEQ(wc_SignEccsiHash(&keyPub, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, NULL, &realSigSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(realSigSz, (word32)(32 * 4 + 1));
/* keyPub's idHash was already set by wc_HashEccsiId() above, so it
* cannot isolate the idHashSz==0 leg here. Use a freshly made scratch
* key (valid PRIVATEKEY type, idHash never set) instead: sig != NULL,
* idHashSz == 0 -> (sig!=NULL) && (idHashSz==0) both true ->
* BAD_STATE_E. (If keyPub were used here, its idHashSz != 0 would
* make this decision false and fall through into real signing, which
* fails since keyPub has no SSK set -- an easy trap to fall into.) */
ExpectIntEQ(wc_InitEccsiKey(&keyScratch, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_MakeEccsiKey(&keyScratch, &rng), 0);
realSigSz = sizeof(sigBuf);
ExpectIntEQ(wc_SignEccsiHash(&keyScratch, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, &realSigSz), WC_NO_ERR_TRACE(BAD_STATE_E));
wc_FreeEccsiKey(&keyScratch);
/* sig != NULL, idHashSz != 0 (keyPriv, set above): (sig!=NULL) true,
* (idHashSz==0) false -> AND false; *sigSz too small -> BAD_FUNC_ARG. */
realSigSz = 4;
ExpectIntEQ(wc_SignEccsiHash(&keyPriv, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, &realSigSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Success: full valid call, also used for wc_VerifyEccsiHash() below. */
realSigSz = sizeof(sigBuf);
ExpectIntEQ(wc_SignEccsiHash(&keyPriv, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, &realSigSz), 0);
ExpectIntEQ(realSigSz, (word32)(32 * 4 + 1));
/* Set keyPub's idHash (same value as keyPriv's) so it can verify. */
ExpectIntEQ(wc_SetEccsiHash(&keyPub, hashBuf, hBSz), 0);
/* --- wc_VerifyEccsiHash() (CLIENT) ---
* eccsi.c ~line 2208: (key==NULL)||(msg==NULL)||(sig==NULL)
* ||(verified==NULL) [4-operand OR]
* eccsi.c ~line 2211: (err==0) && (type!=PRIVATEKEY) && (type!=PUBLICKEY)
* eccsi.c ~line 2215: (err==0) && (idHashSz==0)
* eccsi_decode_sig_r_pvt() ~line 2067: sigSz != key size * 4 + 1
* eccsi.c ~line 2244/2247 (r range): mp_iszero(r); mp_cmp(r,order)
* eccsi_calc_j() ~line 2155/2158 (s range): mp_iszero(s); mp_cmp(s,order)
*/
ExpectIntEQ(wc_VerifyEccsiHash(NULL, WC_HASH_TYPE_SHA256, msg, msgSz,
sigBuf, realSigSz, &verified), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, NULL, msgSz,
sigBuf, realSigSz, &verified), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg, msgSz,
NULL, realSigSz, &verified), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg, msgSz,
sigBuf, realSigSz, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyState0 is neither -> BAD_STATE_E. */
ExpectIntEQ(wc_VerifyEccsiHash(&keyState0, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, realSigSz, &verified), WC_NO_ERR_TRACE(BAD_STATE_E));
/* keyScratch: valid type but never had wc_SetEccsiHash()/wc_HashEccsiId()
* called -> idHashSz == 0 -> BAD_STATE_E. Re-init and make it a real
* PRIVATEKEY so the type check's "false" leg is taken and the idHashSz
* check is isolated. */
ExpectIntEQ(wc_InitEccsiKey(&keyScratch, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_MakeEccsiKey(&keyScratch, &rng), 0);
ExpectIntEQ(wc_VerifyEccsiHash(&keyScratch, WC_HASH_TYPE_SHA256, msg,
msgSz, sigBuf, realSigSz, &verified), WC_NO_ERR_TRACE(BAD_STATE_E));
wc_FreeEccsiKey(&keyScratch);
/* eccsi_decode_sig_r_pvt(): sigSz mismatch -> BAD_FUNC_ARG. */
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg, msgSz,
sigBuf, realSigSz - 1, &verified), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* State: keyPub is PUBLICKEY (second term false), idHashSz != 0
* (set above) -> success, genuine signature verifies. */
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg, msgSz,
sigBuf, realSigSz, &verified), 0);
ExpectIntEQ(verified, 1);
/* State: keyPriv is PRIVATEKEY (first term false) -> success too. */
ExpectIntEQ(wc_VerifyEccsiHash(&keyPriv, WC_HASH_TYPE_SHA256, msg, msgSz,
sigBuf, realSigSz, &verified), 0);
ExpectIntEQ(verified, 1);
/* r == 0 -> MP_ZERO_E (checked before pvt/HE/Y are ever touched). */
{
byte badSig[32 * 4 + 1];
XMEMCPY(badSig, sigBuf, sizeof(badSig));
XMEMSET(badSig, 0x00, 32);
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg,
msgSz, badSig, sizeof(badSig), &verified),
WC_NO_ERR_TRACE(MP_ZERO_E));
}
/* r >= order -> ECC_OUT_OF_RANGE_E. */
{
byte badSig[32 * 4 + 1];
XMEMCPY(badSig, sigBuf, sizeof(badSig));
XMEMSET(badSig, 0xFF, 32);
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg,
msgSz, badSig, sizeof(badSig), &verified),
WC_NO_ERR_TRACE(ECC_OUT_OF_RANGE_E));
}
/* s == 0 (r/pvt left valid) -> MP_ZERO_E from eccsi_calc_j(). */
{
byte badSig[32 * 4 + 1];
XMEMCPY(badSig, sigBuf, sizeof(badSig));
XMEMSET(badSig + 32, 0x00, 32);
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg,
msgSz, badSig, sizeof(badSig), &verified),
WC_NO_ERR_TRACE(MP_ZERO_E));
}
/* s >= order -> ECC_OUT_OF_RANGE_E from eccsi_calc_j(). */
{
byte badSig[32 * 4 + 1];
XMEMCPY(badSig, sigBuf, sizeof(badSig));
XMEMSET(badSig + 32, 0xFF, 32);
ExpectIntEQ(wc_VerifyEccsiHash(&keyPub, WC_HASH_TYPE_SHA256, msg,
msgSz, badSig, sizeof(badSig), &verified),
WC_NO_ERR_TRACE(ECC_OUT_OF_RANGE_E));
}
if (decPvt != NULL) {
wc_ecc_del_point(decPvt);
}
if (badPvt != NULL) {
wc_ecc_del_point(badPvt);
}
if (pvt != NULL) {
wc_ecc_del_point(pvt);
}
mp_free(&decSsk);
mp_free(&ssk);
wc_FreeRng(&rng);
wc_FreeEccsiKey(&keyState0);
wc_FreeEccsiKey(&keyPub);
wc_FreeEccsiKey(&keyPriv);
#endif
return EXPECT_RESULT();
}
/*
* Positive ECCSI flow, modeled on wolfcrypt/test/test.c's eccsi_test():
* wc_InitEccsiKey() -> wc_MakeEccsiKey() -> wc_MakeEccsiPair() ->
* wc_ValidateEccsiPair() / wc_ValidateEccsiPvt() ->
* wc_EncodeEccsiPair()/Ssk()/Pvt() + wc_DecodeEccsiPair()/Ssk()/Pvt()
* round-trips -> wc_HashEccsiId() -> wc_SetEccsiHash()/wc_SetEccsiPair() ->
* wc_SignEccsiHash() -> wc_VerifyEccsiHash() -> wc_FreeEccsiKey().
* Uses NIST P-256, WC_HASH_TYPE_SHA256 and the "test@wolfssl.com" identity,
* matching the KAT helper's conventions.
*/
int test_wc_Eccsi_FeatureCoverage(void)
{
EXPECT_DECLS;
#ifdef WOLFCRYPT_HAVE_ECCSI
EccsiKey priv;
EccsiKey pub;
WC_RNG rng;
mp_int ssk;
mp_int decSsk;
ecc_point* pvt = NULL;
ecc_point* decPvt = NULL;
char mail[] = "test@wolfssl.com";
byte* id = (byte*)mail;
word32 idSz;
int valid = 0;
int verified = 0;
byte pairData[32 * 3];
word32 pairSz;
byte sskData[32];
word32 sskSz;
byte pvtData[32 * 2];
word32 pvtSz;
byte hashPriv[WC_MAX_DIGEST_SIZE];
byte hashPub[WC_MAX_DIGEST_SIZE];
byte hashSz;
byte sig[32 * 4 + 1];
word32 sigSz;
byte msg[1] = { 0x00 };
word32 msgSz = (word32)sizeof(msg);
XMEMSET(&priv, 0, sizeof(priv));
XMEMSET(&pub, 0, sizeof(pub));
XMEMSET(pairData, 0, sizeof(pairData));
XMEMSET(sskData, 0, sizeof(sskData));
XMEMSET(pvtData, 0, sizeof(pvtData));
XMEMSET(hashPriv, 0, sizeof(hashPriv));
XMEMSET(hashPub, 0, sizeof(hashPub));
XMEMSET(sig, 0, sizeof(sig));
idSz = (word32)XSTRLEN(mail);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectNotNull(pvt = wc_ecc_new_point());
ExpectNotNull(decPvt = wc_ecc_new_point());
ExpectIntEQ(mp_init(&ssk), MP_OKAY);
ExpectIntEQ(mp_init(&decSsk), MP_OKAY);
/* KMS key: generates the (KSAK, KPAK) pair and the client's (SSK,PVT). */
ExpectIntEQ(wc_InitEccsiKey(&priv, HEAP_HINT, INVALID_DEVID), 0);
/* Client/verifier key: only ever holds the public KPAK. */
ExpectIntEQ(wc_InitEccsiKey(&pub, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_MakeEccsiKey(&priv, &rng), 0);
ExpectIntEQ(wc_MakeEccsiPair(&priv, &rng, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt), 0);
/* Import the KPAK into the client's key (as a trusted value) so it can
* validate/verify independently of the KMS key. */
{
byte pubKeyData[32 * 2];
word32 pubKeySz = sizeof(pubKeyData);
ExpectIntEQ(wc_ExportEccsiPublicKey(&priv, pubKeyData, &pubKeySz,
1), 0);
ExpectIntEQ(wc_ImportEccsiPublicKey(&pub, pubKeyData, pubKeySz, 1),
0);
}
/* Client validates the (SSK, PVT) pair and PVT it received. */
ExpectIntEQ(wc_ValidateEccsiPair(&pub, WC_HASH_TYPE_SHA256, id, idSz,
&ssk, pvt, &valid), 0);
ExpectIntEQ(valid, 1);
ExpectIntEQ(wc_ValidateEccsiPvt(&pub, pvt, &valid), 0);
ExpectIntEQ(valid, 1);
/* Encode/decode (SSK, PVT) pair, SSK alone, and PVT alone; verify each
* round-trips back to the original values. */
pairSz = sizeof(pairData);
ExpectIntEQ(wc_EncodeEccsiPair(&priv, &ssk, pvt, pairData, &pairSz), 0);
ExpectIntEQ(wc_DecodeEccsiPair(&priv, pairData, pairSz, &decSsk, decPvt),
0);
ExpectIntEQ(mp_cmp(&ssk, &decSsk), MP_EQ);
ExpectIntEQ(wc_ecc_cmp_point(pvt, decPvt), MP_EQ);
sskSz = sizeof(sskData);
ExpectIntEQ(wc_EncodeEccsiSsk(&priv, &ssk, sskData, &sskSz), 0);
ExpectIntEQ(wc_DecodeEccsiSsk(&priv, sskData, sskSz, &decSsk), 0);
ExpectIntEQ(mp_cmp(&ssk, &decSsk), MP_EQ);
pvtSz = sizeof(pvtData);
ExpectIntEQ(wc_EncodeEccsiPvt(&priv, pvt, pvtData, &pvtSz, 1), 0);
ExpectIntEQ(wc_DecodeEccsiPvt(&priv, pvtData, pvtSz, decPvt), 0);
ExpectIntEQ(wc_ecc_cmp_point(pvt, decPvt), MP_EQ);
/* Both the signer and verifier compute the same identity hash. */
ExpectIntEQ(wc_HashEccsiId(&priv, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashPriv, &hashSz), 0);
ExpectIntEQ(hashSz, (byte)32);
ExpectIntEQ(wc_HashEccsiId(&pub, WC_HASH_TYPE_SHA256, id, idSz, pvt,
hashPub, &hashSz), 0);
ExpectIntEQ(hashSz, (byte)32);
ExpectBufEQ(hashPriv, hashPub, hashSz);
ExpectIntEQ(wc_SetEccsiHash(&priv, hashPriv, hashSz), 0);
ExpectIntEQ(wc_SetEccsiPair(&priv, &ssk, pvt), 0);
/* Length-query then real sign. */
sigSz = sizeof(sig);
ExpectIntEQ(wc_SignEccsiHash(&priv, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, NULL, &sigSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
ExpectIntEQ(sigSz, (word32)(32 * 4 + 1));
ExpectIntEQ(wc_SignEccsiHash(&priv, &rng, WC_HASH_TYPE_SHA256, msg,
msgSz, sig, &sigSz), 0);
ExpectIntEQ(wc_SetEccsiHash(&pub, hashPub, hashSz), 0);
ExpectIntEQ(wc_VerifyEccsiHash(&pub, WC_HASH_TYPE_SHA256, msg, msgSz,
sig, sigSz, &verified), 0);
ExpectIntEQ(verified, 1);
/* Verifying with the KMS key itself also works. */
ExpectIntEQ(wc_VerifyEccsiHash(&priv, WC_HASH_TYPE_SHA256, msg, msgSz,
sig, sigSz, &verified), 0);
ExpectIntEQ(verified, 1);
if (decPvt != NULL) {
wc_ecc_del_point(decPvt);
}
if (pvt != NULL) {
wc_ecc_del_point(pvt);
}
mp_free(&decSsk);
mp_free(&ssk);
wc_FreeRng(&rng);
wc_FreeEccsiKey(&pub);
wc_FreeEccsiKey(&priv);
#endif
return EXPECT_RESULT();
}