diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c815ed10..3937a6fab 100644
--- a/CMakeLists.txt
+++ b/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)"
diff --git a/IDE/WIN/wolfssl-fips.vcxproj b/IDE/WIN/wolfssl-fips.vcxproj
index 1de003294..614b1d1bb 100644
--- a/IDE/WIN/wolfssl-fips.vcxproj
+++ b/IDE/WIN/wolfssl-fips.vcxproj
@@ -309,6 +309,7 @@
+
diff --git a/IDE/WIN10/wolfssl-fips.vcxproj b/IDE/WIN10/wolfssl-fips.vcxproj
index 7f7f2adaa..bb19a5f4a 100644
--- a/IDE/WIN10/wolfssl-fips.vcxproj
+++ b/IDE/WIN10/wolfssl-fips.vcxproj
@@ -279,6 +279,7 @@
+
diff --git a/cmake/functions.cmake b/cmake/functions.cmake
index deb20819a..c2155bed0 100644
--- a/cmake/functions.cmake
+++ b/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()
diff --git a/configure.ac b/configure.ac
index 111ed9a7d..2e0cbf679 100644
--- a/configure.ac
+++ b/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" ||
diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h
index 6650d7817..1cba16f15 100644
--- a/doc/dox_comments/header_files/ssl.h
+++ b/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);
diff --git a/src/dtls.c b/src/dtls.c
new file mode 100644
index 000000000..970cb4119
--- /dev/null
+++ b/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
+#endif
+
+#include
+
+#if defined(WOLFSSL_DTLS_CID)
+
+#include
+#include
+#include
+
+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 */
diff --git a/src/dtls13.c b/src/dtls13.c
index cf45b8ae4..1b248b466 100644
--- a/src/dtls13.c
+++ b/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);
diff --git a/src/include.am b/src/include.am
index 81e2b88ab..40903938a 100644
--- a/src/include.am
+++ b/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
diff --git a/src/internal.c b/src/internal.c
index 26ed41f84..756ea75d8 100644
--- a/src/internal.c
+++ b/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;
diff --git a/src/tls.c b/src/tls.c
index edf0493e6..bc3ad363f 100644
--- a/src/tls.c
+++ b/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");
}
diff --git a/src/tls13.c b/src/tls13.c
index 4e3b64296..b4f3305c1 100644
--- a/src/tls13.c
+++ b/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
diff --git a/wolfssl.vcproj b/wolfssl.vcproj
index c49dfed8b..7aa2def99 100644
--- a/wolfssl.vcproj
+++ b/wolfssl.vcproj
@@ -159,6 +159,10 @@
RelativePath=".\src\dtls13.c"
>
+
+
diff --git a/wolfssl.vcxproj b/wolfssl.vcxproj
index bebef5489..442710d8f 100644
--- a/wolfssl.vcxproj
+++ b/wolfssl.vcxproj
@@ -278,6 +278,7 @@
+
diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h
index 1e0bbb021..319037966 100644
--- a/wolfssl/error-ssl.h
+++ b/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 */
diff --git a/wolfssl/internal.h b/wolfssl/internal.h
index 2ceb2aa69..7c917e843 100644
--- a/wolfssl/internal.h
+++ b/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,
diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h
index d59ca0852..2601feb86 100644
--- a/wolfssl/ssl.h
+++ b/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
diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h
index d17e3710b..b79f27021 100644
--- a/wolfssl/wolfcrypt/settings.h
+++ b/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: