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: