#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifndef NO_DSA
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/wolfmath.h>
#include <wolfssl/wolfcrypt/sha.h>
#include <wolfssl/wolfcrypt/dsa.h>
#include <wolfssl/wolfcrypt/hash.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && !defined(WOLFSSL_SP_ASM)
#undef SAVE_VECTOR_REGISTERS
#define SAVE_VECTOR_REGISTERS(fail_clause) SAVE_NO_VECTOR_REGISTERS(fail_clause)
#undef RESTORE_VECTOR_REGISTERS
#define RESTORE_VECTOR_REGISTERS() RESTORE_NO_VECTOR_REGISTERS()
#endif
#ifdef _MSC_VER
#pragma warning(disable:4127)
#endif
int wc_InitDsaKey(DsaKey* key)
{
if (key == NULL)
return BAD_FUNC_ARG;
key->type = -1;
key->heap = NULL;
return mp_init_multi(
&key->p,
&key->q,
&key->g,
&key->y,
&key->x,
NULL
);
}
int wc_InitDsaKey_h(DsaKey* key, void* h)
{
int ret = wc_InitDsaKey(key);
if (ret == 0)
key->heap = h;
return ret;
}
void wc_FreeDsaKey(DsaKey* key)
{
if (key == NULL)
return;
mp_forcezero(&key->x);
mp_clear(&key->y);
mp_clear(&key->g);
mp_clear(&key->q);
mp_clear(&key->p);
}
static int CheckDsaLN(int modLen, int divLen)
{
int ret = -1;
switch (modLen) {
#ifdef WOLFSSL_DSA_768_MODULUS
case 768:
#endif
case 1024:
if (divLen == 160)
ret = 0;
break;
case 2048:
if (divLen == 224 || divLen == 256)
ret = 0;
break;
case 3072:
if (divLen == 256)
ret = 0;
break;
default:
break;
}
return ret;
}
#ifdef WOLFSSL_KEY_GEN
int wc_MakeDsaKey(WC_RNG *rng, DsaKey *dsa)
{
int qSz, pSz, cSz, err;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
mp_int *tmpQ = NULL;
byte* cBuf = NULL;
#else
mp_int tmpQ[1];
byte cBuf[(3072+64)/WOLFSSL_BIT_SIZE ];
#endif
if (rng == NULL || dsa == NULL)
return BAD_FUNC_ARG;
qSz = mp_unsigned_bin_size(&dsa->q);
pSz = mp_unsigned_bin_size(&dsa->p);
if (CheckDsaLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0)
return BAD_FUNC_ARG;
cSz = qSz + (64 / WOLFSSL_BIT_SIZE);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
cBuf = (byte*)XMALLOC((size_t)cSz, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (cBuf == NULL) {
return MEMORY_E;
}
#else
if (sizeof(cBuf) < (size_t)cSz) {
return BUFFER_E;
}
#endif
SAVE_VECTOR_REGISTERS(;);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
if ((tmpQ = (mp_int *)XMALLOC(sizeof(*tmpQ), NULL,
DYNAMIC_TYPE_WOLF_BIGINT)) == NULL)
err = MEMORY_E;
else
err = MP_OKAY;
if (err == MP_OKAY)
#endif
err = mp_init_multi(&dsa->x, &dsa->y, tmpQ, NULL, NULL, NULL);
if (err == MP_OKAY) {
do {
err = wc_RNG_GenerateBlock(rng, cBuf, (word32)cSz);
if (err != MP_OKAY)
break;
err = mp_read_unsigned_bin(&dsa->x, cBuf, (word32)cSz);
if (err != MP_OKAY)
break;
} while (mp_cmp_d(&dsa->x, 1) != MP_GT);
}
if (err == MP_OKAY)
err = mp_copy(&dsa->q, tmpQ);
if (err == MP_OKAY)
err = mp_sub_d(tmpQ, 1, tmpQ);
if (err == MP_OKAY)
err = mp_mod(&dsa->x, tmpQ, &dsa->x);
if (err == MP_OKAY)
err = mp_add_d(&dsa->x, 1, &dsa->x);
if (err == MP_OKAY) {
err = mp_exptmod_ex(&dsa->g, &dsa->x, (int)dsa->q.used, &dsa->p,
&dsa->y);
}
if (err == MP_OKAY)
dsa->type = DSA_PRIVATE;
if (err != MP_OKAY) {
mp_forcezero(&dsa->x);
mp_clear(&dsa->y);
}
ForceZero(cBuf, (word32)cSz);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (tmpQ != NULL) {
mp_clear(tmpQ);
XFREE(tmpQ, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#else
mp_clear(tmpQ);
#endif
RESTORE_VECTOR_REGISTERS();
return err;
}
int wc_MakeDsaParameters(WC_RNG *rng, int modulus_size, DsaKey *dsa)
{
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
mp_int *tmp = NULL, *tmp2 = NULL;
unsigned char *buf = NULL;
#else
mp_int tmp[1], tmp2[1];
unsigned char buf[(3072/WOLFSSL_BIT_SIZE)-32];
#endif
int err, msize, qsize,
loop_check_prime = 0,
check_prime = MP_NO;
if (rng == NULL || dsa == NULL)
return BAD_FUNC_ARG;
switch (modulus_size) {
#ifdef WOLFSSL_DSA_768_MODULUS
case 768:
#endif
case 1024:
qsize = 20;
break;
case 2048:
case 3072:
qsize = 32;
break;
default:
return BAD_FUNC_ARG;
}
msize = modulus_size / WOLFSSL_BIT_SIZE;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
buf = (unsigned char *)XMALLOC((size_t)(msize - qsize),
dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (buf == NULL) {
return MEMORY_E;
}
#else
if (sizeof(buf) < (size_t)(msize - qsize)) {
return BUFFER_E;
}
#endif
err = wc_RNG_GenerateBlock(rng, buf, (word32)(msize - qsize));
if (err != MP_OKAY) {
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return err;
}
buf[0] |= 0xC0;
buf[msize - qsize - 1] &= (unsigned char)~1;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
if (((tmp = (mp_int *)XMALLOC(sizeof(*tmp), NULL, DYNAMIC_TYPE_WOLF_BIGINT)) == NULL) ||
((tmp2 = (mp_int *)XMALLOC(sizeof(*tmp2), NULL, DYNAMIC_TYPE_WOLF_BIGINT)) == NULL))
err = MEMORY_E;
else
err = MP_OKAY;
if (err == MP_OKAY)
#endif
err = mp_init_multi(tmp, tmp2, &dsa->p, &dsa->q, &dsa->g, 0);
if (err == MP_OKAY)
err = mp_read_unsigned_bin(tmp2, buf, (word32)(msize - qsize));
if (err == MP_OKAY)
err = mp_rand_prime(&dsa->q, qsize, rng, NULL);
if (err == MP_OKAY)
err = mp_mul(&dsa->q, tmp2, &dsa->p);
if (err == MP_OKAY)
err = mp_add_d(&dsa->p, 1, &dsa->p);
if (err == MP_OKAY)
err = mp_add(&dsa->q, &dsa->q, tmp);
if (err == MP_OKAY) {
while (check_prime == MP_NO) {
err = mp_prime_is_prime_ex(&dsa->p, 8, &check_prime, rng);
if (err != MP_OKAY)
break;
if (check_prime != MP_YES) {
err = mp_add(tmp, &dsa->p, &dsa->p);
if (err != MP_OKAY)
break;
loop_check_prime++;
}
}
}
if (err == MP_OKAY) {
if (loop_check_prime)
err = mp_add_d(tmp2, 2 * (mp_digit)loop_check_prime, tmp2);
}
if (err == MP_OKAY)
err = mp_set(&dsa->g, 1);
if (err == MP_OKAY) {
do {
err = mp_add_d(&dsa->g, 1, &dsa->g);
if (err != MP_OKAY)
break;
err = mp_exptmod(&dsa->g, tmp2, &dsa->p, tmp);
if (err != MP_OKAY)
break;
} while (mp_cmp_d(tmp, 1) == MP_EQ);
}
if (err == MP_OKAY) {
#ifndef USE_FAST_MATH
err = mp_exch(tmp, &dsa->g);
#else
err = mp_copy(tmp, &dsa->g);
#endif
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (tmp != NULL) {
if ((err != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(err != WC_NO_ERR_TRACE(MEMORY_E)))
mp_clear(tmp);
XFREE(tmp, NULL, DYNAMIC_TYPE_WOLF_BIGINT);
}
if (tmp2 != NULL) {
if ((err != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(err != WC_NO_ERR_TRACE(MEMORY_E)))
mp_clear(tmp2);
XFREE(tmp2, NULL, DYNAMIC_TYPE_WOLF_BIGINT);
}
#else
if (err != WC_NO_ERR_TRACE(MP_INIT_E)) {
mp_clear(tmp);
mp_clear(tmp2);
}
#endif
if ((err != MP_OKAY) && (err != WC_NO_ERR_TRACE(MP_INIT_E))) {
mp_clear(&dsa->q);
mp_clear(&dsa->p);
mp_clear(&dsa->g);
}
return err;
}
#endif
static int _DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q,
const char* g, int trusted, WC_RNG* rng)
{
int err;
int pSz, qSz;
if (dsa == NULL || p == NULL || q == NULL || g == NULL)
return BAD_FUNC_ARG;
err = mp_read_radix(&dsa->p, p, MP_RADIX_HEX);
if (err == MP_OKAY && !trusted) {
int isPrime = 1;
if (rng == NULL)
err = mp_prime_is_prime(&dsa->p, 8, &isPrime);
else
err = mp_prime_is_prime_ex(&dsa->p, 8, &isPrime, rng);
if (err == MP_OKAY) {
if (!isPrime)
err = DH_CHECK_PUB_E;
}
}
if (err == MP_OKAY)
err = mp_read_radix(&dsa->q, q, MP_RADIX_HEX);
if (err == MP_OKAY)
err = mp_read_radix(&dsa->g, g, MP_RADIX_HEX);
pSz = mp_unsigned_bin_size(&dsa->p);
qSz = mp_unsigned_bin_size(&dsa->q);
if (CheckDsaLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) {
WOLFSSL_MSG("Invalid DSA p or q parameter size");
err = BAD_FUNC_ARG;
}
if (err != MP_OKAY) {
mp_clear(&dsa->p);
mp_clear(&dsa->q);
mp_clear(&dsa->g);
}
return err;
}
int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q,
const char* g)
{
return _DsaImportParamsRaw(dsa, p, q, g, 1, NULL);
}
int wc_DsaImportParamsRawCheck(DsaKey* dsa, const char* p, const char* q,
const char* g, int trusted, WC_RNG* rng)
{
return _DsaImportParamsRaw(dsa, p, q, g, trusted, rng);
}
int wc_DsaExportParamsRaw(DsaKey* dsa, byte* p, word32* pSz,
byte* q, word32* qSz, byte* g, word32* gSz)
{
int err;
word32 pLen, qLen, gLen;
if (dsa == NULL || pSz == NULL || qSz == NULL || gSz == NULL)
return BAD_FUNC_ARG;
pLen = (word32)mp_unsigned_bin_size(&dsa->p);
qLen = (word32)mp_unsigned_bin_size(&dsa->q);
gLen = (word32)mp_unsigned_bin_size(&dsa->g);
if (p == NULL && q == NULL && g == NULL) {
*pSz = pLen;
*qSz = qLen;
*gSz = gLen;
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if (p == NULL || q == NULL || g == NULL)
return BAD_FUNC_ARG;
if (*pSz < pLen) {
WOLFSSL_MSG("Output buffer for DSA p parameter too small, "
"required size placed into pSz");
*pSz = pLen;
return BUFFER_E;
}
*pSz = pLen;
err = mp_to_unsigned_bin(&dsa->p, p);
if (err == MP_OKAY) {
if (*qSz < qLen) {
WOLFSSL_MSG("Output buffer for DSA q parameter too small, "
"required size placed into qSz");
*qSz = qLen;
return BUFFER_E;
}
*qSz = qLen;
err = mp_to_unsigned_bin(&dsa->q, q);
}
if (err == MP_OKAY) {
if (*gSz < gLen) {
WOLFSSL_MSG("Output buffer for DSA g parameter too small, "
"required size placed into gSz");
*gSz = gLen;
return BUFFER_E;
}
*gSz = gLen;
err = mp_to_unsigned_bin(&dsa->g, g);
}
return err;
}
int wc_DsaExportKeyRaw(DsaKey* dsa, byte* x, word32* xSz, byte* y, word32* ySz)
{
int err;
word32 xLen, yLen;
if (dsa == NULL || xSz == NULL || ySz == NULL)
return BAD_FUNC_ARG;
xLen = (word32)mp_unsigned_bin_size(&dsa->x);
yLen = (word32)mp_unsigned_bin_size(&dsa->y);
if (x == NULL && y == NULL) {
*xSz = xLen;
*ySz = yLen;
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if (x == NULL || y == NULL)
return BAD_FUNC_ARG;
if (*xSz < xLen) {
WOLFSSL_MSG("Output buffer for DSA private key (x) too small, "
"required size placed into xSz");
*xSz = xLen;
return BUFFER_E;
}
*xSz = xLen;
err = mp_to_unsigned_bin(&dsa->x, x);
if (err == MP_OKAY) {
if (*ySz < yLen) {
WOLFSSL_MSG("Output buffer to DSA public key (y) too small, "
"required size placed into ySz");
*ySz = yLen;
return BUFFER_E;
}
*ySz = yLen;
err = mp_to_unsigned_bin(&dsa->y, y);
}
return err;
}
int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, WC_RNG* rng)
{
return wc_DsaSign_ex(digest, WC_SHA_DIGEST_SIZE, out, key, rng);
}
int wc_DsaSign_ex(const byte* digest, word32 digestSz, byte* out, DsaKey* key,
WC_RNG* rng)
{
#ifdef WOLFSSL_SMALL_STACK
mp_int *k = NULL;
mp_int *kInv = NULL;
mp_int *r = NULL;
mp_int *s = NULL;
mp_int *H = NULL;
#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME
mp_int *b = NULL;
#endif
byte *buffer = NULL;
#else
mp_int k[1], kInv[1], r[1], s[1], H[1];
#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME
mp_int b[1];
#endif
byte buffer[DSA_MAX_HALF_SIZE];
#endif
mp_int* qMinus1;
int ret = 0;
word32 halfSz = 0;
if (digest == NULL || out == NULL || key == NULL || rng == NULL)
return BAD_FUNC_ARG;
if ((digestSz > WC_MAX_DIGEST_SIZE) ||
(digestSz < WC_MIN_DIGEST_SIZE))
{
return BAD_LENGTH_E;
}
SAVE_VECTOR_REGISTERS(return _svr_ret;);
do {
#ifdef WOLFSSL_SMALL_STACK
k = (mp_int *)XMALLOC(sizeof *k, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
kInv = (mp_int *)XMALLOC(sizeof *kInv, key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
r = (mp_int *)XMALLOC(sizeof *r, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
s = (mp_int *)XMALLOC(sizeof *s, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
H = (mp_int *)XMALLOC(sizeof *H, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME
b = (mp_int *)XMALLOC(sizeof *b, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
buffer = (byte *)XMALLOC(DSA_MAX_HALF_SIZE, key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if ((k == NULL) ||
(kInv == NULL) ||
(r == NULL) ||
(s == NULL) ||
(H == NULL)
#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME
|| (b == NULL)
#endif
|| (buffer == NULL)) {
ret = MEMORY_E;
break;
}
#endif
#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME
if (mp_init_multi(k, kInv, r, s, H, 0) != MP_OKAY)
#else
if (mp_init_multi(k, kInv, r, s, H, b) != MP_OKAY)
#endif
{
ret = MP_INIT_E;
break;
}
halfSz = min(DSA_MAX_HALF_SIZE, (word32)mp_unsigned_bin_size(&key->q));
if (halfSz == 0) {
ret = BAD_FUNC_ARG;
break;
}
qMinus1 = kInv;
if (mp_sub_d(&key->q, 1, qMinus1)) {
ret = MP_SUB_E;
break;
}
if (mp_iszero(qMinus1) || mp_isneg(qMinus1)) {
ret = BAD_FUNC_ARG;
break;
}
do {
if ((ret = wc_RNG_GenerateBlock(rng, buffer, halfSz))) {
break;
}
if (mp_read_unsigned_bin(k, buffer, halfSz) != MP_OKAY) {
ret = MP_READ_E;
break;
}
} while (mp_cmp(k, qMinus1) != MP_LT);
if (ret != 0)
break;
if (mp_add_d(k, 1, k) != MP_OKAY) {
ret = MP_MOD_E;
break;
}
#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME
if (mp_invmod(k, &key->q, kInv) != MP_OKAY) {
ret = MP_INVMOD_E;
break;
}
if (mp_exptmod_ex(&key->g, k, key->q.used, &key->p, r) != MP_OKAY) {
ret = MP_EXPTMOD_E;
break;
}
if (mp_mod(r, &key->q, r) != MP_OKAY) {
ret = MP_MOD_E;
break;
}
if (mp_read_unsigned_bin(H, digest, digestSz) != MP_OKAY) {
ret = MP_READ_E;
break;
}
if (mp_mul(&key->x, r, s) != MP_OKAY) {
ret = MP_MUL_E;
break;
}
if (mp_add(s, H, s) != MP_OKAY) {
ret = MP_ADD_E;
break;
}
if (mp_mulmod(s, kInv, &key->q, s) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
#else
do {
if ((ret = wc_RNG_GenerateBlock(rng, buffer, halfSz))) {
break;
}
if (mp_read_unsigned_bin(b, buffer, halfSz) != MP_OKAY) {
ret = MP_READ_E;
break;
}
} while (mp_cmp(b, qMinus1) != MP_LT);
if (ret != 0)
break;
if (mp_add_d(b, 1, b) != MP_OKAY) {
ret = MP_MOD_E;
break;
}
if (mp_read_unsigned_bin(H, digest, digestSz) != MP_OKAY) {
ret = MP_READ_E;
break;
}
if (mp_exptmod_ex(&key->g, k, (int)key->q.used, &key->p, r) !=
MP_OKAY) {
ret = MP_EXPTMOD_E;
break;
}
if (mp_mulmod(k, b, &key->q, k) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_invmod(k, &key->q, kInv) != MP_OKAY) {
ret = MP_INVMOD_E;
break;
}
if (mp_mod(r, &key->q, r) != MP_OKAY) {
ret = MP_MOD_E;
break;
}
if (mp_mul(&key->x, r, s) != MP_OKAY) {
ret = MP_MUL_E;
break;
}
if (mp_mulmod(s, kInv, &key->q, s) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_mulmod(H, kInv, &key->q, H) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_add(s, H, s) != MP_OKAY) {
ret = MP_ADD_E;
break;
}
if (mp_mulmod(s, b, &key->q, s) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_mod(s, &key->q, s) != MP_OKAY) {
ret = MP_MOD_E;
break;
}
#endif
if ((mp_iszero(r) == MP_YES) || (mp_iszero(s) == MP_YES)) {
ret = MP_ZERO_E;
break;
}
{
if (mp_to_unsigned_bin_len(r, out, (int)halfSz) != MP_OKAY)
ret = MP_TO_E;
else {
out += halfSz;
ret = mp_to_unsigned_bin_len(s, out, (int)halfSz);
}
}
} while (0);
RESTORE_VECTOR_REGISTERS();
#ifdef WOLFSSL_SMALL_STACK
if (k) {
if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(ret != WC_NO_ERR_TRACE(MEMORY_E)))
mp_forcezero(k);
XFREE(k, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (kInv) {
if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(ret != WC_NO_ERR_TRACE(MEMORY_E)))
mp_forcezero(kInv);
XFREE(kInv, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (r) {
if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(ret != WC_NO_ERR_TRACE(MEMORY_E)))
mp_clear(r);
XFREE(r, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (s) {
if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(ret != WC_NO_ERR_TRACE(MEMORY_E)))
mp_clear(s);
XFREE(s, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (H) {
if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(ret != WC_NO_ERR_TRACE(MEMORY_E)))
mp_clear(H);
XFREE(H, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME
if (b) {
if ((ret != WC_NO_ERR_TRACE(MP_INIT_E)) &&
(ret != WC_NO_ERR_TRACE(MEMORY_E)))
mp_forcezero(b);
XFREE(b, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
if (buffer) {
ForceZero(buffer, halfSz);
XFREE(buffer, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#else
if (ret != WC_NO_ERR_TRACE(MP_INIT_E)) {
ForceZero(buffer, halfSz);
mp_forcezero(kInv);
mp_forcezero(k);
#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME
mp_forcezero(b);
#endif
mp_clear(H);
mp_clear(s);
mp_clear(r);
}
#endif
return ret;
}
int wc_DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer)
{
return wc_DsaVerify_ex(digest, WC_SHA_DIGEST_SIZE, sig, key, answer);
}
int wc_DsaVerify_ex(const byte* digest, word32 digestSz, const byte* sig,
DsaKey* key, int* answer)
{
#ifdef WOLFSSL_SMALL_STACK
mp_int *w = NULL;
mp_int *u1 = NULL;
mp_int *u2 = NULL;
mp_int *v = NULL;
mp_int *r = NULL;
mp_int *s = NULL;
#else
mp_int w[1], u1[1], u2[1], v[1], r[1], s[1];
#endif
int ret = 0;
int qSz;
if (digest == NULL || sig == NULL || key == NULL || answer == NULL)
return BAD_FUNC_ARG;
if ((digestSz > WC_MAX_DIGEST_SIZE) ||
(digestSz < WC_SHA_DIGEST_SIZE))
{
return BAD_LENGTH_E;
}
do {
#ifdef WOLFSSL_SMALL_STACK
w = (mp_int *)XMALLOC(sizeof *w, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
u1 = (mp_int *)XMALLOC(sizeof *u1, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
u2 = (mp_int *)XMALLOC(sizeof *u2, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
v = (mp_int *)XMALLOC(sizeof *v, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
r = (mp_int *)XMALLOC(sizeof *r, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
s = (mp_int *)XMALLOC(sizeof *s, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if ((w == NULL) ||
(u1 == NULL) ||
(u2 == NULL) ||
(v == NULL) ||
(r == NULL) ||
(s == NULL)) {
ret = MEMORY_E;
break;
}
#endif
if (mp_init_multi(w, u1, u2, v, r, s) != MP_OKAY) {
ret = MP_INIT_E;
break;
}
qSz = mp_unsigned_bin_size(&key->q);
if (qSz <= 0) {
ret = BAD_FUNC_ARG;
break;
}
if (mp_read_unsigned_bin(r, sig, (word32)qSz) != MP_OKAY ||
mp_read_unsigned_bin(s, sig + qSz, (word32)qSz) != MP_OKAY) {
ret = MP_READ_E;
break;
}
if (mp_iszero(r) == MP_YES || mp_iszero(s) == MP_YES ||
mp_cmp(r, &key->q) != MP_LT || mp_cmp(s, &key->q) != MP_LT) {
ret = MP_ZERO_E;
break;
}
if (mp_read_unsigned_bin(u1,digest, digestSz) != MP_OKAY) {
ret = MP_READ_E;
break;
}
if (mp_invmod(s, &key->q, w) != MP_OKAY) {
ret = MP_INVMOD_E;
break;
}
if (mp_mulmod(u1, w, &key->q, u1) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_mulmod(r, w, &key->q, u2) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_exptmod(&key->g, u1, &key->p, u1) != MP_OKAY) {
ret = MP_EXPTMOD_E;
break;
}
if (mp_exptmod(&key->y, u2, &key->p, u2) != MP_OKAY) {
ret = MP_EXPTMOD_E;
break;
}
if (mp_mulmod(u1, u2, &key->p, v) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_mod(v, &key->q, v) != MP_OKAY) {
ret = MP_MULMOD_E;
break;
}
if (mp_cmp(r, v) == MP_EQ)
*answer = 1;
else
*answer = 0;
} while (0);
#ifdef WOLFSSL_SMALL_STACK
if (s) {
if (ret != WC_NO_ERR_TRACE(MP_INIT_E) && ret != WC_NO_ERR_TRACE(MEMORY_E))
mp_clear(s);
XFREE(s, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (r) {
if (ret != WC_NO_ERR_TRACE(MP_INIT_E) && ret != WC_NO_ERR_TRACE(MEMORY_E))
mp_clear(r);
XFREE(r, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (u1) {
if (ret != WC_NO_ERR_TRACE(MP_INIT_E) && ret != WC_NO_ERR_TRACE(MEMORY_E))
mp_clear(u1);
XFREE(u1, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (u2) {
if (ret != WC_NO_ERR_TRACE(MP_INIT_E) && ret != WC_NO_ERR_TRACE(MEMORY_E))
mp_clear(u2);
XFREE(u2, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (w) {
if (ret != WC_NO_ERR_TRACE(MP_INIT_E) && ret != WC_NO_ERR_TRACE(MEMORY_E))
mp_clear(w);
XFREE(w, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
if (v) {
if (ret != WC_NO_ERR_TRACE(MP_INIT_E) && ret != WC_NO_ERR_TRACE(MEMORY_E))
mp_clear(v);
XFREE(v, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#else
if (ret != WC_NO_ERR_TRACE(MP_INIT_E)) {
mp_clear(s);
mp_clear(r);
mp_clear(u1);
mp_clear(u2);
mp_clear(w);
mp_clear(v);
}
#endif
return ret;
}
#endif