forked from wolfSSL/wolfssl
dtls 1.3: Stateless ClientHello parsing
This commit is contained in:
@ -14,6 +14,7 @@
|
||||
#define WC_RSA_PSS
|
||||
#define WOLFSSL_DTLS
|
||||
#define WOLFSSL_DTLS13
|
||||
#define WOLFSSL_SEND_HRR_COOKIE
|
||||
#define WOLFSSL_DTLS_CID
|
||||
|
||||
/* Configurations */
|
||||
|
542
src/dtls.c
542
src/dtls.c
@ -46,6 +46,8 @@
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; }
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
|
||||
void DtlsResetState(WOLFSSL* ssl)
|
||||
@ -54,11 +56,6 @@ void DtlsResetState(WOLFSSL* ssl)
|
||||
* ClientHello that contains the cookie. Don't gate on IsAtLeastTLSv1_3
|
||||
* to handle the edge case when the peer wants a lower version. */
|
||||
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
/* Remove cookie so that it will get computed again */
|
||||
TLSX_Remove(&ssl->extensions, TLSX_COOKIE, ssl->heap);
|
||||
#endif
|
||||
|
||||
/* Reset DTLS window */
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
w64Zero(&ssl->dtls13Epochs[0].nextSeqNumber);
|
||||
@ -79,10 +76,10 @@ 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;
|
||||
}
|
||||
|
||||
#if !defined(NO_WOLFSSL_SERVER)
|
||||
@ -114,7 +111,11 @@ typedef struct WolfSSL_CH {
|
||||
WolfSSL_ConstVector cipherSuite;
|
||||
WolfSSL_ConstVector compression;
|
||||
WolfSSL_ConstVector extension;
|
||||
const byte* msg;
|
||||
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 +134,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->cookie.size < OPAQUE16_LEN + 1)
|
||||
return BUFFER_E;
|
||||
ato16(ch->cookie.elements, &len);
|
||||
if (ch->cookie.size - OPAQUE16_LEN != len)
|
||||
return BUFFER_E;
|
||||
ret = TlsCheckCookie(ssl, ch->cookie.elements + OPAQUE16_LEN,
|
||||
ch->cookie.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 +221,7 @@ static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch)
|
||||
if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz)
|
||||
return BUFFER_ERROR;
|
||||
|
||||
ch->msg = input - DTLS_HANDSHAKE_HEADER_SZ;
|
||||
ch->pv = (ProtocolVersion*)(input + idx);
|
||||
idx += OPAQUE16_LEN;
|
||||
ch->random = (byte*)(input + idx);
|
||||
@ -202,12 +241,12 @@ static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch)
|
||||
idx += ReadVector16(input + idx, &ch->extension);
|
||||
if (idx > helloSz)
|
||||
return BUFFER_ERROR;
|
||||
ch->length = idx;
|
||||
ch->length = idx + DTLS_HANDSHAKE_HEADER_SZ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
#if (defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) && defined(HAVE_SESSION_TICKET)) \
|
||||
|| defined(WOLFSSL_DTLS13)
|
||||
static int TlsxFindByType(WolfSSL_ConstVector* ret, word16 extType,
|
||||
WolfSSL_ConstVector exts)
|
||||
{
|
||||
@ -232,16 +271,18 @@ static int TlsxFindByType(WolfSSL_ConstVector* ret, word16 extType,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int TlsTicketIsValid(WOLFSSL* ssl, WolfSSL_ConstVector exts,
|
||||
byte* isValid)
|
||||
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
static int TlsTicketIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector exts,
|
||||
PskInfo* pskInfo)
|
||||
{
|
||||
WolfSSL_ConstVector tlsxSessionTicket;
|
||||
byte tempTicket[SESSION_TICKET_LEN];
|
||||
InternalTicket* it;
|
||||
int ret;
|
||||
|
||||
*isValid = 0;
|
||||
ret = TlsxFindByType(&tlsxSessionTicket, TLSX_SESSION_TICKET, exts);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
@ -250,23 +291,28 @@ static int TlsTicketIsValid(WOLFSSL* ssl, WolfSSL_ConstVector exts,
|
||||
if (tlsxSessionTicket.size > SESSION_TICKET_LEN)
|
||||
return 0;
|
||||
XMEMCPY(tempTicket, tlsxSessionTicket.elements, tlsxSessionTicket.size);
|
||||
ret = DoDecryptTicket(ssl, tempTicket, (word32)tlsxSessionTicket.size, &it);
|
||||
ret = DoDecryptTicket((WOLFSSL*)ssl, tempTicket,
|
||||
(word32)tlsxSessionTicket.size, &it);
|
||||
if (ret != WOLFSSL_TICKET_RET_OK && ret != WOLFSSL_TICKET_RET_CREATE)
|
||||
return 0;
|
||||
/* Store info for later */
|
||||
pskInfo->pv = it->pv;
|
||||
pskInfo->cipherSuite0 = it->suite[0];
|
||||
pskInfo->cipherSuite = it->suite[1];
|
||||
ato16(it->namedGroup, &pskInfo->namedGroup);
|
||||
|
||||
ForceZero(it, sizeof(InternalTicket));
|
||||
*isValid = 1;
|
||||
pskInfo->isValid = 1;
|
||||
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,
|
||||
PskInfo* pskInfo)
|
||||
{
|
||||
WOLFSSL_SESSION* sess;
|
||||
word32 sessRow;
|
||||
int ret;
|
||||
|
||||
*isValid = 0;
|
||||
if (ssl->options.sessionCacheOff)
|
||||
return 0;
|
||||
if (sessionID.size != ID_LEN)
|
||||
@ -277,9 +323,16 @@ 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;
|
||||
/* Store info for later */
|
||||
pskInfo->pv = sess->version;
|
||||
pskInfo->cipherSuite0 = sess->cipherSuite0;
|
||||
pskInfo->cipherSuite = sess->cipherSuite;
|
||||
pskInfo->namedGroup = sess->namedGroup;
|
||||
|
||||
pskInfo->isValid = 1;
|
||||
wolfSSL_FreeSession(ssl->ctx, sess);
|
||||
return 0;
|
||||
}
|
||||
@ -290,60 +343,385 @@ static int TlsSessionIdIsValid(WOLFSSL* ssl, WolfSSL_ConstVector sessionID,
|
||||
#endif
|
||||
ret = TlsSessionCacheGetAndLock(sessionID.elements, &sess, &sessRow, 1);
|
||||
if (ret == 0 && sess != NULL) {
|
||||
*isValid = 1;
|
||||
/* Store info for later */
|
||||
pskInfo->pv = sess->version;
|
||||
pskInfo->cipherSuite0 = sess->cipherSuite0;
|
||||
pskInfo->cipherSuite = sess->cipherSuite;
|
||||
pskInfo->namedGroup = sess->namedGroup;
|
||||
|
||||
pskInfo->isValid = 1;
|
||||
TlsSessionCacheUnlockRow(sessRow);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TlsResumptionIsValid(WOLFSSL* ssl, WolfSSL_CH* ch, byte* isValid)
|
||||
static int TlsResumptionIsValid(const WOLFSSL* ssl, WolfSSL_CH* ch,
|
||||
PskInfo* pskInfo)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*isValid = 0;
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
ret = TlsTicketIsValid(ssl, ch->extension, isValid);
|
||||
ret = TlsTicketIsValid(ssl, ch->extension, pskInfo);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (*isValid)
|
||||
if (pskInfo->isValid)
|
||||
return 0;
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
ret = TlsSessionIdIsValid(ssl, ch->sessionId, isValid);
|
||||
ret = TlsSessionIdIsValid(ssl, ch->sessionId, pskInfo);
|
||||
return ret;
|
||||
}
|
||||
#endif /* 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, PskInfo* pskInfo)
|
||||
{
|
||||
WolfSSL_ConstVector tlsxSupportedVersions;
|
||||
int ret;
|
||||
ProtocolVersion pv = ssl->version;
|
||||
|
||||
ret = TlsxFindByType(&tlsxSupportedVersions, TLSX_SUPPORTED_VERSIONS,
|
||||
ch->extension);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (tlsxSupportedVersions.size == 0) {
|
||||
*isTls13 = 0;
|
||||
return 0;
|
||||
}
|
||||
ret = TLSX_SupportedVersions_Parse(ssl, tlsxSupportedVersions.elements,
|
||||
tlsxSupportedVersions.size, client_hello, &pv, NULL, NULL);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (pskInfo->isValid && (pskInfo->pv.major != pv.major ||
|
||||
pskInfo->pv.minor != pv.minor))
|
||||
return VERSION_ERROR;
|
||||
if (IsAtLeastTLSv1_3(pv))
|
||||
*isTls13 = 1;
|
||||
else
|
||||
*isTls13 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CopyExtensions(TLSX* src, TLSX** dst, void* heap)
|
||||
{
|
||||
/* Copy the following extensions
|
||||
* * SupportedCurves */
|
||||
TLSX* extension;
|
||||
int ret;
|
||||
|
||||
extension = TLSX_Find(src, TLSX_SUPPORTED_GROUPS);
|
||||
if (extension != NULL) {
|
||||
SupportedCurve* curve;
|
||||
curve = (SupportedCurve*)extension->data;
|
||||
for (curve = (SupportedCurve*)extension->data; curve != NULL;
|
||||
curve = curve->next) {
|
||||
ret = TLSX_UseSupportedCurve(dst, curve->name, heap);
|
||||
if (ret != WOLFSSL_SUCCESS)
|
||||
return MEMORY_E;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int SendStatelessReply(const WOLFSSL* ssl, WolfSSL_CH* ch, byte isTls13,
|
||||
PskInfo* pskInfo)
|
||||
{
|
||||
int ret;
|
||||
(void)isTls13;
|
||||
(void)pskInfo;
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (isTls13) {
|
||||
#ifdef WOLFSSL_SEND_HRR_COOKIE
|
||||
if (ch->cookie.size == 0) {
|
||||
TLSX* parsedExts = NULL;
|
||||
WolfSSL_ConstVector tlsx;
|
||||
Suites suites;
|
||||
word16 len;
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
byte haveKS = 0;
|
||||
byte usePSK = 0;
|
||||
byte doKE = 0;
|
||||
#endif
|
||||
CipherSuite cs;
|
||||
CipherSpecs specs;
|
||||
|
||||
XMEMSET(&cs, 0, sizeof(cs));
|
||||
XMEMSET(&specs, 0, sizeof(specs));
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Hashes are reset in SendTls13ServerHello when sending a HRR */
|
||||
ret = Dtls13HashHandshake((WOLFSSL*)ssl, ch->msg, ch->length);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
|
||||
/* Populate the suites struct to find a common ciphersuite */
|
||||
XMEMSET(&suites, 0, sizeof(suites));
|
||||
suites.suiteSz = 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 = CopyExtensions(ssl->extensions, &parsedExts, ssl->heap);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
|
||||
/* Signature algs */
|
||||
ret = TlsxFindByType(&tlsx, TLSX_SIGNATURE_ALGORITHMS,
|
||||
ch->extension);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsx.size > OPAQUE16_LEN) {
|
||||
ato16(tlsx.elements, &len);
|
||||
if (len != tlsx.size - OPAQUE16_LEN)
|
||||
ERROR_OUT(BUFFER_ERROR, dtls13_cleanup);
|
||||
if ((len % 2) != 0)
|
||||
ERROR_OUT(BUFFER_ERROR, dtls13_cleanup);
|
||||
suites.hashSigAlgoSz = len;
|
||||
XMEMCPY(suites.hashSigAlgo, tlsx.elements + OPAQUE16_LEN,
|
||||
len);
|
||||
}
|
||||
|
||||
/* Supported groups */
|
||||
ret = TlsxFindByType(&tlsx, TLSX_SUPPORTED_GROUPS,
|
||||
ch->extension);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsx.size != 0) {
|
||||
ret = TLSX_SupportedCurve_Parse(ssl, tlsx.elements,
|
||||
tlsx.size, 1, &parsedExts);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
}
|
||||
|
||||
/* Key share */
|
||||
ret = TlsxFindByType(&tlsx, TLSX_KEY_SHARE,
|
||||
ch->extension);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsx.size != 0) {
|
||||
ret = TLSX_KeyShare_Parse_ClientHello(ssl, tlsx.elements,
|
||||
tlsx.size, &parsedExts);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
haveKS = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
/* Pre-shared key */
|
||||
ret = TlsxFindByType(&tlsx, TLSX_PRE_SHARED_KEY, ch->extension);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsx.size != 0) {
|
||||
/* 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;
|
||||
|
||||
ret = TlsxFindByType(&tlsx, TLSX_PSK_KEY_EXCHANGE_MODES,
|
||||
ch->extension);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if (tlsx.size == 0)
|
||||
ERROR_OUT(MISSING_HANDSHAKE_DATA, 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(MISSING_HANDSHAKE_DATA, dtls13_cleanup);
|
||||
doKE = 1;
|
||||
}
|
||||
else {
|
||||
if ((modes & (1 << PSK_KE)) == 0)
|
||||
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
if (usePSK) {
|
||||
if (pskInfo->isValid) {
|
||||
cs.cipherSuite0 = pskInfo->cipherSuite0;
|
||||
cs.cipherSuite = pskInfo->cipherSuite;
|
||||
}
|
||||
else {
|
||||
/* Only support the default ciphersuite for PSK */
|
||||
cs.cipherSuite0 = TLS13_BYTE;
|
||||
cs.cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
ret = MatchSuite_ex(ssl, &suites, &cs, parsedExts);
|
||||
if (ret < 0) {
|
||||
WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
|
||||
SendAlert((WOLFSSL*)ssl, alert_fatal, handshake_failure);
|
||||
goto dtls13_cleanup;
|
||||
}
|
||||
}
|
||||
if (cs.doHelloRetry) {
|
||||
ret = TLSX_KeyShare_SetSupported(ssl, &parsedExts);
|
||||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
}
|
||||
|
||||
/* Need to remove the keyshare ext if we are not doing PSK and we
|
||||
* found a common group. */
|
||||
if (cs.clientKSE != NULL
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
&& !usePSK
|
||||
#endif
|
||||
)
|
||||
{
|
||||
TLSX_Remove(&parsedExts, TLSX_KEY_SHARE, ssl->heap);
|
||||
}
|
||||
|
||||
{
|
||||
WOLFSSL* nonConstSSL = (WOLFSSL*)ssl;
|
||||
TLSX* sslExts = nonConstSSL->extensions;
|
||||
|
||||
/* This is required to correctly generate the hash */
|
||||
ret = SetCipherSpecs_ex(WOLFSSL_SERVER_END, cs.cipherSuite0,
|
||||
cs.cipherSuite, &nonConstSSL->specs, NULL);
|
||||
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 = ch->sessionId.size;
|
||||
nonConstSSL->options.cipherSuite0 = cs.cipherSuite0;
|
||||
nonConstSSL->options.cipherSuite = cs.cipherSuite;
|
||||
nonConstSSL->extensions = parsedExts;
|
||||
|
||||
|
||||
ret = SendTls13ServerHello(nonConstSSL, hello_retry_request);
|
||||
|
||||
InitCipherSpecs(&nonConstSSL->specs);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
ret = SendAlert((WOLFSSL*)ssl, alert_fatal, illegal_parameter);
|
||||
#else
|
||||
#error "WOLFSSL_SEND_HRR_COOKIE has to be defined to use DTLS 1.3 server"
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
|
||||
word32* inOutIdx, word32 helloSz)
|
||||
{
|
||||
byte cookie[DTLS_COOKIE_SZ];
|
||||
int ret;
|
||||
WolfSSL_CH ch;
|
||||
byte isTls13 = 0;
|
||||
PskInfo pskInfo;
|
||||
|
||||
*process = 1;
|
||||
XMEMSET(&pskInfo, 0, sizeof(pskInfo));
|
||||
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);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (isValid)
|
||||
return 0;
|
||||
ret = TlsResumptionIsValid(ssl, &ch, &pskInfo);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (pskInfo.isValid) {
|
||||
ssl->options.dtlsStateful = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */
|
||||
|
||||
ret = CreateDtlsCookie(ssl, &ch, cookie);
|
||||
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_DTLS13
|
||||
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||
ret = TlsCheckSupportedVersion(ssl, &ch, &isTls13, &pskInfo);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (isTls13) {
|
||||
ret = TlsxFindByType(&ch.cookie, TLSX_COOKIE, ch.extension);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ch.cookie.size == 0) {
|
||||
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13, &pskInfo);
|
||||
}
|
||||
else {
|
||||
byte cookieGood;
|
||||
ret = CheckDtlsCookie(ssl, &ch, isTls13, &cookieGood);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (!cookieGood)
|
||||
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13, &pskInfo);
|
||||
else
|
||||
ssl->options.dtlsStateful = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -330,7 +330,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 */
|
||||
|
120
src/internal.c
120
src/internal.c
@ -558,7 +558,7 @@ int IsDtlsNotSctpMode(WOLFSSL* ssl)
|
||||
/* Secure Real-time Transport Protocol */
|
||||
/* If SRTP is not enabled returns the state of the dtls option.
|
||||
* If SRTP is enabled returns dtls && !dtlsSrtpProfiles. */
|
||||
static WC_INLINE int IsDtlsNotSrtpMode(WOLFSSL* ssl)
|
||||
int IsDtlsNotSrtpMode(WOLFSSL* ssl)
|
||||
{
|
||||
#ifdef WOLFSSL_SRTP
|
||||
return ssl->options.dtls && !ssl->dtlsSrtpProfiles;
|
||||
@ -15663,8 +15663,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
|
||||
@ -20451,7 +20449,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 +20493,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 +20535,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 +22877,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 +27042,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)
|
||||
@ -32546,7 +32544,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(WOLFSSL* ssl, const Suites* suites, word16 idx,
|
||||
CipherSuite* cs, TLSX* extensions)
|
||||
{
|
||||
#ifndef NO_PSK
|
||||
int havePSK = ssl->options.havePSK;
|
||||
@ -32630,7 +32629,7 @@ 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)) {
|
||||
WOLFSSL_MSG("Don't have matching curves");
|
||||
return 0;
|
||||
}
|
||||
@ -32640,25 +32639,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 +32669,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 +32694,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 +32714,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 +32724,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 +32733,46 @@ 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, ssl->extensions);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ssl->options.cipherSuite0 = cs.cipherSuite0;
|
||||
ssl->options.cipherSuite = cs.cipherSuite;
|
||||
ssl->ecdhCurveOID = cs.ecdhCurveOID;
|
||||
|
||||
ret = SetCipherSpecs(ssl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = PickHashSigAlgo(ssl, peerSuites->hashSigAlgo,
|
||||
peerSuites->hashSigAlgoSz);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (cs.doHelloRetry) {
|
||||
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
|
||||
return TLSX_KeyShare_SetSupported(ssl, &ssl->extensions);
|
||||
}
|
||||
|
||||
#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,6 +33141,8 @@ 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 &&
|
||||
@ -33121,14 +33157,14 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
* Client Hello. */
|
||||
ssl->keys.dtls_handshake_number =
|
||||
ssl->keys.dtls_peer_handshake_number;
|
||||
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz,
|
||||
&process);
|
||||
if (ret != 0 || !process) {
|
||||
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
|
||||
if (ret != 0 || !ssl->options.dtlsStateful) {
|
||||
*inOutIdx += helloSz;
|
||||
DtlsResetState(ssl);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ssl->options.dtlsStateful = 1;
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
/* protocol version, random and session id length check */
|
||||
|
2737
src/keys.c
2737
src/keys.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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 &&
|
||||
|
140
src/tls13.c
140
src/tls13.c
@ -3337,7 +3337,8 @@ 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)
|
||||
static int CreateCookieExt(const WOLFSSL* ssl, byte* hash, byte hashSz,
|
||||
TLSX** exts)
|
||||
{
|
||||
int ret;
|
||||
byte mac[WC_MAX_DIGEST_SIZE] = {0};
|
||||
@ -3380,7 +3381,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, hash, hashSz, mac, macSz, 1, exts);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3390,52 +3391,40 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
|
||||
#define HRR_MAX_HS_HEADER_SZ HANDSHAKE_HEADER_SZ
|
||||
#endif /* WOLFSSL_DTLS13 */
|
||||
|
||||
/* Restart the handshake hash with a hash of the previous messages.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
static int CreateCookieHash(const WOLFSSL* ssl, byte** hash, byte* hashSz,
|
||||
Hashes* hashes, TLSX** exts)
|
||||
{
|
||||
int ret;
|
||||
Hashes hashes;
|
||||
byte header[HANDSHAKE_HEADER_SZ] = {0};
|
||||
byte* hash = NULL;
|
||||
byte hashSz = 0;
|
||||
|
||||
ret = BuildCertHashes(ssl, &hashes);
|
||||
(void)exts;
|
||||
|
||||
ret = BuildCertHashes(ssl, hashes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
*hash = NULL;
|
||||
switch (ssl->specs.mac_algorithm) {
|
||||
#ifndef NO_SHA256
|
||||
case sha256_mac:
|
||||
hash = hashes.sha256;
|
||||
*hash = hashes->sha256;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_SHA384
|
||||
case sha384_mac:
|
||||
hash = hashes.sha384;
|
||||
*hash = hashes->sha384;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_TLS13_SHA512
|
||||
case sha512_mac:
|
||||
hash = hashes.sha512;
|
||||
*hash = hashes->sha512;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
hashSz = ssl->specs.hash_size;
|
||||
*hashSz = ssl->specs.hash_size;
|
||||
|
||||
/* check hash */
|
||||
if (hash == NULL && hashSz > 0)
|
||||
if (*hash == NULL && *hashSz > 0)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
AddTls13HandShakeHeader(header, hashSz, 0, 0, message_hash, ssl);
|
||||
|
||||
#ifdef WOLFSSL_DEBUG_TLS
|
||||
WOLFSSL_MSG("Restart Hash");
|
||||
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];
|
||||
@ -3443,20 +3432,55 @@ int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
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++] = *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;
|
||||
if (kse == NULL) {
|
||||
WOLFSSL_MSG("KeyShareEntry can't be empty when negotiating "
|
||||
"parameters");
|
||||
return BAD_STATE_E;
|
||||
}
|
||||
c16toa(kse->group, cookie + idx);
|
||||
idx += OPAQUE16_LEN;
|
||||
}
|
||||
return CreateCookie(ssl, cookie, idx);
|
||||
ret = CreateCookieExt(ssl, cookie, idx, exts);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Restart the handshake hash with a hash of the previous messages.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
* returns 0 on success, otherwise failure.
|
||||
*/
|
||||
int RestartHandshakeHash(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
byte header[HANDSHAKE_HEADER_SZ] = {0};
|
||||
Hashes hashes;
|
||||
byte* hash = NULL;
|
||||
byte hashSz = 0;
|
||||
|
||||
ret = CreateCookieHash(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);
|
||||
|
||||
#ifdef WOLFSSL_DEBUG_TLS
|
||||
WOLFSSL_MSG("Restart Hash");
|
||||
WOLFSSL_BUFFER(hash, hashSz);
|
||||
#endif
|
||||
|
||||
ret = InitHandshakeHashes(ssl);
|
||||
if (ret != 0)
|
||||
@ -5975,7 +5999,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, byte cookieSz)
|
||||
{
|
||||
int ret;
|
||||
byte mac[WC_MAX_DIGEST_SIZE] = {0};
|
||||
@ -6064,11 +6088,11 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
|
||||
int keyShareExt = 0;
|
||||
int ret;
|
||||
|
||||
cookieDataSz = ret = CheckCookie(ssl, &cookie->data, cookie->len);
|
||||
cookieDataSz = ret = TlsCheckCookie(ssl, cookie->data, cookie->len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
hashSz = cookie->data;
|
||||
cookieData = &cookie->data;
|
||||
hashSz = cookie->data[0];
|
||||
cookieData = cookie->data;
|
||||
idx = OPAQUE8_LEN;
|
||||
|
||||
/* Restart handshake hash with synthetic message hash. */
|
||||
@ -6346,6 +6370,22 @@ 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;
|
||||
DtlsResetState(ssl);
|
||||
goto exit_dch;
|
||||
}
|
||||
}
|
||||
ssl->options.dtlsStateful = 1;
|
||||
#endif /* WOLFSSL_DTLS */
|
||||
|
||||
args->idx = *inOutIdx;
|
||||
args->begin = args->idx;
|
||||
|
||||
@ -6761,8 +6801,21 @@ exit_dch:
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret == VERSION_ERROR)
|
||||
if (ret == VERSION_ERROR) {
|
||||
#ifdef WOLFSSL_DTLS
|
||||
if (ssl->options.dtls) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
|
||||
}
|
||||
|
||||
FreeDch13Args(ssl, args);
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
@ -11335,6 +11388,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 +11903,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 */
|
||||
@ -12520,6 +12580,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)
|
||||
|
167
tests/api.c
167
tests/api.c
@ -37545,7 +37545,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
|
||||
@ -59249,12 +59248,174 @@ 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(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;
|
||||
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.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;
|
||||
|
||||
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 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;
|
||||
|
||||
wolfSSL_dtls_set_using_nonblock(ssl, 1);
|
||||
tcp_set_nonblocking(&fd);
|
||||
|
||||
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);
|
||||
tcp_set_blocking(&fd);
|
||||
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@ -59269,10 +59430,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
|
||||
};
|
||||
|
||||
|
@ -2123,6 +2123,14 @@ struct Suites {
|
||||
byte setSuites; /* user set suites from default */
|
||||
};
|
||||
|
||||
typedef struct CipherSuite {
|
||||
byte cipherSuite0;
|
||||
byte cipherSuite;
|
||||
word32 ecdhCurveOID;
|
||||
struct KeyShareEntry* clientKSE;
|
||||
int doHelloRetry;
|
||||
} CipherSuite;
|
||||
|
||||
WOLFSSL_LOCAL void InitSuitesHashSigAlgo(Suites* suites, int haveECDSAsig,
|
||||
int haveRSAsig, int haveFalconSig,
|
||||
int haveDilithiumSig, int haveAnon,
|
||||
@ -2140,6 +2148,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 +2703,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) \
|
||||
@ -2886,13 +2904,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, CipherSuite* cs);
|
||||
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 +3043,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,
|
||||
byte cookieSz);
|
||||
|
||||
|
||||
/* Key Share - TLS v1.3 Specification */
|
||||
@ -3050,11 +3077,20 @@ 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_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)
|
||||
@ -3096,7 +3132,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 +3842,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 {
|
||||
@ -3888,6 +3926,16 @@ typedef struct TicketNonce {
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DTLS
|
||||
typedef struct PskInfo {
|
||||
ProtocolVersion pv;
|
||||
byte cipherSuite0;
|
||||
byte cipherSuite;
|
||||
word16 namedGroup;
|
||||
byte isValid:1;
|
||||
} PskInfo;
|
||||
#endif
|
||||
|
||||
/* wolfSSL session type */
|
||||
struct WOLFSSL_SESSION {
|
||||
/* WARNING Do not add fields here. They will be ignored in
|
||||
@ -4221,6 +4269,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 */
|
||||
@ -5625,6 +5674,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 SetCipherSpecs_ex(word16 side, byte cipherSuite0,
|
||||
byte cipherSuite, CipherSpecs* specs, Options* opts);
|
||||
WOLFSSL_LOCAL int MakeMasterSecret(WOLFSSL* ssl);
|
||||
|
||||
WOLFSSL_LOCAL int DeriveKeys(WOLFSSL* ssl);
|
||||
@ -5640,7 +5691,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 +5708,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 +5856,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 +5869,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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user