Переглянути джерело

dtls13: client: recompute transcript hash on downgrade

If a lower version is negotiated, the transcript hash must be recomputed using
the <= v1.2 rules.
Marco Oliverio 1 рік тому
батько
коміт
8fe3f51ecb
4 змінених файлів з 105 додано та 6 видалено
  1. 32 0
      src/dtls13.c
  2. 24 6
      src/internal.c
  3. 47 0
      src/tls13.c
  4. 2 0
      wolfssl/internal.h

+ 32 - 0
src/dtls13.c

@@ -716,6 +716,35 @@ static void Dtls13RtxRemoveCurAck(WOLFSSL* ssl)
     }
 }
 
+static void Dtls13MaybeSaveClientHello(WOLFSSL* ssl)
+{
+    Dtls13RtxRecord *r, **prev_next;
+
+    r = ssl->dtls13Rtx.rtxRecords;
+    prev_next = &ssl->dtls13Rtx.rtxRecords;
+
+    if (ssl->options.side == WOLFSSL_CLIENT_END &&
+        ssl->options.connectState >= CLIENT_HELLO_SENT &&
+        ssl->options.connectState <= HELLO_AGAIN_REPLY &&
+        ssl->options.downgrade && ssl->options.minDowngrade >= DTLSv1_2_MINOR) {
+        while (r != NULL) {
+            if (r->handshakeType == client_hello) {
+                Dtls13RtxRecordUnlink(ssl, prev_next, r);
+                if (ssl->dtls13ClientHello != NULL)
+                    XFREE(ssl->dtls13ClientHello, ssl->heap,
+                        DYNAMIC_TYPE_DTLS_MSG);
+                ssl->dtls13ClientHello = r->data;
+                ssl->dtls13ClientHelloSz = r->length;
+                r->data = NULL;
+                Dtls13FreeRtxBufferRecord(ssl, r);
+                return;
+            }
+            prev_next = &r->next;
+            r = r->next;
+        }
+    }
+}
+
 static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
     word32 fragOffset)
 {
@@ -725,6 +754,9 @@ static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
         ssl->keys.dtls_peer_handshake_number >=
             ssl->keys.dtls_expected_peer_handshake_number) {
 
+        if (hs == server_hello)
+            Dtls13MaybeSaveClientHello(ssl);
+
         /* In the handshake, receiving part of the next flight, acknowledge the
            sent flight. The only exception is, on the server side, receiving the
            last client flight does not ACK any sent new_session_ticket

+ 24 - 6
src/internal.c

@@ -7284,6 +7284,15 @@ void SSL_ResourceFree(WOLFSSL* ssl)
     XFREE(ssl->buffers.dtlsCookieSecret.buffer, ssl->heap,
           DYNAMIC_TYPE_COOKIE_PWD);
 #endif
+
+#ifdef WOLFSSL_DTLS13
+    if (ssl->dtls13ClientHello != NULL) {
+        XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
+        ssl->dtls13ClientHello = NULL;
+        ssl->dtls13ClientHelloSz = 0;
+    }
+#endif /* WOLFSSL_DTLS13 */
+
 #endif /* WOLFSSL_DTLS */
 #ifdef OPENSSL_EXTRA
 #ifndef NO_BIO
@@ -7503,12 +7512,21 @@ void FreeHandshakeResources(WOLFSSL* ssl)
     WOLFSSL_ENTER("FreeHandshakeResources");
 
 #ifdef WOLFSSL_DTLS
-    /* DTLS_POOL (DTLSv1.3 flushes the queue autonomously) */
-    if (ssl->options.dtls && !IsAtLeastTLSv1_3(ssl->version)) {
-        DtlsMsgPoolReset(ssl);
-        DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
-        ssl->dtls_rx_msg_list = NULL;
-        ssl->dtls_rx_msg_list_sz = 0;
+    if (ssl->options.dtls) {
+        /* DTLS_POOL (DTLSv1.3 flushes the queue autonomously) */
+        if(!IsAtLeastTLSv1_3(ssl->version)) {
+            DtlsMsgPoolReset(ssl);
+            DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap);
+            ssl->dtls_rx_msg_list = NULL;
+            ssl->dtls_rx_msg_list_sz = 0;
+        }
+#ifdef WOLFSSL_DTLS13
+        if (ssl->dtls13ClientHello != NULL) {
+            XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
+            ssl->dtls13ClientHello = NULL;
+            ssl->dtls13ClientHelloSz = 0;
+        }
+#endif /* WOLFSSL_DTLS13 */
     }
 #endif
 

+ 47 - 0
src/tls13.c

@@ -3641,6 +3641,28 @@ int SendTls13ClientHello(WOLFSSL* ssl)
     return ret;
 }
 
+#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_CLIENT)
+static int Dtls13DoDowngrade(WOLFSSL* ssl)
+{
+    int ret;
+    if (ssl->dtls13ClientHello == NULL)
+        return BAD_STATE_E;
+
+    /* v1.3 and v1.2 hash messages to compute the transcript hash. When we are
+     * using DTLSv1.3 we hash the first clientHello following v1.3 but the
+     * server can negotiate a lower version. So we need to re-hash the
+     * clientHello to adhere to DTLS <= v1.2 rules. */
+    ret = InitHandshakeHashes(ssl);
+    if (ret != 0)
+        return ret;
+    ret = HashRaw(ssl, ssl->dtls13ClientHello, ssl->dtls13ClientHelloSz);
+    XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
+    ssl->dtls13ClientHello = NULL;
+    ssl->dtls13ClientHelloSz = 0;
+    return ret;
+}
+#endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_CLIENT*/
+
 /* handle processing of TLS 1.3 server_hello (2) and hello_retry_request (6) */
 /* Handle the ServerHello message from the server.
  * Only a client will receive this message.
@@ -3762,6 +3784,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
             if (ssl->options.dtls) {
                 ssl->chVersion.minor = DTLSv1_2_MINOR;
                 ssl->version.minor = DTLSv1_2_MINOR;
+                ret = Dtls13DoDowngrade(ssl);
+                if (ret != 0)
+                    return ret;
             }
 #endif /* WOLFSSL_DTLS13 */
 
@@ -3839,6 +3864,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
         if (ssl->options.dtls) {
             ssl->chVersion.minor = DTLSv1_2_MINOR;
             ssl->version.minor = DTLSv1_2_MINOR;
+            ret = Dtls13DoDowngrade(ssl);
+            if (ret != 0)
+                return ret;
         }
 #endif /* WOLFSSL_DTLS13 */
 
@@ -3893,9 +3921,28 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                 return VERSION_ERROR;
 
             ssl->version.minor = args->pv.minor;
+
+#ifdef WOLFSSL_DTLS13
+            if (ssl->options.dtls) {
+                ret = Dtls13DoDowngrade(ssl);
+                if (ret != 0)
+                    return ret;
+            }
+#endif /* WOLFSSL_DTLS13 */
         }
     }
 
+#ifdef WOLFSSL_DTLS13
+    /* we are sure that version is >= v1.3 now, we can get rid of buffered
+     * ClientHello that was buffered to re-compute the hash in case of
+     * downgrade */
+    if (ssl->options.dtls && ssl->dtls13ClientHello != NULL) {
+        XFREE(ssl->dtls13ClientHello, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
+        ssl->dtls13ClientHello = NULL;
+        ssl->dtls13ClientHelloSz = 0;
+    }
+#endif /* WOLFSSL_DTLS13 */
+
     /* Advance state and proceed */
     ssl->options.asyncState = TLS_ASYNC_BUILD;
     } /* case TLS_ASYNC_BEGIN */

+ 2 - 0
wolfssl/internal.h

@@ -4659,6 +4659,8 @@ struct WOLFSSL {
     word32 dtls13FragOffset;
     byte dtls13FragHandshakeType;
     Dtls13Rtx dtls13Rtx;
+    byte *dtls13ClientHello;
+    word16 dtls13ClientHelloSz;
 
 #endif /* WOLFSSL_DTLS13 */
 #endif /* WOLFSSL_DTLS */