Browse Source

dtls 1.3: Stateless ClientHello parsing

Juliusz Sosinowicz 1 year ago
parent
commit
984d709db0
11 changed files with 1682 additions and 838 deletions
  1. 1 0
      IDE/WIN/user_settings.h
  2. 459 81
      src/dtls.c
  3. 2 1
      src/dtls13.c
  4. 78 42
      src/internal.c
  5. 469 382
      src/keys.c
  6. 5 1
      src/ssl.c
  7. 310 279
      src/tls.c
  8. 104 36
      src/tls13.c
  9. 165 2
      tests/api.c
  10. 68 14
      wolfssl/internal.h
  11. 21 0
      wolfssl/test.h

+ 1 - 0
IDE/WIN/user_settings.h

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

+ 459 - 81
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);
+    }
+
+    return ret;
+}
+
+static int CheckDtlsCookie(const WOLFSSL* ssl, WolfSSL_CH* ch,
+                           byte isTls13, byte* cookieGood)
+{
+    int ret = 0;
+
+    (void)isTls13;
 
-out:
-    wc_HmacFree(&cookieHmac);
+    *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);
+    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 */
+
+#ifdef WOLFSSL_DTLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        ret = TlsCheckSupportedVersion(ssl, &ch, &isTls13, &pskInfo);
         if (ret != 0)
             return ret;
-        if (isValid)
-            return 0;
+        if (isTls13) {
+            ret = TlsxFindByType(&ch.cookie, TLSX_COOKIE, ch.extension);
+            if (ret != 0)
+                return ret;
+        }
     }
-#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */
+#endif
 
-    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);
+    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;

+ 2 - 1
src/dtls13.c

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

+ 78 - 42
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 */

File diff suppressed because it is too large
+ 469 - 382
src/keys.c


+ 5 - 1
src/ssl.c

@@ -13288,6 +13288,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
             ssl->options.dtls   = 1;
             ssl->options.tls    = 1;
             ssl->options.tls1_1 = 1;
+            ssl->options.dtlsStateful = 1;
         }
         #endif
 
@@ -13837,6 +13838,9 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
             ssl->options.dtls   = 1;
             ssl->options.tls    = 1;
             ssl->options.tls1_1 = 1;
+            if (!IsDtlsNotSctpMode(ssl) || !IsDtlsNotSrtpMode(ssl) ||
+                    IsSCR(ssl))
+                ssl->options.dtlsStateful = 1;
         }
     #endif
 
@@ -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 &&

File diff suppressed because it is too large
+ 310 - 279
src/tls.c


+ 104 - 36
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)

+ 165 - 2
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
     };
 

+ 68 - 14
wolfssl/internal.h

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

+ 21 - 0
wolfssl/test.h

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

Some files were not shown because too many files changed in this diff