mirror of https://github.com/wolfSSL/wolfssl.git
tests: MC/DC decision coverage for dh.c and dsa.c
Adds tests/api DecisionCoverage functions closing MC/DC gaps identified
by the per-module campaign (iso26262/mcdc-per-module):
dh.c: BEFORE 51/173 (29.48%) -> AFTER 107/173 (61.85%), union across
6 native variants (sp_default, sp_dh, sp_dh_nonblock,
small_stack, no_dh186, validate_keygen). New coverage: wc_DhSetKey
family bad-args and the FFDHE-table primality fast-path, named-key
helpers (SetNamedKey/GetNamedKeyParamSize/CopyNamedKey/CmpNamedKey),
wc_DhGenerateKeyPair/GeneratePublic bad-args plus a multi-group
(2048/3072/4096) generate+agree(+ct) round trip, WC_DH_NONBLOCK's
incremental state machine, wc_DhImportKeyPair/ExportKeyPair,
wc_DhCheckPubKey(_ex)/wc_DhCheckPrivKey(_ex)/wc_DhCheckKeyPair
(+ WOLFSSL_VALIDATE_DH_KEYGEN), wc_DhGenerateParams/
wc_DhExportParamsRaw, and CheckDhLN's divLen==224/256 MC/DC pair.
dsa.c: BEFORE 34/110 (30.91%) -> AFTER 51/110 (46.36%), union across
4 native variants (default, invmod_ct, fastmath, small_stack).
New coverage: wc_DsaSign_ex/wc_DsaVerify_ex digestSz bad-argument
checks and the q==1 qMinus1-iszero guard, individual single-operand
NULL-argument combinations for ImportParamsRaw/ExportParamsRaw/
ExportKeyRaw, and CheckDsaLN's case-2048 divLen==224/256 MC/DC pair.
Both modules build and pass their tests/api group + KATs across every
native variant with zero failures (10/10 variant runs).
pull/10876/head
parent
ba9084bdd6
commit
2e1d38d5a3
|
|
@ -33,6 +33,22 @@
|
|||
#include <tests/api/api.h>
|
||||
#include <tests/api/test_dh.h>
|
||||
|
||||
/* A sane, fixed private/public/agree buffer size for the tests below,
|
||||
* comfortably covering the largest enabled FFDHE named group (FFDHE-4096,
|
||||
* 512-byte p). NOT the library's own DH_MAX_SIZE: under WOLFSSL_SP_MATH_ALL,
|
||||
* DH_MAX_SIZE expands to WC_BITS_FULL_BYTES(SP_INT_BITS), and
|
||||
* WC_BITS_FULL_BYTES(x) is defined as (WC_BITS_TO_BYTES(x) << 3) - i.e. it
|
||||
* returns SP_INT_BITS itself (rounded up to a byte multiple), NOT
|
||||
* SP_INT_BITS/8 as its name suggests. With this campaign's SP_INT_BITS 4096,
|
||||
* DH_MAX_SIZE is therefore 4096 (bytes!), not the 512 a caller would
|
||||
* reasonably expect. Passing that value as *privSz (a requested private-key
|
||||
* size, not just a buffer capacity) to wc_DhGenerateKeyPair overflows the
|
||||
* fixed-capacity internal mp_int in GeneratePrivateDh186 (MP_VAL). The
|
||||
* canonical wolfcrypt/test/test.c dh_test() uses a plain byte[256] for the
|
||||
* same reason. Reported as a library macro-naming/semantics finding; not
|
||||
* fixed here (out of scope for this test-only change). */
|
||||
#define TEST_DH_BUF_SIZE 512
|
||||
|
||||
/*
|
||||
* Testing wc_DhPublicKeyDecode
|
||||
*/
|
||||
|
|
@ -217,3 +233,837 @@ int test_wc_DhAgree_subgroup_check(void)
|
|||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhSetKey() / wc_DhSetKey_ex() / wc_DhSetCheckKey() bad args and
|
||||
* the untrusted-prime-check path: a known FFDHE prime short-circuits the
|
||||
* primality test (XMEMCMP fast-path in _DhSetKey), a trusted key skips the
|
||||
* primality test entirely, and an untrusted, non-table prime goes through
|
||||
* the generic mp_prime_is_prime(_ex) check and is rejected.
|
||||
*/
|
||||
int test_wc_DhSetKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(HAVE_PUBLIC_FFDHE) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
const DhParams* params = NULL;
|
||||
byte g[] = { 0x02 };
|
||||
byte notPrime[] = { 0x04 }; /* even -> not prime, tiny -> fast reject */
|
||||
|
||||
XMEMSET(&key, 0, sizeof(DhKey));
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectNotNull(params = wc_Dh_ffdhe2048_Get());
|
||||
|
||||
/* bad args: wc_DhSetKey */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
if (params != NULL) {
|
||||
ExpectIntEQ(wc_DhSetKey(NULL, params->p, params->p_len, params->g,
|
||||
params->g_len), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhSetKey(&key, NULL, params->p_len, params->g,
|
||||
params->g_len), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhSetKey(&key, params->p, 0, params->g,
|
||||
params->g_len), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhSetKey(&key, params->p, params->p_len, NULL,
|
||||
params->g_len), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhSetKey(&key, params->p, params->p_len, params->g,
|
||||
0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
}
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
if (params != NULL) {
|
||||
/* valid: known FFDHE prime, short-circuits the primality test */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetKey(&key, params->p, params->p_len, params->g,
|
||||
params->g_len), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* valid: wc_DhSetKey_ex with an explicit q (untrusted path; still
|
||||
* matches the known FFDHE prime, so the fast-path memcmp - not an
|
||||
* actual primality search - sets isPrime). */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
#ifdef HAVE_FFDHE_Q
|
||||
ExpectIntEQ(wc_DhSetKey_ex(&key, params->p, params->p_len,
|
||||
params->g, params->g_len, params->q, params->q_len), 0);
|
||||
#else
|
||||
ExpectIntEQ(wc_DhSetKey_ex(&key, params->p, params->p_len,
|
||||
params->g, params->g_len, NULL, 0), 0);
|
||||
#endif
|
||||
wc_FreeDhKey(&key);
|
||||
}
|
||||
|
||||
/* wc_DhSetCheckKey: trusted=1 skips the primality test entirely, so a
|
||||
* non-prime p is accepted. */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetCheckKey(&key, notPrime, sizeof(notPrime), g,
|
||||
sizeof(g), NULL, 0, 1, NULL), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* wc_DhSetCheckKey: untrusted, non-FFDHE-table p forces the generic
|
||||
* mp_prime_is_prime_ex(rng) / mp_prime_is_prime(NULL) path; the value
|
||||
* is even (not prime) so both are rejected without a costly search. */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetCheckKey(&key, notPrime, sizeof(notPrime), g,
|
||||
sizeof(g), NULL, 0, 0, &rng), WC_NO_ERR_TRACE(DH_CHECK_PUB_E));
|
||||
wc_FreeDhKey(&key);
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetCheckKey(&key, notPrime, sizeof(notPrime), g,
|
||||
sizeof(g), NULL, 0, 0, NULL), WC_NO_ERR_TRACE(DH_CHECK_PUB_E));
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhSetNamedKey(), wc_DhGetNamedKeyParamSize(),
|
||||
* wc_DhCopyNamedKey() and wc_DhCmpNamedKey().
|
||||
*/
|
||||
int test_wc_DhSetNamedKey_and_helpers(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(HAVE_PUBLIC_FFDHE) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
const DhParams* p2048 = NULL;
|
||||
word32 pSz = 0, gSz = 0, qSz = 0;
|
||||
byte pOut[TEST_DH_BUF_SIZE];
|
||||
byte gOut[TEST_DH_BUF_SIZE];
|
||||
byte qOut[TEST_DH_BUF_SIZE];
|
||||
|
||||
ExpectNotNull(p2048 = wc_Dh_ffdhe2048_Get());
|
||||
|
||||
/* wc_DhSetNamedKey: unknown name -> default case leaves p/g NULL,
|
||||
* _DhSetKey then rejects with BAD_FUNC_ARG (p==NULL). */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, 9999), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* valid named groups: exercise each HAVE_FFDHE_* case arm. */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
#ifdef HAVE_FFDHE_3072
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_3072), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
#endif
|
||||
#ifdef HAVE_FFDHE_4096
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_4096), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
#endif
|
||||
|
||||
/* wc_DhGetNamedKeyParamSize: NULL out pointers (each skipped
|
||||
* independently), unknown name (all sizes stay 0), valid name. */
|
||||
ExpectIntEQ(wc_DhGetNamedKeyParamSize(WC_FFDHE_2048, &pSz, &gSz, &qSz),
|
||||
0);
|
||||
ExpectIntEQ(pSz, p2048 != NULL ? p2048->p_len : 0);
|
||||
ExpectIntEQ(wc_DhGetNamedKeyParamSize(WC_FFDHE_2048, NULL, &gSz, &qSz),
|
||||
0);
|
||||
ExpectIntEQ(wc_DhGetNamedKeyParamSize(WC_FFDHE_2048, &pSz, NULL, &qSz),
|
||||
0);
|
||||
ExpectIntEQ(wc_DhGetNamedKeyParamSize(WC_FFDHE_2048, &pSz, &gSz, NULL),
|
||||
0);
|
||||
pSz = 1234; gSz = 1234; qSz = 1234;
|
||||
ExpectIntEQ(wc_DhGetNamedKeyParamSize(9999, &pSz, &gSz, &qSz), 0);
|
||||
ExpectIntEQ(pSz, 0);
|
||||
ExpectIntEQ(gSz, 0);
|
||||
ExpectIntEQ(qSz, 0);
|
||||
|
||||
/* wc_DhCopyNamedKey: NULL output buffers (each skipped independently
|
||||
* both for the copy and the size-out); unknown name (pC/gC/qC stay
|
||||
* NULL, only the *Sz outs are touched, left at 0). */
|
||||
if (p2048 != NULL) {
|
||||
XMEMSET(pOut, 0, sizeof(pOut));
|
||||
XMEMSET(gOut, 0, sizeof(gOut));
|
||||
XMEMSET(qOut, 0, sizeof(qOut));
|
||||
pSz = sizeof(pOut); gSz = sizeof(gOut); qSz = sizeof(qOut);
|
||||
ExpectIntEQ(wc_DhCopyNamedKey(WC_FFDHE_2048, pOut, &pSz, gOut, &gSz,
|
||||
qOut, &qSz), 0);
|
||||
ExpectIntEQ(pSz, p2048->p_len);
|
||||
ExpectIntEQ(XMEMCMP(pOut, p2048->p, pSz), 0);
|
||||
ExpectIntEQ(XMEMCMP(gOut, p2048->g, gSz), 0);
|
||||
}
|
||||
ExpectIntEQ(wc_DhCopyNamedKey(WC_FFDHE_2048, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL), 0);
|
||||
pSz = 999; gSz = 999; qSz = 999;
|
||||
ExpectIntEQ(wc_DhCopyNamedKey(9999, pOut, &pSz, gOut, &gSz, qOut, &qSz),
|
||||
0);
|
||||
ExpectIntEQ(pSz, 0);
|
||||
ExpectIntEQ(gSz, 0);
|
||||
ExpectIntEQ(qSz, 0);
|
||||
|
||||
/* wc_DhCmpNamedKey: goodName false (unknown name -> cmp stays 0);
|
||||
* goodName true with a full p/g/q match (cmp=1); mismatched p, g and q
|
||||
* in turn (cmp=0 each time); matching p/g with noQ=1 and a corrupted q
|
||||
* (q ignored -> cmp=1). DhParams has no q/q_len member at all unless
|
||||
* HAVE_FFDHE_Q, so every p2048->q/q_len use below is guarded; without
|
||||
* HAVE_FFDHE_Q, noQ=1 with a NULL/0 q exercises the same p/g compare
|
||||
* logic (the q-compare operand of the cmp expression is skipped either
|
||||
* way when noQ is true). */
|
||||
if (p2048 != NULL) {
|
||||
#ifdef HAVE_FFDHE_Q
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(9999, 0, p2048->p, p2048->p_len,
|
||||
p2048->g, p2048->g_len, p2048->q, p2048->q_len), 0);
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 0, p2048->p,
|
||||
p2048->p_len, p2048->g, p2048->g_len, p2048->q, p2048->q_len),
|
||||
1);
|
||||
|
||||
XMEMCPY(pOut, p2048->p, p2048->p_len);
|
||||
pOut[0] ^= 0x01;
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 0, pOut, p2048->p_len,
|
||||
p2048->g, p2048->g_len, p2048->q, p2048->q_len), 0);
|
||||
|
||||
XMEMCPY(gOut, p2048->g, p2048->g_len);
|
||||
gOut[0] ^= 0x01;
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 0, p2048->p,
|
||||
p2048->p_len, gOut, p2048->g_len, p2048->q, p2048->q_len), 0);
|
||||
|
||||
XMEMCPY(qOut, p2048->q, p2048->q_len);
|
||||
qOut[0] ^= 0x01;
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 0, p2048->p,
|
||||
p2048->p_len, p2048->g, p2048->g_len, qOut, p2048->q_len), 0);
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 1, p2048->p,
|
||||
p2048->p_len, p2048->g, p2048->g_len, qOut, p2048->q_len), 1);
|
||||
#else
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(9999, 1, p2048->p, p2048->p_len,
|
||||
p2048->g, p2048->g_len, NULL, 0), 0);
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 1, p2048->p,
|
||||
p2048->p_len, p2048->g, p2048->g_len, NULL, 0), 1);
|
||||
|
||||
XMEMCPY(pOut, p2048->p, p2048->p_len);
|
||||
pOut[0] ^= 0x01;
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 1, pOut, p2048->p_len,
|
||||
p2048->g, p2048->g_len, NULL, 0), 0);
|
||||
|
||||
XMEMCPY(gOut, p2048->g, p2048->g_len);
|
||||
gOut[0] ^= 0x01;
|
||||
ExpectIntEQ(wc_DhCmpNamedKey(WC_FFDHE_2048, 1, p2048->p,
|
||||
p2048->p_len, gOut, p2048->g_len, NULL, 0), 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhGenerateKeyPair() / wc_DhGeneratePublic() bad args.
|
||||
*/
|
||||
int test_wc_DhGenerateKeyPair_bad_args(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
byte priv[TEST_DH_BUF_SIZE];
|
||||
byte pub[TEST_DH_BUF_SIZE];
|
||||
word32 privSz = sizeof(priv), pubSz = sizeof(pub);
|
||||
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(NULL, &rng, priv, &privSz, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, NULL, priv, &privSz, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, NULL, &privSz, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, NULL, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, NULL,
|
||||
&pubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
ExpectIntEQ(wc_DhGeneratePublic(NULL, priv, 1, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGeneratePublic(&key, NULL, 1, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGeneratePublic(&key, priv, 0, pub, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGeneratePublic(&key, priv, 1, NULL, &pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGeneratePublic(&key, priv, 1, pub, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_FreeDhKey(&key);
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Full key-generation + agreement round trip across every enabled FFDHE
|
||||
* named group. Exercises GeneratePrivateDh186 (q known from the named
|
||||
* group), GeneratePublicDh's SP-accelerated dispatch (2048/3072/4096, when
|
||||
* WOLFSSL_HAVE_SP_DH is compiled in) and its generic mp_exptmod fallback,
|
||||
* and the wc_DhAgree_Sync body (peer-key validation, SP dispatch, generic
|
||||
* fallback, and the constant-time fold-back via wc_DhAgree_ct).
|
||||
*/
|
||||
int test_wc_DhGenerateKeyPair_and_Agree(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH)
|
||||
DhKey aliceKey, bobKey;
|
||||
WC_RNG rng;
|
||||
byte alicePriv[TEST_DH_BUF_SIZE], alicePub[TEST_DH_BUF_SIZE];
|
||||
byte bobPriv[TEST_DH_BUF_SIZE], bobPub[TEST_DH_BUF_SIZE];
|
||||
byte aliceAgree[TEST_DH_BUF_SIZE], bobAgree[TEST_DH_BUF_SIZE];
|
||||
word32 alicePrivSz, alicePubSz, bobPrivSz, bobPubSz;
|
||||
word32 aliceAgreeSz, bobAgreeSz;
|
||||
static const int groups[] = {
|
||||
#ifdef HAVE_FFDHE_2048
|
||||
WC_FFDHE_2048,
|
||||
#endif
|
||||
#ifdef HAVE_FFDHE_3072
|
||||
WC_FFDHE_3072,
|
||||
#endif
|
||||
#ifdef HAVE_FFDHE_4096
|
||||
WC_FFDHE_4096,
|
||||
#endif
|
||||
0 /* keep the array non-empty when no HAVE_FFDHE_* is enabled */
|
||||
};
|
||||
size_t i;
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
|
||||
for (i = 0; i < sizeof(groups) / sizeof(groups[0]) - 1; i++) {
|
||||
XMEMSET(&aliceKey, 0, sizeof(aliceKey));
|
||||
XMEMSET(&bobKey, 0, sizeof(bobKey));
|
||||
ExpectIntEQ(wc_InitDhKey(&aliceKey), 0);
|
||||
ExpectIntEQ(wc_InitDhKey(&bobKey), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&aliceKey, groups[i]), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&bobKey, groups[i]), 0);
|
||||
|
||||
alicePrivSz = sizeof(alicePriv);
|
||||
alicePubSz = sizeof(alicePub);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&aliceKey, &rng, alicePriv,
|
||||
&alicePrivSz, alicePub, &alicePubSz), 0);
|
||||
|
||||
bobPrivSz = sizeof(bobPriv);
|
||||
bobPubSz = sizeof(bobPub);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&bobKey, &rng, bobPriv, &bobPrivSz,
|
||||
bobPub, &bobPubSz), 0);
|
||||
|
||||
aliceAgreeSz = sizeof(aliceAgree);
|
||||
ExpectIntEQ(wc_DhAgree(&aliceKey, aliceAgree, &aliceAgreeSz,
|
||||
alicePriv, alicePrivSz, bobPub, bobPubSz), 0);
|
||||
bobAgreeSz = sizeof(bobAgree);
|
||||
ExpectIntEQ(wc_DhAgree(&bobKey, bobAgree, &bobAgreeSz, bobPriv,
|
||||
bobPrivSz, alicePub, alicePubSz), 0);
|
||||
ExpectIntEQ(aliceAgreeSz, bobAgreeSz);
|
||||
ExpectIntEQ(XMEMCMP(aliceAgree, bobAgree, aliceAgreeSz), 0);
|
||||
|
||||
/* wc_DhAgree bad args (all-valid baseline is the call above) */
|
||||
ExpectIntEQ(wc_DhAgree(NULL, aliceAgree, &aliceAgreeSz, alicePriv,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree(&aliceKey, NULL, &aliceAgreeSz, alicePriv,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree(&aliceKey, aliceAgree, NULL, alicePriv,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree(&aliceKey, aliceAgree, &aliceAgreeSz, NULL,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree(&aliceKey, aliceAgree, &aliceAgreeSz,
|
||||
alicePriv, alicePrivSz, NULL, bobPubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* constant-time variant of the same exchange, plus its own bad
|
||||
* args and the too-small-buffer BUFFER_E path. */
|
||||
aliceAgreeSz = sizeof(aliceAgree);
|
||||
ExpectIntEQ(wc_DhAgree_ct(&aliceKey, aliceAgree, &aliceAgreeSz,
|
||||
alicePriv, alicePrivSz, bobPub, bobPubSz), 0);
|
||||
ExpectIntEQ(wc_DhAgree_ct(NULL, aliceAgree, &aliceAgreeSz,
|
||||
alicePriv, alicePrivSz, bobPub, bobPubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree_ct(&aliceKey, NULL, &aliceAgreeSz, alicePriv,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree_ct(&aliceKey, aliceAgree, NULL, alicePriv,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree_ct(&aliceKey, aliceAgree, &aliceAgreeSz, NULL,
|
||||
alicePrivSz, bobPub, bobPubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhAgree_ct(&aliceKey, aliceAgree, &aliceAgreeSz,
|
||||
alicePriv, alicePrivSz, NULL, bobPubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
aliceAgreeSz = 1;
|
||||
ExpectIntEQ(wc_DhAgree_ct(&aliceKey, aliceAgree, &aliceAgreeSz,
|
||||
alicePriv, alicePrivSz, bobPub, bobPubSz),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
|
||||
wc_FreeDhKey(&aliceKey);
|
||||
wc_FreeDhKey(&bobKey);
|
||||
}
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* WC_DH_NONBLOCK: drives the incremental sp_DhExp_*_nb state machine in
|
||||
* wc_DhAgree_Sync (both the cached-pubkey-validation branch and the nb
|
||||
* dispatch itself), pairing with the default (key->nb == NULL) path
|
||||
* exercised by every other test in this file.
|
||||
*/
|
||||
int test_wc_DhAgree_nonblock(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(WC_DH_NONBLOCK) && defined(HAVE_FFDHE_2048)
|
||||
DhKey aliceKey, bobKey;
|
||||
WC_RNG rng;
|
||||
DhNb nb;
|
||||
byte alicePriv[TEST_DH_BUF_SIZE], alicePub[TEST_DH_BUF_SIZE];
|
||||
byte bobPriv[TEST_DH_BUF_SIZE], bobPub[TEST_DH_BUF_SIZE];
|
||||
byte agree[TEST_DH_BUF_SIZE];
|
||||
word32 alicePrivSz = sizeof(alicePriv), alicePubSz = sizeof(alicePub);
|
||||
word32 bobPrivSz = sizeof(bobPriv), bobPubSz = sizeof(bobPub);
|
||||
word32 agreeSz;
|
||||
int ret;
|
||||
int rounds;
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_InitDhKey(&aliceKey), 0);
|
||||
ExpectIntEQ(wc_InitDhKey(&bobKey), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&aliceKey, WC_FFDHE_2048), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&bobKey, WC_FFDHE_2048), 0);
|
||||
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&aliceKey, &rng, alicePriv,
|
||||
&alicePrivSz, alicePub, &alicePubSz), 0);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&bobKey, &rng, bobPriv, &bobPrivSz,
|
||||
bobPub, &bobPubSz), 0);
|
||||
|
||||
XMEMSET(&nb, 0, sizeof(nb));
|
||||
ExpectIntEQ(wc_DhSetNonBlock(&aliceKey, &nb), 0);
|
||||
ExpectIntEQ(wc_DhSetNonBlock(NULL, &nb), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* first op: key->nb->pubKeyValidated starts unset, so the peer-key
|
||||
* validation runs and caches its result. */
|
||||
ret = WC_NO_ERR_TRACE(MP_WOULDBLOCK);
|
||||
for (rounds = 0; ret == WC_NO_ERR_TRACE(MP_WOULDBLOCK) && rounds < 200000;
|
||||
rounds++) {
|
||||
agreeSz = sizeof(agree);
|
||||
ret = wc_DhAgree(&aliceKey, agree, &agreeSz, alicePriv, alicePrivSz,
|
||||
bobPub, bobPubSz);
|
||||
}
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* second op on the same nb-attached key: pubKeyValidated was cleared
|
||||
* after the first op completed, so this re-enters the same validation
|
||||
* + dispatch path a second time. */
|
||||
ret = WC_NO_ERR_TRACE(MP_WOULDBLOCK);
|
||||
for (rounds = 0; ret == WC_NO_ERR_TRACE(MP_WOULDBLOCK) && rounds < 200000;
|
||||
rounds++) {
|
||||
agreeSz = sizeof(agree);
|
||||
ret = wc_DhAgree(&aliceKey, agree, &agreeSz, alicePriv, alicePrivSz,
|
||||
bobPub, bobPubSz);
|
||||
}
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
/* disable non-blocking mode (nb == NULL) */
|
||||
ExpectIntEQ(wc_DhSetNonBlock(&aliceKey, NULL), 0);
|
||||
agreeSz = sizeof(agree);
|
||||
ExpectIntEQ(wc_DhAgree(&aliceKey, agree, &agreeSz, alicePriv,
|
||||
alicePrivSz, bobPub, bobPubSz), 0);
|
||||
|
||||
wc_FreeDhKey(&aliceKey);
|
||||
wc_FreeDhKey(&bobKey);
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhImportKeyPair() / wc_DhExportKeyPair() (WOLFSSL_DH_EXTRA).
|
||||
*/
|
||||
int test_wc_DhImportExportKeyPair(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
byte priv[TEST_DH_BUF_SIZE], pub[TEST_DH_BUF_SIZE];
|
||||
word32 privSz = sizeof(priv), pubSz = sizeof(pub);
|
||||
byte privOut[TEST_DH_BUF_SIZE], pubOut[TEST_DH_BUF_SIZE];
|
||||
word32 privOutSz, pubOutSz;
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, &pubSz),
|
||||
0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* bad args */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhImportKeyPair(NULL, priv, privSz, pub, pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* neither priv nor pub supplied -> BAD_FUNC_ARG */
|
||||
ExpectIntEQ(wc_DhImportKeyPair(&key, NULL, 0, NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* priv only */
|
||||
ExpectIntEQ(wc_DhImportKeyPair(&key, priv, privSz, NULL, 0), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* pub only */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhImportKeyPair(&key, NULL, 0, pub, pubSz), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* both */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhImportKeyPair(&key, priv, privSz, pub, pubSz), 0);
|
||||
|
||||
/* export bad args */
|
||||
privOutSz = sizeof(privOut);
|
||||
pubOutSz = sizeof(pubOut);
|
||||
ExpectIntEQ(wc_DhExportKeyPair(NULL, privOut, &privOutSz, pubOut,
|
||||
&pubOutSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhExportKeyPair(&key, privOut, NULL, pubOut, &pubOutSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhExportKeyPair(&key, privOut, &privOutSz, pubOut, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* valid: neither priv nor pub requested (guard is all-false) */
|
||||
ExpectIntEQ(wc_DhExportKeyPair(&key, NULL, NULL, NULL, NULL), 0);
|
||||
|
||||
/* valid: full export */
|
||||
privOutSz = sizeof(privOut);
|
||||
pubOutSz = sizeof(pubOut);
|
||||
ExpectIntEQ(wc_DhExportKeyPair(&key, privOut, &privOutSz, pubOut,
|
||||
&pubOutSz), 0);
|
||||
ExpectIntEQ(XMEMCMP(privOut, priv, privOutSz), 0);
|
||||
ExpectIntEQ(XMEMCMP(pubOut, pub, pubOutSz), 0);
|
||||
|
||||
/* buffer too small, priv then pub */
|
||||
privOutSz = 1;
|
||||
ExpectIntEQ(wc_DhExportKeyPair(&key, privOut, &privOutSz, NULL, NULL),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
pubOutSz = 1;
|
||||
ExpectIntEQ(wc_DhExportKeyPair(&key, NULL, NULL, pubOut, &pubOutSz),
|
||||
WC_NO_ERR_TRACE(BUFFER_E));
|
||||
|
||||
wc_FreeDhKey(&key);
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhCheckPubKey() / wc_DhCheckPubKey_ex() (the file-static
|
||||
* _ffc_validate_public_key, reached only through these two thin wrappers).
|
||||
*/
|
||||
int test_wc_DhCheckPubKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(HAVE_PUBLIC_FFDHE) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
const DhParams* params = NULL;
|
||||
byte priv[TEST_DH_BUF_SIZE], pub[TEST_DH_BUF_SIZE];
|
||||
word32 privSz = sizeof(priv), pubSz = sizeof(pub);
|
||||
byte tiny[1] = { 0x01 };
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectNotNull(params = wc_Dh_ffdhe2048_Get());
|
||||
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, &pubSz),
|
||||
0);
|
||||
|
||||
/* bad args */
|
||||
ExpectIntEQ(wc_DhCheckPubKey(NULL, pub, pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckPubKey(&key, NULL, pubSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckPubKey_ex(NULL, pub, pubSz, NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckPubKey_ex(&key, NULL, pubSz, NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* valid: uses key->q (named group, q known) */
|
||||
ExpectIntEQ(wc_DhCheckPubKey(&key, pub, pubSz), 0);
|
||||
if (params != NULL) {
|
||||
/* valid: explicit prime (q) override */
|
||||
#ifdef HAVE_FFDHE_Q
|
||||
ExpectIntEQ(wc_DhCheckPubKey_ex(&key, pub, pubSz, params->q,
|
||||
params->q_len), 0);
|
||||
#endif
|
||||
|
||||
/* invalid: pub >= p - 1 (use p itself, definitely out of range) */
|
||||
ExpectIntEQ(wc_DhCheckPubKey(&key, params->p, params->p_len),
|
||||
WC_NO_ERR_TRACE(MP_CMP_E));
|
||||
}
|
||||
|
||||
/* invalid: pub < 2 */
|
||||
ExpectIntEQ(wc_DhCheckPubKey(&key, tiny, sizeof(tiny)),
|
||||
WC_NO_ERR_TRACE(MP_CMP_E));
|
||||
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
if (params != NULL) {
|
||||
/* key with no q known: the order-q subgroup check is skipped
|
||||
* entirely (prime==NULL && mp_iszero(&key->q)==MP_NO is false). */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetKey(&key, params->p, params->p_len, params->g,
|
||||
params->g_len), 0);
|
||||
ExpectIntEQ(wc_DhCheckPubKey(&key, pub, pubSz), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
}
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhCheckPrivKey() / wc_DhCheckPrivKey_ex().
|
||||
*/
|
||||
int test_wc_DhCheckPrivKey(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(HAVE_PUBLIC_FFDHE) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
const DhParams* params = NULL;
|
||||
byte priv[TEST_DH_BUF_SIZE], pub[TEST_DH_BUF_SIZE];
|
||||
word32 privSz = sizeof(priv), pubSz = sizeof(pub);
|
||||
byte zero[1] = { 0x00 };
|
||||
byte big[TEST_DH_BUF_SIZE];
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectNotNull(params = wc_Dh_ffdhe2048_Get());
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, &pubSz),
|
||||
0);
|
||||
|
||||
/* bad args */
|
||||
ExpectIntEQ(wc_DhCheckPrivKey(NULL, priv, privSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckPrivKey(&key, NULL, privSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckPrivKey_ex(NULL, priv, privSz, NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckPrivKey_ex(&key, NULL, privSz, NULL, 0),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* valid: key->q known */
|
||||
ExpectIntEQ(wc_DhCheckPrivKey(&key, priv, privSz), 0);
|
||||
/* invalid: priv == 0 */
|
||||
ExpectIntEQ(wc_DhCheckPrivKey(&key, zero, sizeof(zero)),
|
||||
WC_NO_ERR_TRACE(MP_CMP_E));
|
||||
|
||||
if (params != NULL) {
|
||||
#ifdef HAVE_FFDHE_Q
|
||||
/* valid: explicit prime (q) override */
|
||||
ExpectIntEQ(wc_DhCheckPrivKey_ex(&key, priv, privSz, params->q,
|
||||
params->q_len), 0);
|
||||
|
||||
/* invalid: priv > q - 1 (use q itself as priv, too big by 1) */
|
||||
XMEMSET(big, 0, sizeof(big));
|
||||
XMEMCPY(big, params->q, params->q_len);
|
||||
ExpectIntEQ(wc_DhCheckPrivKey(&key, big, params->q_len),
|
||||
WC_NO_ERR_TRACE(DH_CHECK_PRIV_E));
|
||||
#endif
|
||||
}
|
||||
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
if (params != NULL) {
|
||||
/* key with no q known: only the priv==0 sanity check applies. */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetKey(&key, params->p, params->p_len, params->g,
|
||||
params->g_len), 0);
|
||||
ExpectIntEQ(wc_DhCheckPrivKey(&key, priv, privSz), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
}
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhCheckKeyPair() (the file-static _ffc_pairwise_consistency_
|
||||
* test) and the WOLFSSL_VALIDATE_DH_KEYGEN generate-time equivalent.
|
||||
*/
|
||||
int test_wc_DhCheckKeyPair(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
byte priv[TEST_DH_BUF_SIZE], pub[TEST_DH_BUF_SIZE];
|
||||
word32 privSz = sizeof(priv), pubSz = sizeof(pub);
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, &pubSz),
|
||||
0);
|
||||
|
||||
/* bad args */
|
||||
ExpectIntEQ(wc_DhCheckKeyPair(NULL, pub, pubSz, priv, privSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckKeyPair(&key, NULL, pubSz, priv, privSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhCheckKeyPair(&key, pub, pubSz, NULL, privSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* valid pair */
|
||||
ExpectIntEQ(wc_DhCheckKeyPair(&key, pub, pubSz, priv, privSz), 0);
|
||||
|
||||
/* mismatched pair: corrupt the public key */
|
||||
pub[pubSz - 1] ^= 0x01;
|
||||
ExpectIntEQ(wc_DhCheckKeyPair(&key, pub, pubSz, priv, privSz),
|
||||
WC_NO_ERR_TRACE(MP_CMP_E));
|
||||
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* wc_DhGenerateKeyPair / wc_DhGeneratePublic with
|
||||
* WOLFSSL_VALIDATE_DH_KEYGEN on: exercises _ffc_validate_public_key +
|
||||
* _ffc_pairwise_consistency_test from the generate path itself. */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
|
||||
privSz = sizeof(priv); pubSz = sizeof(pub);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub,
|
||||
&pubSz), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DhGenerateParams() and wc_DhExportParamsRaw() (WOLFSSL_KEY_GEN).
|
||||
*/
|
||||
int test_wc_DhGenerateParams_and_ExportRaw(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DH) && defined(WOLFSSL_KEY_GEN)
|
||||
DhKey dh;
|
||||
WC_RNG rng;
|
||||
/* g is found by an unbounded incrementing search (wc_DhGenerateParams),
|
||||
* so size its buffer the same as p/q rather than assuming it stays
|
||||
* small. */
|
||||
byte pOut[TEST_DH_BUF_SIZE], qOut[TEST_DH_BUF_SIZE];
|
||||
byte gOut[TEST_DH_BUF_SIZE];
|
||||
word32 pSz, qSz, gSz;
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_InitDhKey(&dh), 0);
|
||||
|
||||
/* bad args */
|
||||
ExpectIntEQ(wc_DhGenerateParams(NULL, 1024, &dh),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhGenerateParams(&rng, 1024, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
ExpectIntEQ(wc_DhGenerateParams(&rng, 1024, &dh), 0);
|
||||
|
||||
/* bad args */
|
||||
pSz = sizeof(pOut); qSz = sizeof(qOut); gSz = sizeof(gOut);
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(NULL, pOut, &pSz, qOut, &qSz, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, NULL, qOut, &qSz, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, qOut, NULL, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, qOut, &qSz, gOut,
|
||||
NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* length-only query (all three buffer pointers NULL) */
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, NULL, &pSz, NULL, &qSz, NULL,
|
||||
&gSz), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
|
||||
|
||||
/* mixed NULL (some but not all buffers NULL) -> BAD_FUNC_ARG */
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, NULL, &qSz, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* buffer too small for each of p/q/g in turn. 0 (rather than a small
|
||||
* fixed literal) guarantees BUFFER_E regardless of the actual byte
|
||||
* length wc_DhGenerateParams happened to produce for p/q/g (g in
|
||||
* particular is found by an unbounded incrementing search, so its
|
||||
* length is not fixed). */
|
||||
pSz = 0; qSz = sizeof(qOut); gSz = sizeof(gOut);
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, qOut, &qSz, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BUFFER_E));
|
||||
pSz = sizeof(pOut); qSz = 0; gSz = sizeof(gOut);
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, qOut, &qSz, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BUFFER_E));
|
||||
pSz = sizeof(pOut); qSz = sizeof(qOut); gSz = 0;
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, qOut, &qSz, gOut,
|
||||
&gSz), WC_NO_ERR_TRACE(BUFFER_E));
|
||||
|
||||
/* full valid export */
|
||||
pSz = sizeof(pOut); qSz = sizeof(qOut); gSz = sizeof(gOut);
|
||||
ExpectIntEQ(wc_DhExportParamsRaw(&dh, pOut, &pSz, qOut, &qSz, gOut,
|
||||
&gSz), 0);
|
||||
|
||||
wc_FreeDhKey(&dh);
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* WOLFSSL_NO_DH186 axis coverage for CheckDhLN: a real FFDHE prime (so the
|
||||
* untrusted primality check fast-paths via the table memcmp, no expensive
|
||||
* search) paired with synthetic q sizes drives CheckDhLN's
|
||||
* "divLen==224 || divLen==256" MC/DC pair, plus the all-false rejection.
|
||||
* Compiled out entirely under WOLFSSL_NO_DH186 (CheckDhLN does not exist).
|
||||
*/
|
||||
int test_wc_DhGenerateKeyPair_CheckDhLN(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
/* WOLFSSL_VALIDATE_DH_KEYGEN is excluded: the synthetic q values below are
|
||||
* chosen only to hit CheckDhLN's bit-length arithmetic, not to be the real
|
||||
* subgroup order of the FFDHE-2048 (p, g) pair, so the pairwise-consistency
|
||||
* / public-key subgroup check that WOLFSSL_VALIDATE_DH_KEYGEN adds to
|
||||
* wc_DhGeneratePublic would (correctly) reject the generated key. */
|
||||
#if !defined(NO_DH) && !defined(WOLFSSL_NO_DH186) && \
|
||||
!defined(WOLFSSL_VALIDATE_DH_KEYGEN) && \
|
||||
defined(HAVE_PUBLIC_FFDHE) && defined(HAVE_FFDHE_2048)
|
||||
DhKey key;
|
||||
WC_RNG rng;
|
||||
const DhParams* params = NULL;
|
||||
byte priv[TEST_DH_BUF_SIZE], pub[TEST_DH_BUF_SIZE];
|
||||
word32 privSz, pubSz;
|
||||
byte q224[28];
|
||||
byte qBad[25];
|
||||
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectNotNull(params = wc_Dh_ffdhe2048_Get());
|
||||
XMEMSET(q224, 0x01, sizeof(q224));
|
||||
XMEMSET(qBad, 0x01, sizeof(qBad));
|
||||
|
||||
if (params != NULL) {
|
||||
/* real FFDHE-2048 prime + synthetic 224-bit q:
|
||||
* CheckDhLN(2048, 224) -> divLen==224 true, divLen==256 false. */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetCheckKey(&key, params->p, params->p_len,
|
||||
params->g, params->g_len, q224, sizeof(q224), 0, &rng), 0);
|
||||
privSz = sizeof(priv); pubSz = sizeof(pub);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub,
|
||||
&pubSz), 0);
|
||||
wc_FreeDhKey(&key);
|
||||
|
||||
/* same prime, q whose bit length is neither 224 nor 256:
|
||||
* CheckDhLN rejects (-1) -> BAD_FUNC_ARG (both operands false). */
|
||||
ExpectIntEQ(wc_InitDhKey(&key), 0);
|
||||
ExpectIntEQ(wc_DhSetCheckKey(&key, params->p, params->p_len,
|
||||
params->g, params->g_len, qBad, sizeof(qBad), 0, &rng), 0);
|
||||
privSz = sizeof(priv); pubSz = sizeof(pub);
|
||||
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz, pub,
|
||||
&pubSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
wc_FreeDhKey(&key);
|
||||
}
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,31 @@
|
|||
|
||||
int test_wc_DhPublicKeyDecode(void);
|
||||
int test_wc_DhAgree_subgroup_check(void);
|
||||
int test_wc_DhSetKey(void);
|
||||
int test_wc_DhSetNamedKey_and_helpers(void);
|
||||
int test_wc_DhGenerateKeyPair_bad_args(void);
|
||||
int test_wc_DhGenerateKeyPair_and_Agree(void);
|
||||
int test_wc_DhAgree_nonblock(void);
|
||||
int test_wc_DhImportExportKeyPair(void);
|
||||
int test_wc_DhCheckPubKey(void);
|
||||
int test_wc_DhCheckPrivKey(void);
|
||||
int test_wc_DhCheckKeyPair(void);
|
||||
int test_wc_DhGenerateParams_and_ExportRaw(void);
|
||||
int test_wc_DhGenerateKeyPair_CheckDhLN(void);
|
||||
|
||||
#define TEST_DH_DECLS \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhPublicKeyDecode), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhAgree_subgroup_check)
|
||||
#define TEST_DH_DECLS \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhPublicKeyDecode), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhAgree_subgroup_check), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhSetKey), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhSetNamedKey_and_helpers), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhGenerateKeyPair_bad_args), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhGenerateKeyPair_and_Agree), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhAgree_nonblock), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhImportExportKeyPair), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhCheckPubKey), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhCheckPrivKey), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhCheckKeyPair), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhGenerateParams_and_ExportRaw), \
|
||||
TEST_DECL_GROUP("dh", test_wc_DhGenerateKeyPair_CheckDhLN)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_DH_H */
|
||||
|
|
|
|||
|
|
@ -733,3 +733,308 @@ int test_wc_DsaCheckPubKey(void)
|
|||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_DsaCheckPubKey */
|
||||
|
||||
/* Fill dst (a NUL-terminated hex-digit buffer of len+1 bytes) with a
|
||||
* synthetic hex string representing an len/2-byte-long value with the top
|
||||
* nibble forced to 0xf (top bit set, so the value is exactly 4*len bits
|
||||
* long) and every other nibble set to 0x1 (odd bottom nibble, arbitrary
|
||||
* non-zero filler; the exact digits do not matter for these tests, only the
|
||||
* bit length does). len must be even. */
|
||||
static void dsa_test_fill_hex(char* dst, int len)
|
||||
{
|
||||
int i;
|
||||
dst[0] = 'f';
|
||||
for (i = 1; i < len; i++)
|
||||
dst[i] = '1';
|
||||
dst[len] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing wc_DsaSign_ex() / wc_DsaVerify_ex() digestSz bad-argument checks
|
||||
* (WC_MIN_DIGEST_SIZE_FOR_SIGN/_VERIFY / WC_MAX_DIGEST_SIZE) and the
|
||||
* qMinus1 iszero/isneg guard in wc_DsaSign_ex (q == 1 -> qMinus1 == 0).
|
||||
*/
|
||||
int test_wc_DsaSign_bad_digestSz(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DSA) && !defined(WC_FIPS_186_5_PLUS)
|
||||
DsaKey key;
|
||||
WC_RNG rng;
|
||||
byte signature[DSA_SIG_SIZE];
|
||||
byte hash[WC_MAX_DIGEST_SIZE + 16];
|
||||
int answer = 0;
|
||||
#ifdef USE_CERT_BUFFERS_1024
|
||||
byte tmp[ONEK_BUF];
|
||||
word32 bytes = sizeof_dsa_key_der_1024;
|
||||
#elif defined(USE_CERT_BUFFERS_2048)
|
||||
byte tmp[TWOK_BUF];
|
||||
word32 bytes = sizeof_dsa_key_der_2048;
|
||||
#else
|
||||
byte tmp[TWOK_BUF];
|
||||
XFILE fp = XBADFILE;
|
||||
word32 bytes = 0;
|
||||
#endif
|
||||
word32 idx = 0;
|
||||
|
||||
XMEMSET(hash, 0xAA, sizeof(hash));
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&rng, 0, sizeof(rng));
|
||||
|
||||
#ifdef USE_CERT_BUFFERS_1024
|
||||
XMEMCPY(tmp, dsa_key_der_1024, sizeof_dsa_key_der_1024);
|
||||
#elif defined(USE_CERT_BUFFERS_2048)
|
||||
XMEMCPY(tmp, dsa_key_der_2048, sizeof_dsa_key_der_2048);
|
||||
#else
|
||||
XMEMSET(tmp, 0, sizeof(tmp));
|
||||
ExpectTrue((fp = XFOPEN("./certs/dsa2048.der", "rb")) != XBADFILE);
|
||||
ExpectTrue((bytes = (word32)XFREAD(tmp, 1, sizeof(tmp), fp)) > 0);
|
||||
if (fp != XBADFILE)
|
||||
XFCLOSE(fp);
|
||||
#endif
|
||||
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_DsaPrivateKeyDecode(tmp, &idx, &key, bytes), 0);
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
|
||||
/* digestSz too large */
|
||||
ExpectIntEQ(wc_DsaSign_ex(hash, WC_MAX_DIGEST_SIZE + 1, signature, &key,
|
||||
&rng), WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
/* digestSz too small */
|
||||
ExpectIntEQ(wc_DsaSign_ex(hash, WC_MIN_DIGEST_SIZE_FOR_SIGN - 1,
|
||||
signature, &key, &rng), WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
/* a valid digestSz signs successfully (all-false baseline) */
|
||||
ExpectIntEQ(wc_DsaSign_ex(hash, WC_SHA_DIGEST_SIZE, signature, &key,
|
||||
&rng), 0);
|
||||
|
||||
ExpectIntEQ(wc_DsaVerify_ex(hash, WC_MAX_DIGEST_SIZE + 1, signature,
|
||||
&key, &answer), WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
ExpectIntEQ(wc_DsaVerify_ex(hash, WC_MIN_DIGEST_SIZE_FOR_VERIFY - 1,
|
||||
signature, &key, &answer), WC_NO_ERR_TRACE(BAD_LENGTH_E));
|
||||
ExpectIntEQ(wc_DsaVerify_ex(hash, WC_SHA_DIGEST_SIZE, signature, &key,
|
||||
&answer), 0);
|
||||
ExpectIntEQ(answer, 1);
|
||||
|
||||
#if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) && defined(WOLFSSL_PUBLIC_MP)
|
||||
/* q == 1: qMinus1 (q - 1) == 0 -> mp_iszero(qMinus1) true */
|
||||
ExpectIntEQ(mp_set(&key.q, 1), 0);
|
||||
ExpectIntEQ(wc_DsaSign_ex(hash, WC_SHA_DIGEST_SIZE, signature, &key,
|
||||
&rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
#endif
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
wc_FreeDsaKey(&key);
|
||||
#endif /* !NO_DSA && !WC_FIPS_186_5_PLUS */
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_DsaSign_bad_digestSz */
|
||||
|
||||
/*
|
||||
* Testing the individual (single-operand) NULL/mismatch combinations of
|
||||
* _DsaImportParamsRaw()'s guard (reached via wc_DsaImportParamsRaw() and
|
||||
* wc_DsaImportParamsRawCheck()) that the existing all-NULL / all-valid
|
||||
* tests in test_wc_DsaImportParamsRaw don't reach: each of p/q/g NULL
|
||||
* individually (others valid), and CheckDsaLN's divLen==224/divLen==256
|
||||
* MC/DC pair at a 2048-bit modulus size (untrusted path, synthetic
|
||||
* non-prime p - trusted=1 for wc_DsaImportParamsRaw so no primality
|
||||
* search is run).
|
||||
*/
|
||||
int test_wc_DsaImportParamsRaw_individual_args(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DSA)
|
||||
DsaKey key;
|
||||
const char* p = "d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d"
|
||||
"4b725ef341eabb47cf8a7a8a41e792a156b7ce97206c4f9c"
|
||||
"5ce6fc5ae7912102b6b502e59050b5b21ce263dddb2044b6"
|
||||
"52236f4d42ab4b5d6aa73189cef1ace778d7845a5c1c1c71"
|
||||
"47123188f8dc551054ee162b634d60f097f719076640e209"
|
||||
"80a0093113a8bd73";
|
||||
const char* q = "96c5390a8b612c0e422bb2b0ea194a3ec935a281";
|
||||
const char* g = "06b7861abbd35cc89e79c52f68d20875389b127361ca66822"
|
||||
"138ce4991d2b862259d6b4548a6495b195aa0e0b6137ca37e"
|
||||
"b23b94074d3c3d300042bdf15762812b6333ef7b07ceba786"
|
||||
"07610fcc9ee68491dbc1e34cd12615474e52b18bc934fb00c"
|
||||
"61d39e7da8902291c4434a4e2224c3f4fd9f93cd6f4f17fc0"
|
||||
"76341a7e7d9";
|
||||
/* 2048-bit (512 hex digit) synthetic p, 224-bit (56 hex digit) and
|
||||
* 256-bit (64 hex digit) synthetic q, to drive CheckDsaLN's case-2048
|
||||
* divLen==224/divLen==256 MC/DC pair. Trusted import (wc_DsaImport
|
||||
* ParamsRaw hardcodes trusted=1) skips the primality search entirely,
|
||||
* so p need not actually be prime. */
|
||||
char p2048[513];
|
||||
char q224[57];
|
||||
char q256[65];
|
||||
|
||||
dsa_test_fill_hex(p2048, 512);
|
||||
dsa_test_fill_hex(q224, 56);
|
||||
dsa_test_fill_hex(q256, 64);
|
||||
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
/* q == NULL alone (p, g valid) */
|
||||
ExpectIntEQ(wc_DsaImportParamsRaw(&key, p, NULL, g),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* g == NULL alone (p, q valid) */
|
||||
ExpectIntEQ(wc_DsaImportParamsRaw(&key, p, q, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* p == NULL alone (q, g valid) */
|
||||
ExpectIntEQ(wc_DsaImportParamsRaw(&key, NULL, q, g),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
wc_FreeDsaKey(&key);
|
||||
|
||||
/* CheckDsaLN(2048, 224): divLen==224 true, divLen==256 false */
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_DsaImportParamsRaw(&key, p2048, q224, g), 0);
|
||||
wc_FreeDsaKey(&key);
|
||||
|
||||
/* CheckDsaLN(2048, 256): divLen==224 false, divLen==256 true */
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_DsaImportParamsRaw(&key, p2048, q256, g), 0);
|
||||
wc_FreeDsaKey(&key);
|
||||
|
||||
#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
|
||||
/* untrusted path (wc_DsaImportParamsRawCheck, trusted=0): err==MP_OKAY
|
||||
* (the p hex-radix read succeeded) && !trusted (true) -> the primality
|
||||
* check runs, and the synthetic (non-prime) p is rejected internally
|
||||
* with DH_CHECK_PUB_E. Note: _DsaImportParamsRaw's final CheckDsaLN
|
||||
* check is NOT itself guarded by "if (err == MP_OKAY)" the way every
|
||||
* other step in this function is, so once the primality rejection sets
|
||||
* err it still falls through to the q/g bit-length check; q was never
|
||||
* read (the "if (err == MP_OKAY) err = mp_read_radix(&dsa->q, ...)"
|
||||
* step above is skipped once err != MP_OKAY), so dsa->q is still the
|
||||
* key's original zero value, CheckDsaLN(2048, 0) fails, and its
|
||||
* "err = BAD_FUNC_ARG" unconditionally overwrites the earlier
|
||||
* DH_CHECK_PUB_E. The function's actual observable return code for
|
||||
* this input is therefore BAD_FUNC_ARG, not DH_CHECK_PUB_E - noted as
|
||||
* a library finding (the CheckDsaLN block arguably should also be
|
||||
* gated on err == MP_OKAY), not fixed here. */
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_DsaImportParamsRawCheck(&key, p2048, q256, g, 0, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
wc_FreeDsaKey(&key);
|
||||
#endif
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_DsaImportParamsRaw_individual_args */
|
||||
|
||||
/*
|
||||
* Testing the individual (single-operand) NULL/mixed-NULL combinations of
|
||||
* wc_DsaExportParamsRaw()'s two guards that the existing
|
||||
* test_wc_DsaExportParamsRaw doesn't reach: qSz/gSz NULL individually, and
|
||||
* a mixed (not all-NULL, not all-valid) p/q/g buffer combination for both
|
||||
* the LENGTH_ONLY_E all-NULL check and the BAD_FUNC_ARG partial-NULL check.
|
||||
*/
|
||||
int test_wc_DsaExportParamsRaw_individual_args(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DSA)
|
||||
DsaKey key;
|
||||
const char* p = "d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d"
|
||||
"4b725ef341eabb47cf8a7a8a41e792a156b7ce97206c4f9c"
|
||||
"5ce6fc5ae7912102b6b502e59050b5b21ce263dddb2044b6"
|
||||
"52236f4d42ab4b5d6aa73189cef1ace778d7845a5c1c1c71"
|
||||
"47123188f8dc551054ee162b634d60f097f719076640e209"
|
||||
"80a0093113a8bd73";
|
||||
const char* q = "96c5390a8b612c0e422bb2b0ea194a3ec935a281";
|
||||
const char* g = "06b7861abbd35cc89e79c52f68d20875389b127361ca66822"
|
||||
"138ce4991d2b862259d6b4548a6495b195aa0e0b6137ca37e"
|
||||
"b23b94074d3c3d300042bdf15762812b6333ef7b07ceba786"
|
||||
"07610fcc9ee68491dbc1e34cd12615474e52b18bc934fb00c"
|
||||
"61d39e7da8902291c4434a4e2224c3f4fd9f93cd6f4f17fc0"
|
||||
"76341a7e7d9";
|
||||
byte pOut[MAX_DSA_PARAM_SIZE];
|
||||
byte qOut[MAX_DSA_PARAM_SIZE];
|
||||
byte gOut[MAX_DSA_PARAM_SIZE];
|
||||
word32 pOutSz, qOutSz, gOutSz;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(DsaKey));
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_DsaImportParamsRaw(&key, p, q, g), 0);
|
||||
|
||||
pOutSz = sizeof(pOut); qOutSz = sizeof(qOut); gOutSz = sizeof(gOut);
|
||||
/* qSz == NULL alone */
|
||||
ExpectIntEQ(wc_DsaExportParamsRaw(&key, pOut, &pOutSz, qOut, NULL, gOut,
|
||||
&gOutSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* gSz == NULL alone */
|
||||
ExpectIntEQ(wc_DsaExportParamsRaw(&key, pOut, &pOutSz, qOut, &qOutSz,
|
||||
gOut, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
/* mixed: p NULL, q and g non-NULL (not all-NULL -> skips LENGTH_ONLY_E;
|
||||
* not all-valid -> BAD_FUNC_ARG from the second guard) */
|
||||
ExpectIntEQ(wc_DsaExportParamsRaw(&key, NULL, &pOutSz, qOut, &qOutSz,
|
||||
gOut, &gOutSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* mixed: q NULL only */
|
||||
ExpectIntEQ(wc_DsaExportParamsRaw(&key, pOut, &pOutSz, NULL, &qOutSz,
|
||||
gOut, &gOutSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* mixed: g NULL only */
|
||||
ExpectIntEQ(wc_DsaExportParamsRaw(&key, pOut, &pOutSz, qOut, &qOutSz,
|
||||
NULL, &gOutSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_FreeDsaKey(&key);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_DsaExportParamsRaw_individual_args */
|
||||
|
||||
/*
|
||||
* Testing the individual (single-operand) NULL/zero-only combinations of
|
||||
* wc_DsaExportKeyRaw()'s guards that the existing test_wc_DsaExportKeyRaw
|
||||
* doesn't reach: ySz NULL alone, y NULL alone (x valid), and only one of
|
||||
* (x, y) zero (the mp_iszero(x) && mp_iszero(y) "both zero" check).
|
||||
*/
|
||||
int test_wc_DsaExportKeyRaw_individual_args(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_DSA) && defined(WOLFSSL_KEY_GEN)
|
||||
DsaKey key;
|
||||
WC_RNG rng;
|
||||
byte xOut[MAX_DSA_PARAM_SIZE];
|
||||
byte yOut[MAX_DSA_PARAM_SIZE];
|
||||
word32 xOutSz, yOutSz;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&rng, 0, sizeof(rng));
|
||||
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_MakeDsaParameters(&rng, 1024, &key), 0);
|
||||
ExpectIntEQ(wc_MakeDsaKey(&rng, &key), 0);
|
||||
|
||||
xOutSz = sizeof(xOut); yOutSz = sizeof(yOut);
|
||||
/* ySz == NULL alone */
|
||||
ExpectIntEQ(wc_DsaExportKeyRaw(&key, xOut, &xOutSz, yOut, NULL),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
/* y == NULL alone (x valid): LENGTH_ONLY_E only fires when BOTH x and y
|
||||
* are NULL; with exactly one NULL this falls through to the
|
||||
* "x == NULL || y == NULL" guard -> BAD_FUNC_ARG. */
|
||||
ExpectIntEQ(wc_DsaExportKeyRaw(&key, xOut, &xOutSz, NULL, &yOutSz),
|
||||
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
||||
|
||||
wc_FreeDsaKey(&key);
|
||||
|
||||
#if !defined(HAVE_SELFTEST) && !defined(HAVE_FIPS) && defined(WOLFSSL_PUBLIC_MP)
|
||||
/* only y is zero (x non-zero): mp_iszero(x)==false short-circuits the
|
||||
* "both zero" check before mp_iszero(y) is even evaluated by most
|
||||
* compilers, but the source is a plain && so MC/DC still needs this
|
||||
* combination demonstrated with x forced non-zero and y forced zero. */
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_MakeDsaParameters(&rng, 1024, &key), 0);
|
||||
ExpectIntEQ(wc_MakeDsaKey(&rng, &key), 0);
|
||||
mp_zero(&key.y);
|
||||
xOutSz = sizeof(xOut); yOutSz = sizeof(yOut);
|
||||
ExpectIntEQ(wc_DsaExportKeyRaw(&key, xOut, &xOutSz, yOut, &yOutSz), 0);
|
||||
wc_FreeDsaKey(&key);
|
||||
|
||||
/* only x is zero (y non-zero) */
|
||||
ExpectIntEQ(wc_InitDsaKey(&key), 0);
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_MakeDsaParameters(&rng, 1024, &key), 0);
|
||||
ExpectIntEQ(wc_MakeDsaKey(&rng, &key), 0);
|
||||
mp_zero(&key.x);
|
||||
xOutSz = sizeof(xOut); yOutSz = sizeof(yOut);
|
||||
ExpectIntEQ(wc_DsaExportKeyRaw(&key, xOut, &xOutSz, yOut, &yOutSz), 0);
|
||||
wc_FreeDsaKey(&key);
|
||||
#endif
|
||||
|
||||
DoExpectIntEQ(wc_FreeRng(&rng), 0);
|
||||
#endif /* !NO_DSA && WOLFSSL_KEY_GEN */
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_DsaExportKeyRaw_individual_args */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ int test_wc_DsaImportParamsRawCheck(void);
|
|||
int test_wc_DsaExportParamsRaw(void);
|
||||
int test_wc_DsaExportKeyRaw(void);
|
||||
int test_wc_DsaCheckPubKey(void);
|
||||
int test_wc_DsaSign_bad_digestSz(void);
|
||||
int test_wc_DsaImportParamsRaw_individual_args(void);
|
||||
int test_wc_DsaExportParamsRaw_individual_args(void);
|
||||
int test_wc_DsaExportKeyRaw_individual_args(void);
|
||||
|
||||
#define TEST_DSA_DECLS \
|
||||
TEST_DECL_GROUP("dsa", test_wc_InitDsaKey), \
|
||||
|
|
@ -47,6 +51,10 @@ int test_wc_DsaCheckPubKey(void);
|
|||
TEST_DECL_GROUP("dsa", test_wc_DsaImportParamsRawCheck), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaExportParamsRaw), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaExportKeyRaw), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaCheckPubKey)
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaCheckPubKey), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaSign_bad_digestSz), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaImportParamsRaw_individual_args), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaExportParamsRaw_individual_args), \
|
||||
TEST_DECL_GROUP("dsa", test_wc_DsaExportKeyRaw_individual_args)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_DSA_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue