Browse Source

Merge pull request #5524 from rizlik/protocol_version_alerts

Dtls13: improvements
David Garske 1 year ago
parent
commit
a5a9ab96e6
11 changed files with 476 additions and 108 deletions
  1. 2 1
      scripts/dtls13.test
  2. 14 11
      src/dtls13.c
  3. 53 32
      src/internal.c
  4. 8 0
      src/ssl.c
  5. 1 5
      src/tls.c
  6. 118 58
      src/tls13.c
  7. 242 1
      tests/api.c
  8. 1 0
      tests/include.am
  9. 12 0
      tests/suites.c
  10. 20 0
      tests/test-dtls13-downgrade-fails.conf
  11. 5 0
      wolfssl/ssl.h

+ 2 - 1
scripts/dtls13.test

@@ -167,4 +167,5 @@ if [ ! -z $DTLS13_DO_DELAY_TEST ];then
    test_time_delays
 fi
 
-
+echo
+echo "All tests SUCCEEDED!!!"

+ 14 - 11
src/dtls13.c

@@ -809,7 +809,7 @@ static int Dtls13SendOneFragmentRtx(WOLFSSL* ssl,
     enum HandShakeType handshakeType, word16 outputSize, byte* message,
     word32 length, int hashOutput)
 {
-    Dtls13RtxRecord* rtxRecord;
+    Dtls13RtxRecord* rtxRecord = NULL;
     word16 recordHeaderLength;
     byte isProtected;
     int ret;
@@ -817,20 +817,23 @@ static int Dtls13SendOneFragmentRtx(WOLFSSL* ssl,
     isProtected = Dtls13TypeIsEncrypted(handshakeType);
     recordHeaderLength = Dtls13GetRlHeaderLength(ssl, isProtected);
 
-    rtxRecord = Dtls13RtxNewRecord(ssl, message + recordHeaderLength,
-        (word16)(length - recordHeaderLength), handshakeType,
-        ssl->dtls13EncryptEpoch->nextSeqNumber);
-
-    if (rtxRecord == NULL)
-        return MEMORY_E;
+    if (handshakeType != hello_retry_request) {
+        rtxRecord = Dtls13RtxNewRecord(ssl, message + recordHeaderLength,
+            (word16)(length - recordHeaderLength), handshakeType,
+            ssl->dtls13EncryptEpoch->nextSeqNumber);
+        if (rtxRecord == NULL)
+            return MEMORY_E;
+    }
 
     ret = Dtls13SendFragment(ssl, message, outputSize, (word16)length,
         handshakeType, hashOutput, Dtls13SendNow(ssl, handshakeType));
 
-    if (ret == 0 || ret == WANT_WRITE)
-        Dtls13RtxAddRecord(&ssl->dtls13Rtx, rtxRecord);
-    else
-        Dtls13FreeRtxBufferRecord(ssl, rtxRecord);
+    if (rtxRecord != NULL) {
+        if (ret == 0 || ret == WANT_WRITE)
+            Dtls13RtxAddRecord(&ssl->dtls13Rtx, rtxRecord);
+        else
+            Dtls13FreeRtxBufferRecord(ssl, rtxRecord);
+    }
 
     return ret;
 }

+ 53 - 32
src/internal.c

@@ -10397,13 +10397,8 @@ static int GetRecordHeader(WOLFSSL* ssl, word32* inOutIdx,
         else {
             WOLFSSL_MSG("SSL version error");
             /* send alert per RFC5246 Appendix E. Backward Compatibility */
-            if (ssl->options.side == WOLFSSL_CLIENT_END) {
-#ifdef WOLFSSL_MYSQL_COMPATIBLE
-                SendAlert(ssl, alert_fatal, wc_protocol_version);
-#else
-                SendAlert(ssl, alert_fatal, protocol_version);
-#endif
-            }
+            if (ssl->options.side == WOLFSSL_CLIENT_END)
+                SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
             WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
             return VERSION_ERROR;              /* only use requested version */
         }
@@ -18468,24 +18463,12 @@ const char* AlertTypeToString(int type)
                 return decrypt_error_str;
             }
 
-    #ifdef WOLFSSL_MYSQL_COMPATIBLE
-    /* catch name conflict for enum protocol with MYSQL build */
-        case wc_protocol_version:
-            {
-                static const char wc_protocol_version_str[] =
-                    "wc_protocol_version";
-                return wc_protocol_version_str;
-            }
-
-    #else
-        case protocol_version:
+        case wolfssl_alert_protocol_version:
             {
                 static const char protocol_version_str[] =
                     "protocol_version";
                 return protocol_version_str;
             }
-
-    #endif
         case insufficient_security:
             {
                 static const char insufficient_security_str[] =
@@ -18869,7 +18852,55 @@ static int HandleDTLSDecryptFailed(WOLFSSL* ssl)
     WOLFSSL_MSG("DTLS: Ignoring failed decryption");
     return ret;
 }
-#endif
+
+static int DtlsShouldDrop(WOLFSSL* ssl, int retcode)
+{
+    if (ssl->options.handShakeDone && !IsEncryptionOn(ssl, 0)) {
+        WOLFSSL_MSG("Silently dropping plaintext DTLS message "
+                    "on established connection.");
+        return 1;
+    }
+
+    if ((ssl->options.handShakeDone && retcode != 0)
+        || retcode == SEQUENCE_ERROR || retcode == DTLS_CID_ERROR) {
+        WOLFSSL_MSG_EX("Silently dropping DTLS message: %d", retcode);
+        return 1;
+    }
+
+#ifdef WOLFSSL_DTLS13
+    if (IsAtLeastTLSv1_3(ssl->version) && !w64IsZero(ssl->dtls13Epoch)
+            && w64IsZero(ssl->keys.curEpoch64) && ssl->curRL.type != ack) {
+        WOLFSSL_MSG("Silently dropping plaintext DTLS message "
+                    "during encrypted handshake.");
+        return 1;
+    }
+#endif /* WOLFSSL_DTLS13 */
+
+#ifndef NO_WOLFSSL_SERVER
+    if (ssl->options.side == WOLFSSL_SERVER_END
+            && ssl->curRL.type != handshake) {
+        int beforeCookieVerified = 0;
+        if (!IsAtLeastTLSv1_3(ssl->version)) {
+            beforeCookieVerified =
+                ssl->options.acceptState < ACCEPT_FIRST_REPLY_DONE;
+        }
+#ifdef WOLFSSL_DTLS13
+        else {
+            beforeCookieVerified =
+                ssl->options.acceptState < TLS13_ACCEPT_SECOND_REPLY_DONE;
+        }
+#endif /* WOLFSSL_DTLS13 */
+
+        if (beforeCookieVerified) {
+            WOLFSSL_MSG("Drop non-handshake record before handshake");
+            return 1;
+        }
+    }
+#endif /* NO_WOLFSSL_SERVER */
+
+    return 0;
+}
+#endif /* WOLFSSL_DTLS */
 
 int ProcessReply(WOLFSSL* ssl)
 {
@@ -19064,16 +19095,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
                                        &ssl->curRL, &ssl->curSize);
 
 #ifdef WOLFSSL_DTLS
-            if (ssl->options.dtls) {
-                if ((ssl->options.handShakeDone && !IsEncryptionOn(ssl, 0))
-                        || ret == SEQUENCE_ERROR || ret == DTLS_CID_ERROR) {
-                    if (ssl->options.handShakeDone && !IsEncryptionOn(ssl, 0)) {
-                        WOLFSSL_MSG("Silently dropping plaintext DTLS message "
-                                    "on established connection.");
-                    }
-                    else {
-                        WOLFSSL_MSG("Silently dropping DTLS message");
-                    }
+            if (ssl->options.dtls && DtlsShouldDrop(ssl, ret)) {
                     ssl->options.processReply = doProcessInit;
                     ssl->buffers.inputBuffer.length = 0;
                     ssl->buffers.inputBuffer.idx = 0;
@@ -19089,7 +19111,6 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
 #endif /* WOLFSSL_DTLS13 */
 
                     continue;
-                }
             }
 #endif
             if (ret != 0)

+ 8 - 0
src/ssl.c

@@ -12407,6 +12407,10 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
                 WOLFSSL_ERROR(ssl->error);
                 return WOLFSSL_FATAL_ERROR;
             }
+#ifdef WOLFSSL_DTLS13
+            if (ssl->options.dtls)
+                ssl->dtls13SendingAckOrRtx = 0;
+#endif /* WOLFSSL_DTLS13 */
         }
 
         ret = RetrySendAlert(ssl);
@@ -12949,6 +12953,10 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
                 WOLFSSL_ERROR(ssl->error);
                 return WOLFSSL_FATAL_ERROR;
             }
+#ifdef WOLFSSL_DTLS13
+            if (ssl->options.dtls)
+                ssl->dtls13SendingAckOrRtx = 0;
+#endif /* WOLFSSL_DTLS13 */
         }
 
         ret = RetrySendAlert(ssl);

+ 1 - 5
src/tls.c

@@ -6038,11 +6038,7 @@ static int TLSX_SupportedVersions_Parse(WOLFSSL* ssl, const byte* input,
             set = 1;
         }
         if (!set) {
- #ifdef WOLFSSL_MYSQL_COMPATIBLE
-            SendAlert(ssl, alert_fatal, wc_protocol_version);
- #else
-            SendAlert(ssl, alert_fatal, protocol_version);
- #endif
+            SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
             WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
             return VERSION_ERROR;
         }

+ 118 - 58
src/tls13.c

@@ -3164,8 +3164,9 @@ static int CreateCookie(WOLFSSL* ssl, byte* hash, byte hashSz)
     /* Tie cookie to peer address */
     if (ret == 0) {
         if (ssl->options.dtls && ssl->buffers.dtlsCtx.peer.sz > 0) {
-            ret = wc_HmacUpdate(&cookieHmac, ssl->buffers.dtlsCtx.peer.sa,
-                                    ssl->buffers.dtlsCtx.peer.sz);
+            ret = wc_HmacUpdate(&cookieHmac,
+                (byte*)ssl->buffers.dtlsCtx.peer.sa,
+                ssl->buffers.dtlsCtx.peer.sz);
         }
     }
 #endif
@@ -4184,6 +4185,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
 
     if (args->pv.major != ssl->version.major ||
         args->pv.minor != tls12minor) {
+        SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
         WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
         return VERSION_ERROR;
     }
@@ -4262,11 +4264,14 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
 
 #endif
         ssl->options.haveEMS = 0;
-        if (args->pv.minor < ssl->options.minDowngrade)
+        if (args->pv.minor < ssl->options.minDowngrade) {
+            SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
             return VERSION_ERROR;
+        }
 #ifndef WOLFSSL_NO_TLS12
         return DoServerHello(ssl, input, inOutIdx, helloSz);
 #else
+        SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
         return VERSION_ERROR;
 #endif
     }
@@ -4291,6 +4296,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
             if (!ssl->options.downgrade) {
                 WOLFSSL_MSG("Server trying to downgrade to version less than "
                             "TLS v1.3");
+                SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
                 WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
                 return VERSION_ERROR;
             }
@@ -4307,12 +4313,14 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
 
             if (!ssl->options.dtls &&
                 args->pv.minor < ssl->options.minDowngrade) {
+                SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
                 WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
                 return VERSION_ERROR;
             }
 
             if (ssl->options.dtls &&
                 args->pv.minor > ssl->options.minDowngrade) {
+                SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
                 WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
                 return VERSION_ERROR;
             }
@@ -5328,8 +5336,9 @@ static int CheckCookie(WOLFSSL* ssl, byte* cookie, byte cookieSz)
     /* Tie cookie to peer address */
     if (ret == 0) {
         if (ssl->options.dtls && ssl->buffers.dtlsCtx.peer.sz > 0) {
-            ret = wc_HmacUpdate(&cookieHmac, ssl->buffers.dtlsCtx.peer.sa,
-                                ssl->buffers.dtlsCtx.peer.sz);
+            ret = wc_HmacUpdate(&cookieHmac,
+                (byte*)ssl->buffers.dtlsCtx.peer.sa,
+                ssl->buffers.dtlsCtx.peer.sz);
         }
     }
 #endif
@@ -5679,11 +5688,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
     /* this check pass for DTLS Major (0xff) */
     if (args->pv.major < SSLv3_MAJOR) {
         WOLFSSL_MSG("Legacy version field contains unsupported value");
- #ifdef WOLFSSL_MYSQL_COMPATIBLE
-        SendAlert(ssl, alert_fatal, wc_protocol_version);
- #else
-        SendAlert(ssl, alert_fatal, protocol_version);
- #endif
+        SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
         ERROR_OUT(INVALID_PARAMETER, exit_dch);
     }
 
@@ -5724,9 +5729,6 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
         if (!ssl->options.downgrade) {
             WOLFSSL_MSG("Client trying to connect with lesser version than "
                         "TLS v1.3");
-#if defined(WOLFSSL_EXTRA_ALERTS) ||  defined(OPENSSL_EXTRA)
-            SendAlert(ssl, alert_fatal, handshake_failure);
-#endif
             ERROR_OUT(VERSION_ERROR, exit_dch);
         }
 
@@ -5734,9 +5736,6 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                  && args->pv.minor < ssl->options.minDowngrade) ||
             (ssl->options.dtls && args->pv.minor > ssl->options.minDowngrade)) {
             WOLFSSL_MSG("\tversion below minimum allowed, fatal error");
-#if defined(WOLFSSL_EXTRA_ALERTS) ||  defined(OPENSSL_EXTRA)
-            SendAlert(ssl, alert_fatal, handshake_failure);
-#endif
             ERROR_OUT(VERSION_ERROR, exit_dch);
         }
 
@@ -6056,6 +6055,9 @@ exit_dch:
     }
 #endif
 
+    if (ret == VERSION_ERROR)
+        SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
+
     FreeDch13Args(ssl, args);
 #ifdef WOLFSSL_ASYNC_CRYPT
     FreeAsyncCtx(ssl, 0);
@@ -6088,7 +6090,7 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
     WOLFSSL_ENTER("SendTls13ServerHello");
 
     if (extMsgType == hello_retry_request) {
-        WOLFSSL_MSG("wolfSSL Doing HelloRetryRequest");
+        WOLFSSL_MSG("wolfSSL Sending HelloRetryRequest");
         if ((ret = RestartHandshakeHash(ssl)) < 0)
             return ret;
     }
@@ -10136,7 +10138,10 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
     /* sanity check msg received */
     if ((ret = SanityCheckTls13MsgReceived(ssl, type)) != 0) {
         WOLFSSL_MSG("Sanity Check on handshake message type received failed");
-        SendAlert(ssl, alert_fatal, unexpected_message);
+        if (ret == VERSION_ERROR)
+            SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
+        else
+            SendAlert(ssl, alert_fatal, unexpected_message);
         return ret;
     }
 
@@ -10638,7 +10643,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
             }
 #ifdef WOLFSSL_DTLS13
             if (ssl->options.dtls)
-                ssl->dtls13SendingAckOrRtx =0;
+                ssl->dtls13SendingAckOrRtx = 0;
 #endif /* WOLFSSL_DTLS13 */
 
         }
@@ -11620,6 +11625,80 @@ const char* wolfSSL_get_cipher_name_by_hash(WOLFSSL* ssl, const char* hash)
 
 
 #ifndef NO_WOLFSSL_SERVER
+#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
+static void DtlsResetState(WOLFSSL *ssl)
+{
+    /* Reset the state so that we can statelessly await the
+     * ClientHello that contains the cookie. */
+
+    /* Reset DTLS window */
+    w64Zero(&ssl->dtls13Epochs[0].nextSeqNumber);
+    w64Zero(&ssl->dtls13Epochs[0].nextPeerSeqNumber);
+    XMEMSET(ssl->dtls13Epochs[0].window, 0,
+            sizeof(ssl->dtls13Epochs[0].window));
+
+    ssl->keys.dtls_expected_peer_handshake_number = 0;
+    ssl->keys.dtls_handshake_number = 0;
+
+    ssl->msgsReceived.got_client_hello = 0;
+#ifdef WOLFSSL_SEND_HRR_COOKIE
+    /* Remove cookie so that it will get computed again */
+    TLSX_Remove(&ssl->extensions, TLSX_COOKIE, ssl->heap);
+#endif
+
+    /* Reset states */
+    ssl->options.serverState = NULL_STATE;
+    ssl->options.clientState = NULL_STATE;
+    ssl->options.connectState = CONNECT_BEGIN;
+    ssl->options.acceptState  = ACCEPT_BEGIN;
+    ssl->options.handShakeState  = NULL_STATE;
+
+    Dtls13FreeFsmResources(ssl);
+}
+
+static int DtlsAcceptStateless(WOLFSSL *ssl)
+{
+    int ret;
+
+    if (!ssl->options.dtls)
+        return 0;
+
+    switch (ssl->options.acceptState) {
+    case TLS13_ACCEPT_BEGIN:
+
+        while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
+            ret = ProcessReply(ssl);
+            if (ret != 0)
+                return ret;
+        }
+
+        if (!IsAtLeastTLSv1_3(ssl->version))
+            return wolfSSL_accept(ssl);
+
+        ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE;
+        WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
+        FALL_THROUGH;
+
+    case TLS13_ACCEPT_CLIENT_HELLO_DONE:
+        if (ssl->options.serverState ==
+                                          SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
+            ret = SendTls13ServerHello(ssl, hello_retry_request);
+            DtlsResetState(ssl);
+            return ret;
+        }
+
+        ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE;
+        WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
+        FALL_THROUGH;
+
+    default:
+        return 0;
+    }
+
+    return 0;
+}
+#endif /* WOLFSSL_DTLS13 */
+
 /* The server accepting a connection from a client.
  * The protocol version is expecting to be TLS v1.3.
  * If the client downgrades, and older versions of the protocol are compiled
@@ -11807,6 +11886,19 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
     }
 #endif /* WOLFSSL_DTLS13 */
 
+#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
+    if (ssl->options.dtls && ssl->options.sendCookie) {
+        while (ssl->options.serverState < SERVER_HELLO_COMPLETE) {
+            ret = DtlsAcceptStateless(ssl);
+            if (ret != 0) {
+                ssl->error = ret;
+                WOLFSSL_ERROR(ssl->error);
+                return WOLFSSL_FATAL_ERROR;
+            }
+        }
+    }
+#endif /* defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) */
+
     switch (ssl->options.acceptState) {
 
 #ifdef HAVE_SECURE_RENEGOTIATION
@@ -11814,6 +11906,7 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
 #endif
         case TLS13_ACCEPT_BEGIN :
             /* get client_hello */
+
             while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
                 if ((ssl->error = ProcessReply(ssl)) < 0) {
                     WOLFSSL_ERROR(ssl->error);
@@ -11845,40 +11938,6 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
                     WOLFSSL_ERROR(ssl->error);
                     return WOLFSSL_FATAL_ERROR;
                 }
-#ifdef WOLFSSL_DTLS13
-                if (ssl->options.dtls && wolfSSL_dtls_get_using_nonblock(ssl)) {
-                    /* Reset the state so that we can statelessly await the
-                     * ClientHello that contains the cookie. Return a WANT_READ
-                     * to the user so that we don't drop UDP messages in the
-                     * network callbacks. */
-
-                    /* Reset DTLS window */
-                    w64Zero(&ssl->dtls13Epochs[0].nextSeqNumber);
-                    w64Zero(&ssl->dtls13Epochs[0].nextPeerSeqNumber);
-                    XMEMSET(ssl->dtls13Epochs[0].window, 0,
-                            sizeof(ssl->dtls13Epochs[0].window));
-
-                    ssl->keys.dtls_expected_peer_handshake_number = 0;
-                    ssl->keys.dtls_handshake_number = 0;
-
-                    ssl->msgsReceived.got_client_hello = 0;
-#ifdef WOLFSSL_SEND_HRR_COOKIE
-                    /* Remove cookie so that it will get computed again */
-                    TLSX_Remove(&ssl->extensions, TLSX_COOKIE, ssl->heap);
-#endif
-
-                    /* Reset states */
-                    ssl->options.serverState = NULL_STATE;
-                    ssl->options.clientState = NULL_STATE;
-                    ssl->options.connectState = CONNECT_BEGIN;
-                    ssl->options.acceptState  = ACCEPT_BEGIN;
-                    ssl->options.handShakeState  = NULL_STATE;
-
-                    ssl->error = WANT_READ;
-                    WOLFSSL_ERROR(ssl->error);
-                    return WOLFSSL_FATAL_ERROR;
-                }
-#endif /* WOLFSSL_DTLS13 */
             }
 
             ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE;
@@ -11924,6 +11983,12 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
                 }
             }
 
+            ssl->options.acceptState = TLS13_ACCEPT_SECOND_REPLY_DONE;
+            WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE");
+            FALL_THROUGH;
+
+        case TLS13_ACCEPT_SECOND_REPLY_DONE :
+
 #ifdef WOLFSSL_DTLS
             if (ssl->chGoodCb != NULL) {
                 int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
@@ -11935,11 +12000,6 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
             }
 #endif
 
-            ssl->options.acceptState = TLS13_ACCEPT_SECOND_REPLY_DONE;
-            WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE");
-            FALL_THROUGH;
-
-        case TLS13_ACCEPT_SECOND_REPLY_DONE :
             if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) {
                 WOLFSSL_ERROR(ssl->error);
                 return WOLFSSL_FATAL_ERROR;

+ 242 - 1
tests/api.c

@@ -55856,10 +55856,153 @@ static int test_wolfSSL_dtls_fragments(void)
 
     return 0;
 }
+
+static void test_wolfSSL_dtls_send_alert(WOLFSSL* ssl)
+{
+    int fd, ret;
+    byte alert_msg[] = {
+        0x15, /* alert type */
+        0xfe, 0xfd, /* version */
+        0x00, 0x00, /* epoch */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* seq number */
+        0x00, 0x02, /* length */
+        0x02, /* level: fatal */
+        0x46 /* protocol version */
+    };
+
+    fd = wolfSSL_get_fd(ssl);
+    ret = (int)send(fd, alert_msg, sizeof(alert_msg), 0);
+    AssertIntGT(ret, 0);
+}
+
+static int _test_wolfSSL_ignore_alert_before_cookie(byte version12)
+{
+    callback_functions client_cbs, server_cbs;
+
+    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
+    XMEMSET(&server_cbs, 0, sizeof(server_cbs));
+    client_cbs.doUdp = server_cbs.doUdp = 1;
+    if (version12) {
+        client_cbs.method = wolfDTLSv1_2_client_method;
+        server_cbs.method = wolfDTLSv1_2_server_method;
+    }
+    else {
+#ifdef WOLFSSL_DTLS13
+        client_cbs.method = wolfDTLSv1_3_client_method;
+        server_cbs.method = wolfDTLSv1_3_server_method;
+#else
+        return 0;
+#endif /* WOLFSSL_DTLS13 */
+    }
+
+    client_cbs.ssl_ready = test_wolfSSL_dtls_send_alert;
+    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);
+
+    if (!client_cbs.return_code)
+        return -1;
+    if (!server_cbs.return_code)
+        return -1;
+
+    return 0;
+}
+
+static int test_wolfSSL_ignore_alert_before_cookie(void)
+{
+    int ret;
+    ret =_test_wolfSSL_ignore_alert_before_cookie(0);
+    if (ret != 0)
+        return ret;
+    ret =_test_wolfSSL_ignore_alert_before_cookie(1);
+    if (ret != 0)
+        return ret;
+    return 0;
+}
+
+static void test_wolfSSL_send_bad_record(WOLFSSL* ssl)
+{
+    int ret;
+    int fd;
+
+    byte bad_msg[] = {
+        0x17, /* app data  */
+        0xaa, 0xfd, /* bad version */
+        0x00, 0x01, /* epoch 1 */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* not seen seq number */
+        0x00, 0x26, /* length: 38 bytes */
+        0xae, 0x30, 0x31, 0xb1, 0xf1, 0xb9, 0x6f, 0xda, 0x17, 0x19, 0xd9, 0x57,
+        0xa9, 0x9d, 0x5c, 0x51, 0x9b, 0x53, 0x63, 0xa5, 0x24, 0x70, 0xa1,
+        0xae, 0xdf, 0x1c, 0xb9, 0xfc, 0xe3, 0xd7, 0x77, 0x6d, 0xb6, 0x89, 0x0f,
+        0x03, 0x18, 0x72
+    };
+
+    fd = wolfSSL_get_fd(ssl);
+    AssertIntGE(fd, 0);
+    ret = (int)send(fd, bad_msg, sizeof(bad_msg), 0);
+    AssertIntEQ(ret, sizeof(bad_msg));
+    ret = wolfSSL_write(ssl, "badrecordtest", sizeof("badrecordtest"));
+    AssertIntEQ(ret, sizeof("badrecordtest"));
+}
+
+static void test_wolfSSL_read_string(WOLFSSL* ssl)
+{
+    byte buf[100];
+    int ret;
+
+    ret = wolfSSL_read(ssl, buf, sizeof(buf));
+    AssertIntGT(ret, 0);
+    AssertIntEQ(strcmp((char*)buf, "badrecordtest"), 0);
+}
+
+static int _test_wolfSSL_dtls_bad_record(
+    method_provider client_method, method_provider server_method)
+{
+    callback_functions client_cbs, server_cbs;
+
+    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
+    XMEMSET(&server_cbs, 0, sizeof(server_cbs));
+    client_cbs.doUdp = server_cbs.doUdp = 1;
+    client_cbs.method = client_method;
+    server_cbs.method = server_method;
+
+    client_cbs.on_result = test_wolfSSL_send_bad_record;
+    server_cbs.on_result = test_wolfSSL_read_string;
+
+    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);
+
+    if (!client_cbs.return_code)
+        return -1;
+    if (!server_cbs.return_code)
+        return -1;
+
+    return 0;
+}
+
+static int test_wolfSSL_dtls_bad_record(void)
+{
+    int ret;
+    ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_2_client_method,
+        wolfDTLSv1_2_server_method);
+    if (ret != 0)
+        return ret;
+#ifdef WOLFSSL_DTLS13
+    return _test_wolfSSL_dtls_bad_record(wolfDTLSv1_3_client_method,
+        wolfDTLSv1_3_server_method);
+#else
+    return 0;
+#endif /* WOLFSSL_DTLS13 */
+
+}
+
 #else
 static int test_wolfSSL_dtls_fragments(void) {
     return 0;
 }
+static int test_wolfSSL_ignore_alert_before_cookie(void) {
+    return 0;
+}
+static int test_wolfSSL_dtls_bad_record(void) {
+    return 0;
+}
 #endif
 
 #if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
@@ -56052,7 +56195,6 @@ static int test_wolfSSL_dtls_AEAD_limit(void)
         return -2;
 
     printf(resultFmt, passed);
-
     return 0;
 }
 #else
@@ -56062,6 +56204,102 @@ static int test_wolfSSL_dtls_AEAD_limit(void)
 }
 #endif
 
+#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) && \
+    defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED)
+static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl)
+{
+    int fd, ret;
+    byte ch_msg[] = {
+        0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+        0xfa, 0x01, 0x00, 0x01, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+        0xee, 0xfe, 0xfd, 0xc0, 0xca, 0xb5, 0x6f, 0x3d, 0x23, 0xcc, 0x53, 0x9a,
+        0x67, 0x17, 0x70, 0xd3, 0xfb, 0x23, 0x16, 0x9e, 0x4e, 0xd6, 0x7e, 0x29,
+        0xab, 0xfa, 0x4c, 0xa5, 0x84, 0x95, 0xc3, 0xdb, 0x21, 0x9a, 0x52, 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,
+        0x8e, 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, 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, 0x96, 0xcb, 0x2e, 0x4e, 0xd9, 0x88, 0x71, 0xc7, 0xf3,
+        0x1a, 0x16, 0xdd, 0x7a, 0x7c, 0xf7, 0x67, 0x8a, 0x5d, 0x9a, 0x55, 0xa6,
+        0x4a, 0x90, 0xd9, 0xfb, 0xc7, 0xfb, 0xbe, 0x09, 0xa9, 0x8a, 0xb5, 0x7a,
+        0xd1, 0xde, 0x83, 0x74, 0x27, 0x31, 0x1c, 0xaa, 0xae, 0xef, 0x58, 0x43,
+        0x13, 0x7d, 0x15, 0x4d, 0x7f, 0x68, 0xf6, 0x8a, 0x38, 0xef, 0x0e, 0xb3,
+        0xcf, 0xb8, 0x4a, 0xa9, 0xb4, 0xd7, 0xcb, 0x01, 0x00, 0x01, 0x00, 0x1d,
+        0x0a, 0x22, 0x8a, 0xd1, 0x78, 0x85, 0x1e, 0x5a, 0xe1, 0x1d, 0x1e, 0xb7,
+        0x2d, 0xbc, 0x5f, 0x52, 0xbc, 0x97, 0x5d, 0x8b, 0x6a, 0x8b, 0x9d, 0x1e,
+        0xb1, 0xfc, 0x8a, 0xb2, 0x56, 0xcd, 0xed, 0x4b, 0xfb, 0x66, 0x3f, 0x59,
+        0x3f, 0x15, 0x5d, 0x09, 0x9e, 0x2f, 0x60, 0x5b, 0x31, 0x81, 0x27, 0xf0,
+        0x1c, 0xda, 0xcd, 0x48, 0x66, 0xc6, 0xbb, 0x25, 0xf0, 0x5f, 0xda, 0x4c,
+        0xcf, 0x1d, 0x88, 0xc8, 0xda, 0x1b, 0x53, 0xea, 0xbd, 0xce, 0x6d, 0xf6,
+        0x4a, 0x76, 0xdb, 0x75, 0x99, 0xaf, 0xcf, 0x76, 0x4a, 0xfb, 0xe3, 0xef,
+        0xb2, 0xcb, 0xae, 0x4a, 0xc0, 0xe8, 0x63, 0x1f, 0xd6, 0xe8, 0xe6, 0x45,
+        0xf9, 0xea, 0x0d, 0x06, 0x19, 0xfc, 0xb1, 0xfd, 0x5d, 0x92, 0x89, 0x7b,
+        0xc7, 0x9f, 0x1a, 0xb3, 0x2b, 0xc7, 0xad, 0x0e, 0xfb, 0x13, 0x41, 0x83,
+        0x84, 0x58, 0x3a, 0x25, 0xb9, 0x49, 0x35, 0x1c, 0x23, 0xcb, 0xd6, 0xe7,
+        0xc2, 0x8c, 0x4b, 0x2a, 0x73, 0xa1, 0xdf, 0x4f, 0x73, 0x9b, 0xb3, 0xd2,
+        0xb2, 0x95, 0x00, 0x3c, 0x26, 0x09, 0x89, 0x71, 0x05, 0x39, 0xc8, 0x98,
+        0x8f, 0xed, 0x32, 0x15, 0x78, 0xcd, 0xd3, 0x7e, 0xfb, 0x5a, 0x78, 0x2a,
+        0xdc, 0xca, 0x20, 0x09, 0xb5, 0x14, 0xf9, 0xd4, 0x58, 0xf6, 0x69, 0xf8,
+        0x65, 0x9f, 0xb7, 0xe4, 0x93, 0xf1, 0xa3, 0x84, 0x7e, 0x1b, 0x23, 0x5d,
+        0xea, 0x59, 0x3e, 0x4d, 0xca, 0xfd, 0xa5, 0x55, 0xdd, 0x99, 0xb5, 0x02,
+        0xf8, 0x0d, 0xe5, 0xf4, 0x06, 0xb0, 0x43, 0x9e, 0x2e, 0xbf, 0x05, 0x33,
+        0x65, 0x7b, 0x13, 0x8c, 0xf9, 0x16, 0x4d, 0xc5, 0x15, 0x0b, 0x40, 0x2f,
+        0x66, 0x94, 0xf2, 0x43, 0x95, 0xe7, 0xa9, 0xb6, 0x39, 0x99, 0x73, 0xb3,
+        0xb0, 0x06, 0xfe, 0x52, 0x9e, 0x57, 0xba, 0x75, 0xfd, 0x76, 0x7b, 0x20,
+        0x31, 0x68, 0x4c
+    };
+
+    fd = wolfSSL_get_fd(ssl);
+    ret = (int)send(fd, ch_msg, sizeof(ch_msg), 0);
+    AssertIntGT(ret, 0);
+    /* consume the HRR otherwise handshake will fail */
+    ret = recv(fd, ch_msg, sizeof(ch_msg), 0);
+    AssertIntGT(ret, 0);
+}
+
+static void test_wolfSSL_dtls_enable_hrrcookie(WOLFSSL* ssl)
+{
+    int ret;
+    ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0);
+    AssertIntEQ(ret, WOLFSSL_SUCCESS);
+}
+
+static int test_wolfSSL_dtls_stateless(void)
+{
+    callback_functions client_cbs, server_cbs;
+
+    XMEMSET(&client_cbs, 0, sizeof(client_cbs));
+    XMEMSET(&server_cbs, 0, sizeof(server_cbs));
+    client_cbs.doUdp = server_cbs.doUdp = 1;
+    client_cbs.method = wolfDTLSv1_3_client_method;
+    server_cbs.method = wolfDTLSv1_3_server_method;
+
+    client_cbs.ssl_ready = test_wolfSSL_dtls_send_ch;
+    server_cbs.ssl_ready = test_wolfSSL_dtls_enable_hrrcookie;
+    test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs);
+
+    if (!client_cbs.return_code)
+        return -1;
+    if (!server_cbs.return_code)
+        return -1;
+
+    return 0;
+}
+#else
+static int test_wolfSSL_dtls_stateless(void)
+{
+    return 0;
+}
+#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE &&
+        * HAVE_IO_TESTS_DEPENDENCIES && !SINGLE_THREADED */
+
 #if !defined(NO_RSA) && !defined(NO_SHA) && !defined(NO_FILESYSTEM) && \
     !defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \
     !defined(WOLFSSL_NO_CLIENT_AUTH))
@@ -59056,6 +59294,9 @@ TEST_CASE testCases[] = {
     TEST_DECL(test_wolfSSL_DTLS_either_side),
     TEST_DECL(test_wolfSSL_dtls_fragments),
     TEST_DECL(test_wolfSSL_dtls_AEAD_limit),
+    TEST_DECL(test_wolfSSL_ignore_alert_before_cookie),
+    TEST_DECL(test_wolfSSL_dtls_bad_record),
+    TEST_DECL(test_wolfSSL_dtls_stateless),
     TEST_DECL(test_generate_cookie),
     TEST_DECL(test_wolfSSL_X509_STORE_set_flags),
     TEST_DECL(test_wolfSSL_X509_LOOKUP_load_file),

+ 1 - 0
tests/include.am

@@ -45,6 +45,7 @@ EXTRA_DIST += tests/unit.h \
               tests/test-dtls-srtp-fails.conf \
               tests/test-dtls13.conf \
               tests/test-dtls13-downgrade.conf \
+              tests/test-dtls13-downgrade-fails.conf \
               tests/test-dtls13-psk.conf \
               tests/test-dtls13-cid.conf \
               tests/test-sctp.conf \

+ 12 - 0
tests/suites.c

@@ -1151,6 +1151,18 @@ int SuiteTest(int argc, char** argv)
         args.return_code = EXIT_FAILURE;
         goto exit;
     }
+    args.argc = 3;
+    strcpy(argv0[1], "tests/test-dtls13-downgrade-fails.conf");
+    strcpy(argv0[2], "expFail");
+    printf("starting DTLSv1.3 suite - downgrade - (expFails)\n");
+    test_harness(&args);
+    if (args.return_code != 0) {
+        printf("error from script %d\n", args.return_code);
+        args.return_code = EXIT_FAILURE;
+        goto exit;
+    }
+    args.argc = 2;
+    XMEMSET(argv0[2], 0, sizeof(argv0[2]));
 #endif /* WOLFSSL_NO_TLS12 */
 
 #ifndef NO_PSK

+ 20 - 0
tests/test-dtls13-downgrade-fails.conf

@@ -0,0 +1,20 @@
+# server DTLSv1.3
+-v4
+-u
+-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+
+# client DTLSv1.2
+-v 3
+-u
+-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+
+# server DTLSv1.3
+-vd
+-7 3
+-u
+-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+
+# client DTLSv1.0
+-v 2
+-u
+-l TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

+ 5 - 0
wolfssl/ssl.h

@@ -774,6 +774,11 @@ enum AlertDescription {
     no_application_protocol         = 120
 };
 
+#ifdef WOLFSSL_MYSQL_COMPATIBLE
+#define wolfssl_alert_protocol_version wc_protocol_version
+#else
+#define wolfssl_alert_protocol_version protocol_version
+#endif
 
 enum AlertLevel {
     alert_none = 0, /* Used to indicate no alert level is set */