Small stack fixes

Changes to DH and SSL/TLS code to dynamically allocate large stack
variables when compiled with WOLFSSL_SMALL_STACK.
This commit is contained in:
Sean Parkinson
2018-07-17 09:04:00 +10:00
parent f0422bec41
commit 514a949557
4 changed files with 452 additions and 165 deletions

View File

@@ -162,7 +162,7 @@ static int NonBlockingSSL_Connect(WOLFSSL* ssl)
static void ShowCiphers(void) static void ShowCiphers(void)
{ {
char ciphers[4096]; static char ciphers[4096];
int ret = wolfSSL_get_ciphers(ciphers, (int)sizeof(ciphers)); int ret = wolfSSL_get_ciphers(ciphers, (int)sizeof(ciphers));
@@ -313,7 +313,12 @@ static int ClientBenchmarkConnections(WOLFSSL_CTX* ctx, char* host, word16 port,
} }
#ifdef WOLFSSL_TLS13 #ifdef WOLFSSL_TLS13
if (version >= 4 && resumeSession && !benchResume) { #ifndef NO_SESSION_CACHE
if (version >= 4 && resumeSession && !benchResume)
#else
if (version >= 4 && resumeSession)
#endif
{
if (wolfSSL_write(ssl, msg, sizeof(msg)-1) <= 0) if (wolfSSL_write(ssl, msg, sizeof(msg)-1) <= 0)
err_sys("SSL_write failed"); err_sys("SSL_write failed");

139
src/ssl.c
View File

@@ -4673,19 +4673,29 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff,
#ifdef HAVE_ECC #ifdef HAVE_ECC
if (!rsaKey && !ed25519Key) { if (!rsaKey && !ed25519Key) {
/* make sure ECC key can be used */ /* make sure ECC key can be used */
word32 idx = 0; word32 idx = 0;
ecc_key key; #ifdef WOLFSSL_SMALL_STACK
ecc_key* key = NULL;
#else
ecc_key key[1];
#endif
if (wc_ecc_init_ex(&key, heap, devId) == 0) { #ifdef WOLFSSL_SMALL_STACK
if (wc_EccPrivateKeyDecode(der->buffer, &idx, &key, key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC);
if (key == NULL)
return MEMORY_E;
#endif
if (wc_ecc_init_ex(key, heap, devId) == 0) {
if (wc_EccPrivateKeyDecode(der->buffer, &idx, key,
der->length) == 0) { der->length) == 0) {
int keySz = wc_ecc_size(&key); int keySz = wc_ecc_size(key);
int minKeySz; int minKeySz;
/* check for minimum ECC key size and then free */ /* check for minimum ECC key size and then free */
minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz;
if (keySz < minKeySz) { if (keySz < minKeySz) {
wc_ecc_free(&key); wc_ecc_free(key);
WOLFSSL_MSG("ECC private key too small"); WOLFSSL_MSG("ECC private key too small");
return ECC_KEY_SIZE_E; return ECC_KEY_SIZE_E;
} }
@@ -4709,52 +4719,71 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff,
else else
eccKey = 0; eccKey = 0;
wc_ecc_free(&key); wc_ecc_free(key);
} }
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, heap, DYNAMIC_TYPE_ECC);
#endif
} }
#endif /* HAVE_ECC */ #endif /* HAVE_ECC */
#ifdef HAVE_ED25519 #ifdef HAVE_ED25519
if (!rsaKey && !eccKey) { if (!rsaKey && !eccKey) {
/* make sure Ed25519 key can be used */ /* make sure Ed25519 key can be used */
word32 idx = 0; word32 idx = 0;
ed25519_key key; #ifdef WOLFSSL_SMALL_STACK
const int keySz = ED25519_KEY_SIZE; ed25519_key* key = NULL;
int minKeySz; #else
ed25519_key key[1];
#endif
ret = wc_ed25519_init(&key); #ifdef WOLFSSL_SMALL_STACK
if (ret != 0) { key = (ed25519_key*)XMALLOC(sizeof(ecc_key), heap,
return ret; DYNAMIC_TYPE_ED25519);
} if (key == NULL)
return MEMORY_E;
#endif
if (wc_Ed25519PrivateKeyDecode(der->buffer, &idx, &key, ret = wc_ed25519_init(key);
if (ret == 0) {
if (wc_Ed25519PrivateKeyDecode(der->buffer, &idx, key,
der->length) != 0) { der->length) != 0) {
wc_ed25519_free(&key); ret = WOLFSSL_BAD_FILE;
return WOLFSSL_BAD_FILE; }
if (ret == 0) {
/* check for minimum key size and then free */
int minKeySz = ssl ? ssl->options.minEccKeySz :
ctx->minEccKeySz;
if (ED25519_KEY_SIZE < minKeySz) {
WOLFSSL_MSG("ED25519 private key too small");
ret = ECC_KEY_SIZE_E;
}
}
if (ret == 0) {
if (ssl) {
ssl->buffers.keyType = ed25519_sa_algo;
ssl->buffers.keySz = ED25519_KEY_SIZE;
}
else if (ctx) {
ctx->privateKeyType = ed25519_sa_algo;
ctx->privateKeySz = ED25519_KEY_SIZE;
}
ed25519Key = 1;
if (ssl && ssl->options.side == WOLFSSL_SERVER_END) {
resetSuites = 1;
}
}
wc_ed25519_free(key);
} }
/* check for minimum key size and then free */ #ifdef WOLFSSL_SMALL_STACK
minKeySz = ssl ? ssl->options.minEccKeySz : ctx->minEccKeySz; XFREE(key, heap, DYNAMIC_TYPE_ED25519);
if (keySz < minKeySz) { #endif
wc_ed25519_free(&key); if (ret != 0)
WOLFSSL_MSG("ED25519 private key too small"); return ret;
return ECC_KEY_SIZE_E;
}
if (ssl) {
ssl->buffers.keyType = ed25519_sa_algo;
ssl->buffers.keySz = keySz;
}
else if (ctx) {
ctx->privateKeyType = ed25519_sa_algo;
ctx->privateKeySz = keySz;
}
wc_ed25519_free(&key);
ed25519Key = 1;
if (ssl && ssl->options.side == WOLFSSL_SERVER_END) {
resetSuites = 1;
}
} }
#else #else
if (!rsaKey && !eccKey && !ed25519Key) if (!rsaKey && !eccKey && !ed25519Key)
@@ -5824,7 +5853,11 @@ int wolfSSL_CertManagerLoadCA(WOLFSSL_CERT_MANAGER* cm, const char* file,
* Returns SSL_SUCCESS on good private key and SSL_FAILURE if miss matched. */ * Returns SSL_SUCCESS on good private key and SSL_FAILURE if miss matched. */
int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx)
{ {
DecodedCert der; #ifdef WOLFSSL_SMALL_STACK
DecodedCert* der = NULL;
#else
DecodedCert der[1];
#endif
word32 size; word32 size;
byte* buff; byte* buff;
int ret; int ret;
@@ -5836,18 +5869,30 @@ int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx)
} }
#ifndef NO_CERTS #ifndef NO_CERTS
#ifdef WOLFSSL_SMALL_STACK
der = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT);
if (der == NULL)
return MEMORY_E;
#endif
size = ctx->certificate->length; size = ctx->certificate->length;
buff = ctx->certificate->buffer; buff = ctx->certificate->buffer;
InitDecodedCert(&der, buff, size, ctx->heap); InitDecodedCert(der, buff, size, ctx->heap);
if (ParseCertRelative(&der, CERT_TYPE, NO_VERIFY, NULL) != 0) { if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL) != 0) {
FreeDecodedCert(&der); FreeDecodedCert(der);
#ifdef WOLFSSL_SMALL_STACK
XFREE(der, NULL, DYNAMIC_TYPE_DCERT);
#endif
return WOLFSSL_FAILURE; return WOLFSSL_FAILURE;
} }
size = ctx->privateKey->length; size = ctx->privateKey->length;
buff = ctx->privateKey->buffer; buff = ctx->privateKey->buffer;
ret = wc_CheckPrivateKey(buff, size, &der); ret = wc_CheckPrivateKey(buff, size, der);
FreeDecodedCert(&der); FreeDecodedCert(der);
#ifdef WOLFSSL_SMALL_STACK
XFREE(der, NULL, DYNAMIC_TYPE_DCERT);
#endif
if (ret == 1) { if (ret == 1) {
return WOLFSSL_SUCCESS; return WOLFSSL_SUCCESS;

View File

@@ -5856,7 +5856,11 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
word32 keySz; word32 keySz;
word32 dataSz; word32 dataSz;
const DhParams* params; const DhParams* params;
DhKey dhKey; #ifdef WOLFSSL_SMALL_STACK
DhKey* dhKey = NULL;
#else
DhKey dhKey[1];
#endif
/* TODO: [TLS13] The key size should come from wolfcrypt. */ /* TODO: [TLS13] The key size should come from wolfcrypt. */
/* Pick the parameters from the named group. */ /* Pick the parameters from the named group. */
@@ -5895,9 +5899,19 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
} }
ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId); #ifdef WOLFSSL_SMALL_STACK
if (ret != 0) dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
if (dhKey == NULL)
return MEMORY_E;
#endif
ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
if (ret != 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
}
/* Allocate space for the public key. */ /* Allocate space for the public key. */
dataSz = params->p_len; dataSz = params->p_len;
@@ -5914,19 +5928,19 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
} }
/* Set key */ /* Set key */
ret = wc_DhSetKey(&dhKey, ret = wc_DhSetKey(dhKey,
(byte*)params->p, params->p_len, (byte*)params->p, params->p_len,
(byte*)params->g, params->g_len); (byte*)params->g, params->g_len);
if (ret != 0) if (ret != 0)
goto end; goto end;
/* Generate a new key pair. */ /* Generate a new key pair. */
ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, (byte*)key, &keySz, keyData, ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
&dataSz); &dataSz);
#ifdef WOLFSSL_ASYNC_CRYPT #ifdef WOLFSSL_ASYNC_CRYPT
/* TODO: Make this function non-blocking */ /* TODO: Make this function non-blocking */
if (ret == WC_PENDING_E) { if (ret == WC_PENDING_E) {
ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE); ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
} }
#endif #endif
if (ret != 0) if (ret != 0)
@@ -5950,7 +5964,10 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
end: end:
wc_FreeDhKey(&dhKey); wc_FreeDhKey(dhKey);
#ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
if (ret != 0) { if (ret != 0) {
/* Data owned by key share entry otherwise. */ /* Data owned by key share entry otherwise. */
@@ -6299,7 +6316,11 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
#ifndef NO_DH #ifndef NO_DH
int ret; int ret;
const DhParams* params; const DhParams* params;
DhKey dhKey; #ifdef WOLFSSL_SMALL_STACK
DhKey* dhKey = NULL;
#else
DhKey dhKey[1];
#endif
switch (keyShareEntry->group) { switch (keyShareEntry->group) {
#ifdef HAVE_FFDHE_2048 #ifdef HAVE_FFDHE_2048
@@ -6336,37 +6357,56 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
#endif #endif
ret = wc_InitDhKey_ex(&dhKey, ssl->heap, ssl->devId); #ifdef WOLFSSL_SMALL_STACK
if (ret != 0) dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
return ret; if (dhKey == NULL)
return MEMORY_E;
#endif
/* Set key */ ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
ret = wc_DhSetKey(&dhKey, (byte*)params->p, params->p_len, (byte*)params->g,
params->g_len);
if (ret != 0) { if (ret != 0) {
wc_FreeDhKey(&dhKey); #ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
} }
ret = wc_DhCheckPubKey(&dhKey, keyShareEntry->ke, keyShareEntry->keLen); /* Set key */
ret = wc_DhSetKey(dhKey, (byte*)params->p, params->p_len, (byte*)params->g,
params->g_len);
if (ret != 0) { if (ret != 0) {
wc_FreeDhKey(&dhKey); wc_FreeDhKey(dhKey);
#ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
return ret;
}
ret = wc_DhCheckPubKey(dhKey, keyShareEntry->ke, keyShareEntry->keLen);
if (ret != 0) {
wc_FreeDhKey(dhKey);
#ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
return PEER_KEY_ERROR; return PEER_KEY_ERROR;
} }
/* Derive secret from private key and peer's public key. */ /* Derive secret from private key and peer's public key. */
ret = wc_DhAgree(&dhKey, ret = wc_DhAgree(dhKey,
ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
(const byte*)keyShareEntry->key, keyShareEntry->keyLen, (const byte*)keyShareEntry->key, keyShareEntry->keyLen,
keyShareEntry->ke, keyShareEntry->keLen); keyShareEntry->ke, keyShareEntry->keLen);
#ifdef WOLFSSL_ASYNC_CRYPT #ifdef WOLFSSL_ASYNC_CRYPT
/* TODO: Make this function non-blocking */ /* TODO: Make this function non-blocking */
if (ret == WC_PENDING_E) { if (ret == WC_PENDING_E) {
ret = wc_AsyncWait(ret, &dhKey.asyncDev, WC_ASYNC_FLAG_NONE); ret = wc_AsyncWait(ret, dhKey.asyncDev, WC_ASYNC_FLAG_NONE);
} }
#endif #endif
wc_FreeDhKey(&dhKey); wc_FreeDhKey(dhKey);
#ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
#else #else

View File

@@ -1028,7 +1028,12 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
{ {
byte* cBuf; byte* cBuf;
int qSz, pSz, cSz, err; int qSz, pSz, cSz, err;
mp_int tmpQ, tmpX; #ifdef WOLFSSL_SMALL_STACK
mp_int* tmpQ = NULL;
mp_int* tmpX = NULL;
#else
mp_int tmpQ[1], tmpX[1];
#endif
/* Parameters validated in calling functions. */ /* Parameters validated in calling functions. */
@@ -1052,61 +1057,87 @@ static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
if (cBuf == NULL) { if (cBuf == NULL) {
return MEMORY_E; return MEMORY_E;
} }
#ifdef WOLFSSL_SMALL_STACK
tmpQ = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (tmpQ == NULL) {
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
tmpX = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (tmpX == NULL) {
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
#endif
if ((err = mp_init_multi(&tmpX, &tmpQ, NULL, NULL, NULL, NULL))
if ((err = mp_init_multi(tmpX, tmpQ, NULL, NULL, NULL, NULL))
!= MP_OKAY) { != MP_OKAY) {
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_SMALL_STACK
XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
XFREE(tmpX, key->heap, DYNAMIC_TYPE_DH);
#endif
return err; return err;
} }
do { do {
/* generate N+64 bits (c) from RBG into &tmpX, making sure positive. /* generate N+64 bits (c) from RBG into tmpX, making sure positive.
* Hash_DRBG uses SHA-256 which matches maximum * Hash_DRBG uses SHA-256 which matches maximum
* requested_security_strength of (L,N) */ * requested_security_strength of (L,N) */
err = wc_RNG_GenerateBlock(rng, cBuf, cSz); err = wc_RNG_GenerateBlock(rng, cBuf, cSz);
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_read_unsigned_bin(&tmpX, cBuf, cSz); err = mp_read_unsigned_bin(tmpX, cBuf, cSz);
if (err != MP_OKAY) { if (err != MP_OKAY) {
mp_clear(&tmpX); mp_clear(tmpX);
mp_clear(&tmpQ); mp_clear(tmpQ);
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_SMALL_STACK
XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
XFREE(tmpX, key->heap, DYNAMIC_TYPE_DH);
#endif
return err; return err;
} }
} while (mp_cmp_d(&tmpX, 1) != MP_GT); } while (mp_cmp_d(tmpX, 1) != MP_GT);
ForceZero(cBuf, cSz); ForceZero(cBuf, cSz);
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
/* tmpQ = q - 1 */ /* tmpQ = q - 1 */
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_copy(&key->q, &tmpQ); err = mp_copy(&key->q, tmpQ);
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_sub_d(&tmpQ, 1, &tmpQ); err = mp_sub_d(tmpQ, 1, tmpQ);
/* x = c mod (q-1), &tmpX holds c */ /* x = c mod (q-1), tmpX holds c */
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_mod(&tmpX, &tmpQ, &tmpX); err = mp_mod(tmpX, tmpQ, tmpX);
/* x = c mod (q-1) + 1 */ /* x = c mod (q-1) + 1 */
if (err == MP_OKAY) if (err == MP_OKAY)
err = mp_add_d(&tmpX, 1, &tmpX); err = mp_add_d(tmpX, 1, tmpX);
/* copy tmpX into priv */ /* copy tmpX into priv */
if (err == MP_OKAY) { if (err == MP_OKAY) {
pSz = mp_unsigned_bin_size(&tmpX); pSz = mp_unsigned_bin_size(tmpX);
if (pSz > (int)*privSz) { if (pSz > (int)*privSz) {
WOLFSSL_MSG("DH private key output buffer too small"); WOLFSSL_MSG("DH private key output buffer too small");
err = BAD_FUNC_ARG; err = BAD_FUNC_ARG;
} else { } else {
*privSz = pSz; *privSz = pSz;
err = mp_to_unsigned_bin(&tmpX, priv); err = mp_to_unsigned_bin(tmpX, priv);
} }
} }
mp_forcezero(&tmpX); mp_forcezero(tmpX);
mp_clear(&tmpX); mp_clear(tmpX);
mp_clear(&tmpQ); mp_clear(tmpQ);
#ifdef WOLFSSL_SMALL_STACK
XFREE(tmpQ, key->heap, DYNAMIC_TYPE_DH);
XFREE(tmpX, key->heap, DYNAMIC_TYPE_DH);
#endif
return err; return err;
} }
@@ -1175,8 +1206,13 @@ static int GeneratePublicDh(DhKey* key, byte* priv, word32 privSz,
{ {
int ret = 0; int ret = 0;
#ifndef WOLFSSL_SP_MATH #ifndef WOLFSSL_SP_MATH
mp_int x; #ifdef WOLFSSL_SMALL_STACK
mp_int y; mp_int* x = NULL;
mp_int* y = NULL;
#else
mp_int x[1];
mp_int y[1];
#endif
#endif #endif
#ifdef WOLFSSL_HAVE_SP_DH #ifdef WOLFSSL_HAVE_SP_DH
@@ -1191,23 +1227,37 @@ static int GeneratePublicDh(DhKey* key, byte* priv, word32 privSz,
#endif #endif
#ifndef WOLFSSL_SP_MATH #ifndef WOLFSSL_SP_MATH
if (mp_init_multi(&x, &y, 0, 0, 0, 0) != MP_OKAY) #ifdef WOLFSSL_SMALL_STACK
x = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (x == NULL)
return MEMORY_E;
y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (y == NULL) {
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
#endif
if (mp_init_multi(x, y, 0, 0, 0, 0) != MP_OKAY)
return MP_INIT_E; return MP_INIT_E;
if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY) if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
if (ret == 0 && mp_exptmod(&key->g, &x, &key->p, &y) != MP_OKAY) if (ret == 0 && mp_exptmod(&key->g, x, &key->p, y) != MP_OKAY)
ret = MP_EXPTMOD_E; ret = MP_EXPTMOD_E;
if (ret == 0 && mp_to_unsigned_bin(&y, pub) != MP_OKAY) if (ret == 0 && mp_to_unsigned_bin(y, pub) != MP_OKAY)
ret = MP_TO_E; ret = MP_TO_E;
if (ret == 0) if (ret == 0)
*pubSz = mp_unsigned_bin_size(&y); *pubSz = mp_unsigned_bin_size(y);
mp_clear(&y); mp_clear(y);
mp_clear(&x); mp_clear(x);
#ifdef WOLFSSL_SMALL_STACK
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
#endif
#else #else
ret = WC_KEY_SIZE_E; ret = WC_KEY_SIZE_E;
#endif #endif
@@ -1306,53 +1356,76 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
const byte* prime, word32 primeSz) const byte* prime, word32 primeSz)
{ {
int ret = 0; int ret = 0;
mp_int y; #ifdef WOLFSSL_SMALL_STACK
mp_int p; mp_int* y = NULL;
mp_int q; mp_int* p = NULL;
mp_int* q = NULL;
#else
mp_int y[1];
mp_int p[1];
mp_int q[1];
#endif
if (key == NULL || pub == NULL) { if (key == NULL || pub == NULL) {
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
} }
if (mp_init_multi(&y, &p, &q, NULL, NULL, NULL) != MP_OKAY) { #ifdef WOLFSSL_SMALL_STACK
y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (y == NULL)
return MEMORY_E;
p = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (p == NULL) {
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
q = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (q == NULL) {
XFREE(p, key->heap, DYNAMIC_TYPE_DH);
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
#endif
if (mp_init_multi(y, p, q, NULL, NULL, NULL) != MP_OKAY) {
return MP_INIT_E; return MP_INIT_E;
} }
if (mp_read_unsigned_bin(&y, pub, pubSz) != MP_OKAY) { if (mp_read_unsigned_bin(y, pub, pubSz) != MP_OKAY) {
ret = MP_READ_E; ret = MP_READ_E;
} }
if (ret == 0 && prime != NULL) { if (ret == 0 && prime != NULL) {
if (mp_read_unsigned_bin(&q, prime, primeSz) != MP_OKAY) if (mp_read_unsigned_bin(q, prime, primeSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
} else if (mp_iszero(&key->q) == MP_NO) { } else if (mp_iszero(&key->q) == MP_NO) {
/* use q available in DhKey */ /* use q available in DhKey */
if (mp_copy(&key->q, &q) != MP_OKAY) if (mp_copy(&key->q, q) != MP_OKAY)
ret = MP_INIT_E; ret = MP_INIT_E;
} }
/* SP 800-56Ar3, section 5.6.2.3.1, process step 1 */ /* SP 800-56Ar3, section 5.6.2.3.1, process step 1 */
/* pub (y) should not be 0 or 1 */ /* pub (y) should not be 0 or 1 */
if (ret == 0 && mp_cmp_d(&y, 2) == MP_LT) { if (ret == 0 && mp_cmp_d(y, 2) == MP_LT) {
ret = MP_CMP_E; ret = MP_CMP_E;
} }
/* pub (y) shouldn't be greater than or equal to p - 1 */ /* pub (y) shouldn't be greater than or equal to p - 1 */
if (ret == 0 && mp_copy(&key->p, &p) != MP_OKAY) { if (ret == 0 && mp_copy(&key->p, p) != MP_OKAY) {
ret = MP_INIT_E; ret = MP_INIT_E;
} }
if (ret == 0 && mp_sub_d(&p, 2, &p) != MP_OKAY) { if (ret == 0 && mp_sub_d(p, 2, p) != MP_OKAY) {
ret = MP_SUB_E; ret = MP_SUB_E;
} }
if (ret == 0 && mp_cmp(&y, &p) == MP_GT) { if (ret == 0 && mp_cmp(y, p) == MP_GT) {
ret = MP_CMP_E; ret = MP_CMP_E;
} }
if (ret == 0 && (prime != NULL || (mp_iszero(&key->q) == MP_NO) )) { if (ret == 0 && (prime != NULL || (mp_iszero(&key->q) == MP_NO) )) {
/* restore key->p into p */ /* restore key->p into p */
if (mp_copy(&key->p, &p) != MP_OKAY) if (mp_copy(&key->p, p) != MP_OKAY)
ret = MP_INIT_E; ret = MP_INIT_E;
} }
@@ -1360,7 +1433,7 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
#ifdef WOLFSSL_HAVE_SP_DH #ifdef WOLFSSL_HAVE_SP_DH
#ifndef WOLFSSL_SP_NO_2048 #ifndef WOLFSSL_SP_NO_2048
if (mp_count_bits(&key->p) == 2048) { if (mp_count_bits(&key->p) == 2048) {
ret = sp_ModExp_2048(&y, &q, &p, &y); ret = sp_ModExp_2048(y, q, p, y);
if (ret != 0) if (ret != 0)
ret = MP_EXPTMOD_E; ret = MP_EXPTMOD_E;
} }
@@ -1368,7 +1441,7 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
#endif #endif
#ifndef WOLFSSL_SP_NO_3072 #ifndef WOLFSSL_SP_NO_3072
if (mp_count_bits(&key->p) == 3072) { if (mp_count_bits(&key->p) == 3072) {
ret = sp_ModExp_3072(&y, &q, &p, &y); ret = sp_ModExp_3072(y, q, p, y);
if (ret != 0) if (ret != 0)
ret = MP_EXPTMOD_E; ret = MP_EXPTMOD_E;
} }
@@ -1376,27 +1449,30 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
#endif #endif
#endif #endif
{
/* SP 800-56Ar3, section 5.6.2.3.1, process step 2 */ /* SP 800-56Ar3, section 5.6.2.3.1, process step 2 */
#ifndef WOLFSSL_SP_MATH #ifndef WOLFSSL_SP_MATH
{
/* calculate (y^q) mod(p), store back into y */ /* calculate (y^q) mod(p), store back into y */
if (ret == 0 && mp_exptmod(&y, &q, &p, &y) != MP_OKAY) if (ret == 0 && mp_exptmod(y, q, p, y) != MP_OKAY)
ret = MP_EXPTMOD_E; ret = MP_EXPTMOD_E;
}
#else #else
{
ret = WC_KEY_SIZE_E; ret = WC_KEY_SIZE_E;
}
#endif #endif
}
/* verify above == 1 */ /* verify above == 1 */
if (ret == 0 && mp_cmp_d(&y, 1) != MP_EQ) if (ret == 0 && mp_cmp_d(y, 1) != MP_EQ)
ret = MP_CMP_E; ret = MP_CMP_E;
} }
mp_clear(&y); mp_clear(y);
mp_clear(&p); mp_clear(p);
mp_clear(&q); mp_clear(q);
#ifdef WOLFSSL_SMALL_STACK
XFREE(q, key->heap, DYNAMIC_TYPE_DH);
XFREE(p, key->heap, DYNAMIC_TYPE_DH);
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
} }
@@ -1432,59 +1508,79 @@ int wc_DhCheckPrivKey_ex(DhKey* key, const byte* priv, word32 privSz,
const byte* prime, word32 primeSz) const byte* prime, word32 primeSz)
{ {
int ret = 0; int ret = 0;
mp_int x; #ifdef WOLFSSL_SMALL_STACK
mp_int q; mp_int* x = NULL;
mp_int* q = NULL;
#else
mp_int x[1];
mp_int q[1];
#endif
if (key == NULL || priv == NULL) { if (key == NULL || priv == NULL) {
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
} }
if (mp_init_multi(&x, &q, NULL, NULL, NULL, NULL) != MP_OKAY) { #ifdef WOLFSSL_SMALL_STACK
x = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (x == NULL)
return MEMORY_E;
q = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (q == NULL) {
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
#endif
if (mp_init_multi(x, q, NULL, NULL, NULL, NULL) != MP_OKAY) {
return MP_INIT_E; return MP_INIT_E;
} }
if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY) { if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY) {
ret = MP_READ_E; ret = MP_READ_E;
} }
if (ret == 0) { if (ret == 0) {
if (prime != NULL) { if (prime != NULL) {
if (mp_read_unsigned_bin(&q, prime, primeSz) != MP_OKAY) if (mp_read_unsigned_bin(q, prime, primeSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
} }
else if (mp_iszero(&key->q) == MP_NO) { else if (mp_iszero(&key->q) == MP_NO) {
/* use q available in DhKey */ /* use q available in DhKey */
if (mp_copy(&key->q, &q) != MP_OKAY) if (mp_copy(&key->q, q) != MP_OKAY)
ret = MP_INIT_E; ret = MP_INIT_E;
} }
} }
/* priv (x) should not be 0 */ /* priv (x) should not be 0 */
if (ret == 0) { if (ret == 0) {
if (mp_cmp_d(&x, 0) == MP_EQ) if (mp_cmp_d(x, 0) == MP_EQ)
ret = MP_CMP_E; ret = MP_CMP_E;
} }
if (ret == 0) { if (ret == 0) {
if (mp_iszero(&q) == MP_NO) { if (mp_iszero(q) == MP_NO) {
/* priv (x) shouldn't be greater than q - 1 */ /* priv (x) shouldn't be greater than q - 1 */
if (ret == 0) { if (ret == 0) {
if (mp_copy(&key->q, &q) != MP_OKAY) if (mp_copy(&key->q, q) != MP_OKAY)
ret = MP_INIT_E; ret = MP_INIT_E;
} }
if (ret == 0) { if (ret == 0) {
if (mp_sub_d(&q, 1, &q) != MP_OKAY) if (mp_sub_d(q, 1, q) != MP_OKAY)
ret = MP_SUB_E; ret = MP_SUB_E;
} }
if (ret == 0) { if (ret == 0) {
if (mp_cmp(&x, &q) == MP_GT) if (mp_cmp(x, q) == MP_GT)
ret = DH_CHECK_PRIV_E; ret = DH_CHECK_PRIV_E;
} }
} }
} }
mp_clear(&x); mp_clear(x);
mp_clear(&q); mp_clear(q);
#ifdef WOLFSSL_SMALL_STACK
XFREE(q, key->heap, DYNAMIC_TYPE_DH);
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
} }
@@ -1518,43 +1614,95 @@ int wc_DhCheckPrivKey(DhKey* key, const byte* priv, word32 privSz)
int wc_DhCheckKeyPair(DhKey* key, const byte* pub, word32 pubSz, int wc_DhCheckKeyPair(DhKey* key, const byte* pub, word32 pubSz,
const byte* priv, word32 privSz) const byte* priv, word32 privSz)
{ {
mp_int publicKey; #ifdef WOLFSSL_SMALL_STACK
mp_int privateKey; mp_int* publicKey = NULL;
mp_int checkKey; mp_int* privateKey = NULL;
mp_int* checkKey = NULL;
#else
mp_int publicKey[1];
mp_int privateKey[1];
mp_int checkKey[1];
#endif
int ret = 0; int ret = 0;
if (key == NULL || pub == NULL || priv == NULL) if (key == NULL || pub == NULL || priv == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
if (mp_init_multi(&publicKey, &privateKey, &checkKey, #ifdef WOLFSSL_SMALL_STACK
publicKey = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (publicKey == NULL)
return MEMORY_E;
privateKey = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (privateKey == NULL) {
XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
checkKey = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (checkKey == NULL) {
XFREE(privateKey, key->heap, DYNAMIC_TYPE_DH);
XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
#endif
if (mp_init_multi(publicKey, privateKey, checkKey,
NULL, NULL, NULL) != MP_OKAY) { NULL, NULL, NULL) != MP_OKAY) {
return MP_INIT_E; return MP_INIT_E;
} }
/* Load the private and public keys into big integers. */ /* Load the private and public keys into big integers. */
if (mp_read_unsigned_bin(&publicKey, pub, pubSz) != MP_OKAY || if (mp_read_unsigned_bin(publicKey, pub, pubSz) != MP_OKAY ||
mp_read_unsigned_bin(&privateKey, priv, privSz) != MP_OKAY) { mp_read_unsigned_bin(privateKey, priv, privSz) != MP_OKAY) {
ret = MP_READ_E; ret = MP_READ_E;
} }
/* Calculate checkKey = g^privateKey mod p */ /* Calculate checkKey = g^privateKey mod p */
if (ret == 0) { if (ret == 0) {
if (mp_exptmod(&key->g, &privateKey, &key->p, &checkKey) != MP_OKAY) #ifdef WOLFSSL_HAVE_SP_DH
ret = MP_EXPTMOD_E; #ifndef WOLFSSL_SP_NO_2048
if (mp_count_bits(&key->p) == 2048) {
ret = sp_ModExp_2048(&key->g, privateKey, &key->p, checkKey);
if (ret != 0)
ret = MP_EXPTMOD_E;
}
else
#endif
#ifndef WOLFSSL_SP_NO_3072
if (mp_count_bits(&key->p) == 3072) {
ret = sp_ModExp_3072(&key->g, privateKey, &key->p, checkKey);
if (ret != 0)
ret = MP_EXPTMOD_E;
}
else
#endif
#endif
{
#ifndef WOLFSSL_SP_MATH
if (mp_exptmod(&key->g, privateKey, &key->p, checkKey) != MP_OKAY)
ret = MP_EXPTMOD_E;
#else
ret = WC_KEY_SIZE_E;
#endif
}
} }
/* Compare the calculated public key to the supplied check value. */ /* Compare the calculated public key to the supplied check value. */
if (ret == 0) { if (ret == 0) {
if (mp_cmp(&checkKey, &publicKey) != MP_EQ) if (mp_cmp(checkKey, publicKey) != MP_EQ)
ret = MP_CMP_E; ret = MP_CMP_E;
} }
mp_forcezero(&privateKey); mp_forcezero(privateKey);
mp_clear(&privateKey); mp_clear(privateKey);
mp_clear(&publicKey); mp_clear(publicKey);
mp_clear(&checkKey); mp_clear(checkKey);
#ifdef WOLFSSL_SMALL_STACK
XFREE(checkKey, key->heap, DYNAMIC_TYPE_DH);
XFREE(privateKey, key->heap, DYNAMIC_TYPE_DH);
XFREE(publicKey, key->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
} }
@@ -1588,10 +1736,18 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
const byte* priv, word32 privSz, const byte* otherPub, word32 pubSz) const byte* priv, word32 privSz, const byte* otherPub, word32 pubSz)
{ {
int ret = 0; int ret = 0;
mp_int y; #ifdef WOLFSSL_SMALL_STACK
mp_int* y = NULL;
#ifndef WOLFSSL_SP_MATH #ifndef WOLFSSL_SP_MATH
mp_int x; mp_int* x = NULL;
mp_int z; mp_int* z = NULL;
#endif
#else
mp_int y[1];
#ifndef WOLFSSL_SP_MATH
mp_int x[1];
mp_int z[1];
#endif
#endif #endif
#ifdef WOLFSSL_VALIDATE_FFC_IMPORT #ifdef WOLFSSL_VALIDATE_FFC_IMPORT
@@ -1606,65 +1762,106 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
} }
#endif #endif
#ifdef WOLFSSL_SMALL_STACK
y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (y == NULL)
return MEMORY_E;
#ifndef WOLFSSL_SP_MATH
x = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (x == NULL) {
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
z = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (z == NULL) {
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
return MEMORY_E;
}
#endif
#endif
#ifdef WOLFSSL_HAVE_SP_DH #ifdef WOLFSSL_HAVE_SP_DH
#ifndef WOLFSSL_SP_NO_2048 #ifndef WOLFSSL_SP_NO_2048
if (mp_count_bits(&key->p) == 2048) { if (mp_count_bits(&key->p) == 2048) {
if (mp_init(&y) != MP_OKAY) if (mp_init(y) != MP_OKAY)
return MP_INIT_E; return MP_INIT_E;
if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY) if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
if (ret == 0) if (ret == 0)
ret = sp_DhExp_2048(&y, priv, privSz, &key->p, agree, agreeSz); ret = sp_DhExp_2048(y, priv, privSz, &key->p, agree, agreeSz);
mp_clear(&y); mp_clear(y);
#ifdef WOLFSSL_SMALL_STACK
#ifndef WOLFSSL_SP_MATH
XFREE(z, key->heap, DYNAMIC_TYPE_DH);
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
#endif
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
} }
#endif #endif
#ifndef WOLFSSL_SP_NO_3072 #ifndef WOLFSSL_SP_NO_3072
if (mp_count_bits(&key->p) == 3072) { if (mp_count_bits(&key->p) == 3072) {
if (mp_init(&y) != MP_OKAY) if (mp_init(y) != MP_OKAY)
return MP_INIT_E; return MP_INIT_E;
if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY) if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
if (ret == 0) if (ret == 0)
ret = sp_DhExp_3072(&y, priv, privSz, &key->p, agree, agreeSz); ret = sp_DhExp_3072(y, priv, privSz, &key->p, agree, agreeSz);
mp_clear(&y); mp_clear(y);
#ifdef WOLFSSL_SMALL_STACK
#ifndef WOLFSSL_SP_MATH
XFREE(z, key->heap, DYNAMIC_TYPE_DH);
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
#endif
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
#endif
return ret; return ret;
} }
#endif #endif
#endif #endif
#ifndef WOLFSSL_SP_MATH #ifndef WOLFSSL_SP_MATH
if (mp_init_multi(&x, &y, &z, 0, 0, 0) != MP_OKAY) if (mp_init_multi(x, y, z, 0, 0, 0) != MP_OKAY)
return MP_INIT_E; return MP_INIT_E;
if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY) if (mp_read_unsigned_bin(x, priv, privSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY) if (ret == 0 && mp_read_unsigned_bin(y, otherPub, pubSz) != MP_OKAY)
ret = MP_READ_E; ret = MP_READ_E;
if (ret == 0 && mp_exptmod(&y, &x, &key->p, &z) != MP_OKAY) if (ret == 0 && mp_exptmod(y, x, &key->p, z) != MP_OKAY)
ret = MP_EXPTMOD_E; ret = MP_EXPTMOD_E;
/* make sure z is not one (SP800-56A, 5.7.1.1) */ /* make sure z is not one (SP800-56A, 5.7.1.1) */
if (ret == 0 && (mp_cmp_d(&z, 1) == MP_EQ)) if (ret == 0 && (mp_cmp_d(z, 1) == MP_EQ))
ret = MP_VAL; ret = MP_VAL;
if (ret == 0 && mp_to_unsigned_bin(&z, agree) != MP_OKAY) if (ret == 0 && mp_to_unsigned_bin(z, agree) != MP_OKAY)
ret = MP_TO_E; ret = MP_TO_E;
if (ret == 0) if (ret == 0)
*agreeSz = mp_unsigned_bin_size(&z); *agreeSz = mp_unsigned_bin_size(z);
mp_clear(&z); mp_clear(z);
mp_clear(&y); mp_clear(y);
mp_forcezero(&x); mp_forcezero(x);
#endif
#ifdef WOLFSSL_SMALL_STACK
#ifndef WOLFSSL_SP_MATH
XFREE(z, key->heap, DYNAMIC_TYPE_DH);
XFREE(x, key->heap, DYNAMIC_TYPE_DH);
#endif
XFREE(y, key->heap, DYNAMIC_TYPE_DH);
#endif #endif
return ret; return ret;