Merge pull request #5910 from julek-wolfssl/dtls13-stateless

DTLS 1.3 stateless server ClientHello parsing
This commit is contained in:
JacobBarthelmeh
2023-03-13 09:22:58 -06:00
committed by GitHub
14 changed files with 3803 additions and 2390 deletions

View File

@@ -14,6 +14,7 @@
#define WC_RSA_PSS
#define WOLFSSL_DTLS
#define WOLFSSL_DTLS13
#define WOLFSSL_SEND_HRR_COOKIE
#define WOLFSSL_DTLS_CID
/* Configurations */

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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 &&

1024
src/tls.c

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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),

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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);