forked from wolfSSL/wolfssl
Merge pull request #5910 from julek-wolfssl/dtls13-stateless
DTLS 1.3 stateless server ClientHello parsing
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#define WC_RSA_PSS
|
||||
#define WOLFSSL_DTLS
|
||||
#define WOLFSSL_DTLS13
|
||||
#define WOLFSSL_SEND_HRR_COOKIE
|
||||
#define WOLFSSL_DTLS_CID
|
||||
|
||||
/* Configurations */
|
||||
|
@@ -1446,7 +1446,7 @@ int LoadCRL(WOLFSSL_CRL* crl, const char* path, int type, int monitor)
|
||||
pathLen = (word32)XSTRLEN(path);
|
||||
pathBuf = (char*)XMALLOC(pathLen+1, crl->heap,DYNAMIC_TYPE_CRL_MONITOR);
|
||||
if (pathBuf) {
|
||||
XSTRNCPY(pathBuf, path, pathLen+1);
|
||||
XMEMCPY(pathBuf, path, pathLen+1);
|
||||
|
||||
if (type == WOLFSSL_FILETYPE_PEM) {
|
||||
/* free old path before setting a new one */
|
||||
|
738
src/dtls.c
738
src/dtls.c
@@ -46,6 +46,8 @@
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; }
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
|
||||
void DtlsResetState(WOLFSSL* ssl)
|
||||
@@ -54,11 +56,6 @@ void DtlsResetState(WOLFSSL* ssl)
|
||||
* ClientHello that contains the cookie. Don't gate on IsAtLeastTLSv1_3
|
||||
* to handle the edge case when the peer wants a lower version. */
|
||||
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
/* Remove cookie so that it will get computed again */
|
||||
TLSX_Remove(&ssl->extensions, TLSX_COOKIE, ssl->heap);
|
||||
#endif
|
||||
|
||||
/* Reset DTLS window */
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
w64Zero(&ssl->dtls13Epochs[0].nextSeqNumber);
|
||||
@@ -69,6 +66,8 @@ void DtlsResetState(WOLFSSL* ssl)
|
||||
#endif
|
||||
ssl->keys.dtls_expected_peer_handshake_number = 0;
|
||||
ssl->keys.dtls_handshake_number = 0;
|
||||
ssl->keys.dtls_sequence_number_hi = 0;
|
||||
ssl->keys.dtls_sequence_number_lo = 0;
|
||||
|
||||
/* Reset states */
|
||||
ssl->options.serverState = NULL_STATE;
|
||||
@@ -79,10 +78,47 @@ void DtlsResetState(WOLFSSL* ssl)
|
||||
ssl->msgsReceived.got_client_hello = 0;
|
||||
ssl->keys.dtls_handshake_number = 0;
|
||||
ssl->keys.dtls_expected_peer_handshake_number = 0;
|
||||
ssl->options.clientState = 0;
|
||||
XMEMSET(ssl->keys.peerSeq->window, 0, sizeof(ssl->keys.peerSeq->window));
|
||||
XMEMSET(ssl->keys.peerSeq->prevWindow, 0,
|
||||
sizeof(ssl->keys.peerSeq->prevWindow));
|
||||
XMEMSET(ssl->keys.peerSeq, 0, sizeof(ssl->keys.peerSeq));
|
||||
ssl->options.tls = 0;
|
||||
ssl->options.tls1_1 = 0;
|
||||
ssl->options.tls1_3 = 0;
|
||||
}
|
||||
|
||||
int DtlsIgnoreError(int err)
|
||||
{
|
||||
/* Whitelist of errors not to ignore */
|
||||
switch (err) {
|
||||
case MEMORY_E:
|
||||
case MEMORY_ERROR:
|
||||
case ASYNC_INIT_E:
|
||||
case ASYNC_OP_E:
|
||||
case SOCKET_ERROR_E:
|
||||
case WANT_READ:
|
||||
case WANT_WRITE:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void DtlsSetSeqNumForReply(WOLFSSL* ssl)
|
||||
{
|
||||
/* We cover both DTLS 1.2 and 1.3 cases because we may be negotiating
|
||||
* protocols. */
|
||||
/* We should continue with the same sequence number as the
|
||||
* Client Hello. */
|
||||
ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi;
|
||||
ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->dtls13EncryptEpoch != NULL) {
|
||||
ssl->dtls13EncryptEpoch->nextSeqNumber =
|
||||
w64From32(ssl->keys.curSeq_hi, ssl->keys.curSeq_lo);
|
||||
}
|
||||
#endif
|
||||
/* We should continue with the same handshake number as the
|
||||
* Client Hello. */
|
||||
ssl->keys.dtls_handshake_number =
|
||||
ssl->keys.dtls_peer_handshake_number;
|
||||
}
|
||||
|
||||
#if !defined(NO_WOLFSSL_SERVER)
|
||||
@@ -101,6 +137,15 @@ void DtlsResetState(WOLFSSL* ssl)
|
||||
#define DTLS_COOKIE_SZ WC_SHA256_DIGEST_SIZE
|
||||
#endif /* !NO_SHA256 */
|
||||
|
||||
#if defined(WOLFSSL_DTLS13) && (defined(HAVE_SESSION_TICKET) || \
|
||||
!defined(NO_PSK))
|
||||
typedef struct PskInfo {
|
||||
byte cipherSuite0;
|
||||
byte cipherSuite;
|
||||
byte isValid:1;
|
||||
} PskInfo;
|
||||
#endif
|
||||
|
||||
typedef struct WolfSSL_ConstVector {
|
||||
word32 size;
|
||||
const byte* elements;
|
||||
@@ -114,7 +159,12 @@ typedef struct WolfSSL_CH {
|
||||
WolfSSL_ConstVector cipherSuite;
|
||||
WolfSSL_ConstVector compression;
|
||||
WolfSSL_ConstVector extension;
|
||||
WolfSSL_ConstVector cookieExt;
|
||||
const byte* raw;
|
||||
word32 length;
|
||||
/* Store the DTLS 1.2 cookie since we can just compute it once in dtls.c */
|
||||
byte dtls12cookie[DTLS_COOKIE_SZ];
|
||||
byte dtls12cookieSet:1;
|
||||
} WolfSSL_CH;
|
||||
|
||||
static int ReadVector8(const byte* input, WolfSSL_ConstVector* v)
|
||||
@@ -133,45 +183,82 @@ static int ReadVector16(const byte* input, WolfSSL_ConstVector* v)
|
||||
return v->size + OPAQUE16_LEN;
|
||||
}
|
||||
|
||||
static int CreateDtlsCookie(WOLFSSL* ssl, const WolfSSL_CH* ch, byte* cookie)
|
||||
static int CreateDtls12Cookie(const WOLFSSL* ssl, const WolfSSL_CH* ch,
|
||||
byte* cookie)
|
||||
{
|
||||
Hmac cookieHmac;
|
||||
int ret;
|
||||
|
||||
Hmac cookieHmac;
|
||||
ret = wc_HmacInit(&cookieHmac, ssl->heap, ssl->devId);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_HmacSetKey(&cookieHmac, DTLS_COOKIE_TYPE,
|
||||
ssl->buffers.dtlsCookieSecret.buffer,
|
||||
ssl->buffers.dtlsCookieSecret.length);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacUpdate(&cookieHmac, (const byte*)ssl->buffers.dtlsCtx.peer.sa,
|
||||
ssl->buffers.dtlsCtx.peer.sz);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->pv, OPAQUE16_LEN);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->random, RAN_LEN);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->sessionId.elements,
|
||||
ch->sessionId.size);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->cipherSuite.elements,
|
||||
ch->cipherSuite.size);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->compression.elements,
|
||||
ch->compression.size);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
ret = wc_HmacFinal(&cookieHmac, cookie);
|
||||
if (ret == 0) {
|
||||
ret = wc_HmacSetKey(&cookieHmac, DTLS_COOKIE_TYPE,
|
||||
ssl->buffers.dtlsCookieSecret.buffer,
|
||||
ssl->buffers.dtlsCookieSecret.length);
|
||||
if (ret == 0) {
|
||||
ret = wc_HmacUpdate(&cookieHmac,
|
||||
(const byte*)ssl->buffers.dtlsCtx.peer.sa,
|
||||
ssl->buffers.dtlsCtx.peer.sz);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->pv, OPAQUE16_LEN);
|
||||
if (ret == 0)
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->random, RAN_LEN);
|
||||
if (ret == 0) {
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->sessionId.elements,
|
||||
ch->sessionId.size);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->cipherSuite.elements,
|
||||
ch->cipherSuite.size);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->compression.elements,
|
||||
ch->compression.size);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = wc_HmacFinal(&cookieHmac, cookie);
|
||||
wc_HmacFree(&cookieHmac);
|
||||
}
|
||||
|
||||
out:
|
||||
wc_HmacFree(&cookieHmac);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CheckDtlsCookie(const WOLFSSL* ssl, WolfSSL_CH* ch,
|
||||
byte isTls13, byte* cookieGood)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
(void)isTls13;
|
||||
|
||||
*cookieGood = 0;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (isTls13) {
|
||||
word16 len;
|
||||
if (ch->cookieExt.size < OPAQUE16_LEN + 1)
|
||||
return BUFFER_E;
|
||||
ato16(ch->cookieExt.elements, &len);
|
||||
if (ch->cookieExt.size - OPAQUE16_LEN != len)
|
||||
return BUFFER_E;
|
||||
ret = TlsCheckCookie(ssl, ch->cookieExt.elements + OPAQUE16_LEN,
|
||||
(word16)(ch->cookieExt.size - OPAQUE16_LEN));
|
||||
if (ret < 0 && ret != HRR_COOKIE_ERROR)
|
||||
return ret;
|
||||
*cookieGood = ret > 0;
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (ch->cookie.size != DTLS_COOKIE_SZ)
|
||||
return 0;
|
||||
if (!ch->dtls12cookieSet) {
|
||||
ret = CreateDtls12Cookie(ssl, ch, ch->dtls12cookie);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ch->dtls12cookieSet = 1;
|
||||
}
|
||||
*cookieGood = ConstantCompare(ch->cookie.elements, ch->dtls12cookie,
|
||||
DTLS_COOKIE_SZ) == 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -183,6 +270,7 @@ static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch)
|
||||
if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
|
||||
return BUFFER_ERROR;
|
||||
|
||||
ch->raw = input;
|
||||
ch->pv = (ProtocolVersion*)(input + idx);
|
||||
idx += OPAQUE16_LEN;
|
||||
ch->random = (byte*)(input + idx);
|
||||
@@ -206,10 +294,10 @@ static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
static int TlsxFindByType(WolfSSL_ConstVector* ret, word16 extType,
|
||||
WolfSSL_ConstVector exts)
|
||||
#if (defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) && defined(HAVE_SESSION_TICKET)) \
|
||||
|| defined(WOLFSSL_DTLS13)
|
||||
static int FindExtByType(WolfSSL_ConstVector* ret, word16 extType,
|
||||
WolfSSL_ConstVector exts, int* tlsxFound)
|
||||
{
|
||||
word32 len, idx = 0;
|
||||
word16 type;
|
||||
@@ -217,6 +305,7 @@ static int TlsxFindByType(WolfSSL_ConstVector* ret, word16 extType,
|
||||
|
||||
XMEMSET(ret, 0, sizeof(*ret));
|
||||
len = exts.size;
|
||||
*tlsxFound = FALSE;
|
||||
/* type + len */
|
||||
while (len >= OPAQUE16_LEN + OPAQUE16_LEN) {
|
||||
ato16(exts.elements + idx, &type);
|
||||
@@ -226,23 +315,28 @@ static int TlsxFindByType(WolfSSL_ConstVector* ret, word16 extType,
|
||||
return BUFFER_ERROR;
|
||||
if (type == extType) {
|
||||
XMEMCPY(ret, &ext, sizeof(ext));
|
||||
*tlsxFound = TRUE;
|
||||
return 0;
|
||||
}
|
||||
len = exts.size - idx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int TlsTicketIsValid(WOLFSSL* ssl, WolfSSL_ConstVector exts,
|
||||
byte* isValid)
|
||||
#if defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME)
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
static int TlsTicketIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector exts,
|
||||
int* resume)
|
||||
{
|
||||
WolfSSL_ConstVector tlsxSessionTicket;
|
||||
byte tempTicket[SESSION_TICKET_LEN];
|
||||
InternalTicket* it;
|
||||
int ret;
|
||||
InternalTicket* it = NULL;
|
||||
int ret = 0;
|
||||
int tlsxFound;
|
||||
|
||||
*isValid = 0;
|
||||
ret = TlsxFindByType(&tlsxSessionTicket, TLSX_SESSION_TICKET, exts);
|
||||
ret = FindExtByType(&tlsxSessionTicket, TLSX_SESSION_TICKET, exts,
|
||||
&tlsxFound);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (tlsxSessionTicket.size == 0)
|
||||
@@ -251,22 +345,23 @@ static int TlsTicketIsValid(WOLFSSL* ssl, WolfSSL_ConstVector exts,
|
||||
return 0;
|
||||
XMEMCPY(tempTicket, tlsxSessionTicket.elements, tlsxSessionTicket.size);
|
||||
ret = DoDecryptTicket(ssl, tempTicket, (word32)tlsxSessionTicket.size, &it);
|
||||
if (ret != WOLFSSL_TICKET_RET_OK && ret != WOLFSSL_TICKET_RET_CREATE)
|
||||
return 0;
|
||||
ForceZero(it, sizeof(InternalTicket));
|
||||
*isValid = 1;
|
||||
if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) {
|
||||
/* This logic is only for TLS <= 1.2 tickets. Don't accept TLS 1.3. */
|
||||
if (!IsAtLeastTLSv1_3(it->pv))
|
||||
*resume = TRUE;
|
||||
}
|
||||
if (it != NULL)
|
||||
ForceZero(it, sizeof(InternalTicket));
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
|
||||
static int TlsSessionIdIsValid(WOLFSSL* ssl, WolfSSL_ConstVector sessionID,
|
||||
byte* isValid)
|
||||
static int TlsSessionIdIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector sessionID,
|
||||
int* resume)
|
||||
{
|
||||
WOLFSSL_SESSION* sess;
|
||||
word32 sessRow;
|
||||
int ret;
|
||||
|
||||
*isValid = 0;
|
||||
if (ssl->options.sessionCacheOff)
|
||||
return 0;
|
||||
if (sessionID.size != ID_LEN)
|
||||
@@ -277,11 +372,22 @@ static int TlsSessionIdIsValid(WOLFSSL* ssl, WolfSSL_ConstVector sessionID,
|
||||
if (ssl->ctx->get_sess_cb != NULL) {
|
||||
int unused;
|
||||
sess =
|
||||
ssl->ctx->get_sess_cb(ssl, sessionID.elements, ID_LEN, &unused);
|
||||
ssl->ctx->get_sess_cb((WOLFSSL*)ssl, sessionID.elements, ID_LEN,
|
||||
&unused);
|
||||
if (sess != NULL) {
|
||||
*isValid = 1;
|
||||
wolfSSL_FreeSession(ssl->ctx, sess);
|
||||
return 0;
|
||||
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
|
||||
defined(HAVE_SESSION_TICKET))
|
||||
/* This logic is only for TLS <= 1.2 tickets. Don't accept
|
||||
* TLS 1.3. */
|
||||
if (IsAtLeastTLSv1_3(sess->version))
|
||||
wolfSSL_FreeSession(ssl->ctx, sess);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
*resume = 1;
|
||||
wolfSSL_FreeSession(ssl->ctx, sess);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ssl->ctx->internalCacheLookupOff)
|
||||
@@ -290,60 +396,514 @@ static int TlsSessionIdIsValid(WOLFSSL* ssl, WolfSSL_ConstVector sessionID,
|
||||
#endif
|
||||
ret = TlsSessionCacheGetAndLock(sessionID.elements, &sess, &sessRow, 1);
|
||||
if (ret == 0 && sess != NULL) {
|
||||
*isValid = 1;
|
||||
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
|
||||
defined(HAVE_SESSION_TICKET))
|
||||
/* This logic is only for TLS <= 1.2 tickets. Don't accept
|
||||
* TLS 1.3. */
|
||||
if (!IsAtLeastTLSv1_3(sess->version))
|
||||
#endif
|
||||
{
|
||||
*resume = 1;
|
||||
}
|
||||
TlsSessionCacheUnlockRow(sessRow);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TlsResumptionIsValid(WOLFSSL* ssl, WolfSSL_CH* ch, byte* isValid)
|
||||
static int TlsResumptionIsValid(const WOLFSSL* ssl, WolfSSL_CH* ch,
|
||||
int* resume)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*isValid = 0;
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
ret = TlsTicketIsValid(ssl, ch->extension, isValid);
|
||||
ret = TlsTicketIsValid(ssl, ch->extension, resume);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (*isValid)
|
||||
if (*resume)
|
||||
return 0;
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
ret = TlsSessionIdIsValid(ssl, ch->sessionId, isValid);
|
||||
ret = TlsSessionIdIsValid(ssl, ch->sessionId, resume);
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */
|
||||
#endif /* WOLFSSL_DTLS13 || WOLFSSL_DTLS_NO_HVR_ON_RESUME */
|
||||
|
||||
int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
word32 helloSz, byte* process)
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
static int TlsCheckSupportedVersion(const WOLFSSL* ssl,
|
||||
WolfSSL_CH* ch, byte *isTls13)
|
||||
{
|
||||
WolfSSL_ConstVector tlsxSupportedVersions;
|
||||
int ret;
|
||||
ProtocolVersion pv = ssl->version;
|
||||
int tlsxFound;
|
||||
|
||||
ret = FindExtByType(&tlsxSupportedVersions, TLSX_SUPPORTED_VERSIONS,
|
||||
ch->extension, &tlsxFound);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (!tlsxFound) {
|
||||
*isTls13 = 0;
|
||||
return 0;
|
||||
}
|
||||
ret = TLSX_SupportedVersions_Parse(ssl, tlsxSupportedVersions.elements,
|
||||
(word16)tlsxSupportedVersions.size, client_hello, &pv, NULL, NULL);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (IsAtLeastTLSv1_3(pv))
|
||||
*isTls13 = 1;
|
||||
else
|
||||
*isTls13 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_DTLS13) && \
|
||||
(!defined(NO_PSK) || defined(HAVE_SESSION_TICKET))
|
||||
/* Very simplified version of CheckPreSharedKeys to find the current suite */
|
||||
static void FindPskSuiteFromExt(const WOLFSSL* ssl, TLSX* extensions,
|
||||
PskInfo* pskInfo, Suites* suites)
|
||||
{
|
||||
TLSX* pskExt = TLSX_Find(extensions, TLSX_PRE_SHARED_KEY);
|
||||
PreSharedKey* current;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (pskExt == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < suites->suiteSz; i += 2) {
|
||||
for (current = (PreSharedKey*)pskExt->data; current != NULL;
|
||||
current = current->next) {
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
{
|
||||
/* Decode the identity. */
|
||||
switch (current->decryptRet) {
|
||||
case PSK_DECRYPT_NONE:
|
||||
ret = DoClientTicket_ex(ssl, current);
|
||||
break;
|
||||
case PSK_DECRYPT_OK:
|
||||
ret = WOLFSSL_TICKET_RET_OK;
|
||||
break;
|
||||
case PSK_DECRYPT_CREATE:
|
||||
ret = WOLFSSL_TICKET_RET_CREATE;
|
||||
break;
|
||||
case PSK_DECRYPT_FAIL:
|
||||
default:
|
||||
ret = WOLFSSL_TICKET_RET_REJECT;
|
||||
break;
|
||||
}
|
||||
if (ret == WOLFSSL_TICKET_RET_OK) {
|
||||
if (DoClientTicketCheck(ssl, current, ssl->timeout,
|
||||
suites->suites + i) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pskInfo->cipherSuite0 = current->it->suite[0];
|
||||
pskInfo->cipherSuite = current->it->suite[1];
|
||||
pskInfo->isValid = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef NO_PSK
|
||||
{
|
||||
int found = 0;
|
||||
byte psk_key[MAX_PSK_KEY_LEN];
|
||||
word32 psk_keySz;
|
||||
byte foundSuite[SUITE_LEN];
|
||||
ret = FindPskSuite(ssl, current, psk_key, &psk_keySz,
|
||||
suites->suites + i, &found, foundSuite);
|
||||
/* Clear the key just in case */
|
||||
ForceZero(psk_key, sizeof(psk_key));
|
||||
if (ret == 0 && found) {
|
||||
pskInfo->cipherSuite0 = foundSuite[0];
|
||||
pskInfo->cipherSuite = foundSuite[1];
|
||||
pskInfo->isValid = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty return necessary so we can have both the label and macro guard */
|
||||
cleanup:
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
CleanupClientTickets((PreSharedKey*)pskExt->data);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
|
||||
#ifndef WOLFSSL_SEND_HRR_COOKIE
|
||||
#error "WOLFSSL_SEND_HRR_COOKIE has to be defined to use DTLS 1.3 server"
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_PSK_ONE_ID
|
||||
#error WOLFSSL_PSK_ONE_ID is not compatible with stateless DTLS 1.3 server. \
|
||||
wolfSSL needs to be able to make multiple calls for the same PSK.
|
||||
#endif
|
||||
|
||||
static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch)
|
||||
{
|
||||
int ret = -1;
|
||||
TLSX* parsedExts = NULL;
|
||||
WolfSSL_ConstVector tlsx;
|
||||
int tlsxFound;
|
||||
Suites suites;
|
||||
byte haveSA = 0;
|
||||
byte haveKS = 0;
|
||||
byte haveSG = 0;
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
byte usePSK = 0;
|
||||
byte doKE = 0;
|
||||
#endif
|
||||
CipherSuite cs;
|
||||
CipherSpecs specs;
|
||||
byte cookieHash[WC_MAX_DIGEST_SIZE];
|
||||
int cookieHashSz;
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
PskInfo pskInfo;
|
||||
XMEMSET(&pskInfo, 0, sizeof(pskInfo));
|
||||
#endif
|
||||
|
||||
XMEMSET(&cs, 0, sizeof(cs));
|
||||
|
||||
/* We need to echo the session ID sent by the client */
|
||||
if (ch->sessionId.size > ID_LEN) {
|
||||
/* Too large. We can't echo this. */
|
||||
ERROR_OUT(INVALID_PARAMETER, dtls13_cleanup);
|
||||
}
|
||||
|
||||
/* Populate the suites struct to find a common ciphersuite */
|
||||
XMEMSET(&suites, 0, sizeof(suites));
|
||||
suites.suiteSz = (word16)ch->cipherSuite.size;
|
||||
if ((suites.suiteSz % 2) != 0)
|
||||
ERROR_OUT(INVALID_PARAMETER, dtls13_cleanup);
|
||||
if (suites.suiteSz > WOLFSSL_MAX_SUITE_SZ)
|
||||
ERROR_OUT(BUFFER_ERROR, dtls13_cleanup);
|
||||
XMEMCPY(suites.suites, ch->cipherSuite.elements, suites.suiteSz);
|
||||
|
||||
/* Populate extensions */
|
||||
|
||||
/* Supported versions always need to be present. Has to appear after
|
||||
* key share as that is the order we reconstruct it in
|
||||
* RestartHandshakeHashWithCookie. */
|
||||
ret = TLSX_Push(&parsedExts,
|
||||
TLSX_SUPPORTED_VERSIONS, ssl, ssl->heap);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
/* Set that this is a response extension */
|
||||
parsedExts->resp = 1;
|
||||
|
||||
ret = TLSX_SupportedCurve_Copy(ssl->extensions, &parsedExts, ssl->heap);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
|
||||
/* Signature algs */
|
||||
ret = FindExtByType(&tlsx, TLSX_SIGNATURE_ALGORITHMS,
|
||||
ch->extension, &tlsxFound);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsxFound) {
|
||||
WolfSSL_ConstVector sigAlgs;
|
||||
if (tlsx.size < OPAQUE16_LEN)
|
||||
ERROR_OUT(BUFFER_ERROR, dtls13_cleanup);
|
||||
ReadVector16(tlsx.elements, &sigAlgs);
|
||||
if (sigAlgs.size != tlsx.size - OPAQUE16_LEN)
|
||||
ERROR_OUT(BUFFER_ERROR, dtls13_cleanup);
|
||||
if ((sigAlgs.size % 2) != 0)
|
||||
ERROR_OUT(BUFFER_ERROR, dtls13_cleanup);
|
||||
suites.hashSigAlgoSz = (word16)sigAlgs.size;
|
||||
XMEMCPY(suites.hashSigAlgo, sigAlgs.elements, sigAlgs.size);
|
||||
haveSA = 1;
|
||||
}
|
||||
|
||||
/* Supported groups */
|
||||
ret = FindExtByType(&tlsx, TLSX_SUPPORTED_GROUPS,
|
||||
ch->extension, &tlsxFound);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsxFound) {
|
||||
ret = TLSX_SupportedCurve_Parse(ssl, tlsx.elements,
|
||||
(word16)tlsx.size, 1, &parsedExts);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
haveSG = 1;
|
||||
}
|
||||
|
||||
/* Key share */
|
||||
ret = FindExtByType(&tlsx, TLSX_KEY_SHARE,
|
||||
ch->extension, &tlsxFound);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsxFound) {
|
||||
ret = TLSX_KeyShare_Parse_ClientHello(ssl, tlsx.elements,
|
||||
(word16)tlsx.size, &parsedExts);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
haveKS = 1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
/* Pre-shared key */
|
||||
ret = FindExtByType(&tlsx, TLSX_PRE_SHARED_KEY, ch->extension, &tlsxFound);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsxFound) {
|
||||
/* Let's just assume that the binders are correct here. We will
|
||||
* actually verify this in the stateful part of the processing
|
||||
* and if they don't match we will error out there anyway. */
|
||||
byte modes;
|
||||
|
||||
/* Ask the user for the ciphersuite matching this identity */
|
||||
if (TLSX_PreSharedKey_Parse_ClientHello(&parsedExts,
|
||||
tlsx.elements, tlsx.size, ssl->heap) == 0)
|
||||
FindPskSuiteFromExt(ssl, parsedExts, &pskInfo, &suites);
|
||||
/* Revert to full handshake if PSK parsing failed */
|
||||
|
||||
if (pskInfo.isValid) {
|
||||
ret = FindExtByType(&tlsx, TLSX_PSK_KEY_EXCHANGE_MODES,
|
||||
ch->extension, &tlsxFound);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (!tlsxFound)
|
||||
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
|
||||
ret = TLSX_PskKeyModes_Parse_Modes(tlsx.elements, tlsx.size,
|
||||
client_hello, &modes);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if ((modes & (1 << PSK_DHE_KE)) &&
|
||||
!ssl->options.noPskDheKe) {
|
||||
if (!haveKS)
|
||||
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
|
||||
doKE = 1;
|
||||
}
|
||||
else if ((modes & (1 << PSK_KE)) == 0) {
|
||||
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
|
||||
}
|
||||
usePSK = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
if (usePSK && pskInfo.isValid) {
|
||||
cs.cipherSuite0 = pskInfo.cipherSuite0;
|
||||
cs.cipherSuite = pskInfo.cipherSuite;
|
||||
|
||||
/* https://datatracker.ietf.org/doc/html/rfc8446#section-9.2 */
|
||||
if (haveSG ^ haveKS) {
|
||||
WOLFSSL_MSG("Client needs to send both or none of KeyShare and "
|
||||
"SupportedGroups");
|
||||
ERROR_OUT(INCOMPLETE_DATA, dtls13_cleanup);
|
||||
}
|
||||
|
||||
if (doKE) {
|
||||
byte searched = 0;
|
||||
ret = TLSX_KeyShare_Choose(ssl, parsedExts, &cs.clientKSE,
|
||||
&searched);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (cs.clientKSE == NULL && searched)
|
||||
cs.doHelloRetry = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* https://datatracker.ietf.org/doc/html/rfc8446#section-9.2 */
|
||||
if (!haveKS || !haveSA || !haveSG) {
|
||||
WOLFSSL_MSG("Client didn't send KeyShare or SigAlgs or "
|
||||
"SupportedGroups.");
|
||||
ERROR_OUT(INCOMPLETE_DATA, dtls13_cleanup);
|
||||
}
|
||||
/* TLSX_KeyShare_Choose is done deep inside MatchSuite_ex */
|
||||
ret = MatchSuite_ex(ssl, &suites, &cs, parsedExts);
|
||||
if (ret < 0) {
|
||||
WOLFSSL_MSG("Unsupported cipher suite, ClientHello DTLS 1.3");
|
||||
ERROR_OUT(INCOMPLETE_DATA, dtls13_cleanup);
|
||||
}
|
||||
}
|
||||
if (cs.doHelloRetry) {
|
||||
ret = TLSX_KeyShare_SetSupported(ssl, &parsedExts);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
}
|
||||
else {
|
||||
/* Need to remove the keyshare ext if we found a common group
|
||||
* and are not doing curve negotiation. */
|
||||
TLSX_Remove(&parsedExts, TLSX_KEY_SHARE, ssl->heap);
|
||||
}
|
||||
|
||||
/* This is required to correctly generate the hash */
|
||||
ret = GetCipherSpec(WOLFSSL_SERVER_END, cs.cipherSuite0,
|
||||
cs.cipherSuite, &specs, NULL);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
|
||||
/* Calculate the cookie hash */
|
||||
ret = Dtls13HashClientHello(ssl, cookieHash, &cookieHashSz, ch->raw,
|
||||
ch->length, &specs);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
|
||||
/* Push the cookie to extensions */
|
||||
ret = CreateCookieExt(ssl, cookieHash, (word16)cookieHashSz,
|
||||
&parsedExts, cs.cipherSuite0, cs.cipherSuite);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
|
||||
{
|
||||
WOLFSSL* nonConstSSL = (WOLFSSL*)ssl;
|
||||
TLSX* sslExts = nonConstSSL->extensions;
|
||||
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
nonConstSSL->options.tls = 1;
|
||||
nonConstSSL->options.tls1_1 = 1;
|
||||
nonConstSSL->options.tls1_3 = 1;
|
||||
|
||||
XMEMCPY(nonConstSSL->session->sessionID, ch->sessionId.elements,
|
||||
ch->sessionId.size);
|
||||
nonConstSSL->session->sessionIDSz = (byte)ch->sessionId.size;
|
||||
nonConstSSL->options.cipherSuite0 = cs.cipherSuite0;
|
||||
nonConstSSL->options.cipherSuite = cs.cipherSuite;
|
||||
nonConstSSL->extensions = parsedExts;
|
||||
|
||||
ret = SendTls13ServerHello(nonConstSSL, hello_retry_request);
|
||||
|
||||
/* Can be modified inside SendTls13ServerHello */
|
||||
parsedExts = nonConstSSL->extensions;
|
||||
|
||||
nonConstSSL->session->sessionIDSz = 0;
|
||||
nonConstSSL->options.cipherSuite0 = 0;
|
||||
nonConstSSL->options.cipherSuite = 0;
|
||||
nonConstSSL->extensions = sslExts;
|
||||
|
||||
nonConstSSL->options.tls = 0;
|
||||
nonConstSSL->options.tls1_1 = 0;
|
||||
nonConstSSL->options.tls1_3 = 0;
|
||||
}
|
||||
dtls13_cleanup:
|
||||
TLSX_FreeAll(parsedExts, ssl->heap);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int SendStatelessReply(const WOLFSSL* ssl, WolfSSL_CH* ch, byte isTls13)
|
||||
{
|
||||
int ret;
|
||||
(void)isTls13;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (isTls13) {
|
||||
ret = SendStatelessReplyDtls13(ssl, ch);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!ch->dtls12cookieSet) {
|
||||
ret = CreateDtls12Cookie(ssl, ch, ch->dtls12cookie);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ch->dtls12cookieSet = 1;
|
||||
}
|
||||
ret = SendHelloVerifyRequest((WOLFSSL*)ssl, ch->dtls12cookie,
|
||||
DTLS_COOKIE_SZ);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ClientHelloSanityCheck(WolfSSL_CH* ch, byte isTls13)
|
||||
{
|
||||
/* Do basic checks on the basic fields */
|
||||
|
||||
/* Check the protocol version */
|
||||
if (ch->pv->major != DTLS_MAJOR)
|
||||
return VERSION_ERROR;
|
||||
if (ch->pv->minor != DTLSv1_2_MINOR && ch->pv->minor != DTLS_MINOR)
|
||||
return VERSION_ERROR;
|
||||
if (isTls13) {
|
||||
if (ch->cookie.size != 0)
|
||||
return INVALID_PARAMETER;
|
||||
if (ch->compression.size != COMP_LEN)
|
||||
return INVALID_PARAMETER;
|
||||
if (ch->compression.elements[0] != NO_COMPRESSION)
|
||||
return INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
|
||||
word32* inOutIdx, word32 helloSz)
|
||||
{
|
||||
byte cookie[DTLS_COOKIE_SZ];
|
||||
int ret;
|
||||
WolfSSL_CH ch;
|
||||
byte isTls13 = 0;
|
||||
|
||||
*process = 1;
|
||||
XMEMSET(&ch, 0, sizeof(ch));
|
||||
|
||||
ssl->options.dtlsStateful = 0;
|
||||
ret = ParseClientHello(input + *inOutIdx, helloSz, &ch);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
|
||||
{
|
||||
byte isValid = 0;
|
||||
ret = TlsResumptionIsValid(ssl, &ch, &isValid);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||
ret = TlsCheckSupportedVersion(ssl, &ch, &isTls13);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (isValid)
|
||||
return 0;
|
||||
if (isTls13) {
|
||||
int tlsxFound;
|
||||
ret = FindExtByType(&ch.cookieExt, TLSX_COOKIE, ch.extension,
|
||||
&tlsxFound);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */
|
||||
#endif
|
||||
|
||||
ret = CreateDtlsCookie(ssl, &ch, cookie);
|
||||
ret = ClientHelloSanityCheck(&ch, isTls13);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (ch.cookie.size != DTLS_COOKIE_SZ ||
|
||||
XMEMCMP(ch.cookie.elements, cookie, DTLS_COOKIE_SZ) != 0) {
|
||||
*process = 0;
|
||||
ret = SendHelloVerifyRequest(ssl, cookie, DTLS_COOKIE_SZ);
|
||||
|
||||
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
|
||||
if (!isTls13) {
|
||||
int resume = FALSE;
|
||||
ret = TlsResumptionIsValid(ssl, &ch, &resume);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (resume) {
|
||||
ssl->options.dtlsStateful = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ch.cookie.size == 0 && ch.cookieExt.size == 0) {
|
||||
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
|
||||
}
|
||||
else {
|
||||
byte cookieGood;
|
||||
ret = CheckDtlsCookie(ssl, &ch, isTls13, &cookieGood);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (!cookieGood) {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* Invalid cookie for DTLS 1.3 results in an alert. Alert to be sent
|
||||
* in DoTls13ClientHello. */
|
||||
if (isTls13)
|
||||
ret = INVALID_PARAMETER;
|
||||
else
|
||||
#endif
|
||||
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
|
||||
}
|
||||
else
|
||||
ssl->options.dtlsStateful = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
62
src/dtls13.c
62
src/dtls13.c
@@ -123,6 +123,7 @@ WOLFSSL_METHOD* wolfDTLSv1_3_client_method_ex(void* heap)
|
||||
WOLFSSL_METHOD* method;
|
||||
|
||||
WOLFSSL_ENTER("DTLSv1_3_client_method_ex");
|
||||
(void)heap;
|
||||
|
||||
method = (WOLFSSL_METHOD*)XMALLOC(sizeof(WOLFSSL_METHOD), heap,
|
||||
DYNAMIC_TYPE_METHOD);
|
||||
@@ -145,6 +146,7 @@ WOLFSSL_METHOD* wolfDTLSv1_3_server_method_ex(void* heap)
|
||||
WOLFSSL_METHOD* method;
|
||||
|
||||
WOLFSSL_ENTER("DTLSv1_3_server_method_ex");
|
||||
(void)heap;
|
||||
|
||||
method = (WOLFSSL_METHOD*)XMALLOC(sizeof(WOLFSSL_METHOD), heap,
|
||||
DYNAMIC_TYPE_METHOD);
|
||||
@@ -330,7 +332,8 @@ static byte Dtls13RtxMsgNeedsAck(WOLFSSL* ssl, enum HandShakeType hs)
|
||||
|
||||
static void Dtls13MsgWasProcessed(WOLFSSL* ssl, enum HandShakeType hs)
|
||||
{
|
||||
ssl->keys.dtls_expected_peer_handshake_number++;
|
||||
if (ssl->options.dtlsStateful)
|
||||
ssl->keys.dtls_expected_peer_handshake_number++;
|
||||
|
||||
/* we need to send ACKs on the last message of a flight that needs explicit
|
||||
acknowledgment */
|
||||
@@ -360,8 +363,10 @@ int Dtls13ProcessBufferedMessages(WOLFSSL* ssl)
|
||||
msg->sz, msg->sz);
|
||||
|
||||
/* processing certificate_request triggers a connect. The error came
|
||||
* from there, the message can be considered processed successfully */
|
||||
if (ret == 0 || (msg->type == certificate_request &&
|
||||
* from there, the message can be considered processed successfully.
|
||||
* WANT_WRITE means that we are done with processing the msg and we are
|
||||
* waiting to flush the output buffer. */
|
||||
if ((ret == 0 || ret == WANT_WRITE) || (msg->type == certificate_request &&
|
||||
ssl->options.handShakeDone && ret == WC_PENDING_E)) {
|
||||
Dtls13MsgWasProcessed(ssl, (enum HandShakeType)msg->type);
|
||||
|
||||
@@ -432,8 +437,39 @@ static int Dtls13SendNow(WOLFSSL* ssl, enum HandShakeType handshakeType)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handshake header DTLS only fields are not included in the transcript hash.
|
||||
* body points to the body of the DTLSHandshake message. */
|
||||
int Dtls13HashClientHello(const WOLFSSL* ssl, byte* hash, int* hashSz,
|
||||
const byte* body, word32 length, CipherSpecs* specs)
|
||||
{
|
||||
/* msg_type(1) + length (3) */
|
||||
byte header[OPAQUE32_LEN];
|
||||
int ret;
|
||||
wc_HashAlg hashCtx;
|
||||
int type = wolfSSL_GetHmacType_ex(specs);
|
||||
|
||||
header[0] = (byte)client_hello;
|
||||
c32to24(length, header + 1);
|
||||
|
||||
ret = wc_HashInit_ex(&hashCtx, type, ssl->heap, ssl->devId);
|
||||
if (ret == 0) {
|
||||
ret = wc_HashUpdate(&hashCtx, type, header, OPAQUE32_LEN);
|
||||
if (ret == 0)
|
||||
ret = wc_HashUpdate(&hashCtx, type, body, length);
|
||||
if (ret == 0)
|
||||
ret = wc_HashFinal(&hashCtx, type, hash);
|
||||
if (ret == 0) {
|
||||
*hashSz = wc_HashGetDigestSize(type);
|
||||
if (*hashSz < 0)
|
||||
ret = *hashSz;
|
||||
}
|
||||
wc_HashFree(&hashCtx, type);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Handshake header DTLS only fields are not included in the transcript hash */
|
||||
int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output, word16 length)
|
||||
int Dtls13HashHandshake(WOLFSSL* ssl, const byte* input, word16 length)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -441,18 +477,18 @@ int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output, word16 length)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* msg_type(1) + length (3) */
|
||||
ret = HashRaw(ssl, output, OPAQUE32_LEN);
|
||||
ret = HashRaw(ssl, input, OPAQUE32_LEN);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
output += OPAQUE32_LEN;
|
||||
input += OPAQUE32_LEN;
|
||||
length -= OPAQUE32_LEN;
|
||||
|
||||
/* message_seq(2) + fragment_offset(3) + fragment_length(3) */
|
||||
output += OPAQUE64_LEN;
|
||||
input += OPAQUE64_LEN;
|
||||
length -= OPAQUE64_LEN;
|
||||
|
||||
return HashRaw(ssl, output, length);
|
||||
return HashRaw(ssl, input, length);
|
||||
}
|
||||
|
||||
static int Dtls13SendFragment(WOLFSSL* ssl, byte* output, word16 output_size,
|
||||
@@ -612,12 +648,14 @@ static void Dtls13RtxFlushBuffered(WOLFSSL* ssl, byte keepNewSessionTicket)
|
||||
ssl->dtls13Rtx.rtxRecordTailPtr = prevNext;
|
||||
}
|
||||
|
||||
static Dtls13RecordNumber* Dtls13NewRecordNumber(WOLFSSL* ssl, w64wrapper epoch,
|
||||
w64wrapper seq)
|
||||
static Dtls13RecordNumber* Dtls13NewRecordNumber(w64wrapper epoch,
|
||||
w64wrapper seq, void* heap)
|
||||
{
|
||||
Dtls13RecordNumber* rn;
|
||||
|
||||
rn = (Dtls13RecordNumber*)XMALLOC(sizeof(*rn), ssl->heap,
|
||||
(void)heap;
|
||||
|
||||
rn = (Dtls13RecordNumber*)XMALLOC(sizeof(*rn), heap,
|
||||
DYNAMIC_TYPE_DTLS_MSG);
|
||||
if (rn == NULL)
|
||||
return NULL;
|
||||
@@ -635,7 +673,7 @@ static int Dtls13RtxAddAck(WOLFSSL* ssl, w64wrapper epoch, w64wrapper seq)
|
||||
|
||||
WOLFSSL_ENTER("Dtls13RtxAddAck");
|
||||
|
||||
rn = Dtls13NewRecordNumber(ssl, epoch, seq);
|
||||
rn = Dtls13NewRecordNumber(epoch, seq, ssl->heap);
|
||||
if (rn == NULL)
|
||||
return MEMORY_E;
|
||||
|
||||
|
552
src/internal.c
552
src/internal.c
@@ -558,7 +558,7 @@ int IsDtlsNotSctpMode(WOLFSSL* ssl)
|
||||
/* Secure Real-time Transport Protocol */
|
||||
/* If SRTP is not enabled returns the state of the dtls option.
|
||||
* If SRTP is enabled returns dtls && !dtlsSrtpProfiles. */
|
||||
static WC_INLINE int IsDtlsNotSrtpMode(WOLFSSL* ssl)
|
||||
int IsDtlsNotSrtpMode(WOLFSSL* ssl)
|
||||
{
|
||||
#ifdef WOLFSSL_SRTP
|
||||
return ssl->options.dtls && !ssl->dtlsSrtpProfiles;
|
||||
@@ -6691,6 +6691,8 @@ int ReinitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
|
||||
(void)ctx;
|
||||
|
||||
ssl->options.shutdownDone = 0;
|
||||
if (ssl->session != NULL)
|
||||
ssl->session->side = (byte)ssl->options.side;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -15663,8 +15665,6 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
|
||||
/* above checks handshake state */
|
||||
/* hello_request not hashed */
|
||||
/* Also, skip hashing the client_hello message here for DTLS. It will be
|
||||
* hashed later if the DTLS cookie is correct. */
|
||||
if (type != hello_request
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
&& ssl->error != WC_PENDING_E
|
||||
@@ -20125,7 +20125,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
||||
) {
|
||||
/* Shrink input buffer when we successfully finish record
|
||||
* processing */
|
||||
if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag)
|
||||
if ((ret == 0) && ssl->buffers.inputBuffer.dynamicFlag)
|
||||
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
|
||||
return ret;
|
||||
}
|
||||
@@ -20451,7 +20451,7 @@ static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
|
||||
#endif /* !NO_OLD_TLS && !WOLFSSL_AEAD_ONLY */
|
||||
|
||||
#if !defined(NO_MD5) && !defined(NO_OLD_TLS)
|
||||
static int BuildMD5_CertVerify(WOLFSSL* ssl, byte* digest)
|
||||
static int BuildMD5_CertVerify(const WOLFSSL* ssl, byte* digest)
|
||||
{
|
||||
int ret;
|
||||
byte md5_result[WC_MD5_DIGEST_SIZE];
|
||||
@@ -20495,7 +20495,7 @@ static int BuildMD5_CertVerify(WOLFSSL* ssl, byte* digest)
|
||||
|
||||
#if !defined(NO_SHA) && (!defined(NO_OLD_TLS) || \
|
||||
defined(WOLFSSL_ALLOW_TLS_SHA1))
|
||||
static int BuildSHA_CertVerify(WOLFSSL* ssl, byte* digest)
|
||||
static int BuildSHA_CertVerify(const WOLFSSL* ssl, byte* digest)
|
||||
{
|
||||
int ret;
|
||||
byte sha_result[WC_SHA_DIGEST_SIZE];
|
||||
@@ -20537,7 +20537,7 @@ static int BuildSHA_CertVerify(WOLFSSL* ssl, byte* digest)
|
||||
}
|
||||
#endif /* !NO_SHA && (!NO_OLD_TLS || WOLFSSL_ALLOW_TLS_SHA1) */
|
||||
|
||||
int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes)
|
||||
int BuildCertHashes(const WOLFSSL* ssl, Hashes* hashes)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -22879,7 +22879,11 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type)
|
||||
ssl->alert_history.last_tx.code = type;
|
||||
ssl->alert_history.last_tx.level = severity;
|
||||
if (severity == alert_fatal) {
|
||||
ssl->options.isClosed = 1; /* Don't send close_notify */
|
||||
#ifdef WOLFSSL_DTLS
|
||||
/* Mark as closed in dtls only once we enter stateful mode. */
|
||||
if (!ssl->options.dtls || ssl->options.dtlsStateful)
|
||||
#endif
|
||||
ssl->options.isClosed = 1; /* Don't send close_notify */
|
||||
}
|
||||
|
||||
/* send encrypted alert if encryption is on - can be a rehandshake over
|
||||
@@ -27040,17 +27044,13 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType,
|
||||
|
||||
|
||||
/* Make sure client setup is valid for this suite, true on success */
|
||||
int VerifyClientSuite(WOLFSSL* ssl)
|
||||
int VerifyClientSuite(word16 havePSK, byte cipherSuite0, byte cipherSuite)
|
||||
{
|
||||
#ifndef NO_PSK
|
||||
int havePSK = ssl->options.havePSK;
|
||||
#endif
|
||||
byte first = ssl->options.cipherSuite0;
|
||||
byte second = ssl->options.cipherSuite;
|
||||
(void)havePSK;
|
||||
|
||||
WOLFSSL_ENTER("VerifyClientSuite");
|
||||
|
||||
if (CipherRequires(first, second, REQUIRES_PSK)) {
|
||||
if (CipherRequires(cipherSuite0, cipherSuite, REQUIRES_PSK)) {
|
||||
WOLFSSL_MSG("Requires PSK");
|
||||
#ifndef NO_PSK
|
||||
if (havePSK == 0)
|
||||
@@ -30658,6 +30658,32 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
}
|
||||
#endif /* HAVE_ECC */
|
||||
|
||||
int TranslateErrorToAlert(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case BUFFER_ERROR:
|
||||
return decode_error;
|
||||
case EXT_NOT_ALLOWED:
|
||||
case PEER_KEY_ERROR:
|
||||
case ECC_PEERKEY_ERROR:
|
||||
case BAD_KEY_SHARE_DATA:
|
||||
case PSK_KEY_ERROR:
|
||||
case INVALID_PARAMETER:
|
||||
case HRR_COOKIE_ERROR:
|
||||
return illegal_parameter;
|
||||
break;
|
||||
case INCOMPLETE_DATA:
|
||||
return missing_extension;
|
||||
case MATCH_SUITE_ERROR:
|
||||
case MISSING_HANDSHAKE_DATA:
|
||||
return handshake_failure;
|
||||
case VERSION_ERROR:
|
||||
return wolfssl_alert_protocol_version;
|
||||
default:
|
||||
return invalid_alert;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
|
||||
@@ -32546,7 +32572,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
* Returns 1 for valid server suite or 0 if not found
|
||||
* For asynchronous this can return WC_PENDING_E
|
||||
*/
|
||||
static int VerifyServerSuite(WOLFSSL* ssl, const Suites* suites, word16 idx)
|
||||
static int VerifyServerSuite(const WOLFSSL* ssl, const Suites* suites,
|
||||
word16 idx, CipherSuite* cs, TLSX* extensions)
|
||||
{
|
||||
#ifndef NO_PSK
|
||||
int havePSK = ssl->options.havePSK;
|
||||
@@ -32554,6 +32581,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
byte first;
|
||||
byte second;
|
||||
|
||||
(void)cs;
|
||||
(void)extensions;
|
||||
|
||||
WOLFSSL_ENTER("VerifyServerSuite");
|
||||
|
||||
if (suites == NULL) {
|
||||
@@ -32630,7 +32660,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
|
||||
defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES)
|
||||
if (!TLSX_ValidateSupportedCurves(ssl, first, second)) {
|
||||
if (!TLSX_ValidateSupportedCurves(ssl, first, second,
|
||||
&cs->ecdhCurveOID)) {
|
||||
WOLFSSL_MSG("Don't have matching curves");
|
||||
return 0;
|
||||
}
|
||||
@@ -32640,25 +32671,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
if (IsAtLeastTLSv1_3(ssl->version) &&
|
||||
ssl->options.side == WOLFSSL_SERVER_END) {
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
int doHelloRetry = 0;
|
||||
/* Try to establish a key share. */
|
||||
int ret = TLSX_KeyShare_Establish(ssl, &doHelloRetry);
|
||||
byte searched = 0;
|
||||
int ret = TLSX_KeyShare_Choose(ssl, extensions, &cs->clientKSE,
|
||||
&searched);
|
||||
|
||||
if (ret == MEMORY_E) {
|
||||
WOLFSSL_MSG("TLSX_KeyShare_Establish() failed in "
|
||||
WOLFSSL_MSG("TLSX_KeyShare_Choose() failed in "
|
||||
"VerifyServerSuite() with MEMORY_E");
|
||||
return 0;
|
||||
}
|
||||
if (doHelloRetry) {
|
||||
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
|
||||
}
|
||||
if (cs->clientKSE == NULL && searched)
|
||||
cs->doHelloRetry = 1;
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (ret == WC_PENDING_E)
|
||||
return ret;
|
||||
#endif
|
||||
if (!doHelloRetry && ret != 0) {
|
||||
if (!cs->doHelloRetry && ret != 0)
|
||||
return 0; /* not found */
|
||||
}
|
||||
#endif /* HAVE_SUPPORTED_CURVES */
|
||||
}
|
||||
else if (first == TLS13_BYTE || (first == ECC_BYTE &&
|
||||
@@ -32672,26 +32701,22 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CompareSuites(WOLFSSL* ssl, const Suites* suites,
|
||||
Suites* peerSuites, word16 i, word16 j)
|
||||
static int CompareSuites(const WOLFSSL* ssl, const Suites* suites,
|
||||
Suites* peerSuites, word16 i, word16 j,
|
||||
CipherSuite* cs, TLSX* extensions)
|
||||
{
|
||||
if (suites->suites[i] == peerSuites->suites[j] &&
|
||||
suites->suites[i+1] == peerSuites->suites[j+1] ) {
|
||||
|
||||
int ret = VerifyServerSuite(ssl, suites, i);
|
||||
int ret = VerifyServerSuite(ssl, suites, i, cs, extensions);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (ret) {
|
||||
WOLFSSL_MSG("Verified suite validity");
|
||||
ssl->options.cipherSuite0 = suites->suites[i];
|
||||
ssl->options.cipherSuite = suites->suites[i+1];
|
||||
ret = SetCipherSpecs(ssl);
|
||||
if (ret == 0) {
|
||||
ret = PickHashSigAlgo(ssl, peerSuites->hashSigAlgo,
|
||||
peerSuites->hashSigAlgoSz);
|
||||
}
|
||||
return ret;
|
||||
cs->cipherSuite0 = suites->suites[i];
|
||||
cs->cipherSuite = suites->suites[i+1];
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Could not verify suite validity, continue");
|
||||
@@ -32701,7 +32726,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
return MATCH_SUITE_ERROR;
|
||||
}
|
||||
|
||||
int MatchSuite(WOLFSSL* ssl, Suites* peerSuites)
|
||||
int MatchSuite_ex(const WOLFSSL* ssl, Suites* peerSuites, CipherSuite* cs,
|
||||
TLSX* extensions)
|
||||
{
|
||||
int ret;
|
||||
word16 i, j;
|
||||
@@ -32720,7 +32746,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
/* Server order */
|
||||
for (i = 0; i < suites->suiteSz; i += 2) {
|
||||
for (j = 0; j < peerSuites->suiteSz; j += 2) {
|
||||
ret = CompareSuites(ssl, suites, peerSuites, i, j);
|
||||
ret = CompareSuites(ssl, suites, peerSuites, i, j, cs, extensions);
|
||||
if (ret != MATCH_SUITE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
@@ -32730,7 +32756,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
/* Client order */
|
||||
for (j = 0; j < peerSuites->suiteSz; j += 2) {
|
||||
for (i = 0; i < suites->suiteSz; i += 2) {
|
||||
ret = CompareSuites(ssl, suites, peerSuites, i, j);
|
||||
ret = CompareSuites(ssl, suites, peerSuites, i, j, cs, extensions);
|
||||
if (ret != MATCH_SUITE_ERROR)
|
||||
return ret;
|
||||
}
|
||||
@@ -32739,6 +32765,57 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
WOLFSSL_ERROR_VERBOSE(MATCH_SUITE_ERROR);
|
||||
return MATCH_SUITE_ERROR;
|
||||
|
||||
}
|
||||
|
||||
int MatchSuite(WOLFSSL* ssl, Suites* peerSuites)
|
||||
{
|
||||
int ret;
|
||||
CipherSuite cs;
|
||||
|
||||
XMEMSET(&cs, 0, sizeof(cs));
|
||||
|
||||
ret = MatchSuite_ex(ssl, peerSuites, &cs,
|
||||
#ifdef HAVE_TLS_EXTENSIONS
|
||||
ssl->extensions
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ssl->options.cipherSuite0 = cs.cipherSuite0;
|
||||
ssl->options.cipherSuite = cs.cipherSuite;
|
||||
#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_CURVE25519) || \
|
||||
defined(HAVE_ED448) || defined(HAVE_CURVE448)
|
||||
ssl->ecdhCurveOID = cs.ecdhCurveOID;
|
||||
#endif
|
||||
|
||||
ret = SetCipherSpecs(ssl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = PickHashSigAlgo(ssl, peerSuites->hashSigAlgo,
|
||||
peerSuites->hashSigAlgoSz);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
|
||||
if (cs.doHelloRetry) {
|
||||
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
|
||||
return TLSX_KeyShare_SetSupported(ssl, &ssl->extensions);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
|
||||
if (IsAtLeastTLSv1_3(ssl->version) &&
|
||||
ssl->options.side == WOLFSSL_SERVER_END) {
|
||||
ret = TLSX_KeyShare_Setup(ssl, cs.clientKSE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef OLD_HELLO_ALLOWED
|
||||
@@ -33107,28 +33184,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
/* do not change state in the SSL object before the next region of code
|
||||
* to be able to statelessly compute a DTLS cookie */
|
||||
#ifdef WOLFSSL_DTLS
|
||||
/* Update the ssl->options.dtlsStateful setting `if` statement in
|
||||
* wolfSSL_accept when changing this one. */
|
||||
if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) {
|
||||
byte process = 0;
|
||||
if (((ssl->keys.dtls_sequence_number_hi == ssl->keys.curSeq_hi &&
|
||||
ssl->keys.dtls_sequence_number_lo < ssl->keys.curSeq_lo) ||
|
||||
(ssl->keys.dtls_sequence_number_hi < ssl->keys.curSeq_hi))) {
|
||||
/* We should continue with the same sequence number as the
|
||||
* Client Hello if available. */
|
||||
ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi;
|
||||
ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo;
|
||||
}
|
||||
/* We should continue with the same handshake number as the
|
||||
* Client Hello. */
|
||||
ssl->keys.dtls_handshake_number =
|
||||
ssl->keys.dtls_peer_handshake_number;
|
||||
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz,
|
||||
&process);
|
||||
if (ret != 0 || !process) {
|
||||
DtlsSetSeqNumForReply(ssl);
|
||||
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
|
||||
if (ret != 0 || !ssl->options.dtlsStateful) {
|
||||
int alertType = TranslateErrorToAlert(ret);
|
||||
if (alertType != invalid_alert)
|
||||
SendAlert(ssl, alert_fatal, alertType);
|
||||
*inOutIdx += helloSz;
|
||||
DtlsResetState(ssl);
|
||||
if (DtlsIgnoreError(ret))
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ssl->options.dtlsStateful = 1;
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
/* protocol version, random and session id length check */
|
||||
@@ -34471,7 +34543,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
}
|
||||
|
||||
int DoDecryptTicket(WOLFSSL* ssl, const byte* input, word32 len,
|
||||
int DoDecryptTicket(const WOLFSSL* ssl, const byte* input, word32 len,
|
||||
InternalTicket **it)
|
||||
{
|
||||
ExternalTicket* et;
|
||||
@@ -34513,7 +34585,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
ret = WOLFSSL_TICKET_RET_REJECT;
|
||||
}
|
||||
else {
|
||||
ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv,
|
||||
/* Callback uses ssl without const but for DTLS, it really shouldn't
|
||||
* modify its state. */
|
||||
ret = ssl->ctx->ticketEncCb((WOLFSSL*)ssl, et->key_name, et->iv,
|
||||
et->enc_ticket + inLen, 0,
|
||||
et->enc_ticket, inLen, &outLen,
|
||||
ssl->ctx->ticketEncCtx);
|
||||
@@ -34538,142 +34612,271 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse ticket sent by client, returns callback return value */
|
||||
int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len)
|
||||
static int DoClientTicketCheckVersion(const WOLFSSL* ssl,
|
||||
InternalTicket* it)
|
||||
{
|
||||
InternalTicket* it;
|
||||
int ret;
|
||||
if (ssl->version.minor < it->pv.minor) {
|
||||
WOLFSSL_MSG("Ticket has greater version");
|
||||
return VERSION_ERROR;
|
||||
}
|
||||
else if (ssl->version.minor > it->pv.minor) {
|
||||
if (IsAtLeastTLSv1_3(it->pv) != IsAtLeastTLSv1_3(ssl->version)) {
|
||||
WOLFSSL_MSG("Tickets cannot be shared between "
|
||||
"TLS 1.3 and TLS 1.2 and lower");
|
||||
return VERSION_ERROR;
|
||||
}
|
||||
|
||||
if (!ssl->options.downgrade) {
|
||||
WOLFSSL_MSG("Ticket has lesser version");
|
||||
return VERSION_ERROR;
|
||||
}
|
||||
|
||||
WOLFSSL_MSG("Downgrading protocol due to ticket");
|
||||
|
||||
if (it->pv.minor < ssl->options.minDowngrade) {
|
||||
WOLFSSL_MSG("Ticket has lesser version than allowed");
|
||||
return VERSION_ERROR;
|
||||
}
|
||||
}
|
||||
/* Check resumption master secret. */
|
||||
if (IsAtLeastTLSv1_3(it->pv) &&
|
||||
it->ticketNonceLen > MAX_TICKET_NONCE_STATIC_SZ) {
|
||||
WOLFSSL_MSG("Unsupported ticketNonce len in ticket");
|
||||
return BAD_TICKET_ENCRYPT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 0 when check successful. <0 on failure. */
|
||||
int DoClientTicketCheck(const WOLFSSL* ssl, const PreSharedKey* psk,
|
||||
sword64 timeout, const byte* suite)
|
||||
{
|
||||
word32 ticketAdd;
|
||||
#ifdef WOLFSSL_32BIT_MILLI_TIME
|
||||
word32 now;
|
||||
sword64 diff;
|
||||
word32 ticketSeen; /* Time ticket seen (ms) */
|
||||
|
||||
ato32(psk->it->timestamp, &ticketSeen);
|
||||
|
||||
now = TimeNowInMilliseconds();
|
||||
if (now == 0)
|
||||
return GETTIME_ERROR;
|
||||
/* Difference between now and time ticket constructed
|
||||
* (from decrypted ticket). */
|
||||
diff = now;
|
||||
diff -= ticketSeen;
|
||||
if (diff > timeout * 1000 ||
|
||||
diff > (sword64)TLS13_MAX_TICKET_AGE * 1000)
|
||||
return -1;
|
||||
#else
|
||||
sword64 diff;
|
||||
sword64 ticketSeen; /* Time ticket seen (ms) */
|
||||
word32 seenHi, seenLo;
|
||||
|
||||
ato32(psk->it->timestamp , &seenHi);
|
||||
ato32(psk->it->timestamp + OPAQUE32_LEN, &seenLo);
|
||||
ticketSeen = ((sword64)seenHi << 32) + seenLo;
|
||||
|
||||
diff = TimeNowInMilliseconds();
|
||||
if (diff == 0)
|
||||
return GETTIME_ERROR;
|
||||
/* Difference between now and time ticket constructed
|
||||
* (from decrypted ticket). */
|
||||
diff -= ticketSeen;
|
||||
if (diff > timeout * 1000 ||
|
||||
diff > (sword64)TLS13_MAX_TICKET_AGE * 1000)
|
||||
return -1;
|
||||
#endif
|
||||
ato32(psk->it->ageAdd, &ticketAdd);
|
||||
/* Subtract client's ticket age and unobfuscate. */
|
||||
diff -= psk->ticketAge;
|
||||
diff += ticketAdd;
|
||||
/* Check session and ticket age timeout.
|
||||
* Allow +/- 1000 milliseconds on ticket age.
|
||||
*/
|
||||
if (diff < -1000 || diff - MAX_TICKET_AGE_DIFF * 1000 > 1000)
|
||||
return -1;
|
||||
|
||||
#if !defined(WOLFSSL_PSK_ONE_ID) && !defined(WOLFSSL_PRIORITIZE_PSK)
|
||||
/* Check whether resumption is possible based on suites in SSL and
|
||||
* ciphersuite in ticket.
|
||||
*/
|
||||
(void)ssl;
|
||||
if (XMEMCMP(suite, psk->it->suite, SUITE_LEN) != 0)
|
||||
return -1;
|
||||
#else
|
||||
(void)suite;
|
||||
if (!FindSuiteSSL(ssl, psk->it->suite))
|
||||
return -1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoClientTicketFinalize(WOLFSSL* ssl, InternalTicket* it)
|
||||
{
|
||||
#ifdef WOLFSSL_TICKET_HAVE_ID
|
||||
ssl->session->haveAltSessionID = 1;
|
||||
XMEMCPY(ssl->session->altSessionID, it->id, ID_LEN);
|
||||
if (wolfSSL_GetSession(ssl, NULL, 1) != NULL) {
|
||||
WOLFSSL_MSG("Found session matching the session id"
|
||||
" found in the ticket");
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Can't find session matching the session id"
|
||||
" found in the ticket");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!IsAtLeastTLSv1_3(ssl->version)) {
|
||||
XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN);
|
||||
/* Copy the haveExtendedMasterSecret property from the ticket to
|
||||
* the saved session, so the property may be checked later. */
|
||||
ssl->session->haveEMS = it->haveEMS;
|
||||
ato32((const byte*)&it->timestamp, &ssl->session->bornOn);
|
||||
#ifndef NO_RESUME_SUITE_CHECK
|
||||
ssl->session->cipherSuite0 = it->suite[0];
|
||||
ssl->session->cipherSuite = it->suite[1];
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef WOLFSSL_TLS13
|
||||
/* This should have been already checked in
|
||||
* DoClientTicketCheckVersion */
|
||||
if (it->ticketNonceLen > MAX_TICKET_NONCE_STATIC_SZ) {
|
||||
WOLFSSL_MSG("Unsupported ticketNonce len in ticket");
|
||||
return;
|
||||
}
|
||||
/* Restore information to renegotiate. */
|
||||
#ifdef WOLFSSL_32BIT_MILLI_TIME
|
||||
ato32(it->timestamp, &ssl->session->ticketSeen);
|
||||
#else
|
||||
word32 seenHi, seenLo;
|
||||
|
||||
ato32(it->timestamp , &seenHi);
|
||||
ato32(it->timestamp + OPAQUE32_LEN, &seenLo);
|
||||
ssl->session->ticketSeen = ((sword64)seenHi << 32) + seenLo;
|
||||
#endif
|
||||
ato32(it->ageAdd, &ssl->session->ticketAdd);
|
||||
ssl->session->cipherSuite0 = it->suite[0];
|
||||
ssl->session->cipherSuite = it->suite[1];
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
ato32(it->maxEarlyDataSz, &ssl->session->maxEarlyDataSz);
|
||||
#endif
|
||||
/* Resumption master secret. */
|
||||
XMEMCPY(ssl->session->masterSecret, it->msecret, SECRET_LEN);
|
||||
#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \
|
||||
(!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
|
||||
if (ssl->session->ticketNonce.data
|
||||
!= ssl->session->ticketNonce.dataStatic) {
|
||||
XFREE(ssl->session->ticketNonce.data, ssl->heap,
|
||||
DYNAMIC_TYPE_SESSION_TICK);
|
||||
ssl->session->ticketNonce.data =
|
||||
ssl->session->ticketNonce.dataStatic;
|
||||
}
|
||||
#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */
|
||||
XMEMCPY(ssl->session->ticketNonce.data, it->ticketNonce,
|
||||
it->ticketNonceLen);
|
||||
ssl->session->ticketNonce.len = it->ticketNonceLen;
|
||||
ato16(it->namedGroup, &ssl->session->namedGroup);
|
||||
#endif
|
||||
}
|
||||
ssl->version.minor = it->pv.minor;
|
||||
}
|
||||
|
||||
/* Parse ticket sent by client, returns callback return value. Doesn't
|
||||
* modify ssl and stores the InternalTicket inside psk */
|
||||
int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk)
|
||||
{
|
||||
int decryptRet;
|
||||
int ret;
|
||||
|
||||
WOLFSSL_START(WC_FUNC_TICKET_DO);
|
||||
WOLFSSL_ENTER("DoClientTicket");
|
||||
WOLFSSL_ENTER("DoClientTicket_ex");
|
||||
|
||||
ret = DoDecryptTicket(ssl, input, len, &it);
|
||||
if (ret != WOLFSSL_TICKET_RET_OK && ret != WOLFSSL_TICKET_RET_CREATE) {
|
||||
WOLFSSL_LEAVE("DoClientTicket", ret);
|
||||
return ret;
|
||||
decryptRet = DoDecryptTicket(ssl, psk->identity, psk->identityLen,
|
||||
&psk->it);
|
||||
switch (decryptRet) {
|
||||
case WOLFSSL_TICKET_RET_OK:
|
||||
psk->decryptRet = PSK_DECRYPT_OK;
|
||||
break;
|
||||
case WOLFSSL_TICKET_RET_CREATE:
|
||||
psk->decryptRet = PSK_DECRYPT_CREATE;
|
||||
break;
|
||||
default:
|
||||
psk->decryptRet = PSK_DECRYPT_FAIL;
|
||||
return decryptRet;
|
||||
}
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
/* Internal ticket successfully decrypted. */
|
||||
wc_MemZero_Add("Do Client Ticket internal", it, sizeof(InternalTicket));
|
||||
#endif
|
||||
|
||||
/* get master secret */
|
||||
if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) {
|
||||
if (ssl->version.minor < it->pv.minor) {
|
||||
WOLFSSL_MSG("Ticket has greater version");
|
||||
ret = VERSION_ERROR;
|
||||
goto error;
|
||||
}
|
||||
else if (ssl->version.minor > it->pv.minor) {
|
||||
if (IsAtLeastTLSv1_3(it->pv) != IsAtLeastTLSv1_3(ssl->version)) {
|
||||
WOLFSSL_MSG("Tickets cannot be shared between "
|
||||
"TLS 1.3 and TLS 1.2 and lower");
|
||||
ret = VERSION_ERROR;
|
||||
goto error;
|
||||
}
|
||||
ret = DoClientTicketCheckVersion(ssl, psk->it);
|
||||
if (ret != 0) {
|
||||
psk->decryptRet = PSK_DECRYPT_FAIL;
|
||||
ForceZero(psk->identity, psk->identityLen);
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
wc_MemZero_Check(psk->it, sizeof(InternalTicket));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
return decryptRet;
|
||||
}
|
||||
|
||||
if (!ssl->options.downgrade) {
|
||||
WOLFSSL_MSG("Ticket has lesser version");
|
||||
ret = VERSION_ERROR;
|
||||
goto error;
|
||||
}
|
||||
/* Parse ticket sent by client, returns callback return value */
|
||||
int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len)
|
||||
{
|
||||
int decryptRet;
|
||||
int ret;
|
||||
InternalTicket* it
|
||||
|
||||
WOLFSSL_MSG("Downgrading protocol due to ticket");
|
||||
WOLFSSL_START(WC_FUNC_TICKET_DO);
|
||||
WOLFSSL_ENTER("DoClientTicket");
|
||||
|
||||
if (it->pv.minor < ssl->options.minDowngrade) {
|
||||
WOLFSSL_MSG("Ticket has lesser version than allowed");
|
||||
ret = VERSION_ERROR;
|
||||
goto error;
|
||||
}
|
||||
ssl->version.minor = it->pv.minor;
|
||||
}
|
||||
decryptRet = DoDecryptTicket(ssl, input, len, &it);
|
||||
if (decryptRet != WOLFSSL_TICKET_RET_OK &&
|
||||
decryptRet != WOLFSSL_TICKET_RET_CREATE)
|
||||
return decryptRet;
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
/* Internal ticket successfully decrypted. */
|
||||
wc_MemZero_Add("Do Client Ticket internal", it, sizeof(InternalTicket));
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_TICKET_HAVE_ID
|
||||
{
|
||||
ssl->session->haveAltSessionID = 1;
|
||||
XMEMCPY(ssl->session->altSessionID, it->id, ID_LEN);
|
||||
if (wolfSSL_GetSession(ssl, NULL, 1) != NULL) {
|
||||
WOLFSSL_MSG("Found session matching the session id"
|
||||
" found in the ticket");
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Can't find session matching the session id"
|
||||
" found in the ticket");
|
||||
}
|
||||
}
|
||||
ret = DoClientTicketCheckVersion(ssl, it);
|
||||
if (ret != 0) {
|
||||
ForceZero(it, sizeof(*it));
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
wc_MemZero_Check(it, sizeof(InternalTicket));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
DoClientTicketFinalize(ssl, it);
|
||||
|
||||
ForceZero(it, sizeof(*it));
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
wc_MemZero_Check(it, sizeof(InternalTicket));
|
||||
#endif
|
||||
|
||||
if (!IsAtLeastTLSv1_3(ssl->version)) {
|
||||
XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN);
|
||||
/* Copy the haveExtendedMasterSecret property from the ticket to
|
||||
* the saved session, so the property may be checked later. */
|
||||
ssl->session->haveEMS = it->haveEMS;
|
||||
ato32((const byte*)&it->timestamp, &ssl->session->bornOn);
|
||||
#ifndef NO_RESUME_SUITE_CHECK
|
||||
ssl->session->cipherSuite0 = it->suite[0];
|
||||
ssl->session->cipherSuite = it->suite[1];
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef WOLFSSL_TLS13
|
||||
/* Restore information to renegotiate. */
|
||||
#ifdef WOLFSSL_32BIT_MILLI_TIME
|
||||
ato32(it->timestamp, &ssl->session->ticketSeen);
|
||||
#else
|
||||
word32 seenHi, seenLo;
|
||||
return decryptRet;
|
||||
}
|
||||
|
||||
ato32(it->timestamp , &seenHi);
|
||||
ato32(it->timestamp + OPAQUE32_LEN, &seenLo);
|
||||
ssl->session->ticketSeen = ((sword64)seenHi << 32) + seenLo;
|
||||
#endif
|
||||
ato32(it->ageAdd, &ssl->session->ticketAdd);
|
||||
ssl->session->cipherSuite0 = it->suite[0];
|
||||
ssl->session->cipherSuite = it->suite[1];
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
ato32(it->maxEarlyDataSz, &ssl->session->maxEarlyDataSz);
|
||||
#endif
|
||||
/* Resumption master secret. */
|
||||
XMEMCPY(ssl->session->masterSecret, it->msecret, SECRET_LEN);
|
||||
if (it->ticketNonceLen > MAX_TICKET_NONCE_STATIC_SZ) {
|
||||
WOLFSSL_MSG("Unsupported ticketNonce len in ticket");
|
||||
WOLFSSL_LEAVE("DoClientTicket", BAD_TICKET_ENCRYPT);
|
||||
return BAD_TICKET_ENCRYPT;
|
||||
}
|
||||
#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \
|
||||
(!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
|
||||
if (ssl->session->ticketNonce.data
|
||||
!= ssl->session->ticketNonce.dataStatic) {
|
||||
XFREE(ssl->session->ticketNonce.data, ssl->heap,
|
||||
DYNAMIC_TYPE_SESSION_TICK);
|
||||
ssl->session->ticketNonce.data =
|
||||
ssl->session->ticketNonce.dataStatic;
|
||||
}
|
||||
#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */
|
||||
XMEMCPY(ssl->session->ticketNonce.data, it->ticketNonce,
|
||||
it->ticketNonceLen);
|
||||
ssl->session->ticketNonce.len = it->ticketNonceLen;
|
||||
ato16(it->namedGroup, &ssl->session->namedGroup);
|
||||
void CleanupClientTickets(PreSharedKey* psk)
|
||||
{
|
||||
for (; psk != NULL; psk = psk->next) {
|
||||
if (psk->decryptRet == PSK_DECRYPT_OK ||
|
||||
psk->decryptRet == PSK_DECRYPT_CREATE) {
|
||||
psk->decryptRet = PSK_DECRYPT_NONE;
|
||||
ForceZero(psk->identity, psk->identityLen);
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
/* We want to check the InternalTicket area since that is what
|
||||
* we registered in DoClientTicket_ex */
|
||||
wc_MemZero_Check((((ExternalTicket*)psk->identity)->enc_ticket),
|
||||
sizeof(InternalTicket));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ForceZero(it, sizeof(*it));
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
wc_MemZero_Check(it, sizeof(InternalTicket));
|
||||
#endif
|
||||
|
||||
WOLFSSL_LEAVE("DoClientTicket", ret);
|
||||
WOLFSSL_END(WC_FUNC_TICKET_DO);
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
ForceZero(it, sizeof(*it));
|
||||
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||
wc_MemZero_Check(it, sizeof(InternalTicket));
|
||||
#endif
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
return WOLFSSL_TICKET_RET_REJECT;
|
||||
}
|
||||
|
||||
|
||||
@@ -35391,7 +35594,6 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
|
||||
}
|
||||
|
||||
ssl->buffers.outputBuffer.length += sendSz;
|
||||
DtlsResetState(ssl);
|
||||
|
||||
return SendBuffered(ssl);
|
||||
}
|
||||
|
2739
src/keys.c
2739
src/keys.c
File diff suppressed because it is too large
Load Diff
10
src/ssl.c
10
src/ssl.c
@@ -13288,6 +13288,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
|
||||
ssl->options.dtls = 1;
|
||||
ssl->options.tls = 1;
|
||||
ssl->options.tls1_1 = 1;
|
||||
ssl->options.dtlsStateful = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13837,6 +13838,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
|
||||
ssl->options.dtls = 1;
|
||||
ssl->options.tls = 1;
|
||||
ssl->options.tls1_1 = 1;
|
||||
if (!IsDtlsNotSctpMode(ssl) || !IsDtlsNotSrtpMode(ssl) ||
|
||||
IsSCR(ssl))
|
||||
ssl->options.dtlsStateful = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15031,8 +15035,8 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
|
||||
}
|
||||
else {
|
||||
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL)
|
||||
WOLFSSL_MSG("Session is expired but return success for \
|
||||
OpenSSL compatibility");
|
||||
WOLFSSL_MSG("Session is expired but return success for "
|
||||
"OpenSSL compatibility");
|
||||
ret = WOLFSSL_SUCCESS;
|
||||
#else
|
||||
ret = WOLFSSL_FAILURE; /* session timed out */
|
||||
@@ -35408,7 +35412,7 @@ void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, const unsigned char **
|
||||
#endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */
|
||||
|
||||
#ifdef OPENSSL_EXTRA
|
||||
int wolfSSL_curve_is_disabled(WOLFSSL* ssl, word16 curve_id)
|
||||
int wolfSSL_curve_is_disabled(const WOLFSSL* ssl, word16 curve_id)
|
||||
{
|
||||
return (curve_id <= WOLFSSL_ECC_MAX &&
|
||||
ssl->disabledCurves &&
|
||||
|
585
src/tls13.c
585
src/tls13.c
@@ -3242,14 +3242,14 @@ exit_buildmsg:
|
||||
|
||||
#if !defined(NO_WOLFSSL_CLIENT) || (!defined(NO_WOLFSSL_SERVER) && \
|
||||
(defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
|
||||
defined(WOLFSSL_PSK_ONE_ID)) \
|
||||
(defined(WOLFSSL_PSK_ONE_ID) || defined(WOLFSSL_PRIORITIZE_PSK)))
|
||||
/* Find the cipher suite in the suites set in the SSL.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* suite Cipher suite to look for.
|
||||
* returns 1 when suite is found in SSL/TLS object's list and 0 otherwise.
|
||||
*/
|
||||
static int FindSuiteSSL(const WOLFSSL* ssl, byte* suite)
|
||||
int FindSuiteSSL(const WOLFSSL* ssl, byte* suite)
|
||||
{
|
||||
word16 i;
|
||||
const Suites* suites = WOLFSSL_SUITES(ssl);
|
||||
@@ -3337,13 +3337,34 @@ byte SuiteMac(const byte* suite)
|
||||
* hashSz The size of the hash data in bytes.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
int CreateCookieExt(const WOLFSSL* ssl, byte* hash, word16 hashSz,
|
||||
TLSX** exts, byte cipherSuite0, byte cipherSuite)
|
||||
{
|
||||
int ret;
|
||||
byte mac[WC_MAX_DIGEST_SIZE] = {0};
|
||||
Hmac cookieHmac;
|
||||
byte cookieType = 0;
|
||||
byte macSz = 0;
|
||||
byte cookie[OPAQUE8_LEN + WC_MAX_DIGEST_SIZE + OPAQUE16_LEN * 2];
|
||||
TLSX* ext;
|
||||
word16 cookieSz = 0;
|
||||
|
||||
/* Cookie Data = Hash Len | Hash | CS | KeyShare Group */
|
||||
cookie[cookieSz++] = (byte)hashSz;
|
||||
XMEMCPY(cookie + cookieSz, hash, hashSz);
|
||||
cookieSz += hashSz;
|
||||
cookie[cookieSz++] = cipherSuite0;
|
||||
cookie[cookieSz++] = cipherSuite;
|
||||
if ((ext = TLSX_Find(*exts, TLSX_KEY_SHARE)) != NULL) {
|
||||
KeyShareEntry* kse = (KeyShareEntry*)ext->data;
|
||||
if (kse == NULL) {
|
||||
WOLFSSL_MSG("KeyShareEntry can't be empty when negotiating "
|
||||
"parameters");
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
c16toa(kse->group, cookie + cookieSz);
|
||||
cookieSz += OPAQUE16_LEN;
|
||||
}
|
||||
|
||||
#if !defined(NO_SHA) && defined(NO_SHA256)
|
||||
cookieType = SHA;
|
||||
@@ -3361,7 +3382,7 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
ssl->buffers.tls13CookieSecret.length);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = wc_HmacUpdate(&cookieHmac, hash, hashSz);
|
||||
ret = wc_HmacUpdate(&cookieHmac, cookie, cookieSz);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* Tie cookie to peer address */
|
||||
if (ret == 0) {
|
||||
@@ -3380,7 +3401,7 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
return ret;
|
||||
|
||||
/* The cookie data is the hash and the integrity check. */
|
||||
return TLSX_Cookie_Use(ssl, hash, hashSz, mac, macSz, 1);
|
||||
return TLSX_Cookie_Use(ssl, cookie, cookieSz, mac, macSz, 1, exts);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3390,6 +3411,45 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
#define HRR_MAX_HS_HEADER_SZ HANDSHAKE_HEADER_SZ
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
static int CreateCookie(const WOLFSSL* ssl, byte** hash, byte* hashSz,
|
||||
Hashes* hashes, TLSX** exts)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
(void)exts;
|
||||
|
||||
*hash = NULL;
|
||||
switch (ssl->specs.mac_algorithm) {
|
||||
#ifndef NO_SHA256
|
||||
case sha256_mac:
|
||||
*hash = hashes->sha256;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA384
|
||||
case sha384_mac:
|
||||
*hash = hashes->sha384;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_TLS13_SHA512
|
||||
case sha512_mac:
|
||||
*hash = hashes->sha512;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
*hashSz = ssl->specs.hash_size;
|
||||
|
||||
/* check hash */
|
||||
if (*hash == NULL && *hashSz > 0)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
|
||||
if (ssl->options.sendCookie && ssl->options.side == WOLFSSL_SERVER_END)
|
||||
ret = CreateCookieExt(ssl, *hash, *hashSz, exts,
|
||||
ssl->options.cipherSuite0, ssl->options.cipherSuite);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Restart the handshake hash with a hash of the previous messages.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
@@ -3398,36 +3458,21 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
Hashes hashes;
|
||||
byte header[HANDSHAKE_HEADER_SZ] = {0};
|
||||
Hashes hashes;
|
||||
byte* hash = NULL;
|
||||
byte hashSz = 0;
|
||||
|
||||
ret = BuildCertHashes(ssl, &hashes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
switch (ssl->specs.mac_algorithm) {
|
||||
#ifndef NO_SHA256
|
||||
case sha256_mac:
|
||||
hash = hashes.sha256;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA384
|
||||
case sha384_mac:
|
||||
hash = hashes.sha384;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_TLS13_SHA512
|
||||
case sha512_mac:
|
||||
hash = hashes.sha512;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
hashSz = ssl->specs.hash_size;
|
||||
|
||||
/* check hash */
|
||||
if (hash == NULL && hashSz > 0)
|
||||
return BAD_FUNC_ARG;
|
||||
ret = CreateCookie(ssl, &hash, &hashSz, &hashes, &ssl->extensions);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
|
||||
if (ssl->options.sendCookie && ssl->options.side == WOLFSSL_SERVER_END)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl);
|
||||
|
||||
@@ -3436,28 +3481,6 @@ int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
WOLFSSL_BUFFER(hash, hashSz);
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
|
||||
if (ssl->options.sendCookie && ssl->options.side == WOLFSSL_SERVER_END) {
|
||||
byte cookie[OPAQUE8_LEN + WC_MAX_DIGEST_SIZE + OPAQUE16_LEN * 2];
|
||||
TLSX* ext;
|
||||
word32 idx = 0;
|
||||
|
||||
/* Cookie Data = Hash Len | Hash | CS | KeyShare Group */
|
||||
cookie[idx++] = hashSz;
|
||||
if (hash)
|
||||
XMEMCPY(cookie + idx, hash, hashSz);
|
||||
idx += hashSz;
|
||||
cookie[idx++] = ssl->options.cipherSuite0;
|
||||
cookie[idx++] = ssl->options.cipherSuite;
|
||||
if ((ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE)) != NULL) {
|
||||
KeyShareEntry* kse = (KeyShareEntry*)ext->data;
|
||||
c16toa(kse->group, cookie + idx);
|
||||
idx += OPAQUE16_LEN;
|
||||
}
|
||||
return CreateCookie(ssl, cookie, idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = InitHandshakeHashes(ssl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
@@ -4381,10 +4404,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
|
||||
if (ssl->options.dtls) {
|
||||
ret = Dtls13HandshakeSend(ssl, args->output, (word16)args->sendSz,
|
||||
(word16)args->idx, client_hello, 0);
|
||||
|
||||
WOLFSSL_LEAVE("SendTls13ClientHello", ret);
|
||||
WOLFSSL_END(WC_FUNC_CLIENT_HELLO_SEND);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
@@ -5472,6 +5492,65 @@ static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites)
|
||||
|
||||
|
||||
#ifndef NO_PSK
|
||||
int FindPskSuite(const WOLFSSL* ssl, PreSharedKey* psk, byte* psk_key,
|
||||
word32* psk_keySz, const byte* suite, int* found, byte* foundSuite)
|
||||
{
|
||||
const char* cipherName = NULL;
|
||||
byte cipherSuite0 = TLS13_BYTE;
|
||||
byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
|
||||
int ret = 0;
|
||||
|
||||
*found = 0;
|
||||
(void)suite;
|
||||
|
||||
if (ssl->options.server_psk_tls13_cb != NULL) {
|
||||
*psk_keySz = ssl->options.server_psk_tls13_cb((WOLFSSL*)ssl,
|
||||
(char*)psk->identity, psk_key, MAX_PSK_KEY_LEN, &cipherName);
|
||||
if (*psk_keySz != 0) {
|
||||
int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE;
|
||||
*found = (GetCipherSuiteFromName(cipherName, &cipherSuite0,
|
||||
&cipherSuite, &cipherSuiteFlags) == 0);
|
||||
(void)cipherSuiteFlags;
|
||||
}
|
||||
}
|
||||
if (*found == 0 && (ssl->options.server_psk_cb != NULL)) {
|
||||
*psk_keySz = ssl->options.server_psk_cb((WOLFSSL*)ssl,
|
||||
(char*)psk->identity, psk_key,
|
||||
MAX_PSK_KEY_LEN);
|
||||
*found = (*psk_keySz != 0);
|
||||
}
|
||||
if (*found) {
|
||||
if (*psk_keySz > MAX_PSK_KEY_LEN) {
|
||||
WOLFSSL_MSG("Key len too long in FindPsk()");
|
||||
ret = PSK_KEY_ERROR;
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
*found = 0;
|
||||
}
|
||||
if (ret == 0) {
|
||||
#if !defined(WOLFSSL_PSK_ONE_ID) && !defined(WOLFSSL_PRIORITIZE_PSK)
|
||||
/* Check whether PSK ciphersuite is in SSL. */
|
||||
*found = (suite[0] == cipherSuite0) && (suite[1] == cipherSuite);
|
||||
#else
|
||||
(void)suite;
|
||||
/* Check whether PSK ciphersuite is in SSL. */
|
||||
{
|
||||
byte s[2] = {
|
||||
cipherSuite0,
|
||||
cipherSuite,
|
||||
};
|
||||
*found = FindSuiteSSL(ssl, s);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (*found && foundSuite != NULL) {
|
||||
foundSuite[0] = cipherSuite0;
|
||||
foundSuite[1] = cipherSuite;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Attempt to find the PSK (not session ticket) that matches.
|
||||
*
|
||||
* @param [in, out] ssl The SSL/TLS object.
|
||||
@@ -5489,51 +5568,11 @@ static int FindPsk(WOLFSSL* ssl, PreSharedKey* psk, const byte* suite, int* err)
|
||||
{
|
||||
int ret = 0;
|
||||
int found = 0;
|
||||
const char* cipherName = NULL;
|
||||
byte cipherSuite0 = TLS13_BYTE;
|
||||
byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
|
||||
Arrays* sa = ssl->arrays;
|
||||
byte foundSuite[SUITE_LEN];
|
||||
|
||||
(void)suite;
|
||||
|
||||
if (ssl->options.server_psk_tls13_cb != NULL) {
|
||||
sa->psk_keySz = ssl->options.server_psk_tls13_cb(ssl,
|
||||
sa->client_identity, sa->psk_key, MAX_PSK_KEY_LEN, &cipherName);
|
||||
if (sa->psk_keySz != 0) {
|
||||
int cipherSuiteFlags = WOLFSSL_CIPHER_SUITE_FLAG_NONE;
|
||||
found = (GetCipherSuiteFromName(cipherName, &cipherSuite0,
|
||||
&cipherSuite, &cipherSuiteFlags) == 0);
|
||||
(void)cipherSuiteFlags;
|
||||
}
|
||||
}
|
||||
if (!found && (ssl->options.server_psk_cb != NULL)) {
|
||||
sa->psk_keySz = ssl->options.server_psk_cb(ssl,
|
||||
sa->client_identity, sa->psk_key,
|
||||
MAX_PSK_KEY_LEN);
|
||||
found = (sa->psk_keySz != 0);
|
||||
}
|
||||
if (found) {
|
||||
if (sa->psk_keySz > MAX_PSK_KEY_LEN) {
|
||||
WOLFSSL_MSG("Key len too long in FindPsk");
|
||||
ret = PSK_KEY_ERROR;
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
}
|
||||
if (ret == 0) {
|
||||
#if !defined(WOLFSSL_PSK_ONE_ID) && !defined(WOLFSSL_PRIORITIZE_PSK)
|
||||
/* Check whether PSK ciphersuite is in SSL. */
|
||||
found = (suite[0] == cipherSuite0) && (suite[1] == cipherSuite);
|
||||
#else
|
||||
(void)suite;
|
||||
/* Check whether PSK ciphersuite is in SSL. */
|
||||
{
|
||||
byte s[2] = {
|
||||
cipherSuite0,
|
||||
cipherSuite,
|
||||
};
|
||||
found = FindSuiteSSL(ssl, s);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ret = FindPskSuite(ssl, psk, ssl->arrays->psk_key, &ssl->arrays->psk_keySz,
|
||||
suite, &found, foundSuite);
|
||||
if (ret == 0 && found) {
|
||||
if ((ret == 0) && found) {
|
||||
/* Default to ciphersuite if cb doesn't specify. */
|
||||
ssl->options.resuming = 0;
|
||||
@@ -5548,8 +5587,8 @@ static int FindPsk(WOLFSSL* ssl, PreSharedKey* psk, const byte* suite, int* err)
|
||||
}
|
||||
if ((ret == 0) && found) {
|
||||
/* Set PSK ciphersuite into SSL. */
|
||||
ssl->options.cipherSuite0 = cipherSuite0;
|
||||
ssl->options.cipherSuite = cipherSuite;
|
||||
ssl->options.cipherSuite0 = foundSuite[0];
|
||||
ssl->options.cipherSuite = foundSuite[1];
|
||||
ret = SetCipherSpecs(ssl);
|
||||
}
|
||||
if ((ret == 0) && found) {
|
||||
@@ -5616,68 +5655,31 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz,
|
||||
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
/* Decode the identity. */
|
||||
ret = DoClientTicket(ssl, current->identity, current->identityLen);
|
||||
switch (current->decryptRet) {
|
||||
case PSK_DECRYPT_NONE:
|
||||
ret = DoClientTicket_ex(ssl, current);
|
||||
break;
|
||||
case PSK_DECRYPT_OK:
|
||||
ret = WOLFSSL_TICKET_RET_OK;
|
||||
break;
|
||||
case PSK_DECRYPT_CREATE:
|
||||
ret = WOLFSSL_TICKET_RET_CREATE;
|
||||
break;
|
||||
case PSK_DECRYPT_FAIL:
|
||||
ret = WOLFSSL_TICKET_RET_REJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (ret == WC_PENDING_E)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
if (ret == WOLFSSL_TICKET_RET_OK) {
|
||||
#ifdef WOLFSSL_32BIT_MILLI_TIME
|
||||
word32 now;
|
||||
sword64 diff;
|
||||
|
||||
now = TimeNowInMilliseconds();
|
||||
if (now == 0)
|
||||
return GETTIME_ERROR;
|
||||
/* Difference between now and time ticket constructed
|
||||
* (from decrypted ticket). */
|
||||
diff = now;
|
||||
diff -= ssl->session->ticketSeen;
|
||||
if (diff > (sword64)ssl->timeout * 1000 ||
|
||||
diff > (sword64)TLS13_MAX_TICKET_AGE * 1000) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
sword64 diff;
|
||||
|
||||
diff = TimeNowInMilliseconds();
|
||||
if (diff == 0)
|
||||
return GETTIME_ERROR;
|
||||
/* Difference between now and time ticket constructed
|
||||
* (from decrypted ticket). */
|
||||
diff -= ssl->session->ticketSeen;
|
||||
if (diff > (sword64)ssl->timeout * 1000 ||
|
||||
diff > (sword64)TLS13_MAX_TICKET_AGE * 1000) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* Subtract client's ticket age and unobfuscate. */
|
||||
diff -= current->ticketAge;
|
||||
diff += ssl->session->ticketAdd;
|
||||
/* Check session and ticket age timeout.
|
||||
* Allow +/- 1000 milliseconds on ticket age.
|
||||
*/
|
||||
if (diff < -1000 || diff - MAX_TICKET_AGE_DIFF * 1000 > 1000)
|
||||
if (DoClientTicketCheck(ssl, current, ssl->timeout, suite) != 0)
|
||||
continue;
|
||||
|
||||
#if !defined(WOLFSSL_PSK_ONE_ID) && !defined(WOLFSSL_PRIORITIZE_PSK)
|
||||
/* Check whether resumption is possible based on suites in SSL and
|
||||
* ciphersuite in ticket.
|
||||
*/
|
||||
if ((suite[0] != ssl->session->cipherSuite0) ||
|
||||
(suite[1] != ssl->session->cipherSuite))
|
||||
continue;
|
||||
#else
|
||||
{
|
||||
byte s[2] = {
|
||||
ssl->session->cipherSuite0,
|
||||
ssl->session->cipherSuite,
|
||||
};
|
||||
if (!FindSuiteSSL(ssl, s))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
DoClientTicketFinalize(ssl, current->it);
|
||||
|
||||
/* SERVER: using secret in session ticket for peer auth. */
|
||||
ssl->options.peerAuthGood = 1;
|
||||
@@ -5851,13 +5853,23 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
||||
ret = DoPreSharedKeys(ssl, input, helloSz - bindersLen,
|
||||
suites->suites + i, usingPSK, &first);
|
||||
if (ret != 0) {
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (ret != WC_PENDING_E)
|
||||
#endif
|
||||
CleanupClientTickets((PreSharedKey*)ext->data);
|
||||
#endif
|
||||
WOLFSSL_MSG_EX("DoPreSharedKeys: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
CleanupClientTickets((PreSharedKey*)ext->data);
|
||||
#endif
|
||||
#else
|
||||
ret = DoPreSharedKeys(ssl, input, helloSz - bindersLen, suite, usingPSK,
|
||||
&first);
|
||||
CleanupClientTickets((PreSharedKey*)ext->data);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_MSG_EX("DoPreSharedKeys: %d", ret);
|
||||
return ret;
|
||||
@@ -5975,7 +5987,7 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
||||
* cookieSz The length of the cookie data in bytes.
|
||||
* returns Length of the hash on success, otherwise failure.
|
||||
*/
|
||||
static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz)
|
||||
int TlsCheckCookie(const WOLFSSL* ssl, const byte* cookie, word16 cookieSz)
|
||||
{
|
||||
int ret;
|
||||
byte mac[WC_MAX_DIGEST_SIZE] = {0};
|
||||
@@ -6059,16 +6071,17 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
|
||||
word32 idx;
|
||||
byte hashSz;
|
||||
byte* cookieData;
|
||||
byte cookieDataSz;
|
||||
word16 cookieDataSz;
|
||||
word16 length;
|
||||
int keyShareExt = 0;
|
||||
int ret;
|
||||
|
||||
cookieDataSz = ret = CheckCookie(ssl, &cookie->data, cookie->len);
|
||||
ret = TlsCheckCookie(ssl, cookie->data, (byte)cookie->len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
hashSz = cookie->data;
|
||||
cookieData = &cookie->data;
|
||||
cookieDataSz = (word16)ret;
|
||||
hashSz = cookie->data[0];
|
||||
cookieData = cookie->data;
|
||||
idx = OPAQUE8_LEN;
|
||||
|
||||
/* Restart handshake hash with synthetic message hash. */
|
||||
@@ -6169,7 +6182,7 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls) {
|
||||
ret = Dtls13HashHandshake(ssl, hrr, hrrIdx);
|
||||
ret = Dtls13HashHandshake(ssl, hrr, (word16)hrrIdx);
|
||||
}
|
||||
else
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
@@ -6346,6 +6359,21 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
|
||||
#endif
|
||||
|
||||
/* do not change state in the SSL object before the next region of code
|
||||
* to be able to statelessly compute a DTLS cookie */
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
/* Update the ssl->options.dtlsStateful setting `if` statement in
|
||||
* wolfSSL_accept_TLSv13 when changing this one. */
|
||||
if (IsDtlsNotSctpMode(ssl) && ssl->options.sendCookie) {
|
||||
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
|
||||
if (ret != 0 || !ssl->options.dtlsStateful) {
|
||||
*inOutIdx += helloSz;
|
||||
goto exit_dch;
|
||||
}
|
||||
}
|
||||
ssl->options.dtlsStateful = 1;
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
args->idx = *inOutIdx;
|
||||
args->begin = args->idx;
|
||||
|
||||
@@ -6363,8 +6391,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
/* this check pass for DTLS Major (0xff) */
|
||||
if (args->pv.major < SSLv3_MAJOR) {
|
||||
WOLFSSL_MSG("Legacy version field contains unsupported value");
|
||||
SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
|
||||
ERROR_OUT(INVALID_PARAMETER, exit_dch);
|
||||
ERROR_OUT(VERSION_ERROR, exit_dch);
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
@@ -6442,13 +6469,13 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#endif
|
||||
|
||||
sessIdSz = input[args->idx++];
|
||||
if (sessIdSz != ID_LEN && sessIdSz != 0)
|
||||
if (sessIdSz != ID_LEN && sessIdSz != 0) {
|
||||
ERROR_OUT(INVALID_PARAMETER, exit_dch);
|
||||
|
||||
if (sessIdSz + args->idx > helloSz) {
|
||||
ERROR_OUT(BUFFER_ERROR, exit_dch);
|
||||
}
|
||||
|
||||
if (sessIdSz + args->idx > helloSz)
|
||||
ERROR_OUT(BUFFER_ERROR, exit_dch);
|
||||
|
||||
ssl->session->sessionIDSz = sessIdSz;
|
||||
if (sessIdSz == ID_LEN) {
|
||||
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
|
||||
@@ -6457,8 +6484,13 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* legacy_cookie */
|
||||
if (ssl->options.dtls)
|
||||
args->idx += OPAQUE8_LEN;
|
||||
if (ssl->options.dtls) {
|
||||
/* https://www.rfc-editor.org/rfc/rfc9147.html#section-5.3 */
|
||||
byte cookieLen = input[args->idx++];
|
||||
if (cookieLen != 0) {
|
||||
ERROR_OUT(INVALID_PARAMETER, exit_dch);
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
args->clSuites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap,
|
||||
@@ -6549,6 +6581,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
ssl->options.sendVerify = SEND_CERT;
|
||||
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
ssl->options.cookieGood = 0;
|
||||
if (ssl->options.sendCookie &&
|
||||
(ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
@@ -6565,30 +6598,19 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
*/
|
||||
if (ext->resp == 0) {
|
||||
ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* Send a new cookie request */
|
||||
if (ret == HRR_COOKIE_ERROR && ssl->options.dtls)
|
||||
ssl->options.serverState = NULL_STATE;
|
||||
else
|
||||
#endif
|
||||
if (ret != 0)
|
||||
goto exit_dch;
|
||||
ssl->options.serverState = SERVER_HELLO_COMPLETE;
|
||||
/* Don't change state here as we may want to enter
|
||||
* DoTls13ClientHello again. */
|
||||
ssl->options.cookieGood = 1;
|
||||
}
|
||||
else {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls)
|
||||
ssl->options.serverState = NULL_STATE;
|
||||
else
|
||||
#endif
|
||||
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
|
||||
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
|
||||
}
|
||||
}
|
||||
else
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (!ssl->options.dtls)
|
||||
#endif
|
||||
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
|
||||
else {
|
||||
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6616,12 +6638,10 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#ifndef NO_CERTS
|
||||
if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
|
||||
WOLFSSL_MSG("Client did not send a KeyShare extension");
|
||||
SendAlert(ssl, alert_fatal, missing_extension);
|
||||
ERROR_OUT(INCOMPLETE_DATA, exit_dch);
|
||||
}
|
||||
if (TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS) == NULL) {
|
||||
WOLFSSL_MSG("Client did not send a SignatureAlgorithms extension");
|
||||
SendAlert(ssl, alert_fatal, missing_extension);
|
||||
ERROR_OUT(INCOMPLETE_DATA, exit_dch);
|
||||
}
|
||||
#else
|
||||
@@ -6635,23 +6655,23 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
if ((ret = ALPN_Select(ssl)) != 0)
|
||||
goto exit_dch;
|
||||
#endif
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_BUILD;
|
||||
} /* case TLS_ASYNC_BEGIN */
|
||||
FALL_THROUGH;
|
||||
|
||||
case TLS_ASYNC_BUILD:
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_DO;
|
||||
FALL_THROUGH;
|
||||
|
||||
case TLS_ASYNC_DO:
|
||||
{
|
||||
#ifndef NO_CERTS
|
||||
if (!args->usingPSK) {
|
||||
if ((ret = MatchSuite(ssl, args->clSuites)) < 0) {
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
if (ret == WC_PENDING_E)
|
||||
goto exit_dch;
|
||||
if (ret != WC_PENDING_E)
|
||||
#endif
|
||||
WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
|
||||
SendAlert(ssl, alert_fatal, handshake_failure);
|
||||
WOLFSSL_MSG("Unsupported cipher suite, ClientHello 1.3");
|
||||
goto exit_dch;
|
||||
}
|
||||
}
|
||||
@@ -6673,10 +6693,31 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#endif
|
||||
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_FINALIZE;
|
||||
ssl->options.asyncState = TLS_ASYNC_VERIFY;
|
||||
} /* case TLS_ASYNC_BUILD || TLS_ASYNC_DO */
|
||||
FALL_THROUGH;
|
||||
|
||||
case TLS_ASYNC_VERIFY:
|
||||
{
|
||||
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_SUPPORTED_CURVES)
|
||||
/* Check if the KeyShare calculations from the previous state are complete.
|
||||
* wolfSSL_AsyncPop advances ssl->options.asyncState so we may end up here
|
||||
* with a pending calculation. */
|
||||
TLSX* extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
|
||||
if (extension != NULL && extension->resp == 1) {
|
||||
KeyShareEntry* serverKSE = (KeyShareEntry*)extension->data;
|
||||
if (serverKSE != NULL && serverKSE->lastRet == WC_PENDING_E) {
|
||||
ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
|
||||
if (ret != 0)
|
||||
goto exit_dch;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_FINALIZE;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
|
||||
case TLS_ASYNC_FINALIZE:
|
||||
{
|
||||
*inOutIdx = args->idx;
|
||||
@@ -6699,8 +6740,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
if (ssl->options.cipherSuite0 != TLS13_BYTE) {
|
||||
WOLFSSL_MSG("Negotiated ciphersuite from lesser version than "
|
||||
"TLS v1.3");
|
||||
SendAlert(ssl, alert_fatal, handshake_failure);
|
||||
ERROR_OUT(VERSION_ERROR, exit_dch);
|
||||
ERROR_OUT(MATCH_SUITE_ERROR, exit_dch);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
@@ -6721,23 +6761,26 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
ret = INPUT_CASE_ERROR;
|
||||
} /* switch (ssl->options.asyncState) */
|
||||
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
if (ret == 0 && ssl->options.sendCookie && ssl->options.cookieGood &&
|
||||
(ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* DTLS cookie exchange should be done in stateless code in
|
||||
* DoClientHelloStateless. If we verified the cookie then
|
||||
* always advance the state. */
|
||||
|| ssl->options.dtls
|
||||
#endif
|
||||
))
|
||||
ssl->options.serverState = SERVER_HELLO_COMPLETE;
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
/* We are using DTLSv13 and set the HRR cookie secret, use the cookie to
|
||||
perform a return-routability check. */
|
||||
if (ret == 0 && ssl->options.dtls && ssl->options.sendCookie &&
|
||||
ssl->options.serverState < SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
|
||||
|
||||
/* ssl->options.serverState < SERVER_HELLO_RETRY_REQUEST_COMPLETE
|
||||
so the client already provided a good KeyShareEntry. In this case
|
||||
we don't add the KEY_SHARE extension to the HelloRetryRequest or
|
||||
in the Cookie. The RFC8446 forbids to select a supported group
|
||||
with KeyShare extension in HelloRetryRequest if the client
|
||||
already provided a KeyShareEntry for that group. See rfc8446
|
||||
section 4.1.4 */
|
||||
TLSX_Remove(&ssl->extensions, TLSX_KEY_SHARE, ssl->heap);
|
||||
|
||||
/* send an HRR (see wolfSSL_Accept_TLSv13()) */
|
||||
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
|
||||
ssl->options.serverState <= SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
|
||||
/* Cookie and key share negotiation should be handled in
|
||||
* DoClientHelloStateless. If we enter here then something went wrong
|
||||
* in our logic. */
|
||||
ERROR_OUT(BAD_HELLO, exit_dch);
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
@@ -6761,9 +6804,6 @@ exit_dch:
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret == VERSION_ERROR)
|
||||
SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
|
||||
|
||||
FreeDch13Args(ssl, args);
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
FreeAsyncCtx(ssl, 0);
|
||||
@@ -6810,7 +6850,13 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
|
||||
WOLFSSL_START(WC_FUNC_SERVER_HELLO_SEND);
|
||||
WOLFSSL_ENTER("SendTls13ServerHello");
|
||||
|
||||
if (extMsgType == hello_retry_request) {
|
||||
/* When ssl->options.dtlsStateful is not set then cookie is calculated in
|
||||
* dtls.c */
|
||||
if (extMsgType == hello_retry_request
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
&& (!ssl->options.dtls || ssl->options.dtlsStateful)
|
||||
#endif
|
||||
) {
|
||||
WOLFSSL_MSG("wolfSSL Sending HelloRetryRequest");
|
||||
if ((ret = RestartHandshakeHash(ssl)) < 0)
|
||||
return ret;
|
||||
@@ -6897,7 +6943,14 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
|
||||
if (ssl->options.sendCookie && extMsgType == hello_retry_request) {
|
||||
/* Reset the hashes from here. We will be able to restart the hashes
|
||||
* from the cookie in RestartHandshakeHashWithCookie */
|
||||
ret = InitHandshakeHashes(ssl);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* When ssl->options.dtlsStateful is not set then cookie is calculated
|
||||
* in dtls.c */
|
||||
if (ssl->options.dtls && !ssl->options.dtlsStateful)
|
||||
ret = 0;
|
||||
else
|
||||
#endif
|
||||
ret = InitHandshakeHashes(ssl);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -10852,6 +10905,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
{
|
||||
int ret = 0;
|
||||
word32 inIdx = *inOutIdx;
|
||||
int alertType = invalid_alert;
|
||||
#if defined(HAVE_ECH)
|
||||
TLSX* echX = NULL;
|
||||
word32 echInOutIdx;
|
||||
@@ -11058,12 +11112,14 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
ret = HashInput(ssl, input + inIdx, size);
|
||||
}
|
||||
|
||||
if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA)
|
||||
SendAlert(ssl, alert_fatal, decode_error);
|
||||
else if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR ||
|
||||
ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA ||
|
||||
ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) {
|
||||
SendAlert(ssl, alert_fatal, illegal_parameter);
|
||||
alertType = TranslateErrorToAlert(ret);
|
||||
|
||||
if (alertType != invalid_alert) {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (type == client_hello && ssl->options.dtls)
|
||||
DtlsSetSeqNumForReply(ssl);
|
||||
#endif
|
||||
SendAlert(ssl, alert_fatal, alertType);
|
||||
}
|
||||
|
||||
if (ret == 0 && ssl->options.tls1_3) {
|
||||
@@ -11178,7 +11234,15 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
#endif /* NO_WOLFSSL_SERVER */
|
||||
}
|
||||
|
||||
WOLFSSL_LEAVE("DoTls13HandShakeMsgType", ret);
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls && !ssl->options.dtlsStateful) {
|
||||
DtlsResetState(ssl);
|
||||
if (DtlsIgnoreError(ret))
|
||||
ret = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
WOLFSSL_LEAVE("DoTls13HandShakeMsgType()", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -11335,6 +11399,13 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->version.major == DTLS_MAJOR) {
|
||||
ssl->options.dtls = 1;
|
||||
ssl->options.dtlsStateful = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_WOLFSENTRY_HOOKS
|
||||
if ((ssl->ConnectFilter != NULL) &&
|
||||
(ssl->options.connectState == CONNECT_BEGIN))
|
||||
@@ -11843,7 +11914,7 @@ int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group)
|
||||
(void)ret;
|
||||
(void)group;
|
||||
#else
|
||||
ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL);
|
||||
ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL, &ssl->extensions);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif /* NO_TLS */
|
||||
@@ -12432,49 +12503,6 @@ const char* wolfSSL_get_cipher_name_by_hash(WOLFSSL* ssl, const char* hash)
|
||||
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
static int DtlsAcceptStateless(WOLFSSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!ssl->options.dtls)
|
||||
return 0;
|
||||
|
||||
switch (ssl->options.acceptState) {
|
||||
case TLS13_ACCEPT_BEGIN:
|
||||
|
||||
while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
|
||||
ret = ProcessReply(ssl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!IsAtLeastTLSv1_3(ssl->version))
|
||||
return wolfSSL_accept(ssl);
|
||||
|
||||
ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE;
|
||||
WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
|
||||
FALL_THROUGH;
|
||||
|
||||
case TLS13_ACCEPT_CLIENT_HELLO_DONE:
|
||||
if (ssl->options.serverState ==
|
||||
SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
|
||||
ret = SendTls13ServerHello(ssl, hello_retry_request);
|
||||
DtlsResetState(ssl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE;
|
||||
WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
|
||||
FALL_THROUGH;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
/* The server accepting a connection from a client.
|
||||
* The protocol version is expecting to be TLS v1.3.
|
||||
@@ -12520,6 +12548,14 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->version.major == DTLS_MAJOR) {
|
||||
ssl->options.dtls = 1;
|
||||
if (!IsDtlsNotSctpMode(ssl) || !ssl->options.sendCookie)
|
||||
ssl->options.dtlsStateful = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_WOLFSENTRY_HOOKS
|
||||
if ((ssl->AcceptFilter != NULL) &&
|
||||
((ssl->options.acceptState == TLS13_ACCEPT_BEGIN)
|
||||
@@ -12663,19 +12699,6 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
if (ssl->options.dtls && ssl->options.sendCookie) {
|
||||
while (ssl->options.serverState < SERVER_HELLO_COMPLETE) {
|
||||
ret = DtlsAcceptStateless(ssl);
|
||||
if (ret != 0) {
|
||||
ssl->error = ret;
|
||||
WOLFSSL_ERROR(ssl->error);
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) */
|
||||
|
||||
switch (ssl->options.acceptState) {
|
||||
|
||||
#ifdef HAVE_SECURE_RENEGOTIATION
|
||||
|
317
tests/api.c
317
tests/api.c
@@ -5149,13 +5149,11 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args)
|
||||
opts->return_code = TEST_FAIL;
|
||||
cbf = opts->callbacks;
|
||||
|
||||
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
|
||||
if (cbf != NULL && cbf->ctx) {
|
||||
ctx = cbf->ctx;
|
||||
sharedCtx = 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
WOLFSSL_METHOD* method = NULL;
|
||||
if (cbf != NULL && cbf->method != NULL) {
|
||||
@@ -37629,7 +37627,6 @@ static int test_wolfSSL_DTLS_either_side(void)
|
||||
callback_functions client_cb;
|
||||
callback_functions server_cb;
|
||||
|
||||
/* create a failed connection and inspect the error */
|
||||
#ifdef WOLFSSL_TIRTOS
|
||||
fdOpenSession(Task_self());
|
||||
#endif
|
||||
@@ -59333,12 +59330,197 @@ static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl)
|
||||
AssertIntGT(ret, 0);
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
static void test_wolfSSL_dtls_send_ch_with_invalid_cookie(WOLFSSL* ssl)
|
||||
{
|
||||
int fd, ret;
|
||||
byte ch_msh_invalid_cookie[] = {
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
|
||||
0x4e, 0x01, 0x00, 0x02, 0x42, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x42, 0xfe, 0xfd, 0x69, 0xca, 0x77, 0x60, 0x6f, 0xfc, 0xd1, 0x5b, 0x60,
|
||||
0x5d, 0xf1, 0xa6, 0x5c, 0x44, 0x71, 0xae, 0xca, 0x62, 0x19, 0x0c, 0xb6,
|
||||
0xf7, 0x2c, 0xa6, 0xd5, 0xd2, 0x99, 0x9d, 0x18, 0xae, 0xac, 0x11, 0x00,
|
||||
0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0,
|
||||
0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc,
|
||||
0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0,
|
||||
0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00,
|
||||
0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01,
|
||||
0xe2, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20,
|
||||
0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06,
|
||||
0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01,
|
||||
0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x2c, 0x00, 0x45,
|
||||
0x00, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00,
|
||||
0x03, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x19,
|
||||
0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00,
|
||||
0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17, 0x00, 0x41, 0x04, 0x7c,
|
||||
0x5a, 0xc2, 0x5a, 0xfd, 0xcd, 0x2b, 0x08, 0xb2, 0xeb, 0x8e, 0xc0, 0x02,
|
||||
0x03, 0x9d, 0xb1, 0xc1, 0x0d, 0x7b, 0x7f, 0x46, 0x43, 0xdf, 0xf3, 0xee,
|
||||
0x2b, 0x78, 0x0e, 0x29, 0x8c, 0x42, 0x11, 0x2c, 0xde, 0xd7, 0x41, 0x0f,
|
||||
0x28, 0x94, 0x80, 0x41, 0x70, 0xc4, 0x17, 0xfd, 0x6d, 0xfa, 0xee, 0x9a,
|
||||
0xf2, 0xc4, 0x15, 0x4c, 0x5f, 0x54, 0xb6, 0x78, 0x6e, 0xf9, 0x63, 0x27,
|
||||
0x33, 0xb8, 0x7b, 0x01, 0x00, 0x01, 0x00, 0xd4, 0x46, 0x62, 0x9c, 0xbf,
|
||||
0x8f, 0x1b, 0x65, 0x9b, 0xf0, 0x29, 0x64, 0xd8, 0x50, 0x0e, 0x74, 0xf1,
|
||||
0x58, 0x10, 0xc9, 0xd9, 0x82, 0x5b, 0xd9, 0xbe, 0x14, 0xdf, 0xde, 0x86,
|
||||
0xb4, 0x2e, 0x15, 0xee, 0x4f, 0xf6, 0x74, 0x9e, 0x59, 0x11, 0x36, 0x2d,
|
||||
0xb9, 0x67, 0xaa, 0x5a, 0x09, 0x9b, 0x45, 0xf1, 0x01, 0x4c, 0x4e, 0xf6,
|
||||
0xda, 0x6a, 0xae, 0xa7, 0x73, 0x7b, 0x2e, 0xb6, 0x24, 0x89, 0x99, 0xb7,
|
||||
0x52, 0x16, 0x62, 0x0a, 0xab, 0x58, 0xf8, 0x3f, 0x10, 0x5b, 0x83, 0xfd,
|
||||
0x7b, 0x81, 0x77, 0x81, 0x8d, 0xef, 0x24, 0x56, 0x6d, 0xba, 0x49, 0xd4,
|
||||
0x8b, 0xb5, 0xa0, 0xb1, 0xc9, 0x8c, 0x32, 0x95, 0x1c, 0x5e, 0x0a, 0x4b,
|
||||
0xf6, 0x00, 0x50, 0x0a, 0x87, 0x99, 0x59, 0xcf, 0x6f, 0x9d, 0x02, 0xd0,
|
||||
0x1b, 0xa1, 0x96, 0x45, 0x28, 0x76, 0x40, 0x33, 0x28, 0xc9, 0xa1, 0xfd,
|
||||
0x46, 0xab, 0x2c, 0x9e, 0x5e, 0xc6, 0x74, 0x19, 0x9a, 0xf5, 0x9b, 0x51,
|
||||
0x11, 0x4f, 0xc8, 0xb9, 0x99, 0x6b, 0x4e, 0x3e, 0x31, 0x64, 0xb4, 0x92,
|
||||
0xf4, 0x0d, 0x41, 0x4b, 0x2c, 0x65, 0x23, 0xf7, 0x47, 0xe3, 0xa5, 0x2e,
|
||||
0xe4, 0x9c, 0x2b, 0xc9, 0x41, 0x22, 0x83, 0x8a, 0x23, 0xef, 0x29, 0x7e,
|
||||
0x4f, 0x3f, 0xa3, 0xbf, 0x73, 0x2b, 0xd7, 0xcc, 0xc8, 0xc6, 0xe9, 0xbc,
|
||||
0x01, 0xb7, 0x32, 0x63, 0xd4, 0x7e, 0x7f, 0x9a, 0xaf, 0x5f, 0x05, 0x31,
|
||||
0x53, 0xd6, 0x1f, 0xa2, 0xd0, 0xdf, 0x67, 0x56, 0xf1, 0x9c, 0x4a, 0x9d,
|
||||
0x83, 0xb4, 0xef, 0xb3, 0xf2, 0xcc, 0xf1, 0x91, 0x6c, 0x47, 0xc3, 0x8b,
|
||||
0xd0, 0x92, 0x79, 0x3d, 0xa0, 0xc0, 0x3a, 0x57, 0x26, 0x6d, 0x0a, 0xad,
|
||||
0x5f, 0xad, 0xb4, 0x74, 0x48, 0x4a, 0x51, 0xe1, 0xb5, 0x82, 0x0a, 0x4c,
|
||||
0x4f, 0x9d, 0xaf, 0xee, 0x5a, 0xa2, 0x4d, 0x4d, 0x5f, 0xe0, 0x17, 0x00,
|
||||
0x23, 0x00, 0x00
|
||||
};
|
||||
byte alert_reply[50];
|
||||
byte expected_alert_reply[] = {
|
||||
0x15, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x02, 0x02, 0x2f
|
||||
};
|
||||
|
||||
fd = wolfSSL_get_fd(ssl);
|
||||
ret = (int)send(fd, ch_msh_invalid_cookie, sizeof(ch_msh_invalid_cookie), 0);
|
||||
AssertIntGT(ret, 0);
|
||||
/* should reply with an illegal_parameter reply */
|
||||
ret = (int)recv(fd, alert_reply, sizeof(alert_reply), 0);
|
||||
AssertIntEQ(ret, sizeof(expected_alert_reply));
|
||||
AssertIntEQ(XMEMCMP(alert_reply, expected_alert_reply, sizeof(expected_alert_reply)), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl)
|
||||
{
|
||||
#ifndef NO_MD5
|
||||
enum wc_HashType hashType = WC_HASH_TYPE_MD5;
|
||||
#elif !defined(NO_SHA)
|
||||
enum wc_HashType hashType = WC_HASH_TYPE_SHA;
|
||||
#elif !defined(NO_SHA256)
|
||||
enum wc_HashType hashType = WC_HASH_TYPE_SHA256;
|
||||
#else
|
||||
#error "We need a digest to hash the WOLFSSL object"
|
||||
#endif
|
||||
byte hashBuf[WC_MAX_DIGEST_SIZE];
|
||||
wc_HashAlg hash;
|
||||
const TLSX* exts = ssl->extensions;
|
||||
WOLFSSL sslCopy; /* Use a copy to omit certain fields */
|
||||
HS_Hashes* hsHashes = ssl->hsHashes; /* Is re-allocated in
|
||||
* InitHandshakeHashes */
|
||||
|
||||
XMEMCPY(&sslCopy, ssl, sizeof(*ssl));
|
||||
XMEMSET(hashBuf, 0, sizeof(hashBuf));
|
||||
|
||||
/* Following fields are not important to compare */
|
||||
sslCopy.buffers.inputBuffer.buffer = NULL;
|
||||
sslCopy.buffers.inputBuffer.bufferSize = 0;
|
||||
sslCopy.buffers.inputBuffer.dynamicFlag = 0;
|
||||
sslCopy.buffers.inputBuffer.offset = 0;
|
||||
sslCopy.error = 0;
|
||||
sslCopy.curSize = 0;
|
||||
sslCopy.keys.curSeq_lo = 0;
|
||||
XMEMSET(&sslCopy.curRL, 0, sizeof(sslCopy.curRL));
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
XMEMSET(&sslCopy.keys.curSeq, 0, sizeof(sslCopy.keys.curSeq));
|
||||
sslCopy.dtls13FastTimeout = 0;
|
||||
#endif
|
||||
sslCopy.keys.dtls_peer_handshake_number = 0;
|
||||
XMEMSET(&sslCopy.alert_history, 0, sizeof(sslCopy.alert_history));
|
||||
sslCopy.hsHashes = NULL;
|
||||
#ifdef WOLFSSL_ASYNC_IO
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
sslCopy.asyncDev = NULL;
|
||||
#endif
|
||||
sslCopy.async = NULL;
|
||||
#endif
|
||||
|
||||
AssertIntEQ(wc_HashInit(&hash, hashType), 0);
|
||||
AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)&sslCopy, sizeof(sslCopy)), 0);
|
||||
/* hash extension list */
|
||||
while (exts != NULL) {
|
||||
AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)exts, sizeof(*exts)), 0);
|
||||
exts = exts->next;
|
||||
}
|
||||
/* Hash suites */
|
||||
if (sslCopy.suites != NULL) {
|
||||
AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)sslCopy.suites,
|
||||
sizeof(struct Suites)), 0);
|
||||
}
|
||||
/* Hash hsHashes */
|
||||
AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)hsHashes,
|
||||
sizeof(*hsHashes)), 0);
|
||||
AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0);
|
||||
AssertIntEQ(wc_HashFree(&hash, hashType), 0);
|
||||
|
||||
return MakeWordFromHash(hashBuf);
|
||||
}
|
||||
|
||||
static CallbackIORecv test_wolfSSL_dtls_compare_stateless_cb;
|
||||
static int test_wolfSSL_dtls_compare_stateless_cb_call_once;
|
||||
static int test_wolfSSL_dtls_compare_stateless_read_cb_once(WOLFSSL *ssl,
|
||||
char *buf, int sz, void *ctx)
|
||||
{
|
||||
if (test_wolfSSL_dtls_compare_stateless_cb_call_once) {
|
||||
test_wolfSSL_dtls_compare_stateless_cb_call_once = 0;
|
||||
return test_wolfSSL_dtls_compare_stateless_cb(ssl, buf, sz, ctx);
|
||||
}
|
||||
else {
|
||||
return WOLFSSL_CBIO_ERR_WANT_READ;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_wolfSSL_dtls_compare_stateless(WOLFSSL* ssl)
|
||||
{
|
||||
/* Compare the ssl object before and after one ClientHello msg */
|
||||
SOCKET_T fd = wolfSSL_get_fd(ssl);
|
||||
int res;
|
||||
int err;
|
||||
word32 initHash;
|
||||
|
||||
test_wolfSSL_dtls_compare_stateless_cb = ssl->CBIORecv;
|
||||
test_wolfSSL_dtls_compare_stateless_cb_call_once = 1;
|
||||
wolfSSL_dtls_set_using_nonblock(ssl, 1);
|
||||
ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_read_cb_once;
|
||||
|
||||
initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl);
|
||||
(void)initHash;
|
||||
|
||||
res = tcp_select(fd, 5);
|
||||
/* We are expecting a msg. A timeout indicates failure. */
|
||||
AssertIntEQ(res, TEST_RECV_READY);
|
||||
|
||||
res = wolfSSL_accept(ssl);
|
||||
err = wolfSSL_get_error(ssl, res);
|
||||
AssertIntEQ(res, WOLFSSL_FATAL_ERROR);
|
||||
AssertIntEQ(err, WOLFSSL_ERROR_WANT_READ);
|
||||
|
||||
AssertIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl));
|
||||
|
||||
wolfSSL_dtls_set_using_nonblock(ssl, 0);
|
||||
ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_cb;
|
||||
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
static void test_wolfSSL_dtls_enable_hrrcookie(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0);
|
||||
AssertIntEQ(ret, WOLFSSL_SUCCESS);
|
||||
test_wolfSSL_dtls_compare_stateless(ssl);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -59353,10 +59535,12 @@ static int test_wolfSSL_dtls_stateless(void)
|
||||
ssl_callback server_ssl_ready;
|
||||
} test_params[] = {
|
||||
{wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method,
|
||||
test_wolfSSL_dtls_send_ch, NULL},
|
||||
test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_compare_stateless},
|
||||
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
|
||||
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
|
||||
test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_enable_hrrcookie},
|
||||
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
|
||||
test_wolfSSL_dtls_send_ch_with_invalid_cookie, test_wolfSSL_dtls_enable_hrrcookie},
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -62748,6 +62932,130 @@ static int test_wolfSSL_CRL_CERT_REVOKED_alert(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) \
|
||||
&& defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_AESGCM) && \
|
||||
!defined(NO_SHA256) && defined(WOLFSSL_AES_128) && \
|
||||
defined(WOLFSSL_SHA384) && defined(WOLFSSL_AES_256) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
|
||||
|
||||
static WOLFSSL_CTX* test_TLS_13_ticket_different_ciphers_ctx = NULL;
|
||||
static WOLFSSL_SESSION* test_TLS_13_ticket_different_ciphers_session = NULL;
|
||||
static int test_TLS_13_ticket_different_ciphers_run = 0;
|
||||
|
||||
static void test_TLS_13_ticket_different_ciphers_ssl_ready(WOLFSSL* ssl)
|
||||
{
|
||||
switch (test_TLS_13_ticket_different_ciphers_run) {
|
||||
case 0:
|
||||
/* First run */
|
||||
AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES128-GCM-SHA256"),
|
||||
WOLFSSL_SUCCESS);
|
||||
if (wolfSSL_is_server(ssl)) {
|
||||
AssertNotNull(test_TLS_13_ticket_different_ciphers_ctx =
|
||||
wolfSSL_get_SSL_CTX(ssl));
|
||||
AssertIntEQ(WOLFSSL_SUCCESS,
|
||||
wolfSSL_CTX_up_ref(test_TLS_13_ticket_different_ciphers_ctx));
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* Second run */
|
||||
AssertIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-AES256-GCM-SHA384:"
|
||||
"TLS13-AES128-GCM-SHA256"),
|
||||
WOLFSSL_SUCCESS);
|
||||
if (!wolfSSL_is_server(ssl)) {
|
||||
AssertIntEQ(wolfSSL_set_session(ssl,
|
||||
test_TLS_13_ticket_different_ciphers_session),
|
||||
WOLFSSL_SUCCESS);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Bad state? */
|
||||
Fail(("Should not enter here"), ("Should not enter here"));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_TLS_13_ticket_different_ciphers_on_result(WOLFSSL* ssl)
|
||||
{
|
||||
switch (test_TLS_13_ticket_different_ciphers_run) {
|
||||
case 0:
|
||||
/* First run */
|
||||
AssertNotNull(test_TLS_13_ticket_different_ciphers_session =
|
||||
wolfSSL_get1_session(ssl));
|
||||
break;
|
||||
case 1:
|
||||
/* Second run */
|
||||
AssertTrue(wolfSSL_session_reused(ssl));
|
||||
break;
|
||||
default:
|
||||
/* Bad state? */
|
||||
Fail(("Should not enter here"), ("Should not enter here"));
|
||||
}
|
||||
}
|
||||
|
||||
static int test_TLS_13_ticket_different_ciphers(void)
|
||||
{
|
||||
/* Check that we handle the connection when the ticket doesn't match
|
||||
* the first ciphersuite. */
|
||||
callback_functions client_cbs, server_cbs;
|
||||
struct test_params {
|
||||
method_provider client_meth;
|
||||
method_provider server_meth;
|
||||
int doUdp;
|
||||
} params[] = {
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
/* Test that the stateless code handles sessions correctly */
|
||||
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, 1},
|
||||
#endif
|
||||
{wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, 0},
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
|
||||
XMEMSET(&client_cbs, 0, sizeof(client_cbs));
|
||||
XMEMSET(&server_cbs, 0, sizeof(server_cbs));
|
||||
|
||||
test_TLS_13_ticket_different_ciphers_run = 0;
|
||||
|
||||
client_cbs.doUdp = server_cbs.doUdp = params[i].doUdp;
|
||||
|
||||
client_cbs.method = params[i].client_meth;
|
||||
server_cbs.method = params[i].server_meth;
|
||||
|
||||
client_cbs.ssl_ready = test_TLS_13_ticket_different_ciphers_ssl_ready;
|
||||
server_cbs.ssl_ready = test_TLS_13_ticket_different_ciphers_ssl_ready;
|
||||
|
||||
client_cbs.on_result = test_TLS_13_ticket_different_ciphers_on_result;
|
||||
|
||||
server_cbs.ticNoInit = 1;
|
||||
|
||||
test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);
|
||||
|
||||
AssertTrue(client_cbs.return_code);
|
||||
AssertTrue(server_cbs.return_code);
|
||||
|
||||
test_TLS_13_ticket_different_ciphers_run++;
|
||||
|
||||
server_cbs.ctx = test_TLS_13_ticket_different_ciphers_ctx;
|
||||
|
||||
test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);
|
||||
|
||||
AssertTrue(client_cbs.return_code);
|
||||
AssertTrue(server_cbs.return_code);
|
||||
|
||||
wolfSSL_SESSION_free(test_TLS_13_ticket_different_ciphers_session);
|
||||
test_TLS_13_ticket_different_ciphers_session = NULL;
|
||||
wolfSSL_CTX_free(test_TLS_13_ticket_different_ciphers_ctx);
|
||||
test_TLS_13_ticket_different_ciphers_ctx = NULL;
|
||||
}
|
||||
|
||||
return TEST_RES_CHECK(1);
|
||||
}
|
||||
#else
|
||||
static int test_TLS_13_ticket_different_ciphers(void)
|
||||
{
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*
|
||||
| Main
|
||||
*----------------------------------------------------------------------------*/
|
||||
@@ -63748,6 +64056,7 @@ TEST_CASE testCases[] = {
|
||||
* !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) */
|
||||
TEST_DECL(test_wolfSSL_CTX_set_ciphersuites),
|
||||
TEST_DECL(test_wolfSSL_CRL_CERT_REVOKED_alert),
|
||||
TEST_DECL(test_TLS_13_ticket_different_ciphers),
|
||||
TEST_DECL(test_WOLFSSL_dtls_version_alert),
|
||||
TEST_DECL(test_ForceZero),
|
||||
|
||||
|
@@ -2123,6 +2123,16 @@ struct Suites {
|
||||
byte setSuites; /* user set suites from default */
|
||||
};
|
||||
|
||||
typedef struct CipherSuite {
|
||||
byte cipherSuite0;
|
||||
byte cipherSuite;
|
||||
word32 ecdhCurveOID;
|
||||
struct KeyShareEntry* clientKSE;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
|
||||
int doHelloRetry;
|
||||
#endif
|
||||
} CipherSuite;
|
||||
|
||||
WOLFSSL_LOCAL void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig,
|
||||
int haveRSAsig, int haveFalconSig,
|
||||
int haveDilithiumSig, int haveAnon,
|
||||
@@ -2140,6 +2150,9 @@ WOLFSSL_LOCAL void InitSuites(Suites* suites, ProtocolVersion pv, int keySz,
|
||||
word16 haveFalconSig, word16 haveDilithiumSig,
|
||||
word16 haveAnon, word16 haveNull, int side);
|
||||
|
||||
typedef struct TLSX TLSX;
|
||||
WOLFSSL_LOCAL int MatchSuite_ex(const WOLFSSL* ssl, Suites* peerSuites,
|
||||
CipherSuite* cs, TLSX* extensions);
|
||||
WOLFSSL_LOCAL int MatchSuite(WOLFSSL* ssl, Suites* peerSuites);
|
||||
WOLFSSL_LOCAL int SetCipherList(WOLFSSL_CTX* ctx, Suites* suites,
|
||||
const char* list);
|
||||
@@ -2692,10 +2705,17 @@ WOLFSSL_LOCAL int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType,
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_ParseVersion(WOLFSSL* ssl, const byte* input,
|
||||
word16 length, byte msgType, int* found);
|
||||
/* Forward declare opaque pointer to make available for func def */
|
||||
typedef struct Options Options;
|
||||
WOLFSSL_LOCAL int TLSX_SupportedVersions_Parse(const WOLFSSL* ssl,
|
||||
const byte* input, word16 length, byte msgType, ProtocolVersion* pv,
|
||||
Options* opts, TLSX** exts);
|
||||
WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
||||
byte msgType, Suites *suites);
|
||||
WOLFSSL_LOCAL int TLSX_Push(TLSX** list, TLSX_Type type,
|
||||
const void* data, void* heap);
|
||||
WOLFSSL_LOCAL int TLSX_Append(TLSX** list, TLSX_Type type,
|
||||
const void* data, void* heap);
|
||||
|
||||
#elif defined(HAVE_SNI) \
|
||||
|| defined(HAVE_MAX_FRAGMENT) \
|
||||
@@ -2879,6 +2899,7 @@ typedef struct PointFormat {
|
||||
struct PointFormat* next; /* List Behavior */
|
||||
} PointFormat;
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap);
|
||||
WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name,
|
||||
void* heap);
|
||||
|
||||
@@ -2886,13 +2907,15 @@ WOLFSSL_LOCAL int TLSX_UsePointFormat(TLSX** extensions, byte point,
|
||||
void* heap);
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first,
|
||||
byte second);
|
||||
WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(const WOLFSSL* ssl, byte first,
|
||||
byte second, word32* ecdhCurveOID);
|
||||
WOLFSSL_LOCAL int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl);
|
||||
#endif
|
||||
WOLFSSL_LOCAL int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl,
|
||||
int checkSupported);
|
||||
WOLFSSL_LOCAL int TLSX_SupportedCurve_Parse(const WOLFSSL* ssl,
|
||||
const byte* input, word16 length, byte isRequest, TLSX** extensions);
|
||||
|
||||
#endif /* HAVE_SUPPORTED_CURVES */
|
||||
|
||||
@@ -3023,11 +3046,18 @@ int TLSX_EncryptThenMac_Respond(WOLFSSL* ssl);
|
||||
/* Cookie extension information - cookie data. */
|
||||
typedef struct Cookie {
|
||||
word16 len;
|
||||
byte data;
|
||||
/* Ignore "nonstandard extension used : zero-sized array in struct/union"
|
||||
* MSVC warning */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4200)
|
||||
#endif
|
||||
byte data[];
|
||||
} Cookie;
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_Cookie_Use(WOLFSSL* ssl, const byte* data, word16 len,
|
||||
byte* mac, byte macSz, int resp);
|
||||
WOLFSSL_LOCAL int TLSX_Cookie_Use(const WOLFSSL* ssl, const byte* data,
|
||||
word16 len, byte* mac, byte macSz, int resp, TLSX** exts);
|
||||
WOLFSSL_LOCAL int TlsCheckCookie(const WOLFSSL* ssl, const byte* cookie,
|
||||
word16 cookieSz);
|
||||
|
||||
|
||||
/* Key Share - TLS v1.3 Specification */
|
||||
@@ -3050,15 +3080,32 @@ typedef struct KeyShareEntry {
|
||||
struct KeyShareEntry* next; /* List pointer */
|
||||
} KeyShareEntry;
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len,
|
||||
byte* data, KeyShareEntry **kse);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group,
|
||||
word16 len, byte* data, KeyShareEntry **kse, TLSX** extensions);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Empty(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_SetSupported(const WOLFSSL* ssl,
|
||||
TLSX** extensions);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Choose(const WOLFSSL *ssl, TLSX* extensions,
|
||||
KeyShareEntry** kse, byte* searched);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Setup(WOLFSSL *ssl, KeyShareEntry* clientKSE);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Establish(WOLFSSL* ssl, int* doHelloRetry);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_DeriveSecret(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_DeriveSecret(WOLFSSL* sclientKSEclientKSEsl);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Parse(WOLFSSL* ssl, const byte* input,
|
||||
word16 length, byte msgType);
|
||||
WOLFSSL_LOCAL int TLSX_KeyShare_Parse_ClientHello(const WOLFSSL* ssl,
|
||||
const byte* input, word16 length, TLSX** extensions);
|
||||
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
|
||||
enum PskDecryptReturn {
|
||||
PSK_DECRYPT_NONE = 0,
|
||||
PSK_DECRYPT_OK,
|
||||
PSK_DECRYPT_CREATE,
|
||||
PSK_DECRYPT_FAIL,
|
||||
};
|
||||
|
||||
/* The PreSharedKey extension information - entry in a linked list. */
|
||||
typedef struct PreSharedKey {
|
||||
word16 identityLen; /* Length of identity */
|
||||
@@ -3069,8 +3116,12 @@ typedef struct PreSharedKey {
|
||||
word32 binderLen; /* Length of HMAC */
|
||||
byte binder[WC_MAX_DIGEST_SIZE]; /* HMAC of handshake */
|
||||
byte hmac; /* HMAC algorithm */
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
InternalTicket* it; /* ptr to ticket */
|
||||
#endif
|
||||
byte resumption:1; /* Resumption PSK */
|
||||
byte chosen:1; /* Server's choice */
|
||||
byte decryptRet:3; /* Ticket decrypt return */
|
||||
struct PreSharedKey* next; /* List pointer */
|
||||
} PreSharedKey;
|
||||
|
||||
@@ -3079,11 +3130,14 @@ WOLFSSL_LOCAL int TLSX_PreSharedKey_WriteBinders(PreSharedKey* list,
|
||||
word16* pSz);
|
||||
WOLFSSL_LOCAL int TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list,
|
||||
byte msgType, word16* pSz);
|
||||
WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(WOLFSSL* ssl, const byte* identity,
|
||||
WOLFSSL_LOCAL int TLSX_PreSharedKey_Use(TLSX** extensions, const byte* identity,
|
||||
word16 len, word32 age, byte hmac,
|
||||
byte cipherSuite0, byte cipherSuite,
|
||||
byte resumption,
|
||||
PreSharedKey **preSharedKey);
|
||||
PreSharedKey **preSharedKey,
|
||||
void* heap);
|
||||
WOLFSSL_LOCAL int TLSX_PreSharedKey_Parse_ClientHello(TLSX** extensions,
|
||||
const byte* input, word16 length, void* heap);
|
||||
|
||||
/* The possible Pre-Shared Key key exchange modes. */
|
||||
enum PskKeyExchangeMode {
|
||||
@@ -3096,7 +3150,9 @@ enum PskKeyExchangeMode {
|
||||
#define WOLFSSL_DEF_PSK_CIPHER TLS_AES_128_GCM_SHA256
|
||||
#endif
|
||||
|
||||
WOLFSSL_LOCAL int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes);
|
||||
WOLFSSL_LOCAL int TLSX_PskKeyModes_Use(WOLFSSL* ssl, byte modes);
|
||||
WOLFSSL_LOCAL int TLSX_PskKeyModes_Parse_Modes(const byte* input, word16 length,
|
||||
byte msgType, byte* modes);
|
||||
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
WOLFSSL_LOCAL int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max, int is_response);
|
||||
@@ -3804,7 +3860,7 @@ typedef struct Hashes {
|
||||
#endif
|
||||
} Hashes;
|
||||
|
||||
WOLFSSL_LOCAL int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes);
|
||||
WOLFSSL_LOCAL int BuildCertHashes(const WOLFSSL* ssl, Hashes* hashes);
|
||||
|
||||
#ifdef WOLFSSL_TLS13
|
||||
typedef union Digest {
|
||||
@@ -4221,6 +4277,7 @@ typedef struct Options {
|
||||
word16 tls1_1:1; /* using TLSv1.1+ ? */
|
||||
word16 tls1_3:1; /* using TLSv1.3+ ? */
|
||||
word16 dtls:1; /* using datagrams ? */
|
||||
word16 dtlsStateful:1; /* allow stateful processing ? */
|
||||
word16 connReset:1; /* has the peer reset */
|
||||
word16 isClosed:1; /* if we consider conn closed */
|
||||
word16 closeNotify:1; /* we've received a close notify */
|
||||
@@ -4334,10 +4391,13 @@ typedef struct Options {
|
||||
word16 tls13MiddleBoxCompat:1; /* TLSv1.3 middlebox compatibility */
|
||||
#endif
|
||||
#ifdef WOLFSSL_DTLS_CID
|
||||
byte useDtlsCID:1;
|
||||
word16 useDtlsCID:1;
|
||||
#endif /* WOLFSSL_DTLS_CID */
|
||||
#if defined(HAVE_ECH)
|
||||
byte useEch:1;
|
||||
word16 useEch:1;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
word16 cookieGood:1;
|
||||
#endif
|
||||
|
||||
/* need full byte values for this section */
|
||||
@@ -5593,10 +5653,16 @@ extern const WOLF_EC_NIST_NAME kNistCurves[];
|
||||
WOLFSSL_LOCAL int SendChangeCipher(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int SendTicket(WOLFSSL* ssl);
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
WOLFSSL_LOCAL int DoDecryptTicket(WOLFSSL* ssl, const byte* input, word32 len,
|
||||
InternalTicket **it);
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
WOLFSSL_LOCAL int DoDecryptTicket(const WOLFSSL* ssl, const byte* input,
|
||||
word32 len, InternalTicket **it);
|
||||
/* Return 0 when check successful. <0 on failure. */
|
||||
WOLFSSL_LOCAL int DoClientTicketCheck(const WOLFSSL* ssl,
|
||||
const PreSharedKey* psk, sword64 timeout, const byte* suite);
|
||||
WOLFSSL_LOCAL void DoClientTicketFinalize(WOLFSSL* ssl, InternalTicket* it);
|
||||
WOLFSSL_LOCAL void CleanupClientTickets(PreSharedKey* psk);
|
||||
WOLFSSL_LOCAL int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len);
|
||||
WOLFSSL_LOCAL int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk);
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
WOLFSSL_LOCAL int SendData(WOLFSSL* ssl, const void* data, int sz);
|
||||
#ifdef WOLFSSL_TLS13
|
||||
WOLFSSL_LOCAL int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType);
|
||||
@@ -5625,6 +5691,8 @@ WOLFSSL_LOCAL int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr);
|
||||
WOLFSSL_LOCAL const char* AlertTypeToString(int type);
|
||||
|
||||
WOLFSSL_LOCAL int SetCipherSpecs(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int GetCipherSpec(word16 side, byte cipherSuite0,
|
||||
byte cipherSuite, CipherSpecs* specs, Options* opts);
|
||||
WOLFSSL_LOCAL int MakeMasterSecret(WOLFSSL* ssl);
|
||||
|
||||
WOLFSSL_LOCAL int DeriveKeys(WOLFSSL* ssl);
|
||||
@@ -5640,7 +5708,8 @@ WOLFSSL_LOCAL void FreeHandshakeResources(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree);
|
||||
WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl);
|
||||
|
||||
WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int VerifyClientSuite(word16 havePSK, byte cipherSuite0,
|
||||
byte cipherSuite);
|
||||
|
||||
WOLFSSL_LOCAL int SetTicket(WOLFSSL* ssl, const byte* ticket, word32 length);
|
||||
WOLFSSL_LOCAL int wolfSSL_GetMaxFragSize(WOLFSSL* ssl, int maxFragment);
|
||||
@@ -5656,7 +5725,8 @@ WOLFSSL_LOCAL int SetECKeyExternal(WOLFSSL_EC_KEY* eckey);
|
||||
#endif
|
||||
|
||||
#if defined(OPENSSL_EXTRA)
|
||||
WOLFSSL_LOCAL int wolfSSL_curve_is_disabled(WOLFSSL* ssl, word16 named_curve);
|
||||
WOLFSSL_LOCAL int wolfSSL_curve_is_disabled(const WOLFSSL* ssl,
|
||||
word16 named_curve);
|
||||
#else
|
||||
#define wolfSSL_curve_is_disabled(ssl, c) ((void)(ssl), (void)(c), 0)
|
||||
#endif
|
||||
@@ -5803,8 +5873,8 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl);
|
||||
const byte* cookie, byte cookieSz);
|
||||
|
||||
#if !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_LOCAL int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
|
||||
word32* inOutIdx, word32 helloSz, byte *process);
|
||||
WOLFSSL_LOCAL int DoClientHelloStateless(WOLFSSL* ssl,
|
||||
const byte* input, word32* inOutIdx, word32 helloSz);
|
||||
#endif /* !defined(NO_WOLFSSL_SERVER) */
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
@@ -5816,6 +5886,7 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl);
|
||||
#endif
|
||||
WOLFSSL_LOCAL int IsSCR(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int IsDtlsNotSctpMode(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int IsDtlsNotSrtpMode(WOLFSSL* ssl);
|
||||
|
||||
WOLFSSL_LOCAL void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out);
|
||||
|
||||
@@ -5826,10 +5897,11 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL sword64 TimeNowInMilliseconds(void);
|
||||
#endif
|
||||
|
||||
WOLFSSL_LOCAL int FindSuiteMac(WOLFSSL* ssl, byte* suite);
|
||||
#endif
|
||||
WOLFSSL_LOCAL word32 LowResTimer(void);
|
||||
|
||||
WOLFSSL_LOCAL int FindSuiteSSL(const WOLFSSL* ssl, byte* suite);
|
||||
|
||||
#ifndef NO_CERTS
|
||||
WOLFSSL_LOCAL void InitX509Name(WOLFSSL_X509_NAME* name, int dynamicFlag,
|
||||
void* heap);
|
||||
@@ -6009,6 +6081,8 @@ WOLFSSL_LOCAL word32 nid2oid(int nid, int grp);
|
||||
WOLFSSL_API int wolfSSL_DtlsUpdateWindow(word16 cur_hi, word32 cur_lo,
|
||||
word16* next_hi, word32* next_lo, word32 *window);
|
||||
WOLFSSL_LOCAL void DtlsResetState(WOLFSSL *ssl);
|
||||
WOLFSSL_LOCAL int DtlsIgnoreError(int err);
|
||||
WOLFSSL_LOCAL void DtlsSetSeqNumForReply(WOLFSSL* ssl);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
@@ -6064,8 +6138,10 @@ WOLFSSL_LOCAL int Dtls13ReconstructSeqNumber(WOLFSSL* ssl,
|
||||
WOLFSSL_LOCAL int SendDtls13Ack(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int Dtls13RtxProcessingCertificate(WOLFSSL* ssl, byte* input,
|
||||
word32 inputSize);
|
||||
WOLFSSL_LOCAL int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output,
|
||||
WOLFSSL_LOCAL int Dtls13HashHandshake(WOLFSSL* ssl, const byte* input,
|
||||
word16 length);
|
||||
WOLFSSL_LOCAL int Dtls13HashClientHello(const WOLFSSL* ssl, byte* hash,
|
||||
int* hashSz, const byte* body, word32 length, CipherSpecs* specs);
|
||||
WOLFSSL_LOCAL void Dtls13FreeFsmResources(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int Dtls13RtxTimeout(WOLFSSL* ssl);
|
||||
WOLFSSL_LOCAL int Dtls13ProcessBufferedMessages(WOLFSSL* ssl);
|
||||
@@ -6147,6 +6223,23 @@ WOLFSSL_LOCAL int wolfSSL_quic_keys_active(WOLFSSL* ssl, enum encrypt_side side)
|
||||
#define WOLFSSL_IS_QUIC(s) 0
|
||||
#endif /* WOLFSSL_QUIC (else) */
|
||||
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK)
|
||||
WOLFSSL_LOCAL int FindPskSuite(const WOLFSSL* ssl, PreSharedKey* psk,
|
||||
byte* psk_key, word32* psk_keySz, const byte* suite, int* found,
|
||||
byte* foundSuite);
|
||||
#endif
|
||||
|
||||
WOLFSSL_LOCAL int wolfSSL_GetHmacType_ex(CipherSpecs* specs);
|
||||
|
||||
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_LOCAL int CreateCookieExt(const WOLFSSL* ssl, byte* hash,
|
||||
word16 hashSz, TLSX** exts,
|
||||
byte cipherSuite0, byte cipherSuite);
|
||||
#endif
|
||||
|
||||
WOLFSSL_LOCAL int TranslateErrorToAlert(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
@@ -729,6 +729,7 @@ typedef struct WOLFSSL_RAND_METHOD {
|
||||
* Add alert string to the function wolfSSL_alert_type_string_long in src/ssl.c
|
||||
*/
|
||||
enum AlertDescription {
|
||||
invalid_alert = -1,
|
||||
close_notify = 0,
|
||||
unexpected_message = 10,
|
||||
bad_record_mac = 20,
|
||||
|
@@ -2288,6 +2288,27 @@ static WC_INLINE void tcp_set_nonblocking(SOCKET_T* sockfd)
|
||||
#endif
|
||||
}
|
||||
|
||||
static WC_INLINE void tcp_set_blocking(SOCKET_T* sockfd)
|
||||
{
|
||||
#ifdef USE_WINDOWS_API
|
||||
unsigned long blocking = 0;
|
||||
int ret = ioctlsocket(*sockfd, FIONBIO, &blocking);
|
||||
if (ret == SOCKET_ERROR)
|
||||
err_sys_with_errno("ioctlsocket failed");
|
||||
#elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET) \
|
||||
|| defined (WOLFSSL_TIRTOS)|| defined(WOLFSSL_VXWORKS) \
|
||||
|| defined(WOLFSSL_ZEPHYR)
|
||||
/* non blocking not supported, for now */
|
||||
#else
|
||||
int flags = fcntl(*sockfd, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
err_sys_with_errno("fcntl get failed");
|
||||
flags = fcntl(*sockfd, F_SETFL, flags & (~O_NONBLOCK));
|
||||
if (flags < 0)
|
||||
err_sys_with_errno("fcntl set failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_PSK
|
||||
|
||||
|
@@ -170,7 +170,7 @@ WOLFSSL_API void wolfSSL_Debugging_OFF(void);
|
||||
WOLFSSL_API void WOLFSSL_MSG_EX(const char* fmt, ...);
|
||||
#define HAVE_WOLFSSL_MSG_EX
|
||||
#else
|
||||
#define WOLFSSL_MSG_EX(...)
|
||||
#define WOLFSSL_MSG_EX(...) do{} while(0)
|
||||
#endif
|
||||
WOLFSSL_API void WOLFSSL_MSG(const char* msg);
|
||||
WOLFSSL_API void WOLFSSL_BUFFER(const byte* buffer, word32 length);
|
||||
|
Reference in New Issue
Block a user