From 86376db6a6a2b16678b83491340516ac73dcbc28 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 30 Oct 2024 16:11:00 +0100 Subject: [PATCH] DTLS: Add server side stateless and CID QoL API - wolfDTLS_accept_stateless - statelessly listen for incoming connections - wolfSSL_inject - insert data into WOLFSSL object - wolfSSL_SSL(Enable|Disable)Read - enable/disable reading from IO - wolfSSL_get_wfd - get the write side file descriptor - wolfSSL_dtls_set_pending_peer - set the pending peer that will be upgraded to regular peer when we successfully de-protect a DTLS record - wolfSSL_dtls_get0_peer - zero copy access to the peer address - wolfSSL_is_stateful - boolean to check if we have entered stateful processing - wolfSSL_dtls_cid_get0_rx - zero copy access to the rx cid - wolfSSL_dtls_cid_get0_tx - zero copy access to the tx cid - wolfSSL_dtls_cid_parse - extract cid from a datagram/message --- doc/dox_comments/header_files/ssl.h | 245 ++++++++++++++++++++++++- doc/dox_comments/header_files/wolfio.h | 43 +++++ src/dtls.c | 60 ++++++ src/dtls13.c | 5 + src/internal.c | 73 ++++++-- src/ssl.c | 243 +++++++++++++++++++++--- src/wolfio.c | 14 ++ tests/api.c | 191 +++++++++++++++++-- wolfssl/internal.h | 10 + wolfssl/ssl.h | 19 +- wolfssl/wolfio.h | 2 + 11 files changed, 853 insertions(+), 52 deletions(-) diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 04407dfd9f..4d816fc936 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -1997,8 +1997,8 @@ const char* wolfSSL_get_cipher_name(WOLFSSL* ssl); /*! \ingroup IO - \brief This function returns the file descriptor (fd) used as the - input/output facility for the SSL connection. Typically this + \brief This function returns the read file descriptor (fd) used as the + input facility for the SSL connection. Typically this will be a socket file descriptor. \return fd If successful the call will return the SSL session file @@ -2016,9 +2016,38 @@ const char* wolfSSL_get_cipher_name(WOLFSSL* ssl); \endcode \sa wolfSSL_set_fd + \sa wolfSSL_set_read_fd + \sa wolfSSL_set_write_fd */ int wolfSSL_get_fd(const WOLFSSL*); +/*! + \ingroup IO + + \brief This function returns the write file descriptor (fd) used as the + output facility for the SSL connection. Typically this + will be a socket file descriptor. + + \return fd If successful the call will return the SSL session file + descriptor. + + \param ssl pointer to the SSL session, created with wolfSSL_new(). + + _Example_ + \code + int sockfd; + WOLFSSL* ssl = 0; + ... + sockfd = wolfSSL_get_wfd(ssl); + ... + \endcode + + \sa wolfSSL_set_fd + \sa wolfSSL_set_read_fd + \sa wolfSSL_set_write_fd +*/ +int wolfSSL_get_wfd(const WOLFSSL*); + /*! \ingroup Setup @@ -2289,6 +2318,48 @@ int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz); */ int wolfSSL_accept(WOLFSSL*); +/*! + \ingroup IO + + \brief This function is called on the server side and statelessly listens + for an SSL client to initiate the DTLS handshake. + + \return WOLFSSL_SUCCESS ClientHello containing a valid cookie was received. + The connection can be continued with wolfSSL_accept(). + \return WOLFSSL_FAILURE The I/O layer returned WANT_READ. This is either + because there is no data to read and we are using non-blocking sockets or + we sent a cookie request and we are waiting for a reply. The user should + call wolfDTLS_accept_stateless again after data becomes available in + the I/O layer. + \return WOLFSSL_FATAL_ERROR A fatal error occurred. The ssl object should be + free'd and allocated again to continue. + + \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + + _Example_ + \code + int ret = 0; + int err = 0; + WOLFSSL* ssl; + ... + do { + ret = wolfDTLS_accept_stateless(ssl); + if (ret == WOLFSSL_FATAL_ERROR) + // re-allocate the ssl object with wolfSSL_free() and wolfSSL_new() + } while (ret != WOLFSSL_SUCCESS); + ret = wolfSSL_accept(ssl); + if (ret != SSL_SUCCESS) { + err = wolfSSL_get_error(ssl, ret); + printf(“error = %d, %s\n”, err, wolfSSL_ERR_error_string(err, buffer)); + } + \endcode + + \sa wolfSSL_accept + \sa wolfSSL_get_error + \sa wolfSSL_connect +*/ +int wolfDTLS_accept_stateless(WOLFSSL* ssl); + /*! \ingroup Setup @@ -3856,12 +3927,52 @@ int wolfSSL_dtls(WOLFSSL* ssl); \endcode \sa wolfSSL_dtls_get_current_timeout + \sa wolfSSL_dtls_set_pending_peer \sa wolfSSL_dtls_get_peer \sa wolfSSL_dtls_got_timeout \sa wolfSSL_dtls */ int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz); +/*! + \brief This function sets the pending DTLS peer, peer (sockaddr_in) with + size of peerSz. This sets the pending peer that will be upgraded to a + regular peer when we successfully de-protect the next record. This is useful + in scenarios where the peer's address can change to avoid off-path attackers + from changing the peer address. This should be used with Connection ID's to + allow seamless and safe transition to a new peer address. + + \return SSL_SUCCESS will be returned upon success. + \return SSL_FAILURE will be returned upon failure. + \return SSL_NOT_IMPLEMENTED will be returned if wolfSSL was not compiled + with DTLS support. + + \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + \param peer pointer to peer’s sockaddr_in structure. If NULL then the peer + information in ssl is cleared. + \param peerSz size of the sockaddr_in structure pointed to by peer. If 0 + then the peer information in ssl is cleared. + + _Example_ + \code + int ret = 0; + WOLFSSL* ssl; + sockaddr_in addr; + ... + ret = wolfSSL_dtls_set_pending_peer(ssl, &addr, sizeof(addr)); + if (ret != SSL_SUCCESS) { + // failed to set DTLS peer + } + \endcode + + \sa wolfSSL_dtls_get_current_timeout + \sa wolfSSL_dtls_set_peer + \sa wolfSSL_dtls_get_peer + \sa wolfSSL_dtls_got_timeout + \sa wolfSSL_dtls +*/ +int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz); + /*! \brief This function gets the sockaddr_in (of size peerSz) of the current DTLS peer. The function will compare peerSz to the actual DTLS peer size @@ -3899,6 +4010,40 @@ int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz); */ int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz); +/*! + \brief This function gets the sockaddr_in (of size peerSz) of the current + DTLS peer. This is a zero-copy alternative to wolfSSL_dtls_get_peer(). + + \return SSL_SUCCESS will be returned upon success. + \return SSL_FAILURE will be returned upon failure. + \return SSL_NOT_IMPLEMENTED will be returned if wolfSSL was not compiled + with DTLS support. + + \param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + \param peer pointer to return the internal buffer holding the peer address + \param peerSz output the size of the actual sockaddr_in structure + pointed to by peer. + + _Example_ + \code + int ret = 0; + WOLFSSL* ssl; + sockaddr_in* addr; + unsigned int addrSz; + ... + ret = wolfSSL_dtls_get_peer(ssl, &addr, &addrSz); + if (ret != SSL_SUCCESS) { + // failed to get DTLS peer + } + \endcode + + \sa wolfSSL_dtls_get_current_timeout + \sa wolfSSL_dtls_got_timeout + \sa wolfSSL_dtls_set_peer + \sa wolfSSL_dtls +*/ +int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, unsigned int* peerSz); + /*! \ingroup Debug @@ -14138,6 +14283,35 @@ int wolfSSL_write_early_data(WOLFSSL* ssl, const void* data, int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz); +/*! + \ingroup IO + + \brief + + \param [in] ssl a pointer to a WOLFSSL structure, created using wolfSSL_new(). + \param [in] data data to inject into the ssl object. + \param [in] sz number of bytes of data to inject. + + \return BAD_FUNC_ARG if any pointer parameter is NULL or sz <= 0 + \return APP_DATA_READY if there is application data left to read + \return MEMORY_E if allocation fails + \return WOLFSSL_SUCCESS on success + + _Example_ + \code + byte buf[2000] + sz = recv(fd, buf, sizeof(buf), 0); + if (sz <= 0) + // error + if (wolfSSL_inject(ssl, buf, sz) != WOLFSSL_SUCCESS) + // error + sz = wolfSSL_read(ssl, buf, sizeof(buf); + \endcode + + \sa wolfSSL_read +*/ +int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz); + /*! \ingroup Setup @@ -14955,6 +15129,7 @@ connection into the buffer pointed by the parameter buffer. See RFC 9146 and RFC \param buffer A buffer where the ConnectionID will be copied \param bufferSz available space in buffer + \sa wolfSSL_dtls_cid_get0_rx \sa wolfSSL_dtls_cid_use \sa wolfSSL_dtls_cid_is_enabled \sa wolfSSL_dtls_cid_set @@ -14967,6 +15142,27 @@ int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buffer, /*! +\brief Get the ConnectionID used by the other peer. See RFC 9146 and RFC +9147. + + \return WOLFSSL_SUCCESS if ConnectionID was correctly copied, error code + otherwise + + \param ssl A WOLFSSL object pointern + \param cid Pointer that will be set to the internal memory that holds the CID + + \sa wolfSSL_dtls_cid_get_rx + \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_get0_rx(WOLFSSL* ssl, unsigned char** cid); + +/*! + \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. @@ -14998,6 +15194,7 @@ available size need to be provided in bufferSz. \param buffer A buffer where the ConnectionID will be copied \param bufferSz available space in buffer + \sa wolfSSL_dtls_cid_get0_tx \sa wolfSSL_dtls_cid_use \sa wolfSSL_dtls_cid_is_enabled \sa wolfSSL_dtls_cid_set @@ -15008,6 +15205,50 @@ available size need to be provided in bufferSz. int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer, unsigned int bufferSz); +/*! + +\brief Get the ConnectionID used when sending records in this connection. See +RFC 9146 and RFC 9147. + + \return WOLFSSL_SUCCESS if ConnectionID was correctly retrieved, error code + otherwise + + \param ssl A WOLFSSL object pointern + \param cid Pointer that will be set to the internal memory that holds the CID + + \sa wolfSSL_dtls_cid_get_tx + \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_get0_tx(WOLFSSL* ssl, unsigned char** cid); + +/*! + +\brief Extract the ConnectionID from a record datagram/message. See +RFC 9146 and RFC 9147. + + \param msg buffer holding the datagram read from the network + \param msgSz size of msg in bytes + \param cid pointer to the start of the CID inside the msg buffer + \param cidSz the expected size of the CID. The record layer does not have a CID + size field so we have to know beforehand the size of the CID. It is recommended + to use a constant CID for all connections. + + \sa wolfSSL_dtls_cid_get_tx + \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 +*/ +void wolfSSL_dtls_cid_parse(const unsigned char* msg, unsigned int msgSz, + const unsigned char** cid, unsigned int cidSz); + /*! \ingroup TLS diff --git a/doc/dox_comments/header_files/wolfio.h b/doc/dox_comments/header_files/wolfio.h index 5e52e3573b..673242aaf7 100644 --- a/doc/dox_comments/header_files/wolfio.h +++ b/doc/dox_comments/header_files/wolfio.h @@ -575,3 +575,46 @@ int wolfSSL_SetIO_ISOTP(WOLFSSL *ssl, isotp_wolfssl_ctx *ctx, can_recv_fn recv_fn, can_send_fn send_fn, can_delay_fn delay_fn, word32 receive_delay, char *receive_buffer, int receive_buffer_size, void *arg); + +/*! + \ingroup Setup + + \brief This function disables reading from the IO layer. + + \param ssl the wolfSSL context + + _Example_ + \code + WOLFSSL_CTX* ctx = wolfSSL_CTX_new(method); + WOLFSSL* ssl = wolfSSL_new(ctx); + wolfSSL_SSLDisableRead(ssl); + \endcode + + \sa wolfSSL_CTX_SetIORecv + \sa wolfSSL_SSLSetIORecv + \sa wolfSSL_SSLEnableRead + */ +void wolfSSL_SSLDisableRead(WOLFSSL *ssl); + +/*! + \ingroup Setup + + \brief This function enables reading from the IO layer. Reading is enabled + by default and should be used to undo wolfSSL_SSLDisableRead(); + + \param ssl the wolfSSL context + + _Example_ + \code + WOLFSSL_CTX* ctx = wolfSSL_CTX_new(method); + WOLFSSL* ssl = wolfSSL_new(ctx); + wolfSSL_SSLDisableRead(ssl); + ... + wolfSSL_SSLEnableRead(ssl); + \endcode + + \sa wolfSSL_CTX_SetIORecv + \sa wolfSSL_SSLSetIORecv + \sa wolfSSL_SSLEnableRead + */ +void wolfSSL_SSLEnableRead(WOLFSSL *ssl); diff --git a/src/dtls.c b/src/dtls.c index 5b2356a922..edbf835d5c 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -1103,6 +1103,26 @@ static int DtlsCidGet(WOLFSSL* ssl, unsigned char* buf, int bufferSz, int rx) return WOLFSSL_SUCCESS; } +static int DtlsCidGet0(WOLFSSL* ssl, unsigned char** cid, int rx) +{ + ConnectionID* id; + CIDInfo* info; + + if (ssl == NULL || cid == 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; + + *cid = id->id; + return WOLFSSL_SUCCESS; +} + static CIDInfo* DtlsCidGetInfoFromExt(byte* ext) { WOLFSSL** sslPtr; @@ -1361,6 +1381,11 @@ int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buf, return DtlsCidGet(ssl, buf, bufferSz, 1); } +int wolfSSL_dtls_cid_get0_rx(WOLFSSL* ssl, unsigned char** cid) +{ + return DtlsCidGet0(ssl, cid, 1); +} + int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl, unsigned int* size) { return DtlsCidGetSize(ssl, size, 0); @@ -1372,10 +1397,40 @@ int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buf, return DtlsCidGet(ssl, buf, bufferSz, 0); } +int wolfSSL_dtls_cid_get0_tx(WOLFSSL* ssl, unsigned char** cid) +{ + return DtlsCidGet0(ssl, cid, 0); +} + int wolfSSL_dtls_cid_max_size(void) { return DTLS_CID_MAX_SIZE; } + +void wolfSSL_dtls_cid_parse(const unsigned char* msg, unsigned int msgSz, + const unsigned char** cid, unsigned int cidSz) +{ + if (cid == NULL) + return; + *cid = NULL; + /* we need at least the first byte to check version */ + if (msg == NULL || cidSz == 0 || msgSz < OPAQUE8_LEN + cidSz) + return; + if (msg[0] == dtls12_cid) { + /* DTLS 1.2 CID packet */ + if (msgSz < DTLS_RECORD_HEADER_SZ + cidSz) + return; + /* content type(1) + version(2) + epoch(2) + sequence(6) */ + *cid = msg + ENUM_LEN + VERSION_SZ + OPAQUE16_LEN + OPAQUE16_LEN + + OPAQUE32_LEN; + } + else if (Dtls13UnifiedHeaderCIDPresent(msg[0])) { + /* DTLS 1.3 CID packet */ + if (msgSz < OPAQUE8_LEN + cidSz) + return; + *cid = msg + OPAQUE8_LEN; + } +} #endif /* WOLFSSL_DTLS_CID */ byte DtlsGetCidTxSize(WOLFSSL* ssl) @@ -1408,6 +1463,11 @@ byte DtlsGetCidRxSize(WOLFSSL* ssl) #endif } +byte wolfSSL_is_stateful(WOLFSSL* ssl) +{ + return ssl != NULL ? ssl->options.dtlsStateful : 0; +} + #endif /* WOLFSSL_DTLS */ #endif /* WOLFCRYPT_ONLY */ diff --git a/src/dtls13.c b/src/dtls13.c index 5011f7d85b..161ce4f4c5 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -1151,6 +1151,11 @@ static int Dtls13UnifiedHeaderParseCID(WOLFSSL* ssl, byte flags, return 0; } +int Dtls13UnifiedHeaderCIDPresent(byte flags) +{ + return Dtls13IsUnifiedHeader(flags) && (flags & DTLS13_CID_BIT); +} + #else #define Dtls13AddCID(a, b, c, d) 0 #define Dtls13UnifiedHeaderParseCID(a, b, c, d, e) 0 diff --git a/src/internal.c b/src/internal.c index 462e3c7244..c58717a748 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8263,6 +8263,11 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl) } XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); ssl->buffers.dtlsCtx.peer.sa = NULL; +#ifdef WOLFSSL_DTLS_CID + XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; +#endif #ifndef NO_WOLFSSL_SERVER if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { ForceZero(ssl->buffers.dtlsCookieSecret.buffer, @@ -11520,15 +11525,15 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx, #ifdef WOLFSSL_DTLS_CID if (rh->type == dtls12_cid) { - byte cid[DTLS_CID_MAX_SIZE]; + byte* ourCid = NULL; if (ssl->buffers.inputBuffer.length - *inOutIdx < (word32)cidSz + LENGTH_SZ) return LENGTH_ERROR; - if (cidSz > DTLS_CID_MAX_SIZE || - wolfSSL_dtls_cid_get_rx(ssl, cid, cidSz) != WOLFSSL_SUCCESS) + if (cidSz != DtlsGetCidRxSize(ssl) || + wolfSSL_dtls_cid_get0_rx(ssl, &ourCid) != WOLFSSL_SUCCESS) return DTLS_CID_ERROR; - if (XMEMCMP(ssl->buffers.inputBuffer.buffer + *inOutIdx, - cid, cidSz) != 0) + if (XMEMCMP(ssl->buffers.inputBuffer.buffer + *inOutIdx, ourCid, cidSz) + != 0) return DTLS_CID_ERROR; *inOutIdx += cidSz; } @@ -21043,11 +21048,14 @@ static int GetInputData(WOLFSSL *ssl, word32 size) int usedLength; int dtlsExtra = 0; + if (ssl->options.disableRead) + return WC_NO_ERR_TRACE(WANT_READ); /* check max input length */ - usedLength = (int)(ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx); - maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - (word32)usedLength); - inSz = (int)(size - (word32)usedLength); /* from last partial read */ + usedLength = (int)(ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx); + maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - + (word32)usedLength); #ifdef WOLFSSL_DTLS if (ssl->options.dtls && IsDtlsNotSctpMode(ssl)) { @@ -21064,10 +21072,17 @@ static int GetInputData(WOLFSSL *ssl, word32 size) #endif /* check that no lengths or size values are negative */ - if (usedLength < 0 || maxLength < 0 || inSz <= 0) { + if (usedLength < 0 || maxLength < 0) { return BUFFER_ERROR; } + /* Return if we have enough data already in the buffer */ + if (size <= (word32)usedLength) { + return 0; + } + + inSz = (int)(size - (word32)usedLength); /* from last partial read */ + if (inSz > maxLength) { if (GrowInputBuffer(ssl, (int)(size + (word32)dtlsExtra), usedLength) < 0) return MEMORY_E; @@ -21539,6 +21554,23 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) &ssl->curRL, &ssl->curSize); #ifdef WOLFSSL_DTLS +#ifdef WOLFSSL_DTLS_CID + if (ssl->options.dtls) { + if (!ssl->buffers.dtlsCtx.processingPendingRecord) + ssl->buffers.dtlsCtx.processingPendingRecord = 1; + else { + ssl->buffers.dtlsCtx.processingPendingRecord = 0; + if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { + /* Clear the pending peer */ + XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; + ssl->buffers.dtlsCtx.pendingPeer.sz = 0; + ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; + } + } + } +#endif if (ssl->options.dtls && DtlsShouldDrop(ssl, ret)) { ssl->options.processReply = doProcessInit; ssl->buffers.inputBuffer.length = 0; @@ -21963,8 +21995,9 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) /* the record layer is here */ case runProcessingOneRecord: -#ifdef WOLFSSL_DTLS13 +#ifdef WOLFSSL_DTLS if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS13 if (IsAtLeastTLSv1_3(ssl->version)) { if (!Dtls13CheckWindow(ssl)) { /* drop packet */ @@ -21988,11 +22021,27 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) } } } - else if (IsDtlsNotSctpMode(ssl)) { + else +#endif /* WOLFSSL_DTLS13 */ + if (IsDtlsNotSctpMode(ssl)) { DtlsUpdateWindow(ssl); } +#ifdef WOLFSSL_DTLS_CID + /* Update the peer if we were able to de-protect the message */ + if (IsEncryptionOn(ssl, 0) && + ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { + XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.peer = + ssl->buffers.dtlsCtx.pendingPeer; + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; + ssl->buffers.dtlsCtx.pendingPeer.sz = 0; + ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; + ssl->buffers.dtlsCtx.processingPendingRecord = 0; + } +#endif } -#endif /* WOLFSSL_DTLS13 */ +#endif /* WOLFSSL_DTLS */ ssl->options.processReply = runProcessingOneMessage; FALL_THROUGH; diff --git a/src/ssl.c b/src/ssl.c index fd10e5e5b7..fefbb61ddd 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1723,6 +1723,17 @@ int wolfSSL_get_fd(const WOLFSSL* ssl) return fd; } +int wolfSSL_get_wfd(const WOLFSSL* ssl) +{ + int fd = -1; + WOLFSSL_ENTER("wolfSSL_get_fd"); + if (ssl) { + fd = ssl->wfd; + } + WOLFSSL_LEAVE("wolfSSL_get_fd", fd); + return fd; +} + int wolfSSL_dtls(WOLFSSL* ssl) { @@ -1855,38 +1866,89 @@ int wolfSSL_dtls_free_peer(void* addr) } #endif +#ifdef WOLFSSL_DTLS +static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, + unsigned int peerSz, void* heap) +{ + if (peer == NULL || peerSz == 0) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = NULL; + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_SUCCESS; + } + + if (peerSz > sockAddr->bufSz) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = + (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); + if (sockAddr->sa == NULL) { + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_FAILURE; + } + sockAddr->bufSz = peerSz; + } + XMEMCPY(sockAddr->sa, peer, peerSz); + sockAddr->sz = peerSz; + return WOLFSSL_SUCCESS; +} +#endif + int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) { #ifdef WOLFSSL_DTLS - void* sa; + int ret; if (ssl == NULL) return WOLFSSL_FAILURE; - if (peer == NULL || peerSz == 0) { - if (ssl->buffers.dtlsCtx.peer.sa != NULL) - XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR); - ssl->buffers.dtlsCtx.peer.sa = NULL; - ssl->buffers.dtlsCtx.peer.sz = 0; - ssl->buffers.dtlsCtx.peer.bufSz = 0; + ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); + if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) + ssl->buffers.dtlsCtx.userSet = 1; + else ssl->buffers.dtlsCtx.userSet = 0; - return WOLFSSL_SUCCESS; - } + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + +#ifdef WOLFSSL_DTLS_CID +int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret = WOLFSSL_FAILURE; - sa = (void*)XMALLOC(peerSz, ssl->heap, DYNAMIC_TYPE_SOCKADDR); - if (sa != NULL) { - if (ssl->buffers.dtlsCtx.peer.sa != NULL) { - XFREE(ssl->buffers.dtlsCtx.peer.sa,ssl->heap,DYNAMIC_TYPE_SOCKADDR); - ssl->buffers.dtlsCtx.peer.sa = NULL; + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (ssl->buffers.dtlsCtx.peer.sa != NULL && + ssl->buffers.dtlsCtx.peer.sz == peerSz && + XMEMCMP(ssl->buffers.dtlsCtx.peer.sa, peer, peerSz) == 0) { + /* Already the current peer. */ + if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { + /* Clear any other pendingPeer */ + XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; + ssl->buffers.dtlsCtx.pendingPeer.sz = 0; + ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; } - XMEMCPY(sa, peer, peerSz); - ssl->buffers.dtlsCtx.peer.sa = sa; - ssl->buffers.dtlsCtx.peer.sz = peerSz; - ssl->buffers.dtlsCtx.peer.bufSz = peerSz; - ssl->buffers.dtlsCtx.userSet = 1; - return WOLFSSL_SUCCESS; + ret = WOLFSSL_SUCCESS; } - return WOLFSSL_FAILURE; + else { + ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, + ssl->heap); + } + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.processingPendingRecord = 0; + return ret; #else (void)ssl; (void)peer; @@ -1894,6 +1956,7 @@ int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) return WOLFSSL_NOT_IMPLEMENTED; #endif } +#endif int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) { @@ -1918,6 +1981,27 @@ int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) #endif } +int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, + unsigned int* peerSz) +{ +#ifdef WOLFSSL_DTLS + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (peer == NULL || peerSz == NULL) + return WOLFSSL_FAILURE; + + *peer = ssl->buffers.dtlsCtx.peer.sa; + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + return WOLFSSL_SUCCESS; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) @@ -2874,6 +2958,42 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) return ret; } +int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) +{ + int maxLength; + int usedLength; + + WOLFSSL_ENTER("wolfSSL_read_internal"); + + if (ssl == NULL || data == NULL || sz <= 0) + return BAD_FUNC_ARG; + + usedLength = (int)(ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx); + maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - + (word32)usedLength); + + if (sz > maxLength) { + /* Need to make space */ + int ret; + if (ssl->buffers.clearOutputBuffer.length > 0) { + /* clearOutputBuffer points into so reallocating inputBuffer will + * invalidate clearOutputBuffer and lose app data */ + WOLFSSL_MSG("Can't inject while there is application data to read"); + return APP_DATA_READY; + } + ret = GrowInputBuffer(ssl, sz, usedLength); + if (ret < 0) + return ret; + } + + XMEMCPY(ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + data, sz); + ssl->buffers.inputBuffer.length += sz; + + return WOLFSSL_SUCCESS; +} + static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) { int ret; @@ -2999,7 +3119,6 @@ int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) #endif /* WOLFSSL_MULTICAST */ - /* helpers to set the device id, WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) @@ -9202,7 +9321,13 @@ int wolfSSL_dtls_retransmit(WOLFSSL* ssl) return WOLFSSL_FATAL_ERROR; if (!ssl->options.handShakeDone) { - int result = DtlsMsgPoolSend(ssl, 0); + int result; +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + result = Dtls13DoScheduledWork(ssl); + else +#endif + result = DtlsMsgPoolSend(ssl, 0); if (result < 0) { ssl->error = result; WOLFSSL_ERROR(result); @@ -9210,7 +9335,7 @@ int wolfSSL_dtls_retransmit(WOLFSSL* ssl) } } - return 0; + return WOLFSSL_SUCCESS; } #endif /* DTLS */ @@ -10377,6 +10502,76 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, #endif /* NO_WOLFSSL_SERVER */ #if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) +struct chGoodDisableReadCbCtx { + ClientHelloGoodCb userCb; + void* userCtx; +}; + +static int chGoodDisableReadCB(WOLFSSL* ssl, void* ctx) +{ + struct chGoodDisableReadCbCtx* cb = (struct chGoodDisableReadCbCtx*)ctx; + int ret = 0; + if (cb->userCb != NULL) + ret = cb->userCb(ssl, cb->userCtx); + if (ret >= 0) + wolfSSL_SSLDisableRead(ssl); + return ret; +} + +/** + * Statelessly listen for a connection + * @param ssl The ssl object to use for listening to connections + * @return WOLFSSL_SUCCESS - ClientHello containing a valid cookie was received + * The connection can be continued with wolfSSL_accept + * WOLFSSL_FAILURE - The I/O layer returned WANT_READ. This is either + * because there is no data to read and we are using + * non-blocking sockets or we sent a cookie request + * and we are waiting for a reply. The user should + * call wolfDTLS_accept_stateless again after data + * becomes available in the I/O layer. + * WOLFSSL_FATAL_ERROR - A fatal error occurred. The ssl object should + * be free'd and allocated again to continue. + */ +int wolfDTLS_accept_stateless(WOLFSSL* ssl) +{ + byte disableRead; + int ret = WOLFSSL_FATAL_ERROR; + struct chGoodDisableReadCbCtx cb; + + WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + /* Save this to restore it later */ + disableRead = ssl->options.disableRead; + cb.userCb = ssl->chGoodCb; + cb.userCtx = ssl->chGoodCtx; + + /* Register our own callback so that we can disable reading */ + if (wolfDTLS_SetChGoodCb(ssl, chGoodDisableReadCB, &cb) != WOLFSSL_SUCCESS) + return WOLFSSL_FATAL_ERROR; + + ret = wolfSSL_accept(ssl); + /* restore user options */ + ssl->options.disableRead = disableRead; + (void)wolfDTLS_SetChGoodCb(ssl, cb.userCb, cb.userCtx); + if (ret == WOLFSSL_SUCCESS) { + WOLFSSL_MSG("should not happen. maybe the user called " + "wolfDTLS_accept_stateless instead of wolfSSL_accept"); + } + else if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) { + if (ssl->options.dtlsStateful) + ret = WOLFSSL_SUCCESS; + else + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_FATAL_ERROR; + } + return ret; +} + int wolfDTLS_SetChGoodCb(WOLFSSL* ssl, ClientHelloGoodCb cb, void* user_ctx) { WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); diff --git a/src/wolfio.c b/src/wolfio.c index 8d0b2f089b..3aed642675 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -2351,6 +2351,20 @@ void wolfSSL_SSLSetIOSend(WOLFSSL *ssl, CallbackIOSend CBIOSend) } } +void wolfSSL_SSLDisableRead(WOLFSSL *ssl) +{ + if (ssl) { + ssl->options.disableRead = 1; + } +} + +void wolfSSL_SSLEnableRead(WOLFSSL *ssl) +{ + if (ssl) { + ssl->options.disableRead = 0; + } +} + void wolfSSL_SetIOReadCtx(WOLFSSL* ssl, void *rctx) { diff --git a/tests/api.c b/tests/api.c index e7b64124a6..18179becc5 100644 --- a/tests/api.c +++ b/tests/api.c @@ -90204,7 +90204,7 @@ static void test_wolfSSL_dtls_plaintext_server(WOLFSSL* ssl) static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl) { byte ch[50]; - int fd = wolfSSL_get_fd(ssl); + int fd = wolfSSL_get_wfd(ssl); byte msg[] = "This is a msg for the server"; byte reply[40]; @@ -90274,7 +90274,7 @@ static void test_wolfSSL_dtls12_fragments_spammer(WOLFSSL* ssl) size_t seq_offset = 0; size_t msg_offset = 0; int i; - int fd = wolfSSL_get_fd(ssl); + int fd = wolfSSL_get_wfd(ssl); int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ word32 seq_number = 100; /* start high so server definitely reads this */ word16 msg_number = 50; /* start high so server has to buffer this */ @@ -90336,7 +90336,7 @@ static void test_wolfSSL_dtls13_fragments_spammer(WOLFSSL* ssl) byte b[150]; /* buffer for the messages to send */ size_t idx = 0; size_t msg_offset = 0; - int fd = wolfSSL_get_fd(ssl); + int fd = wolfSSL_get_wfd(ssl); word16 msg_number = 10; /* start high so server has to buffer this */ int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ AssertIntEQ(ret, 1); @@ -90441,7 +90441,7 @@ static void test_wolfSSL_dtls_send_alert(WOLFSSL* ssl) 0x46 /* protocol version */ }; - fd = wolfSSL_get_fd(ssl); + fd = wolfSSL_get_wfd(ssl); ret = (int)send(fd, alert_msg, sizeof(alert_msg), 0); AssertIntGT(ret, 0); } @@ -90511,7 +90511,7 @@ static void test_wolfSSL_send_bad_record(WOLFSSL* ssl) 0x03, 0x18, 0x72 }; - fd = wolfSSL_get_fd(ssl); + fd = wolfSSL_get_wfd(ssl); AssertIntGE(fd, 0); ret = (int)send(fd, bad_msg, sizeof(bad_msg), 0); AssertIntEQ(ret, sizeof(bad_msg)); @@ -90838,7 +90838,7 @@ static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl) 0x31, 0x68, 0x4c }; - fd = wolfSSL_get_fd(ssl); + fd = wolfSSL_get_wfd(ssl); ret = (int)send(fd, ch_msg, sizeof(ch_msg), 0); AssertIntGT(ret, 0); /* consume the HRR otherwise handshake will fail */ @@ -90909,7 +90909,7 @@ static void test_wolfSSL_dtls_send_ch_with_invalid_cookie(WOLFSSL* ssl) 0x02, 0x02, 0x2f }; - fd = wolfSSL_get_fd(ssl); + fd = wolfSSL_get_wfd(ssl); ret = (int)send(fd, ch_msh_invalid_cookie, sizeof(ch_msh_invalid_cookie), 0); AssertIntGT(ret, 0); /* should reply with an illegal_parameter reply */ @@ -93822,18 +93822,31 @@ static int test_wolfSSL_dtls_stateless2(void) XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c)); - wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL, + wolfDTLSv1_2_client_method, NULL), 0); + ExpectFalse(wolfSSL_is_stateful(ssl_s)); /* send CH */ ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE); + ExpectFalse(wolfSSL_is_stateful(ssl_s)); ExpectIntNE(test_ctx.c_len, 0); /* consume HRR */ test_ctx.c_len = 0; + /* send CH1 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + /* send HRR */ + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE); + /* send CH2 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + /* send HRR */ + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS); ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectTrue(wolfSSL_is_stateful(ssl_s)); wolfSSL_free(ssl_c2); wolfSSL_free(ssl_c); @@ -100094,6 +100107,157 @@ static int test_ocsp_callback_fails(void) defined(HAVE_OCSP) && \ defined(HAVE_CERTIFICATE_STATUS_REQUEST) */ +#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES +static int test_wolfSSL_SSLDisableRead_recv(WOLFSSL *ssl, char *buf, int sz, + void *ctx) +{ + (void)ssl; + (void)buf; + (void)sz; + (void)ctx; + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int test_wolfSSL_SSLDisableRead(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL *ssl_c = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL, + wolfTLS_client_method, NULL), 0); + wolfSSL_SSLSetIORecv(ssl_c, test_wolfSSL_SSLDisableRead_recv); + wolfSSL_SSLDisableRead(ssl_c); + + /* Disabling reading should not even go into the IO layer */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + wolfSSL_SSLEnableRead(ssl_c); + /* By enabling reading we should reach the IO that will return an error */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), SOCKET_ERROR_E); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + return EXPECT_RESULT(); +} +#else +static int test_wolfSSL_SSLDisableRead(void) +{ + EXPECT_DECLS; + return EXPECT_RESULT(); +} +#endif + +static int test_wolfSSL_inject(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) + size_t i; + struct { + method_provider client_meth; + method_provider server_meth; + const char* tls_version; + } params[] = { +#if defined(WOLFSSL_TLS13) +/* With WOLFSSL_TLS13_MIDDLEBOX_COMPAT a short ID will result in an error */ + { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }, +#ifdef WOLFSSL_DTLS13 + { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" }, +#endif +#endif +#ifndef WOLFSSL_NO_TLS12 + { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }, +#ifdef WOLFSSL_DTLS + { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" }, +#endif +#endif +#if !defined(NO_OLD_TLS) + { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" }, +#ifdef WOLFSSL_DTLS + { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" }, +#endif +#endif + }; + + for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) { + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_ALERT_HISTORY h; + int rounds; + + printf("Testing %s\n", params[i].tls_version); + + XMEMSET(&h, 0, sizeof(h)); + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + params[i].client_meth, params[i].server_meth), 0); + + for (rounds = 0; rounds < 10; rounds++) { + (void)wolfSSL_negotiate(ssl_c); + if (test_ctx.s_len > 0) { + ExpectIntEQ(wolfSSL_inject(ssl_s, test_ctx.s_buff, + test_ctx.s_len), 1); + test_ctx.s_len = 0; + } + (void)wolfSSL_negotiate(ssl_s); + if (test_ctx.c_len > 0) { + ExpectIntEQ(wolfSSL_inject(ssl_c, test_ctx.c_buff, + test_ctx.c_len), 1); + test_ctx.c_len = 0; + } + } + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + } +#endif + return EXPECT_RESULT(); +} + +static int test_wolfSSL_dtls_cid_parse(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + const unsigned char* cid = NULL; + /* Taken from Wireshark. Right-click -> copy -> ... as escaped string */ + /* Plaintext ServerHelloDone. No CID. */ + byte noCid[] = + "\x16\xfe\xfd\x00\x00\x00\x00\x00\x00\x00\x04\x00\x0c\x0e\x00\x00" \ + "\x00\x00\x04\x00\x00\x00\x00\x00\x00"; + /* 1.2 app data containing CID */ + byte cid12[] = + "\x19\xfe\xfd\x00\x01\x00\x00\x00\x00\x00\x01\x77\xa3\x79\x34\xb3" \ + "\xf1\x1f\x34\x00\x1f\xdb\x8c\x28\x25\x9f\xe1\x02\x26\x77\x1c\x3a" \ + "\x50\x1b\x50\x99\xd0\xb5\x20\xd8\x2c\x2e\xaa\x36\x36\xe0\xb7\xb7" \ + "\xf7\x7d\xff\xb0"; + /* 1.3 app data containing CID */ + byte cid13[] = + "\x3f\x70\x64\x04\xc6\xfb\x97\x21\xd9\x28\x27\x00\x17\xc1\x01\x86" \ + "\xe7\x23\x2c\xad\x65\x83\xa8\xf4\xbf\xbf\x7b\x25\x16\x80\x19\xc3" \ + "\x81\xda\xf5\x3f"; + + wolfSSL_dtls_cid_parse(noCid, sizeof(noCid), &cid, 8); + ExpectPtrEq(cid, NULL); + wolfSSL_dtls_cid_parse(cid12, sizeof(cid12), &cid, 8); + ExpectPtrEq(cid, cid12 + 11); + wolfSSL_dtls_cid_parse(cid13, sizeof(cid13), &cid, 8); + ExpectPtrEq(cid, cid13 + 1); + + +#endif + return EXPECT_RESULT(); +} /*----------------------------------------------------------------------------* | Main @@ -101495,6 +101659,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_get_signature_nid), TEST_DECL(test_tls_cert_store_unchanged), TEST_DECL(test_wolfSSL_SendUserCanceled), + TEST_DECL(test_wolfSSL_SSLDisableRead), + TEST_DECL(test_wolfSSL_inject), + TEST_DECL(test_wolfSSL_dtls_cid_parse), /* This test needs to stay at the end to clean up any caches allocated. */ TEST_DECL(test_wolfSSL_Cleanup) }; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index cb070baa31..8518adbd73 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2758,6 +2758,11 @@ struct WOLFSSL_SOCKADDR { typedef struct WOLFSSL_DTLS_CTX { WOLFSSL_SOCKADDR peer; +#ifdef WOLFSSL_DTLS_CID + WOLFSSL_SOCKADDR pendingPeer; /* When using CID's, we don't want to update + * the peer's address until we successfully + * de-protect the record. */ +#endif int rfd; int wfd; byte userSet:1; @@ -2765,6 +2770,9 @@ typedef struct WOLFSSL_DTLS_CTX { * connected (connect() and bind() both called). * This means that sendto and recvfrom do not need to * specify and store the peer address. */ +#ifdef WOLFSSL_DTLS_CID + byte processingPendingRecord:1; +#endif } WOLFSSL_DTLS_CTX; @@ -3711,6 +3719,7 @@ WOLFSSL_LOCAL int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input, WOLFSSL_LOCAL void DtlsCIDOnExtensionsParsed(WOLFSSL* ssl); WOLFSSL_LOCAL byte DtlsCIDCheck(WOLFSSL* ssl, const byte* input, word16 inputSize); +WOLFSSL_LOCAL int Dtls13UnifiedHeaderCIDPresent(byte flags); #endif /* WOLFSSL_DTLS_CID */ WOLFSSL_LOCAL byte DtlsGetCidTxSize(WOLFSSL* ssl); WOLFSSL_LOCAL byte DtlsGetCidRxSize(WOLFSSL* ssl); @@ -5051,6 +5060,7 @@ struct Options { #if defined(HAVE_DANE) word16 useDANE:1; #endif /* HAVE_DANE */ + word16 disableRead:1; #ifdef WOLFSSL_DTLS byte haveMcast; /* using multicast ? */ #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 13a2f1e87a..ed52ac1bd5 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1292,6 +1292,7 @@ WOLFSSL_API const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len); WOLFSSL_API const char* wolfSSL_get_curve_name(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_get_fd(const WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_get_wfd(const WOLFSSL* ssl); /* please see note at top of README if you get an error from connect */ WOLFSSL_ABI WOLFSSL_API int wolfSSL_connect(WOLFSSL* ssl); WOLFSSL_ABI WOLFSSL_API int wolfSSL_write( @@ -1299,6 +1300,7 @@ WOLFSSL_ABI WOLFSSL_API int wolfSSL_write( WOLFSSL_ABI WOLFSSL_API int wolfSSL_read(WOLFSSL* ssl, void* data, int sz); WOLFSSL_API int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz); WOLFSSL_ABI WOLFSSL_API int wolfSSL_accept(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz); WOLFSSL_API int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req); WOLFSSL_API int wolfSSL_mutual_auth(WOLFSSL* ssl, int req); @@ -1666,8 +1668,16 @@ WOLFSSL_API int wolfSSL_dtls(WOLFSSL* ssl); WOLFSSL_API void* wolfSSL_dtls_create_peer(int port, char* ip); WOLFSSL_API int wolfSSL_dtls_free_peer(void* addr); -WOLFSSL_API int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz); -WOLFSSL_API int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz); +WOLFSSL_API int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, + unsigned int peerSz); +WOLFSSL_API int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, + unsigned int peerSz); +WOLFSSL_API int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, + unsigned int* peerSz); +WOLFSSL_API int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, + unsigned int* peerSz); + +WOLFSSL_API byte wolfSSL_is_stateful(WOLFSSL* ssl); #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) WOLFSSL_API int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx); @@ -4636,6 +4646,7 @@ WOLFSSL_API int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx); #if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) +WOLFSSL_API int wolfDTLS_accept_stateless(WOLFSSL* ssl); /* notify user we parsed a verified ClientHello is done. This only has an effect * on the server end. */ typedef int (*ClientHelloGoodCb)(WOLFSSL* ssl, void*); @@ -5774,11 +5785,15 @@ 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_get0_rx(WOLFSSL* ssl, unsigned char** cid); 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); +WOLFSSL_API int wolfSSL_dtls_cid_get0_tx(WOLFSSL* ssl, unsigned char** cid); WOLFSSL_API int wolfSSL_dtls_cid_max_size(void); +WOLFSSL_API void wolfSSL_dtls_cid_parse(const unsigned char* msg, + unsigned int msgSz, const unsigned char** cid, unsigned int cidSz); #endif /* defined(WOLFSSL_DTLS_CID) */ #ifdef WOLFSSL_DTLS_CH_FRAG diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index 576e8f4675..4d1145b005 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -611,6 +611,8 @@ WOLFSSL_API void wolfSSL_CTX_SetIORecv(WOLFSSL_CTX *ctx, CallbackIORecv CBIORecv WOLFSSL_API void wolfSSL_CTX_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend); WOLFSSL_API void wolfSSL_SSLSetIORecv(WOLFSSL *ssl, CallbackIORecv CBIORecv); WOLFSSL_API void wolfSSL_SSLSetIOSend(WOLFSSL *ssl, CallbackIOSend CBIOSend); +WOLFSSL_API void wolfSSL_SSLDisableRead(WOLFSSL *ssl); +WOLFSSL_API void wolfSSL_SSLEnableRead(WOLFSSL *ssl); /* deprecated old name */ #define wolfSSL_SetIORecv wolfSSL_CTX_SetIORecv #define wolfSSL_SetIOSend wolfSSL_CTX_SetIOSend