Fix the TLS v1.3 async key share support. Added WOLFSSL_NO_PUBLIC_FFDHE option to test without public FFDHE API's.

This commit is contained in:
David Garske
2021-10-11 11:45:01 -07:00
committed by Daniel Pouzzner
parent 75e4c0869e
commit 303aa312a8
2 changed files with 195 additions and 227 deletions

418
src/tls.c
View File

@@ -6079,40 +6079,25 @@ static int TLSX_SetSignatureAlgorithmsCert(TLSX** extensions, const void* data,
*/ */
static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse) static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
{ {
int ret; int ret = 0;
#ifndef NO_DH #if !defined(NO_DH) && (!defined(NO_CERTS) || !defined(NO_PSK))
byte* keyData = NULL; word32 pSz = 0;
void* key = NULL; DhKey* dhKey = (DhKey*)kse->key;
word32 keySz;
word32 dataSz;
#ifdef WOLFSSL_SMALL_STACK
DhKey* dhKey = NULL;
#else
DhKey dhKey[1];
#endif
#ifdef HAVE_PUBLIC_FFDHE
const DhParams* params;
#else
word32 p_len;
#endif
if (kse->key != NULL)
return 0;
/* TODO: [TLS13] The key size should come from wolfcrypt. */
/* Pick the parameters from the named group. */ /* Pick the parameters from the named group. */
#ifdef HAVE_PUBLIC_FFDHE #ifdef HAVE_PUBLIC_FFDHE
const DhParams* params = NULL;
switch (kse->group) { switch (kse->group) {
#ifdef HAVE_FFDHE_2048 #ifdef HAVE_FFDHE_2048
case WOLFSSL_FFDHE_2048: case WOLFSSL_FFDHE_2048:
params = wc_Dh_ffdhe2048_Get(); params = wc_Dh_ffdhe2048_Get();
keySz = 29; kse->keyLen = 29;
break; break;
#endif #endif
#ifdef HAVE_FFDHE_3072 #ifdef HAVE_FFDHE_3072
case WOLFSSL_FFDHE_3072: case WOLFSSL_FFDHE_3072:
params = wc_Dh_ffdhe3072_Get(); params = wc_Dh_ffdhe3072_Get();
keySz = 34; kse->keyLen = 34;
break; break;
#endif #endif
#ifdef HAVE_FFDHE_4096 #ifdef HAVE_FFDHE_4096
@@ -6124,142 +6109,138 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
#ifdef HAVE_FFDHE_6144 #ifdef HAVE_FFDHE_6144
case WOLFSSL_FFDHE_6144: case WOLFSSL_FFDHE_6144:
params = wc_Dh_ffdhe6144_Get(); params = wc_Dh_ffdhe6144_Get();
keySz = 46; kse->keyLen = 46;
break; break;
#endif #endif
#ifdef HAVE_FFDHE_8192 #ifdef HAVE_FFDHE_8192
case WOLFSSL_FFDHE_8192: case WOLFSSL_FFDHE_8192:
params = wc_Dh_ffdhe8192_Get(); params = wc_Dh_ffdhe8192_Get();
keySz = 52; kse->keyLen = 52;
break; break;
#endif #endif
default: default:
return BAD_FUNC_ARG; break;
} }
if (params == NULL)
return BAD_FUNC_ARG;
pSz = params->p_len;
#else #else
keySz = wc_DhGetNamedKeyMinSize(kse->group); kse->keyLen = wc_DhGetNamedKeyMinSize(kse->group);
if (keySz == 0) { if (kse->keyLen == 0) {
return BAD_FUNC_ARG;
}
ret = wc_DhGetNamedKeyParamSize(kse->group, &pSz, NULL, NULL);
if (ret != 0) {
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
} }
#endif #endif
kse->pubKeyLen = pSz;
#ifdef WOLFSSL_SMALL_STACK /* Trigger Key Generation */
dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH); if (kse->pubKey == NULL || kse->privKey == NULL) {
if (dhKey == NULL) if (kse->key == NULL) {
return MEMORY_E; kse->key = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap,
#endif DYNAMIC_TYPE_DH);
if (kse->key == NULL)
return MEMORY_E;
ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId); /* Setup Key */
if (ret != 0) { ret = wc_InitDhKey_ex((DhKey*)kse->key, ssl->heap, ssl->devId);
#ifdef WOLFSSL_SMALL_STACK if (ret == 0) {
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); dhKey = (DhKey*)kse->key;
#endif #ifdef HAVE_PUBLIC_FFDHE
return ret; ret = wc_DhSetKey(dhKey, params->p, params->p_len, params->g,
}
/* Allocate space for the public key */
#ifdef HAVE_PUBLIC_FFDHE
dataSz = params->p_len;
#else
ret = wc_DhGetNamedKeyParamSize(kse->group, &p_len, NULL, NULL);
if (ret != 0) {
goto end;
}
dataSz = p_len;
#endif
keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if (keyData == NULL) {
ret = MEMORY_E;
goto end;
}
/* Allocate space for the private key */
#ifndef HAVE_PUBLIC_FFDHE
keySz = wc_DhGetNamedKeyMinSize(kse->group);
if (keySz == 0) {
ret = WC_KEY_SIZE_E;
goto end;
}
#endif
key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
if (key == NULL) {
ret = MEMORY_E;
goto end;
}
/* Set key */
#ifdef HAVE_PUBLIC_FFDHE
ret = wc_DhSetKey(dhKey, params->p, params->p_len, params->g,
params->g_len); params->g_len);
#else #else
ret = wc_DhSetNamedKey(dhKey, kse->group); ret = wc_DhSetNamedKey(dhKey, kse->group);
#endif #endif
if (ret != 0) }
goto end; }
#if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(WOLFSSL_DH_EXTRA) /* Allocate space for the private and public key */
if (ssl->staticKE.dhKey) { if (ret == 0 && kse->pubKey == NULL) {
DerBuffer* keyDer = ssl->staticKE.dhKey; kse->pubKey = (byte*)XMALLOC(kse->pubKeyLen, ssl->heap,
word32 idx = 0; DYNAMIC_TYPE_PUBLIC_KEY);
WOLFSSL_MSG("Using static DH key"); if (kse->pubKey == NULL)
ret = wc_DhKeyDecode(keyDer->buffer, &idx, dhKey, keyDer->length); ret = MEMORY_E;
}
if (ret == 0 && kse->privKey == NULL) {
kse->privKey = (byte*)XMALLOC(kse->keyLen, ssl->heap,
DYNAMIC_TYPE_PRIVATE_KEY);
if (kse->privKey == NULL)
ret = MEMORY_E;
}
if (ret == 0) { if (ret == 0) {
ret = wc_DhExportKeyPair(dhKey, (byte*)key, &keySz, keyData, &dataSz); #if defined(WOLFSSL_STATIC_EPHEMERAL) && defined(WOLFSSL_DH_EXTRA)
if (ssl->staticKE.dhKey) {
DerBuffer* keyDer = ssl->staticKE.dhKey;
word32 idx = 0;
WOLFSSL_MSG("Using static DH key");
ret = wc_DhKeyDecode(keyDer->buffer, &idx, dhKey, keyDer->length);
if (ret == 0) {
ret = wc_DhExportKeyPair(dhKey,
(byte*)kse->privKey, &kse->keyLen, /* private */
kse->pubKey, &kse->pubKeyLen /* public */
);
}
}
else
#endif
{
/* Generate a new key pair */
/* For async this is called once and when event is done, the
* provided buffers will be populated.
* Final processing is zero pad below. */
ret = DhGenKeyPair(ssl, dhKey,
(byte*)kse->privKey, &kse->keyLen, /* private */
kse->pubKey, &kse->pubKeyLen /* public */
);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E) {
return ret;
}
#endif
}
} }
} }
else
#endif if (ret == 0) {
{ if (pSz != kse->pubKeyLen) {
/* Generate a new key pair */ /* Zero pad the front of the public key to match prime "p" size */
ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData, XMEMMOVE(kse->pubKey + pSz - kse->pubKeyLen, kse->pubKey,
&dataSz); kse->pubKeyLen);
#ifdef WOLFSSL_ASYNC_CRYPT XMEMSET(kse->pubKey, 0, pSz - kse->pubKeyLen);
/* TODO: Make this function non-blocking */
if (ret == WC_PENDING_E) {
ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
} }
kse->pubKeyLen = pSz;
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Public DH Key");
WOLFSSL_BUFFER(kse->pubKey, kse->pubKeyLen);
#endif #endif
} }
if (ret != 0)
goto end;
#ifdef HAVE_PUBLIC_FFDHE /* Always release the DH key to free up memory.
if (params->p_len != dataSz) { * The DhKey will be setup again in TLSX_KeyShare_ProcessDh */
/* Zero pad the front of the public key to match prime "p" size */ if (dhKey != NULL)
XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz); wc_FreeDhKey(dhKey);
XMEMSET(keyData, 0, params->p_len - dataSz); if (kse->key != NULL) {
} XFREE(kse->key, ssl->heap, DYNAMIC_TYPE_DH);
kse->pubKeyLen = params->p_len; kse->key = NULL;
#else
if (p_len != dataSz) {
/* Zero pad the front of the public key to match prime "p" size */
XMEMMOVE(keyData + p_len - dataSz, keyData, dataSz);
XMEMSET(keyData, 0, p_len - dataSz);
} }
kse->pubKeyLen = p_len;
#endif
kse->pubKey = keyData;
kse->key = key;
kse->keyLen = keySz;
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Public DH Key");
WOLFSSL_BUFFER(keyData, params->p_len);
#endif
end:
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. */ /* Cleanup on error, otherwise data owned by key share entry */
if (keyData != NULL) if (kse->privKey != NULL) {
XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(kse->privKey, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
if (key != NULL) kse->privKey = NULL;
XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); }
if (kse->pubKey != NULL) {
XFREE(kse->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
kse->pubKey = NULL;
}
} }
#else #else
(void)ssl; (void)ssl;
@@ -6821,6 +6802,9 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
list = current->next; list = current->next;
if (current->group >= MIN_FFHDE_GROUP && if (current->group >= MIN_FFHDE_GROUP &&
current->group <= MAX_FFHDE_GROUP) { current->group <= MAX_FFHDE_GROUP) {
#ifndef NO_DH
wc_FreeDhKey((DhKey*)current->key);
#endif
} }
else if (current->group == WOLFSSL_ECC_X25519) { else if (current->group == WOLFSSL_ECC_X25519) {
#ifdef HAVE_CURVE25519 #ifdef HAVE_CURVE25519
@@ -6940,20 +6924,13 @@ static word16 TLSX_KeyShare_Write(KeyShareEntry* list, byte* output,
*/ */
static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
{ {
#ifndef NO_DH int ret = 0;
int ret; #if !defined(NO_DH) && (!defined(NO_CERTS) || !defined(NO_PSK))
#ifdef HAVE_PUBLIC_FFDHE word32 pSz = 0;
const DhParams* params; DhKey* dhKey = (DhKey*)keyShareEntry->key;
#else
word32 pSz;
#endif
#ifdef WOLFSSL_SMALL_STACK
DhKey* dhKey = NULL;
#else
DhKey dhKey[1];
#endif
#ifdef HAVE_PUBLIC_FFDHE #ifdef HAVE_PUBLIC_FFDHE
const DhParams* params = NULL;
switch (keyShareEntry->group) { switch (keyShareEntry->group) {
#ifdef HAVE_FFDHE_2048 #ifdef HAVE_FFDHE_2048
case WOLFSSL_FFDHE_2048: case WOLFSSL_FFDHE_2048:
@@ -6981,109 +6958,100 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
break; break;
#endif #endif
default: default:
return PEER_KEY_ERROR; break;
} }
#endif if (params == NULL) {
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Peer DH Key");
WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
#endif
#ifdef WOLFSSL_SMALL_STACK
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;
}
/* Set key */
#ifdef HAVE_PUBLIC_FFDHE
ret = wc_DhSetKey(dhKey, params->p, params->p_len, params->g,
params->g_len);
#else
ret = wc_DhSetNamedKey(dhKey, keyShareEntry->group);
#endif
if (ret != 0) {
wc_FreeDhKey(dhKey);
#ifdef WOLFSSL_SMALL_STACK
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
#endif
return ret;
}
#ifndef HAVE_PUBLIC_FFDHE
pSz = wc_DhGetNamedKeyMinSize(keyShareEntry->group);
#endif
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;
} }
pSz = params->p_len;
/* Derive secret from private key and peer's public key. */ #else
ret = wc_DhAgree(dhKey, pSz = wc_DhGetNamedKeyMinSize(keyShareEntry->group);
ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, if (pSz == 0) {
(const byte*)keyShareEntry->key, keyShareEntry->keyLen, return PEER_KEY_ERROR;
keyShareEntry->ke, keyShareEntry->keLen);
#ifdef WOLFSSL_ASYNC_CRYPT
/* TODO: Make this function non-blocking */
if (ret == WC_PENDING_E) {
ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
} }
#endif #endif
/* if DhKey is not setup, do it now */
if (keyShareEntry->key == NULL) {
keyShareEntry->key = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap,
DYNAMIC_TYPE_DH);
if (keyShareEntry->key == NULL)
return MEMORY_E;
/* Setup Key */
ret = wc_InitDhKey_ex((DhKey*)keyShareEntry->key, ssl->heap, ssl->devId);
if (ret == 0) {
dhKey = (DhKey*)keyShareEntry->key;
/* Set key */
#ifdef HAVE_PUBLIC_FFDHE
ret = wc_DhSetKey(dhKey, params->p, params->p_len, params->g,
params->g_len);
#else
ret = wc_DhSetNamedKey(dhKey, keyShareEntry->group);
#endif
}
}
if (ret == 0
#ifdef WOLFSSL_ASYNC_CRYPT
&& keyShareEntry->lastRet == 0 /* don't enter here if WC_PENDING_E */
#endif
) {
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Peer DH Key");
WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
#endif
ssl->options.dhKeySz = (word16)pSz;
/* Derive secret from private key and peer's public key. */
ret = DhAgree(ssl, dhKey,
(const byte*)keyShareEntry->privKey, keyShareEntry->keyLen, /* our private */
keyShareEntry->ke, keyShareEntry->keLen, /* peer's public key */
ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz, /* secret */
NULL, 0
);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E) {
return ret;
}
#endif
}
/* RFC 8446 Section 7.4.1: /* RFC 8446 Section 7.4.1:
* ... left-padded with zeros up to the size of the prime. ... * ... left-padded with zeros up to the size of the prime. ...
*/ */
#ifdef HAVE_PUBLIC_FFDHE if (ret == 0 && (word32)ssl->options.dhKeySz > ssl->arrays->preMasterSz) {
if (params->p_len > ssl->arrays->preMasterSz) { word32 diff = (word32)ssl->options.dhKeySz - ssl->arrays->preMasterSz;
word32 diff = params->p_len - ssl->arrays->preMasterSz;
XMEMMOVE(ssl->arrays->preMasterSecret + diff,
ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
XMEMSET(ssl->arrays->preMasterSecret, 0, diff);
ssl->arrays->preMasterSz = params->p_len;
}
ssl->options.dhKeySz = (word16)params->p_len;
#else
if (pSz > ssl->arrays->preMasterSz) {
word32 diff = pSz - ssl->arrays->preMasterSz;
XMEMMOVE(ssl->arrays->preMasterSecret + diff, XMEMMOVE(ssl->arrays->preMasterSecret + diff,
ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
XMEMSET(ssl->arrays->preMasterSecret, 0, diff); XMEMSET(ssl->arrays->preMasterSecret, 0, diff);
ssl->arrays->preMasterSz = pSz; ssl->arrays->preMasterSz = ssl->options.dhKeySz;
} }
ssl->options.dhKeySz = pSz;
#endif
wc_FreeDhKey(dhKey); /* done with key share, release resources */
#ifdef WOLFSSL_SMALL_STACK if (dhKey)
XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH); wc_FreeDhKey(dhKey);
#endif if (keyShareEntry->key) {
if (keyShareEntry->key != NULL) { XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_DH);
XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
keyShareEntry->key = NULL; keyShareEntry->key = NULL;
} }
XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); if (keyShareEntry->privKey != NULL) {
keyShareEntry->pubKey = NULL; XFREE(keyShareEntry->privKey, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
keyShareEntry->privKey = NULL;
}
if (keyShareEntry->pubKey != NULL) {
XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
keyShareEntry->pubKey = NULL;
}
XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
keyShareEntry->ke = NULL; keyShareEntry->ke = NULL;
return ret;
#else #else
(void)ssl; (void)ssl;
(void)keyShareEntry; (void)keyShareEntry;
return PEER_KEY_ERROR; ret = PEER_KEY_ERROR;
#endif #endif
return ret;
} }
/* Process the X25519 key share extension on the client side. /* Process the X25519 key share extension on the client side.

View File

@@ -2005,8 +2005,8 @@ extern void uITRON4_free(void *p) ;
#endif #endif
#if !defined(HAVE_PUBLIC_FFDHE) && !defined(NO_DH) && \ #if !defined(HAVE_PUBLIC_FFDHE) && !defined(NO_DH) && \
(defined(HAVE_SELFTEST) || \ !defined(WOLFSSL_NO_PUBLIC_FFDHE) && \
FIPS_VERSION_EQ(2,0)) (defined(HAVE_SELFTEST) || FIPS_VERSION_EQ(2,0))
#define HAVE_PUBLIC_FFDHE #define HAVE_PUBLIC_FFDHE
#endif #endif