Browse Source

add initial support for ConnectionID DTLS extension

Marco Oliverio 1 year ago
parent
commit
cfbd061625

+ 12 - 0
CMakeLists.txt

@@ -290,6 +290,18 @@ if(WOLFSSL_DTLS13)
     endif()
 endif()
 
+# DTLS ConnectionID support
+add_option("WOLFSSL_DTLS_CID"
+    "Enables wolfSSL DTLS CID (default: disabled)"
+    "no" "yes;no")
+
+if(WOLFSSL_DTLS_CID)
+    if(NOT WOLFSSL_DTLS13)
+        message(FATAL_ERROR "CID are supported only for DTLSv1.3")
+    endif()
+    list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_DTLS_CID")
+endif()
+
 # Post-handshake authentication
 add_option("WOLFSSL_POSTAUTH"
     "Enable wolfSSL Post-handshake Authentication (default: disabled)"

+ 1 - 0
IDE/WIN/wolfssl-fips.vcxproj

@@ -309,6 +309,7 @@
     <ClCompile Include="..\..\src\tls.c" />
     <ClCompile Include="..\..\src\tls13.c" />
     <ClCompile Include="..\..\src\dtls13.c" />
+    <ClCompile Include="..\..\src\dtls.c" />
     <ClCompile Include="..\..\wolfcrypt\src\wc_encrypt.c" />
     <ClCompile Include="..\..\wolfcrypt\src\wolfmath.c" />
     <ClCompile Include="..\..\wolfcrypt\src\wolfevent.c" />

+ 1 - 0
IDE/WIN10/wolfssl-fips.vcxproj

@@ -279,6 +279,7 @@
     <ClCompile Include="..\..\src\tls.c" />
     <ClCompile Include="..\..\src\tls13.c" />
     <ClCompile Include="..\..\src\dtls13.c" />
+    <ClCompile Include="..\..\src\dtls.c" />
     <ClCompile Include="..\..\wolfcrypt\src\wc_encrypt.c" />
     <ClCompile Include="..\..\wolfcrypt\src\wolfcrypt_first.c" />
     <ClCompile Include="..\..\wolfcrypt\src\wolfcrypt_last.c" />

+ 7 - 0
cmake/functions.cmake

@@ -53,6 +53,9 @@ function(generate_build_flags)
     if(WOLFSSL_SCTP OR WOLFSSL_USER_SETTINGS)
         set(BUILD_SCTP "yes" PARENT_SCOPE)
     endif()
+    if(WOLFSSL_DTLS_CID OR WOLFSSL_USER_SETTINGS)
+        set(BUILD_DTLS_COMMON "yes" PARENT_SCOPE)
+    endif()
     set(BUILD_MCAST ${WOLFSSL_MCAST} PARENT_SCOPE)
     set(BUILD_IPV6 ${WOLFSSL_IPV6} PARENT_SCOPE)
     set(BUILD_LEAN_PSK ${WOLFSSL_LEAN_PSK} PARENT_SCOPE)
@@ -843,6 +846,10 @@ function(generate_lib_src_list LIB_SOURCES)
               if(BUILD_SNIFFER)
                    list(APPEND LIB_SOURCES src/sniffer.c)
               endif()
+
+              if(BUILD_DTLS_COMMON)
+                   list(APPEND LIB_SOURCES src/dtls.c)
+              endif()
          endif()
     endif()
 

+ 16 - 0
configure.ac

@@ -3760,6 +3760,21 @@ then
   fi
 fi
 
+# DTLS CID support
+AC_ARG_ENABLE([dtlscid],
+    [AS_HELP_STRING([--enable-dtlscid],[Enable wolfSSL DTLS ConnectionID (default: disabled)])],
+    [ ENABLED_DTLS_CID=$enableval ],
+    [ ENABLED_DTLS_CID=no ]
+    )
+if test "x$ENABLED_DTLS_CID" = "xyes"
+then
+        if test "x$ENABLED_DTLS13" != "xyes"
+        then
+                AC_MSG_ERROR([You need to enable DTLSv1.3 to use DTLS ConnectionID])
+        fi
+  AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_CID"
+fi
+
 # CODING
 AC_ARG_ENABLE([coding],
     [AS_HELP_STRING([--enable-coding],[Enable Coding base 16/64 (default: enabled)])],
@@ -8077,6 +8092,7 @@ AM_CONDITIONAL([BUILD_DO178],[test "x$ENABLED_DO178" = "xyes"])
 AM_CONDITIONAL([BUILD_PSA],[test "x$ENABLED_PSA" = "xyes"])
 AM_CONDITIONAL([BUILD_DTLS13],[test "x$ENABLED_DTLS13" = "xyes"])
 AM_CONDITIONAL([BUILD_QUIC],[test "x$ENABLED_QUIC" = "xyes"])
+AM_CONDITIONAL([BUILD_DTLS_CID],[test "x$ENABLED_DTLS_CID" = "xyes"])
 
 if test "$ENABLED_REPRODUCIBLE_BUILD" != "yes" &&
    (test "$ax_enable_debug" = "yes" ||

+ 145 - 0
doc/dox_comments/header_files/ssl.h

@@ -14365,4 +14365,149 @@ unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSION *s);
  */
 int wolfSSL_CRYPTO_get_ex_new_index(int, void*, void*, void*, void*);
 
+/*!
+
+\brief Enable use of ConnectionID extensions for the SSL object. See RFC 9146
+and RFC 9147
+
+ \return WOLFSSL_SUCCESS on success, error code otherwise
+
+ \param ssl A WOLFSSL object pointer
+
+ \sa wolfSSL_dtls_cid_is_enabled
+ \sa wolfSSL_dtls_cid_set
+ \sa wolfSSL_dtls_cid_get_rx_size
+ \sa wolfSSL_dtls_cid_get_rx
+ \sa wolfSSL_dtls_cid_get_tx_size
+ \sa wolfSSL_dtls_cid_get_tx
+*/
+int wolfSSL_dtls_cid_use(WOLFSSL* ssl);
+
+/*!
+
+\brief If invoked after the handshake is complete it checks if ConnectionID was
+successfully negotiated for the SSL object. See RFC 9146 and RFC 9147
+
+ \return 1 if ConnectionID was correctly negotiated, 0 otherwise
+
+ \param ssl A WOLFSSL object pointer
+
+ \sa wolfSSL_dtls_cid_use
+ \sa wolfSSL_dtls_cid_set
+ \sa wolfSSL_dtls_cid_get_rx_size
+ \sa wolfSSL_dtls_cid_get_rx
+ \sa wolfSSL_dtls_cid_get_tx_size
+ \sa wolfSSL_dtls_cid_get_tx
+*/
+int wolfSSL_dtls_cid_is_enabled(WOLFSSL* ssl);
+
+/*!
+
+\brief Set the ConnectionID used by the other peer to send records in this
+connection. See RFC 9146 and RFC 9147. The ConnectionID must be at maximum
+DTLS_CID_MAX_SIZE, that is an tunable compile time define, and it can't
+never be bigger than 255 bytes.
+
+ \return WOLFSSL_SUCCESS if ConnectionID was correctly set, error code otherwise
+
+ \param ssl A WOLFSSL object pointern
+ \param cid the ConnectionID to be used
+ \param size of the ConnectionID provided
+
+ \sa wolfSSL_dtls_cid_use
+ \sa wolfSSL_dtls_cid_is_enabled
+ \sa wolfSSL_dtls_cid_get_rx_size
+ \sa wolfSSL_dtls_cid_get_rx
+ \sa wolfSSL_dtls_cid_get_tx_size
+ \sa wolfSSL_dtls_cid_get_tx
+*/
+int wolfSSL_dtls_cid_set(WOLFSSL* ssl, unsigned char* cid,
+    unsigned int size);
+
+/*!
+
+\brief Get the size of the ConnectionID used by the other peer to send records
+in this connection. See RFC 9146 and RFC 9147. The size is stored in the
+parameter size.
 
+ \return WOLFSSL_SUCCESS if ConnectionID was correctly negotiated, error code
+ otherwise
+
+ \param ssl A WOLFSSL object pointern
+ \param size a pointer to an unsigned int where the size will be stored
+
+ \sa wolfSSL_dtls_cid_use
+ \sa wolfSSL_dtls_cid_is_enabled
+ \sa wolfSSL_dtls_cid_set
+ \sa wolfSSL_dtls_cid_get_rx
+ \sa wolfSSL_dtls_cid_get_tx_size
+ \sa wolfSSL_dtls_cid_get_tx
+*/
+int wolfSSL_dtls_cid_get_rx_size(WOLFSSL* ssl,
+    unsigned int* size);
+
+/*!
+
+\brief Copy the ConnectionID used by the other peer to send records in this
+connection into the buffer pointed by the parameter buffer. See RFC 9146 and RFC
+9147. The available space in the buffer need to be provided in bufferSz.
+
+ \return WOLFSSL_SUCCESS if ConnectionID was correctly copied, error code
+ otherwise
+
+ \param ssl A WOLFSSL object pointern
+ \param buffer A buffer where the ConnectionID will be copied
+ \param bufferSz available space in buffer
+
+ \sa wolfSSL_dtls_cid_use
+ \sa wolfSSL_dtls_cid_is_enabled
+ \sa wolfSSL_dtls_cid_set
+ \sa wolfSSL_dtls_cid_get_rx_size
+ \sa wolfSSL_dtls_cid_get_tx_size
+ \sa wolfSSL_dtls_cid_get_tx
+*/
+int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buffer,
+    unsigned int bufferSz);
+
+/*!
+
+\brief Get the size of the ConnectionID used to send records in this
+connection. See RFC 9146 and RFC 9147. The size is stored in the parameter size.
+
+ \return WOLFSSL_SUCCESS if ConnectionID size was correctly stored, error
+ code otherwise
+
+ \param ssl A WOLFSSL object pointern
+ \param size a pointer to an unsigned int where the size will be stored
+
+ \sa wolfSSL_dtls_cid_use
+ \sa wolfSSL_dtls_cid_is_enabled
+ \sa wolfSSL_dtls_cid_set
+ \sa wolfSSL_dtls_cid_get_rx_size
+ \sa wolfSSL_dtls_cid_get_rx
+ \sa wolfSSL_dtls_cid_get_tx
+*/
+int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl, unsigned int* size);
+
+/*!
+
+\brief Copy the ConnectionID used when sending records in this connection into
+the buffer pointer by the parameter buffer. See RFC 9146 and RFC 9147. The
+available size need to be provided in bufferSz.
+
+ \return WOLFSSL_SUCCESS if ConnectionID was correctly copied, error code
+ otherwise
+
+ \param ssl A WOLFSSL object pointern
+ \param buffer A buffer where the ConnectionID will be copied
+ \param bufferSz available space in buffer
+
+ \sa wolfSSL_dtls_cid_use
+ \sa wolfSSL_dtls_cid_is_enabled
+ \sa wolfSSL_dtls_cid_set
+ \sa wolfSSL_dtls_cid_get_rx_size
+ \sa wolfSSL_dtls_cid_get_rx
+ \sa wolfSSL_dtls_cid_get_tx_size
+*/
+int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer,
+    unsigned int bufferSz);

+ 368 - 0
src/dtls.c

@@ -0,0 +1,368 @@
+/* dtls.c
+ *
+ * Copyright (C) 2006-2022 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if defined(WOLFSSL_DTLS_CID)
+
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/internal.h>
+#include <wolfssl/ssl.h>
+
+typedef struct ConnectionID {
+    byte length;
+    byte id[];
+} ConnectionID;
+
+typedef struct CIDInfo {
+    ConnectionID* tx;
+    ConnectionID* rx;
+    byte negotiated : 1;
+} CIDInfo;
+
+static ConnectionID* DtlsCidNew(const byte* cid, byte size, void* heap)
+{
+    ConnectionID* ret;
+
+    ret = (ConnectionID*)XMALLOC(sizeof(ConnectionID) + size, heap,
+        DYNAMIC_TYPE_TLSX);
+    if (ret == NULL)
+        return NULL;
+
+    ret->length = size;
+    XMEMCPY(ret->id, cid, size);
+
+    return ret;
+}
+
+static WC_INLINE CIDInfo* DtlsCidGetInfo(WOLFSSL* ssl)
+{
+    return ssl->dtlsCidInfo;
+}
+
+static int DtlsCidGetSize(WOLFSSL* ssl, unsigned int* size, int rx)
+{
+    ConnectionID* id;
+    CIDInfo* info;
+
+    if (ssl == NULL || size == NULL)
+        return BAD_FUNC_ARG;
+
+    info = DtlsCidGetInfo(ssl);
+    if (info == NULL)
+        return WOLFSSL_FAILURE;
+
+    id = rx ? info->rx : info->tx;
+    if (id == NULL) {
+        *size = 0;
+        return WOLFSSL_SUCCESS;
+    }
+
+    *size = id->length;
+    return WOLFSSL_SUCCESS;
+}
+
+static int DtlsCidGet(WOLFSSL* ssl, unsigned char* buf, int bufferSz, int rx)
+{
+    ConnectionID* id;
+    CIDInfo* info;
+
+    if (ssl == NULL || buf == NULL)
+        return BAD_FUNC_ARG;
+
+    info = DtlsCidGetInfo(ssl);
+    if (info == NULL)
+        return WOLFSSL_FAILURE;
+
+    id = rx ? info->rx : info->tx;
+    if (id == NULL || id->length == 0)
+        return WOLFSSL_SUCCESS;
+
+    if (id->length > bufferSz)
+        return LENGTH_ERROR;
+
+    XMEMCPY(buf, id->id, id->length);
+    return WOLFSSL_SUCCESS;
+}
+
+static CIDInfo* DtlsCidGetInfoFromExt(byte* ext)
+{
+    WOLFSSL** sslPtr;
+    WOLFSSL* ssl;
+
+    if (ext == NULL)
+        return NULL;
+    sslPtr = (WOLFSSL**)ext;
+    ssl = *sslPtr;
+    if (ssl == NULL)
+        return NULL;
+    return ssl->dtlsCidInfo;
+}
+
+static void DtlsCidUnsetInfoFromExt(byte* ext)
+{
+    WOLFSSL** sslPtr;
+    WOLFSSL* ssl;
+
+    if (ext == NULL)
+        return;
+    sslPtr = (WOLFSSL**)ext;
+    ssl = *sslPtr;
+    if (ssl == NULL)
+        return;
+    ssl->dtlsCidInfo = NULL;
+}
+
+void TLSX_ConnectionID_Free(byte* ext, void* heap)
+{
+    CIDInfo* info;
+    (void)heap;
+
+    info = DtlsCidGetInfoFromExt(ext);
+    if (info == NULL)
+        return;
+    if (info->rx != NULL)
+        XFREE(info->rx, heap, DYNAMIC_TYPE_TLSX);
+    if (info->tx != NULL)
+        XFREE(info->tx, heap, DYNAMIC_TYPE_TLSX);
+    XFREE(info, heap, DYNAMIC_TYPE_TLSX);
+    DtlsCidUnsetInfoFromExt(ext);
+    XFREE(ext, heap, DYANMIC_TYPE_TLSX);
+}
+
+word16 TLSX_ConnectionID_Write(byte* ext, byte* output)
+{
+    CIDInfo* info;
+
+    info = DtlsCidGetInfoFromExt(ext);
+    if (info == NULL)
+        return 0;
+
+    /* empty CID */
+    if (info->rx == NULL) {
+        *output = 0;
+        return OPAQUE8_LEN;
+    }
+
+    *output = info->rx->length;
+    XMEMCPY(output + OPAQUE8_LEN, info->rx->id, info->rx->length);
+    return OPAQUE8_LEN + info->rx->length;
+}
+
+word16 TLSX_ConnectionID_GetSize(byte* ext)
+{
+    CIDInfo* info = DtlsCidGetInfoFromExt(ext);
+    if (info == NULL)
+        return 0;
+    return info->rx == NULL ? OPAQUE8_LEN : OPAQUE8_LEN + info->rx->length;
+}
+
+int TLSX_ConnectionID_Use(WOLFSSL* ssl)
+{
+    CIDInfo* info;
+    WOLFSSL** ext;
+    int ret;
+
+    ext = (WOLFSSL**)TLSX_Find(ssl->extensions, TLSX_CONNECTION_ID);
+    if (ext != NULL)
+        return 0;
+
+    info = (CIDInfo*)XMALLOC(sizeof(CIDInfo), ssl->heap, DYNAMIC_TYPE_TLSX);
+    if (info == NULL)
+        return MEMORY_ERROR;
+    ext = (WOLFSSL**)XMALLOC(sizeof(WOLFSSL**), ssl->heap, DYNAMIC_TYPE_TLSX);
+    if (ext == NULL) {
+        XFREE(info, ssl->heap, DYNAMIC_TYPE_TLSX);
+        return MEMORY_ERROR;
+    }
+    XMEMSET(info, 0, sizeof(CIDInfo));
+    /* CIDInfo needs to be accessed every time we send or receive a record. To
+     * avoid the cost of the extension lookup save a pointer to the structure
+     * inside the SSL object itself, and save a pointer to the SSL object in the
+     * extension. The extension freeing routine uses te pointer to the SSL
+     * object to find the structure and to set ssl->dtlsCidInfo pointer to NULL
+     * after freeing the structure. */
+    ssl->dtlsCidInfo = info;
+    *ext = ssl;
+    ret =
+        TLSX_Push(&ssl->extensions, TLSX_CONNECTION_ID, (void*)ext, ssl->heap);
+    if (ret != 0) {
+        XFREE(info, ssl->heap, DYNAMIC_TYPE_TLSX);
+        XFREE(ext, ssl->heap, DYNAMIC_TYPE_TLSX);
+        ssl->dtlsCidInfo = NULL;
+        return ret;
+    }
+
+    return 0;
+}
+
+int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input, word16 length,
+    byte isRequest)
+{
+    ConnectionID* id;
+    CIDInfo* info;
+    byte cidSize;
+    TLSX* ext;
+
+    ext = TLSX_Find(ssl->extensions, TLSX_CONNECTION_ID);
+    if (ext == NULL) {
+        /* CID not enabled */
+        if (isRequest) {
+            WOLFSSL_MSG("Received CID ext but it's not enabled, ignoring");
+            return 0;
+        }
+        else {
+            WOLFSSL_MSG("CID ext not requested by the Client, aborting");
+            return UNSUPPORTED_EXTENSION;
+        }
+    }
+
+    info = DtlsCidGetInfo(ssl);
+    if (info == NULL || info->tx != NULL)
+        return BAD_STATE_E;
+
+    if (length < OPAQUE8_LEN)
+        return BUFFER_ERROR;
+
+    cidSize = *input;
+    if (cidSize + OPAQUE8_LEN > length)
+        return BUFFER_ERROR;
+
+    if (cidSize > 0) {
+        id = (ConnectionID*)XMALLOC(sizeof(*id) + cidSize, ssl->heap,
+            DYNAMIC_TYPE_TLSX);
+        if (id == NULL)
+            return MEMORY_ERROR;
+        XMEMCPY(id->id, input + OPAQUE8_LEN, cidSize);
+        id->length = cidSize;
+        info->tx = id;
+    }
+
+    info->negotiated = 1;
+    if (isRequest)
+        ext->resp = 1;
+
+    return 0;
+}
+
+void DtlsCIDOnExtensionsParsed(WOLFSSL* ssl)
+{
+    CIDInfo* info;
+
+    info = DtlsCidGetInfo(ssl);
+    if (info == NULL)
+        return;
+
+    if (!info->negotiated) {
+        TLSX_Remove(&ssl->extensions, TLSX_CONNECTION_ID, ssl->heap);
+        return;
+    }
+}
+
+byte DtlsCIDCheck(WOLFSSL* ssl, const byte* input, word16 inputSize)
+{
+    CIDInfo* info;
+    info = DtlsCidGetInfo(ssl);
+    if (info == NULL || info->rx == NULL || info->rx->length == 0)
+        return 0;
+    if (inputSize < info->rx->length)
+        return 0;
+    return XMEMCMP(input, info->rx->id, info->rx->length) == 0;
+}
+
+int wolfSSL_dtls_cid_use(WOLFSSL* ssl)
+{
+    int ret;
+
+    /* CID is supported on DTLSv1.3 only */
+    if (!IsAtLeastTLSv1_3(ssl->version))
+        return WOLFSSL_FAILURE;
+
+    ssl->options.useDtlsCID = 1;
+    ret = TLSX_ConnectionID_Use(ssl);
+    if (ret != 0)
+        return ret;
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_dtls_cid_is_enabled(WOLFSSL* ssl)
+{
+    return DtlsCidGetInfo(ssl) != NULL;
+}
+
+int wolfSSL_dtls_cid_set(WOLFSSL* ssl, unsigned char* cid, unsigned int size)
+{
+    ConnectionID* newCid;
+    CIDInfo* cidInfo;
+
+    if (!ssl->options.useDtlsCID)
+        return WOLFSSL_FAILURE;
+
+    cidInfo = DtlsCidGetInfo(ssl);
+    if (cidInfo == NULL)
+        return WOLFSSL_FAILURE;
+
+    if (cidInfo->rx != NULL) {
+        XFREE(cidInfo->rx, ssl->heap, DYNAMIC_TYPE_TLSX);
+        cidInfo->rx = NULL;
+    }
+
+    /* empty CID */
+    if (size == 0)
+        return WOLFSSL_SUCCESS;
+
+    if (size > DTLS_CID_MAX_SIZE)
+        return LENGTH_ERROR;
+
+    newCid = DtlsCidNew(cid, (byte)size, ssl->heap);
+    if (newCid == NULL)
+        return MEMORY_ERROR;
+    cidInfo->rx = newCid;
+    return WOLFSSL_SUCCESS;
+}
+
+int wolfSSL_dtls_cid_get_rx_size(WOLFSSL* ssl, unsigned int* size)
+{
+    return DtlsCidGetSize(ssl, size, 1);
+}
+
+int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buf,
+    unsigned int bufferSz)
+{
+    return DtlsCidGet(ssl, buf, bufferSz, 1);
+}
+
+int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl, unsigned int* size)
+{
+    return DtlsCidGetSize(ssl, size, 0);
+}
+
+int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buf,
+    unsigned int bufferSz)
+{
+    return DtlsCidGet(ssl, buf, bufferSz, 0);
+}
+
+#endif /* WOLFSSL_DTLS_CID */

+ 145 - 71
src/dtls13.c

@@ -88,28 +88,6 @@ typedef struct Dtls13RecordPlaintextHeader {
     byte length[2];
 } Dtls13RecordPlaintextHeader;
 
-/**
- * struct Dtls13RecordCiphertextHeader: represent the header of protected
- * DTLSv1.3 used in wolfSSL
- * @unifiedHdrflags: the first three bits are always 001, then CID bit: if
- * setted the header contains a CID, S bit: if setted the header contains the 16
- * LSBs of sequence number length, otherwise only the 8 LSBs are present, then
- * the L bit: if present the length of the record is present, lastly EE: the
- * last two bits of the epoch
- * @sequenceNumber: 16 LSBs of the sequence number
- * @length: length of the record
- *
- * DTLSv1.3 uses a variable length header, this struct represent only the
- * representation used by wolfSSL, where CID is never present (not supported),
- * the 16 LSBs of the sequence number and the length are always present.
- */
-typedef struct Dtls13RecordCiphertextHeader {
-    /* 0 0 1 C S L E E */
-    byte unifiedHdrFlags;
-    byte sequenceNumber[2];
-    byte length[2];
-} Dtls13RecordCiphertextHeader;
-
 /* size of the len field in the unified header */
 #define DTLS13_LEN_SIZE 2
 /* size of the mask used to encrypt/decrypt Record Number  */
@@ -484,7 +462,7 @@ static int Dtls13SendFragment(WOLFSSL* ssl, byte* output, word16 output_size,
         return BUFFER_ERROR;
 
     isProtected = Dtls13TypeIsEncrypted(handshakeType);
-    recordHeaderLength = Dtls13GetRlHeaderLength(isProtected);
+    recordHeaderLength = Dtls13GetRlHeaderLength(ssl, isProtected);
 
     if (length <= recordHeaderLength)
         return BUFFER_ERROR;
@@ -829,7 +807,7 @@ static int Dtls13SendOneFragmentRtx(WOLFSSL* ssl,
     int ret;
 
     isProtected = Dtls13TypeIsEncrypted(handshakeType);
-    recordHeaderLength = Dtls13GetRlHeaderLength(isProtected);
+    recordHeaderLength = Dtls13GetRlHeaderLength(ssl, isProtected);
 
     rtxRecord = Dtls13RtxNewRecord(ssl, message + recordHeaderLength,
         (word16)(length - recordHeaderLength), handshakeType,
@@ -860,7 +838,7 @@ static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
 
     isEncrypted = Dtls13TypeIsEncrypted(
         (enum HandShakeType)ssl->dtls13FragHandshakeType);
-    rlHeaderLength = Dtls13GetRlHeaderLength(isEncrypted);
+    rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
     maxFragment = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
 
     remainingSize = ssl->dtls13MessageLength - ssl->dtls13FragOffset;
@@ -933,7 +911,7 @@ static int Dtls13SendFragmented(WOLFSSL* ssl, byte* message, word16 length,
     }
 
     isEncrypted = Dtls13TypeIsEncrypted(handshake_type);
-    rlHeaderLength = Dtls13GetRlHeaderLength(isEncrypted);
+    rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
 
     if (length < rlHeaderLength)
         return INCOMPLETE_DATA;
@@ -970,6 +948,96 @@ static WC_INLINE word8 Dtls13GetEpochBits(w64wrapper epoch)
     return w64GetLow32(epoch) & EE_MASK;
 }
 
+#ifdef WOLFSSL_DTLS_CID
+static byte Dtls13GetCidTxSize(WOLFSSL* ssl)
+{
+    unsigned int cidSz;
+    int ret;
+    ret = wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz);
+    if (ret != WOLFSSL_SUCCESS)
+        return 0;
+    return (byte)cidSz;
+}
+
+static byte Dtls13GetCidRxSize(WOLFSSL* ssl)
+{
+    unsigned int cidSz;
+    int ret;
+    ret = wolfSSL_dtls_cid_get_rx_size(ssl, &cidSz);
+    if (ret != WOLFSSL_SUCCESS)
+        return 0;
+    return (byte)cidSz;
+}
+
+static int Dtls13AddCID(WOLFSSL* ssl, byte* flags, byte* out, word16* idx)
+{
+    byte cidSize;
+    int ret;
+
+    if (!wolfSSL_dtls_cid_is_enabled(ssl))
+        return 0;
+
+    cidSize = Dtls13GetCidTxSize(ssl);
+
+    /* no cid */
+    if (cidSize == 0)
+        return 0;
+    *flags |= DTLS13_CID_BIT;
+    /* we know that we have at least cidSize of space */
+    ret = wolfSSL_dtls_cid_get_tx(ssl, out + *idx, cidSize);
+    if (ret != WOLFSSL_SUCCESS)
+        return ret;
+    *idx += cidSize;
+    return 0;
+}
+
+static int Dtls13UnifiedHeaderParseCID(WOLFSSL* ssl, byte flags,
+    const byte* input, word16 inputSize, word16* idx)
+{
+    unsigned int _cidSz;
+    int ret;
+
+    if (flags & DTLS13_CID_BIT) {
+        if (!wolfSSL_dtls_cid_is_enabled(ssl)) {
+            WOLFSSL_MSG("CID while no negotiated CID, ignoring");
+            return DTLS_CID_ERROR;
+        }
+
+        if (!DtlsCIDCheck(ssl, input + *idx, inputSize - *idx)) {
+            WOLFSSL_MSG("Not matching or wrong CID, ignoring");
+            return DTLS_CID_ERROR;
+        }
+
+        ret = wolfSSL_dtls_cid_get_rx_size(ssl, &_cidSz);
+        if (ret != WOLFSSL_SUCCESS)
+            return ret;
+
+        *idx += _cidSz;
+        return 0;
+    }
+
+    /* CID not present */
+    if (wolfSSL_dtls_cid_is_enabled(ssl)) {
+        ret = wolfSSL_dtls_cid_get_rx_size(ssl, &_cidSz);
+        if (ret != WOLFSSL_SUCCESS)
+            return ret;
+
+        if (_cidSz != 0) {
+            WOLFSSL_MSG("expecting CID, ignoring");
+            return DTLS_CID_ERROR;
+        }
+    }
+
+    return 0;
+}
+
+#else
+#define Dtls13AddCID(a, b, c, d) 0
+#define Dtls13GetCidRxSize(a) 0
+#define Dtls13GetCidTxSize(a) 0
+#define Dtls13UnifiedHeaderParseCID(a, b, c, d, e) 0
+#endif /* WOLFSSL_DTLS_CID */
+
 /**
  * dtls13RlAddCiphertextHeader() - add record layer header in the buffer
  * @ssl: ssl object
@@ -978,8 +1046,9 @@ static WC_INLINE word8 Dtls13GetEpochBits(w64wrapper epoch)
  */
 int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out, word16 length)
 {
-    Dtls13RecordCiphertextHeader* hdr;
-    word16 seqNumber;
+    word16 seqNumber, idx;
+    byte* flags;
+    int ret;
 
     if (out == NULL)
         return BAD_FUNC_ARG;
@@ -987,20 +1056,27 @@ int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out, word16 length)
     if (ssl->dtls13EncryptEpoch == NULL)
         return BAD_STATE_E;
 
-    hdr = (Dtls13RecordCiphertextHeader*)out;
+    flags = out;
 
-    hdr->unifiedHdrFlags = DTLS13_FIXED_BITS;
-    hdr->unifiedHdrFlags |=
-        Dtls13GetEpochBits(ssl->dtls13EncryptEpoch->epochNumber);
+    /* header fixed bits */
+    *flags = DTLS13_FIXED_BITS;
+    /* epoch bits */
+    *flags |= Dtls13GetEpochBits(ssl->dtls13EncryptEpoch->epochNumber);
+
+    idx = DTLS13_HDR_FLAGS_SIZE;
+    ret = Dtls13AddCID(ssl, flags, out, &idx);
+    if (ret != 0)
+        return ret;
 
     /* include 16-bit seq */
-    hdr->unifiedHdrFlags |= DTLS13_SEQ_LEN_BIT;
+    *flags |= DTLS13_SEQ_LEN_BIT;
     /* include 16-bit length */
-    hdr->unifiedHdrFlags |= DTLS13_LEN_BIT;
+    *flags |= DTLS13_LEN_BIT;
 
     seqNumber = (word16)w64GetLow32(ssl->dtls13EncryptEpoch->nextSeqNumber);
-    c16toa(seqNumber, hdr->sequenceNumber);
-    c16toa(length, hdr->length);
+    c16toa(seqNumber, out + idx);
+    idx += OPAQUE16_LEN;
+    c16toa(length, out + idx);
 
     return 0;
 }
@@ -1041,19 +1117,21 @@ int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, word16 recordLength)
 {
     int seqLength;
     int hdrLength;
+    int cidSz;
 
     if (ssl == NULL || hdr == NULL)
         return BAD_FUNC_ARG;
 
     /* we need at least a 16 bytes of ciphertext to encrypt record number see
        4.2.3*/
-    if (recordLength < Dtls13GetRlHeaderLength(1) + DTLS13_MIN_CIPHERTEXT)
+    if (recordLength < Dtls13GetRlHeaderLength(ssl, 1) + DTLS13_MIN_CIPHERTEXT)
         return BUFFER_ERROR;
 
     seqLength = (*hdr & DTLS13_LEN_BIT) ? DTLS13_SEQ_16_LEN : DTLS13_SEQ_8_LEN;
 
-    /* header flags + seq number */
-    hdrLength = 1 + seqLength;
+    cidSz = Dtls13GetCidTxSize(ssl);
+    /* header flags + seq number + CID size*/
+    hdrLength = OPAQUE8_LEN + seqLength + cidSz;
 
     /* length present */
     if (*hdr & DTLS13_LEN_BIT)
@@ -1061,7 +1139,7 @@ int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, word16 recordLength)
 
     return Dtls13EncryptDecryptRecordNumber(ssl,
         /* seq number offset */
-        hdr + 1,
+        hdr + OPAQUE8_LEN + cidSz,
         /* seq size */
         seqLength,
         /* cipher text */
@@ -1075,27 +1153,28 @@ int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, word16 recordLength)
  *
  * returns the length of the record layer header in bytes.
  */
-word16 Dtls13GetRlHeaderLength(byte isEncrypted)
+word16 Dtls13GetRlHeaderLength(WOLFSSL* ssl, byte isEncrypted)
 {
-    /* the function looks useless but allow to support variable length unified
-       header in the future */
+    (void)ssl;
+
     if (!isEncrypted)
         return DTLS_RECORD_HEADER_SZ;
 
-    return DTLS13_UNIFIED_HEADER_SIZE;
+    return DTLS13_UNIFIED_HEADER_SIZE + Dtls13GetCidTxSize(ssl);
 }
 
 /**
  * Dtls13GetHeadersLength() - return length of record + handshake header
+ * @ssl: ssl oject
  * @type: type of handshake in the message
  */
-word16 Dtls13GetHeadersLength(enum HandShakeType type)
+word16 Dtls13GetHeadersLength(WOLFSSL* ssl, enum HandShakeType type)
 {
     byte isEncrypted;
 
     isEncrypted = Dtls13TypeIsEncrypted(type);
 
-    return Dtls13GetRlHeaderLength(isEncrypted) + DTLS_HANDSHAKE_HEADER_SZ;
+    return Dtls13GetRlHeaderLength(ssl, isEncrypted) + DTLS_HANDSHAKE_HEADER_SZ;
 }
 
 /**
@@ -1200,18 +1279,15 @@ int Dtls13ReconstructEpochNumber(WOLFSSL* ssl, byte epochBits,
     return SEQUENCE_ERROR;
 }
 
-int Dtls13GetUnifiedHeaderSize(const byte input, word16* size)
+int Dtls13GetUnifiedHeaderSize(WOLFSSL* ssl, const byte input, word16* size)
 {
+    (void)ssl;
+
     if (size == NULL)
         return BAD_FUNC_ARG;
 
-    if (input & DTLS13_CID_BIT) {
-        WOLFSSL_MSG("DTLS1.3 header with connection ID. Not supported");
-        return WOLFSSL_NOT_IMPLEMENTED;
-    }
-
-    /* flags (1) + seq 8bit (1) */
-    *size = OPAQUE8_LEN + OPAQUE8_LEN;
+    /* flags (1) + CID + seq 8bit (1) */
+    *size = OPAQUE8_LEN + Dtls13GetCidRxSize(ssl) + OPAQUE8_LEN;
     if (input & DTLS13_SEQ_LEN_BIT)
         *size += OPAQUE8_LEN;
     if (input & DTLS13_LEN_BIT)
@@ -1237,23 +1313,24 @@ int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input,
 {
     byte seqLen, hasLength;
     byte* seqNum;
+    byte flags;
     word16 idx;
     int ret;
 
-    if (input == NULL || inputSize == 0)
+    if (input == NULL || inputSize < DTLS13_HDR_FLAGS_SIZE)
         return BAD_FUNC_ARG;
 
-    if (*input & DTLS13_CID_BIT) {
-        WOLFSSL_MSG("DTLS1.3 header with connection ID. Not supported");
-        return WOLFSSL_NOT_IMPLEMENTED;
-    }
-
+    flags = *input;
     idx = DTLS13_HDR_FLAGS_SIZE;
+    ret = Dtls13UnifiedHeaderParseCID(ssl, flags, input, inputSize, &idx);
+    if (ret != 0)
+        return ret;
 
-    seqLen = (*input & DTLS13_SEQ_LEN_BIT) != 0 ? DTLS13_SEQ_16_LEN
-                                                : DTLS13_SEQ_8_LEN;
-    hasLength = *input & DTLS13_LEN_BIT;
-    hdrInfo->epochBits = *input & EE_MASK;
+    seqNum = (byte*)input + idx;
+    seqLen = (flags & DTLS13_SEQ_LEN_BIT) != 0 ? DTLS13_SEQ_16_LEN
+                                               : DTLS13_SEQ_8_LEN;
+    hasLength = flags & DTLS13_LEN_BIT;
+    hdrInfo->epochBits = flags & EE_MASK;
 
     idx += seqLen;
 
@@ -1278,8 +1355,6 @@ int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input,
     if (hdrInfo->recordLength < DTLS13_RN_MASK_SIZE)
         return LENGTH_ERROR;
 
-    seqNum = (byte*)(input + DTLS13_HDR_FLAGS_SIZE);
-
     ret = Dtls13EncryptDecryptRecordNumber(ssl, seqNum, seqLen, input + idx,
         DEPROTECT);
     if (ret != 0)
@@ -1356,7 +1431,7 @@ static int Dtls13RtxSendBuffered(WOLFSSL* ssl)
         isLast = r->next == NULL;
         WOLFSSL_MSG("Dtls13Rtx One Record");
 
-        headerLength = Dtls13GetRlHeaderLength(!w64IsZero(r->epoch));
+        headerLength = Dtls13GetRlHeaderLength(ssl, !w64IsZero(r->epoch));
 
         sendSz = r->length + headerLength;
 
@@ -1569,7 +1644,7 @@ int Dtls13AddHeaders(byte* output, word32 length, enum HandShakeType hsType,
     int isEncrypted;
 
     isEncrypted = Dtls13TypeIsEncrypted(hsType);
-    handshakeOffset = Dtls13GetRlHeaderLength(isEncrypted);
+    handshakeOffset = Dtls13GetRlHeaderLength(ssl, isEncrypted);
 
     /* The record header is placed by either Dtls13HandshakeSend() or
        BuildTls13Message() */
@@ -2126,10 +2201,9 @@ static int Dtls13WriteAckMessage(WOLFSSL* ssl,
     if (w64IsZero(ssl->dtls13EncryptEpoch->epochNumber)) {
         /* unprotected ACK */
         headerLength = DTLS_RECORD_HEADER_SZ;
-        ;
     }
     else {
-        headerLength = Dtls13GetRlHeaderLength(1);
+        headerLength = Dtls13GetRlHeaderLength(ssl, 1);
         sendSz += MAX_MSG_EXTRA;
     }
 
@@ -2438,7 +2512,7 @@ int SendDtls13Ack(WOLFSSL* ssl)
         outputSize = ssl->buffers.outputBuffer.bufferSize -
                      ssl->buffers.outputBuffer.length;
 
-        headerSize = Dtls13GetRlHeaderLength(1);
+        headerSize = Dtls13GetRlHeaderLength(ssl, 1);
 
         ret = BuildTls13Message(ssl, output, outputSize, output + headerSize,
             length, ack, 0, 0, 0);

+ 4 - 0
src/include.am

@@ -704,6 +704,10 @@ if BUILD_QUIC
 src_libwolfssl_la_SOURCES += src/quic.c
 endif
 
+if BUILD_DTLS_CID
+src_libwolfssl_la_SOURCES += src/dtls.c
+endif
+
 endif !BUILD_CRYPTONLY
 
 

+ 15 - 6
src/internal.c

@@ -7911,7 +7911,8 @@ void FreeHandshakeResources(WOLFSSL* ssl)
 #endif /* HAVE_PK_CALLBACKS */
 
 #if defined(HAVE_TLS_EXTENSIONS) && !defined(HAVE_SNI) && \
-!defined(NO_TLS) && !defined(HAVE_ALPN) && !defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+!defined(NO_TLS) && !defined(HAVE_ALPN) && !defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
+    !defined(WOLFSSL_DTLS_CID)
     /* Some extensions need to be kept for post-handshake querying. */
     TLSX_FreeAll(ssl->extensions, ssl->heap);
     ssl->extensions = NULL;
@@ -9103,7 +9104,7 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
         if (IsAtLeastTLSv1_3(ssl->version)) {
 #ifdef WOLFSSL_DTLS13
             word16 dtls_record_extra;
-            dtls_record_extra = Dtls13GetRlHeaderLength(IsEncryptionOn(ssl, 1));
+            dtls_record_extra = Dtls13GetRlHeaderLength(ssl, IsEncryptionOn(ssl, 1));
             dtls_record_extra -= RECORD_HEADER_SZ;
 
             adj += dtls_record_extra;
@@ -9947,7 +9948,7 @@ static int GetDtls13RecordHeader(WOLFSSL* ssl, const byte* input,
             return SEQUENCE_ERROR;
     }
 
-    ret = Dtls13GetUnifiedHeaderSize(
+    ret = Dtls13GetUnifiedHeaderSize(ssl,
         *(input+*inOutIdx), &ssl->dtls13CurRlLength);
     if (ret != 0)
         return ret;
@@ -10018,7 +10019,7 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, const byte* input,
         /* version 1.3 already negotiated */
         if (ssl->options.tls1_3) {
             ret = GetDtls13RecordHeader(ssl, input, inOutIdx, rh, size);
-            if (ret == 0 || ret != SEQUENCE_ERROR)
+            if (ret == 0 || ret != SEQUENCE_ERROR || ret != DTLS_CID_ERROR)
                 return ret;
         }
 
@@ -18777,8 +18778,9 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
                                        &ssl->curRL, &ssl->curSize);
 
 #ifdef WOLFSSL_DTLS
-            if (ssl->options.dtls && ret == SEQUENCE_ERROR) {
-                WOLFSSL_MSG("Silently dropping out of order DTLS message");
+            if (ssl->options.dtls &&
+                    (ret == SEQUENCE_ERROR || ret == DTLS_CID_ERROR)) {
+                WOLFSSL_MSG("Silently dropping DTLS message");
                 ssl->options.processReply = doProcessInit;
                 ssl->buffers.inputBuffer.length = 0;
                 ssl->buffers.inputBuffer.idx = 0;
@@ -22846,6 +22848,8 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
     case QUIC_TP_MISSING_E:
         return "QUIC transport parameter not set";
 #endif
+    case DTLS_CID_ERROR:
+        return "DTLS ConnectionID mismatch or missing";
 
     default :
         return "unknown error number";
@@ -32705,6 +32709,11 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
                 *inOutIdx = begin + helloSz; /* skip extensions */
         }
 
+#ifdef WOLFSSL_DTLS_CID
+        if (ssl->options.useDtlsCID)
+            DtlsCIDOnExtensionsParsed(ssl);
+#endif /* WOLFSSL_DTLS_CID */
+
         ssl->options.clientState   = CLIENT_HELLO_COMPLETE;
         ssl->options.haveSessionId = 1;
 

+ 55 - 0
src/tls.c

@@ -10487,6 +10487,18 @@ static int TLSX_QuicTP_Parse(WOLFSSL *ssl, const byte *input, size_t len, int ex
 
 #endif /* WOLFSSL_QUIC */
 
+#if defined(WOLFSSL_DTLS_CID)
+#define CID_GET_SIZE  TLSX_ConnectionID_GetSize
+#define CID_WRITE  TLSX_ConnectionID_Write
+#define CID_PARSE  TLSX_ConnectionID_Parse
+#define CID_FREE  TLSX_ConnectionID_Free
+#else
+#define CID_GET_SIZE(a) 0
+#define CID_WRITE(a, b) 0
+#define CID_PARSE(a, b, c, d) 0
+#define CID_FREE(a, b) 0
+#endif /* defined(WOLFSSL_DTLS_CID) */
+
 /******************************************************************************/
 /* TLS Extensions Framework                                                   */
 /******************************************************************************/
@@ -10637,6 +10649,12 @@ void TLSX_FreeAll(TLSX* list, void* heap)
                 break;
     #endif
 
+#ifdef WOLFSSL_DTLS_CID
+        case TLSX_CONNECTION_ID:
+            CID_FREE((byte*)extension->data, heap);
+            break;
+#endif /* WOLFSSL_DTLS_CID */
+
             default:
                 break;
         }
@@ -10800,6 +10818,11 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
                 length += QTP_GET_SIZE(extension);
                 break;
 #endif
+#ifdef WOLFSSL_DTLS_CID
+            case TLSX_CONNECTION_ID:
+                length += CID_GET_SIZE((byte*)extension->data);
+                break;
+#endif /* WOLFSSL_DTLS_CID */
             default:
                 break;
         }
@@ -10997,6 +11020,12 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
                                     output + offset);
                 break;
 #endif
+#ifdef WOLFSSL_DTLS_CID
+            case TLSX_CONNECTION_ID:
+                offset += CID_WRITE((byte*)extension->data, output+offset);
+                break;
+
+#endif /* WOLFSSL_DTLS_CID */
             default:
                 break;
         }
@@ -11912,6 +11941,9 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
         #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
         #endif
+        #ifdef WOLFSSL_DTLS_CID
+                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID));
+        #endif /* WOLFSSL_DTLS_CID */
                 }
         #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
                 else {
@@ -11965,6 +11997,9 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
         #if defined(HAVE_SERVER_RENEGOTIATION_INFO)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
         #endif
+        #ifdef WOLFSSL_DTLS_CID
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID));
+        #endif /* WOLFSSL_DTLS_CID */
             break;
 
         #ifdef WOLFSSL_EARLY_DATA
@@ -12040,6 +12075,9 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
             #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
             #endif
+            #ifdef WOLFSSL_DTLS_CID
+                    TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID));
+            #endif /* WOLFSSL_DTLS_CID */
                 }
         #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS)
                 else {
@@ -12091,6 +12129,9 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
         #if defined(HAVE_SERVER_RENEGOTIATION_INFO)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
         #endif
+        #ifdef WOLFSSL_DTLS_CID
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID));
+        #endif /* WOLFSSL_DTLS_CID */
                 break;
 
         #ifdef WOLFSSL_EARLY_DATA
@@ -12731,6 +12772,20 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
                 }
                 break;
 #endif /* WOLFSSL_QUIC */
+#if defined(WOLFSSL_DTLS_CID)
+            case TLSX_CONNECTION_ID:
+                /* connection ID not supported in DTLSv1.2 */
+                if (!IsAtLeastTLSv1_3(ssl->version))
+                    break;
+
+                if (msgType != client_hello && msgType != server_hello)
+                    return EXT_NOT_ALLOWED;
+
+                WOLFSSL_MSG("ConnectionID extension received");
+                ret = CID_PARSE(ssl, input + offset, size, isRequest);
+                break;
+
+#endif /* defined(WOLFSSL_DTLS_CID) */
             default:
                 WOLFSSL_MSG("Unknown TLS extension type");
         }

+ 32 - 20
src/tls13.c

@@ -2591,7 +2591,7 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input,
         args->headerSz = RECORD_HEADER_SZ;
 #ifdef WOLFSSL_DTLS13
         if (ssl->options.dtls)
-            args->headerSz = Dtls13GetRlHeaderLength(1);
+            args->headerSz = Dtls13GetRlHeaderLength(ssl, 1);
 #endif /* WOLFSSL_DTLS13 */
 
         args->sz = args->headerSz + inSz;
@@ -3252,8 +3252,8 @@ static int WritePSKBinders(WOLFSSL* ssl, byte* output, word32 idx)
     /* Hash truncated ClientHello - up to binders. */
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls)
-        ret = Dtls13HashHandshake(ssl, output + Dtls13GetRlHeaderLength(0),
-            idx - Dtls13GetRlHeaderLength(0));
+        ret = Dtls13HashHandshake(ssl, output + Dtls13GetRlHeaderLength(ssl, 0),
+            idx - Dtls13GetRlHeaderLength(ssl, 0));
     else
 #endif /* WOLFSSL_DTLS13 */
         ret = HashOutput(ssl, output, idx, 0);
@@ -3659,11 +3659,11 @@ int SendTls13ClientHello(WOLFSSL* ssl)
 #endif
         {
 #ifdef WOLFSSL_DTLS13
-            if (ssl->options.dtls)
-                ret = Dtls13HashHandshake(ssl,
-                    args->output + Dtls13GetRlHeaderLength(0),
-                    args->idx - Dtls13GetRlHeaderLength(0));
-            else
+        if (ssl->options.dtls)
+            ret = Dtls13HashHandshake(ssl,
+                args->output + Dtls13GetRlHeaderLength(ssl, 0),
+                args->idx - Dtls13GetRlHeaderLength(ssl, 0));
+        else
 #endif /* WOLFSSL_DTLS13 */
                 ret = HashOutput(ssl, args->output, args->idx, 0);
         }
@@ -4081,6 +4081,11 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
         args->idx += args->totalExtSz;
     }
 
+#ifdef WOLFSSL_DTLS_CID
+    if (ssl->options.useDtlsCID)
+        DtlsCIDOnExtensionsParsed(ssl);
+#endif /* WOLFSSL_DTLS_CID */
+
     *inOutIdx = args->idx;
 
     ssl->options.serverState = SERVER_HELLO_COMPLETE;
@@ -5513,6 +5518,11 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
         goto exit_dch;
     }
 
+#ifdef WOLFSSL_DTLS_CID
+    if (ssl->options.useDtlsCID)
+        DtlsCIDOnExtensionsParsed(ssl);
+#endif /* WOLFSSL_DTLS_CID */
+
 #ifdef HAVE_SNI
         if ((ret = SNI_Callback(ssl)) != 0)
             return ret;
@@ -5841,8 +5851,8 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
 #ifdef WOLFSSL_DTLS13
         if (ssl->options.dtls) {
             ret = Dtls13HashHandshake(ssl,
-                                      output + Dtls13GetRlHeaderLength(0) ,
-                                      sendSz - Dtls13GetRlHeaderLength(0));
+                                      output + Dtls13GetRlHeaderLength(ssl, 0) ,
+                                      sendSz - Dtls13GetRlHeaderLength(ssl, 0));
         }
         else
 #endif /* WOLFSSL_DTLS13 */
@@ -5913,7 +5923,7 @@ static int SendTls13EncryptedExtensions(WOLFSSL* ssl)
 
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls) {
-        idx = Dtls13GetHeadersLength(encrypted_extensions);
+        idx = Dtls13GetHeadersLength(ssl, encrypted_extensions);
     }
     else
 #endif /* WOLFSSL_DTLS13 */
@@ -6081,7 +6091,7 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx,
     i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls)
-        i = Dtls13GetRlHeaderLength(1) + DTLS_HANDSHAKE_HEADER_SZ;
+        i = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ;
 #endif /* WOLFSSL_DTLS13 */
 
     reqSz = (word16)(OPAQUE8_LEN + reqCtxLen);
@@ -6810,7 +6820,7 @@ static int SendTls13Certificate(WOLFSSL* ssl)
 
 #ifdef WOLFSSL_DTLS13
         if (ssl->options.dtls) {
-            i = Dtls13GetRlHeaderLength(1);
+            i = Dtls13GetRlHeaderLength(ssl, 1);
             sendSz = (int)i;
         }
 #endif /* WOLFSSL_DTLS13 */
@@ -7051,7 +7061,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl)
 #ifdef WOLFSSL_DTLS13
     /* can be negative */
     if (ssl->options.dtls)
-        recordLayerHdrExtra = Dtls13GetRlHeaderLength(1) - RECORD_HEADER_SZ;
+        recordLayerHdrExtra = Dtls13GetRlHeaderLength(ssl, 1) - RECORD_HEADER_SZ;
     else
         recordLayerHdrExtra = 0;
 
@@ -8325,7 +8335,7 @@ static int SendTls13Finished(WOLFSSL* ssl)
 
 #ifdef WOLFSSL_DTLS13
     if (isDtls)
-        input = output + Dtls13GetRlHeaderLength(1);
+        input = output + Dtls13GetRlHeaderLength(ssl, 1);
 #endif /* WOLFSSL_DTLS13 */
 
     AddTls13HandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl);
@@ -8384,7 +8394,8 @@ static int SendTls13Finished(WOLFSSL* ssl)
 #ifdef WOLFSSL_DTLS13
     if (isDtls) {
         dtlsRet = Dtls13HandshakeSend(ssl, output, outputSz,
-            Dtls13GetRlHeaderLength(1) + headerSz + finishedSz, finished, 1);
+            Dtls13GetRlHeaderLength(ssl, 1) + headerSz + finishedSz, finished,
+            1);
         if (dtlsRet != 0 && dtlsRet != WANT_WRITE)
             return ret;
 
@@ -8562,7 +8573,7 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl)
 
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls)
-        i = Dtls13GetRlHeaderLength(1) + DTLS_HANDSHAKE_HEADER_SZ;
+        i = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ;
 #endif /* WOLFSSL_DTLS13 */
 
     outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA;
@@ -8577,7 +8588,7 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl)
 
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls)
-        input = output + Dtls13GetRlHeaderLength(1);
+        input = output + Dtls13GetRlHeaderLength(ssl, 1);
 #endif /* WOLFSSL_DTLS13 */
 
     AddTls13Headers(output, OPAQUE8_LEN, key_update, ssl);
@@ -8595,7 +8606,8 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl)
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls) {
         ret = Dtls13HandshakeSend(ssl, output, outputSz,
-            OPAQUE8_LEN + Dtls13GetRlHeaderLength(1) + DTLS_HANDSHAKE_HEADER_SZ,
+            OPAQUE8_LEN + Dtls13GetRlHeaderLength(ssl, 1) +
+                DTLS_HANDSHAKE_HEADER_SZ,
             key_update, 0);
     }
     else
@@ -9083,7 +9095,7 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl)
 
 #ifdef WOLFSSL_DTLS13
     if (ssl->options.dtls)
-        idx = Dtls13GetRlHeaderLength(1) + DTLS_HANDSHAKE_HEADER_SZ;
+        idx = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ;
 #endif /* WOLFSSL_DTLS13 */
 
 #ifdef WOLFSSL_TLS13_TICKET_BEFORE_FINISHED

+ 4 - 0
wolfssl.vcproj

@@ -159,6 +159,10 @@
 				RelativePath=".\src\dtls13.c"
 				>
 			</File>
+			<File
+				RelativePath=".\src\dtls.c"
+				>
+			</File>
 			<File
 				RelativePath=".\src\internal.c"
 				>

+ 1 - 0
wolfssl.vcxproj

@@ -278,6 +278,7 @@
   <ItemGroup>
     <ClCompile Include="src\crl.c" />
     <ClCompile Include="src\dtls13.c" />
+    <ClCompile Include="src\dtls.c" />
     <ClCompile Include="src\internal.c" />
     <ClCompile Include="src\wolfio.c" />
     <ClCompile Include="src\keys.c" />

+ 1 - 0
wolfssl/error-ssl.h

@@ -179,6 +179,7 @@ enum wolfSSL_ErrorCodes {
     QUIC_TP_MISSING_E            = -452,   /* QUIC transport parameter missing */
     DILITHIUM_KEY_SIZE_E         = -453,   /* Wrong key size for Dilithium. */
 
+    DTLS_CID_ERROR               = -454,   /* Wrong or missing CID */
     /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */
 
     /* begin negotiation parameter errors */

+ 48 - 4
wolfssl/internal.h

@@ -1239,6 +1239,22 @@ enum {
     #define ENCRYPT_BASE_BITS  4096
 #endif
 
+#ifdef WOLFSSL_DTLS_CID
+#ifndef DTLS_CID_MAX_SIZE
+/* DTLSv1.3 parsing code copies the record header in a static buffer to decrypt
+ * the record. Increasing the CID max size does increase also this buffer,
+ * impacting on per-session runtime memory footprint. */
+#define DTLS_CID_MAX_SIZE 2
+#endif
+#else
+#undef DTLS_CID_MAX_SIZE
+#define DTLS_CID_MAX_SIZE 0
+#endif /* WOLFSSL_DTLS_CID */
+
+#if DTLS_CID_MAX_SIZE > 255
+#error "Max size for DTLS CID is 255 bytes"
+#endif
+
 enum Misc {
     CIPHER_BYTE    = 0x00,         /* Default ciphers */
     ECC_BYTE       = 0xC0,         /* ECC first cipher suite byte */
@@ -1360,7 +1376,8 @@ enum Misc {
     DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */
     DTLS_RECORD_HEADER_SZ    = 13, /* normal + epoch(2) + seq_num(6) */
     DTLS_UNIFIED_HEADER_MIN_SZ = 2,
-    DTLS_RECVD_RL_HEADER_MAX_SZ = 5, /* flags + seq_number(2) + length(20)  */
+    /* flags + seq_number(2) + length(2) + CID */
+    DTLS_RECVD_RL_HEADER_MAX_SZ = 5 + DTLS_CID_MAX_SIZE,
     DTLS_RECORD_HEADER_MAX_SZ = 13,
     DTLS_HANDSHAKE_EXTRA     = 8,  /* diff from normal */
     DTLS_RECORD_EXTRA        = 8,  /* diff from normal */
@@ -2454,6 +2471,9 @@ typedef enum {
     TLSX_SIGNATURE_ALGORITHMS_CERT  = 0x0032,
     #endif
     TLSX_KEY_SHARE                  = 0x0033,
+    #if defined(WOLFSSL_DTLS_CID)
+    TLSX_CONNECTION_ID              = 0x0036,
+    #endif /* defined(WOLFSSL_DTLS_CID) */
     #ifdef WOLFSSL_QUIC
     TLSX_KEY_QUIC_TP_PARAMS         = 0x0039, /* RFC 9001, ch. 8.2 */
     #endif
@@ -2926,6 +2946,17 @@ enum KeyUpdateRequest {
 };
 #endif /* WOLFSSL_TLS13 */
 
+#ifdef WOLFSSL_DTLS_CID
+WOLFSSL_LOCAL void TLSX_ConnectionID_Free(byte* ext, void* heap);
+WOLFSSL_LOCAL word16 TLSX_ConnectionID_Write(byte* ext, byte* output);
+WOLFSSL_LOCAL word16 TLSX_ConnectionID_GetSize(byte* ext);
+WOLFSSL_LOCAL int TLSX_ConnectionID_Use(WOLFSSL* ssl);
+WOLFSSL_LOCAL int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input,
+    word16 length, byte isRequest);
+WOLFSSL_LOCAL void DtlsCIDOnExtensionsParsed(WOLFSSL* ssl);
+WOLFSSL_LOCAL byte DtlsCIDCheck(WOLFSSL* ssl, const byte* input,
+    word16 inputSize);
+#endif /* WOLFSSL_DTLS_CID */
 
 #ifdef OPENSSL_EXTRA
 enum SetCBIO {
@@ -4090,6 +4121,9 @@ typedef struct Options {
 #ifdef WOLFSSL_TLS13
     byte            oldMinor;          /* client preferred version < TLS 1.3 */
 #endif
+#ifdef WOLFSSL_DTLS_CID
+    byte            useDtlsCID:1;
+#endif /* WOLFSSL_DTLS_CID */
 } Options;
 
 typedef struct Arrays {
@@ -4623,6 +4657,10 @@ typedef struct Dtls13Rtx {
 
 #endif /* WOLFSSL_DTLS13 */
 
+#ifdef WOLFSSL_DTLS_CID
+typedef struct CIDInfo CIDInfo;
+#endif /* WOLFSSL_DTLS_CID */
+
 /* wolfSSL ssl type */
 struct WOLFSSL {
     WOLFSSL_CTX*    ctx;
@@ -4851,6 +4889,10 @@ struct WOLFSSL {
     word16 dtls13ClientHelloSz;
 
 #endif /* WOLFSSL_DTLS13 */
+#ifdef WOLFSSL_DTLS_CID
+    CIDInfo *dtlsCidInfo;
+#endif /* WOLFSSL_DTLS_CID */
+
 #endif /* WOLFSSL_DTLS */
 #ifdef WOLFSSL_CALLBACKS
     TimeoutInfo     timeoutInfo;        /* info saved during handshake */
@@ -5650,8 +5692,9 @@ WOLFSSL_LOCAL int Dtls13SetRecordNumberKeys(WOLFSSL* ssl,
 
 WOLFSSL_LOCAL int Dtls13AddHeaders(byte* output, word32 length,
     enum HandShakeType hs_type, WOLFSSL* ssl);
-WOLFSSL_LOCAL word16 Dtls13GetHeadersLength(enum HandShakeType type);
-WOLFSSL_LOCAL word16 Dtls13GetRlHeaderLength(byte is_encrypted);
+WOLFSSL_LOCAL word16 Dtls13GetHeadersLength(WOLFSSL *ssl,
+    enum HandShakeType type);
+WOLFSSL_LOCAL word16 Dtls13GetRlHeaderLength(WOLFSSL *ssl, byte is_encrypted);
 WOLFSSL_LOCAL int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out,
     word16 length);
 WOLFSSL_LOCAL int Dtls13RlAddPlaintextHeader(WOLFSSL* ssl, byte* out,
@@ -5659,7 +5702,8 @@ WOLFSSL_LOCAL int Dtls13RlAddPlaintextHeader(WOLFSSL* ssl, byte* out,
 WOLFSSL_LOCAL int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr,
     word16 recordLength);
 WOLFSSL_LOCAL int Dtls13IsUnifiedHeader(byte header_flags);
-WOLFSSL_LOCAL int Dtls13GetUnifiedHeaderSize(const byte input, word16* size);
+WOLFSSL_LOCAL int Dtls13GetUnifiedHeaderSize(WOLFSSL* ssl, const byte input,
+    word16* size);
 WOLFSSL_LOCAL int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input,
     word16 input_size, Dtls13UnifiedHdrInfo* hdrInfo);
 WOLFSSL_LOCAL int Dtls13HandshakeSend(WOLFSSL* ssl, byte* output,

+ 15 - 0
wolfssl/ssl.h

@@ -5108,6 +5108,21 @@ WOLFSSL_API int wolfSSL_CRYPTO_get_ex_new_index(int class_index, long argl, void
                                            WOLFSSL_CRYPTO_EX_free* free_func);
 #endif /* HAVE_EX_DATA || WOLFSSL_WPAS_SMALL */
 
+#if defined(WOLFSSL_DTLS_CID)
+WOLFSSL_API int wolfSSL_dtls_cid_use(WOLFSSL* ssl);
+WOLFSSL_API int wolfSSL_dtls_cid_is_enabled(WOLFSSL* ssl);
+WOLFSSL_API int wolfSSL_dtls_cid_set(WOLFSSL* ssl, unsigned char* cid,
+    unsigned int size);
+WOLFSSL_API int wolfSSL_dtls_cid_get_rx_size(WOLFSSL* ssl,
+    unsigned int* size);
+WOLFSSL_API int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buffer,
+    unsigned int bufferSz);
+WOLFSSL_API int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl,
+    unsigned int* size);
+WOLFSSL_API int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer,
+    unsigned int bufferSz);
+#endif /* defined(WOLFSSL_DTLS_CID) */
+
 /*  */
 #define SSL2_VERSION                     0x0002
 #define SSL3_VERSION                     0x0300

+ 4 - 0
wolfssl/wolfcrypt/settings.h

@@ -2775,6 +2775,10 @@ extern void uITRON4_free(void *p) ;
 #error "DTLS v1.3 requires both WOLFSSL_TLS13 and WOLFSSL_DTLS"
 #endif
 
+#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_DTLS13)
+#error "ConnectionID is supported for DTLSv1.3 only"
+#endif
+
 /* RSA Key Checking is disabled by default unless WOLFSSL_RSA_KEY_CHECK is
  *   defined or FIPS v2 3389, FIPS v5 or later.
  * Not allowed for: