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
pull/8224/head
Juliusz Sosinowicz 2024-10-30 16:11:00 +01:00
parent ba050d6a3f
commit daa57c492d
11 changed files with 876 additions and 57 deletions

View File

@ -1997,8 +1997,8 @@ const char* wolfSSL_get_cipher_name(WOLFSSL* ssl);
/*! /*!
\ingroup IO \ingroup IO
\brief This function returns the file descriptor (fd) used as the \brief This function returns the read file descriptor (fd) used as the
input/output facility for the SSL connection. Typically this input facility for the SSL connection. Typically this
will be a socket file descriptor. will be a socket file descriptor.
\return fd If successful the call will return the SSL session file \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 \endcode
\sa wolfSSL_set_fd \sa wolfSSL_set_fd
\sa wolfSSL_set_read_fd
\sa wolfSSL_set_write_fd
*/ */
int wolfSSL_get_fd(const WOLFSSL*); 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 \ingroup Setup
@ -2289,6 +2318,48 @@ int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz);
*/ */
int wolfSSL_accept(WOLFSSL*); 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 \ingroup Setup
@ -3856,12 +3927,52 @@ int wolfSSL_dtls(WOLFSSL* ssl);
\endcode \endcode
\sa wolfSSL_dtls_get_current_timeout \sa wolfSSL_dtls_get_current_timeout
\sa wolfSSL_dtls_set_pending_peer
\sa wolfSSL_dtls_get_peer \sa wolfSSL_dtls_get_peer
\sa wolfSSL_dtls_got_timeout \sa wolfSSL_dtls_got_timeout
\sa wolfSSL_dtls \sa wolfSSL_dtls
*/ */
int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz); 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 peers 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 \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 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); 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 \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 wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz,
int* outSz); 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 \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 buffer A buffer where the ConnectionID will be copied
\param bufferSz available space in buffer \param bufferSz available space in buffer
\sa wolfSSL_dtls_cid_get0_rx
\sa wolfSSL_dtls_cid_use \sa wolfSSL_dtls_cid_use
\sa wolfSSL_dtls_cid_is_enabled \sa wolfSSL_dtls_cid_is_enabled
\sa wolfSSL_dtls_cid_set \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 \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. 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 buffer A buffer where the ConnectionID will be copied
\param bufferSz available space in buffer \param bufferSz available space in buffer
\sa wolfSSL_dtls_cid_get0_tx
\sa wolfSSL_dtls_cid_use \sa wolfSSL_dtls_cid_use
\sa wolfSSL_dtls_cid_is_enabled \sa wolfSSL_dtls_cid_is_enabled
\sa wolfSSL_dtls_cid_set \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, int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer,
unsigned int bufferSz); 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 \ingroup TLS

View File

@ -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, 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, word32 receive_delay, char *receive_buffer, int receive_buffer_size,
void *arg); 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);

View File

@ -101,6 +101,15 @@ void DtlsResetState(WOLFSSL* ssl)
ssl->options.tls = 0; ssl->options.tls = 0;
ssl->options.tls1_1 = 0; ssl->options.tls1_1 = 0;
ssl->options.tls1_3 = 0; ssl->options.tls1_3 = 0;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID)
ssl->buffers.dtlsCtx.processingPendingRecord = 0;
/* Clear the pending peer in case user set */
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
} }
int DtlsIgnoreError(int err) int DtlsIgnoreError(int err)
@ -1108,6 +1117,26 @@ static int DtlsCidGet(WOLFSSL* ssl, unsigned char* buf, int bufferSz, int rx)
return WOLFSSL_SUCCESS; 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) static CIDInfo* DtlsCidGetInfoFromExt(byte* ext)
{ {
WOLFSSL** sslPtr; WOLFSSL** sslPtr;
@ -1366,6 +1395,11 @@ int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buf,
return DtlsCidGet(ssl, buf, bufferSz, 1); 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) int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl, unsigned int* size)
{ {
return DtlsCidGetSize(ssl, size, 0); return DtlsCidGetSize(ssl, size, 0);
@ -1377,10 +1411,40 @@ int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buf,
return DtlsCidGet(ssl, buf, bufferSz, 0); 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) int wolfSSL_dtls_cid_max_size(void)
{ {
return DTLS_CID_MAX_SIZE; 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 */ #endif /* WOLFSSL_DTLS_CID */
byte DtlsGetCidTxSize(WOLFSSL* ssl) byte DtlsGetCidTxSize(WOLFSSL* ssl)
@ -1413,6 +1477,11 @@ byte DtlsGetCidRxSize(WOLFSSL* ssl)
#endif #endif
} }
byte wolfSSL_is_stateful(WOLFSSL* ssl)
{
return (byte)(ssl != NULL ? ssl->options.dtlsStateful : 0);
}
#endif /* WOLFSSL_DTLS */ #endif /* WOLFSSL_DTLS */
#endif /* WOLFCRYPT_ONLY */ #endif /* WOLFCRYPT_ONLY */

View File

@ -1151,6 +1151,11 @@ static int Dtls13UnifiedHeaderParseCID(WOLFSSL* ssl, byte flags,
return 0; return 0;
} }
int Dtls13UnifiedHeaderCIDPresent(byte flags)
{
return Dtls13IsUnifiedHeader(flags) && (flags & DTLS13_CID_BIT);
}
#else #else
#define Dtls13AddCID(a, b, c, d) 0 #define Dtls13AddCID(a, b, c, d) 0
#define Dtls13UnifiedHeaderParseCID(a, b, c, d, e) 0 #define Dtls13UnifiedHeaderParseCID(a, b, c, d, e) 0

View File

@ -8261,6 +8261,11 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
} }
XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR);
ssl->buffers.dtlsCtx.peer.sa = NULL; 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 #ifndef NO_WOLFSSL_SERVER
if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { if (ssl->buffers.dtlsCookieSecret.buffer != NULL) {
ForceZero(ssl->buffers.dtlsCookieSecret.buffer, ForceZero(ssl->buffers.dtlsCookieSecret.buffer,
@ -11522,15 +11527,15 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx,
#ifdef WOLFSSL_DTLS_CID #ifdef WOLFSSL_DTLS_CID
if (rh->type == dtls12_cid) { if (rh->type == dtls12_cid) {
byte cid[DTLS_CID_MAX_SIZE]; byte* ourCid = NULL;
if (ssl->buffers.inputBuffer.length - *inOutIdx < if (ssl->buffers.inputBuffer.length - *inOutIdx <
(word32)cidSz + LENGTH_SZ) (word32)cidSz + LENGTH_SZ)
return LENGTH_ERROR; return LENGTH_ERROR;
if (cidSz > DTLS_CID_MAX_SIZE || if (cidSz != DtlsGetCidRxSize(ssl) ||
wolfSSL_dtls_cid_get_rx(ssl, cid, cidSz) != WOLFSSL_SUCCESS) wolfSSL_dtls_cid_get0_rx(ssl, &ourCid) != WOLFSSL_SUCCESS)
return DTLS_CID_ERROR; return DTLS_CID_ERROR;
if (XMEMCMP(ssl->buffers.inputBuffer.buffer + *inOutIdx, if (XMEMCMP(ssl->buffers.inputBuffer.buffer + *inOutIdx, ourCid, cidSz)
cid, cidSz) != 0) != 0)
return DTLS_CID_ERROR; return DTLS_CID_ERROR;
*inOutIdx += cidSz; *inOutIdx += cidSz;
} }
@ -11740,7 +11745,7 @@ int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input,
{ {
word32 idx = *inOutIdx; word32 idx = *inOutIdx;
*inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; *inOutIdx += DTLS_HANDSHAKE_HEADER_SZ;
if (*inOutIdx > totalSz) { if (*inOutIdx > totalSz) {
WOLFSSL_ERROR(BUFFER_E); WOLFSSL_ERROR(BUFFER_E);
return BUFFER_E; return BUFFER_E;
@ -21045,11 +21050,14 @@ static int GetInputData(WOLFSSL *ssl, word32 size)
int usedLength; int usedLength;
int dtlsExtra = 0; int dtlsExtra = 0;
if (ssl->options.disableRead)
return WC_NO_ERR_TRACE(WANT_READ);
/* check max input length */ /* check max input length */
usedLength = (int)(ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx); usedLength = (int)(ssl->buffers.inputBuffer.length -
maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - (word32)usedLength); ssl->buffers.inputBuffer.idx);
inSz = (int)(size - (word32)usedLength); /* from last partial read */ maxLength = (int)(ssl->buffers.inputBuffer.bufferSize -
(word32)usedLength);
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
if (ssl->options.dtls && IsDtlsNotSctpMode(ssl)) { if (ssl->options.dtls && IsDtlsNotSctpMode(ssl)) {
@ -21063,11 +21071,20 @@ static int GetInputData(WOLFSSL *ssl, word32 size)
if (size < (word32)inSz) if (size < (word32)inSz)
dtlsExtra = (int)(inSz - size); dtlsExtra = (int)(inSz - size);
} }
else
#endif #endif
{
/* check that no lengths or size values are negative */
if (usedLength < 0 || maxLength < 0) {
return BUFFER_ERROR;
}
/* check that no lengths or size values are negative */ /* Return if we have enough data already in the buffer */
if (usedLength < 0 || maxLength < 0 || inSz <= 0) { if (size <= (word32)usedLength) {
return BUFFER_ERROR; return 0;
}
inSz = (int)(size - (word32)usedLength); /* from last partial read */
} }
if (inSz > maxLength) { if (inSz > maxLength) {
@ -21541,6 +21558,23 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
&ssl->curRL, &ssl->curSize); &ssl->curRL, &ssl->curSize);
#ifdef WOLFSSL_DTLS #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)) { if (ssl->options.dtls && DtlsShouldDrop(ssl, ret)) {
ssl->options.processReply = doProcessInit; ssl->options.processReply = doProcessInit;
ssl->buffers.inputBuffer.length = 0; ssl->buffers.inputBuffer.length = 0;
@ -21965,8 +21999,9 @@ default:
/* the record layer is here */ /* the record layer is here */
case runProcessingOneRecord: case runProcessingOneRecord:
#ifdef WOLFSSL_DTLS13 #ifdef WOLFSSL_DTLS
if (ssl->options.dtls) { if (ssl->options.dtls) {
#ifdef WOLFSSL_DTLS13
if (IsAtLeastTLSv1_3(ssl->version)) { if (IsAtLeastTLSv1_3(ssl->version)) {
if (!Dtls13CheckWindow(ssl)) { if (!Dtls13CheckWindow(ssl)) {
/* drop packet */ /* drop packet */
@ -21990,11 +22025,27 @@ default:
} }
} }
} }
else if (IsDtlsNotSctpMode(ssl)) { else
#endif /* WOLFSSL_DTLS13 */
if (IsDtlsNotSctpMode(ssl)) {
DtlsUpdateWindow(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; ssl->options.processReply = runProcessingOneMessage;
FALL_THROUGH; FALL_THROUGH;

248
src/ssl.c
View File

@ -1732,6 +1732,17 @@ int wolfSSL_get_fd(const WOLFSSL* ssl)
return fd; 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) int wolfSSL_dtls(WOLFSSL* ssl)
{ {
@ -1864,38 +1875,51 @@ int wolfSSL_dtls_free_peer(void* addr)
} }
#endif #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) int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz)
{ {
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
void* sa; int ret;
if (ssl == NULL) if (ssl == NULL)
return WOLFSSL_FAILURE; return WOLFSSL_FAILURE;
if (peer == NULL || peerSz == 0) { ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap);
if (ssl->buffers.dtlsCtx.peer.sa != NULL) if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0))
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;
ssl->buffers.dtlsCtx.userSet = 0;
return WOLFSSL_SUCCESS;
}
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;
}
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; ssl->buffers.dtlsCtx.userSet = 1;
return WOLFSSL_SUCCESS; else
} ssl->buffers.dtlsCtx.userSet = 0;
return WOLFSSL_FAILURE; return ret;
#else #else
(void)ssl; (void)ssl;
(void)peer; (void)peer;
@ -1904,6 +1928,45 @@ int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz)
#endif #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;
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;
}
ret = WOLFSSL_SUCCESS;
}
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;
(void)peerSz;
return WOLFSSL_NOT_IMPLEMENTED;
#endif
}
#endif
int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz)
{ {
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
@ -1927,6 +1990,27 @@ int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz)
#endif #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) #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS)
@ -2897,6 +2981,42 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz)
return ret; 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) static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek)
{ {
int ret; int ret;
@ -9222,7 +9342,13 @@ int wolfSSL_dtls_retransmit(WOLFSSL* ssl)
return WOLFSSL_FATAL_ERROR; return WOLFSSL_FATAL_ERROR;
if (!ssl->options.handShakeDone) { 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) { if (result < 0) {
ssl->error = result; ssl->error = result;
WOLFSSL_ERROR(result); WOLFSSL_ERROR(result);
@ -9230,7 +9356,7 @@ int wolfSSL_dtls_retransmit(WOLFSSL* ssl)
} }
} }
return 0; return WOLFSSL_SUCCESS;
} }
#endif /* DTLS */ #endif /* DTLS */
@ -10399,6 +10525,76 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
#if defined(WOLFSSL_DTLS) && !defined(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 = (byte)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) int wolfDTLS_SetChGoodCb(WOLFSSL* ssl, ClientHelloGoodCb cb, void* user_ctx)
{ {
WOLFSSL_ENTER("wolfDTLS_SetChGoodCb"); WOLFSSL_ENTER("wolfDTLS_SetChGoodCb");

View File

@ -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) void wolfSSL_SetIOReadCtx(WOLFSSL* ssl, void *rctx)
{ {

View File

@ -90313,7 +90313,7 @@ static void test_wolfSSL_dtls_plaintext_server(WOLFSSL* ssl)
static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl) static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl)
{ {
byte ch[50]; 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 msg[] = "This is a msg for the server";
byte reply[40]; byte reply[40];
@ -90383,7 +90383,7 @@ static void test_wolfSSL_dtls12_fragments_spammer(WOLFSSL* ssl)
size_t seq_offset = 0; size_t seq_offset = 0;
size_t msg_offset = 0; size_t msg_offset = 0;
int i; 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 */ int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */
word32 seq_number = 100; /* start high so server definitely reads this */ word32 seq_number = 100; /* start high so server definitely reads this */
word16 msg_number = 50; /* start high so server has to buffer this */ word16 msg_number = 50; /* start high so server has to buffer this */
@ -90445,7 +90445,7 @@ static void test_wolfSSL_dtls13_fragments_spammer(WOLFSSL* ssl)
byte b[150]; /* buffer for the messages to send */ byte b[150]; /* buffer for the messages to send */
size_t idx = 0; size_t idx = 0;
size_t msg_offset = 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 */ word16 msg_number = 10; /* start high so server has to buffer this */
int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */
AssertIntEQ(ret, 1); AssertIntEQ(ret, 1);
@ -90550,7 +90550,7 @@ static void test_wolfSSL_dtls_send_alert(WOLFSSL* ssl)
0x46 /* protocol version */ 0x46 /* protocol version */
}; };
fd = wolfSSL_get_fd(ssl); fd = wolfSSL_get_wfd(ssl);
ret = (int)send(fd, alert_msg, sizeof(alert_msg), 0); ret = (int)send(fd, alert_msg, sizeof(alert_msg), 0);
AssertIntGT(ret, 0); AssertIntGT(ret, 0);
} }
@ -90620,7 +90620,7 @@ static void test_wolfSSL_send_bad_record(WOLFSSL* ssl)
0x03, 0x18, 0x72 0x03, 0x18, 0x72
}; };
fd = wolfSSL_get_fd(ssl); fd = wolfSSL_get_wfd(ssl);
AssertIntGE(fd, 0); AssertIntGE(fd, 0);
ret = (int)send(fd, bad_msg, sizeof(bad_msg), 0); ret = (int)send(fd, bad_msg, sizeof(bad_msg), 0);
AssertIntEQ(ret, sizeof(bad_msg)); AssertIntEQ(ret, sizeof(bad_msg));
@ -90947,7 +90947,7 @@ static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl)
0x31, 0x68, 0x4c 0x31, 0x68, 0x4c
}; };
fd = wolfSSL_get_fd(ssl); fd = wolfSSL_get_wfd(ssl);
ret = (int)send(fd, ch_msg, sizeof(ch_msg), 0); ret = (int)send(fd, ch_msg, sizeof(ch_msg), 0);
AssertIntGT(ret, 0); AssertIntGT(ret, 0);
/* consume the HRR otherwise handshake will fail */ /* consume the HRR otherwise handshake will fail */
@ -91018,7 +91018,7 @@ static void test_wolfSSL_dtls_send_ch_with_invalid_cookie(WOLFSSL* ssl)
0x02, 0x02, 0x2f 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); ret = (int)send(fd, ch_msh_invalid_cookie, sizeof(ch_msh_invalid_cookie), 0);
AssertIntGT(ret, 0); AssertIntGT(ret, 0);
/* should reply with an illegal_parameter reply */ /* should reply with an illegal_parameter reply */
@ -93932,18 +93932,31 @@ static int test_wolfSSL_dtls_stateless2(void)
XMEMSET(&test_ctx, 0, sizeof(test_ctx)); XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL,
wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); wolfDTLSv1_2_client_method, NULL), 0);
wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); ExpectFalse(wolfSSL_is_stateful(ssl_s));
/* send CH */ /* send CH */
ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) &&
(ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ)));
ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE);
(ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); ExpectFalse(wolfSSL_is_stateful(ssl_s));
ExpectIntNE(test_ctx.c_len, 0); ExpectIntNE(test_ctx.c_len, 0);
/* consume HRR */ /* consume HRR */
test_ctx.c_len = 0; 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); 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_c2);
wolfSSL_free(ssl_c); wolfSSL_free(ssl_c);
@ -100204,6 +100217,163 @@ static int test_ocsp_callback_fails(void)
defined(HAVE_OCSP) && \ defined(HAVE_OCSP) && \
defined(HAVE_CERTIFICATE_STATUS_REQUEST) */ 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 && EXPECT_SUCCESS(); rounds++) {
if (wolfSSL_negotiate(ssl_c) != 1) {
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
WOLFSSL_ERROR_WANT_READ);
}
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;
}
if (wolfSSL_negotiate(ssl_s) != 1) {
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1),
WOLFSSL_ERROR_WANT_READ);
}
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 | Main
@ -101607,6 +101777,9 @@ TEST_CASE testCases[] = {
TEST_DECL(test_get_signature_nid), TEST_DECL(test_get_signature_nid),
TEST_DECL(test_tls_cert_store_unchanged), TEST_DECL(test_tls_cert_store_unchanged),
TEST_DECL(test_wolfSSL_SendUserCanceled), 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. */ /* This test needs to stay at the end to clean up any caches allocated. */
TEST_DECL(test_wolfSSL_Cleanup) TEST_DECL(test_wolfSSL_Cleanup)
}; };

View File

@ -2759,6 +2759,11 @@ struct WOLFSSL_SOCKADDR {
typedef struct WOLFSSL_DTLS_CTX { typedef struct WOLFSSL_DTLS_CTX {
WOLFSSL_SOCKADDR peer; 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 rfd;
int wfd; int wfd;
byte userSet:1; byte userSet:1;
@ -2766,6 +2771,9 @@ typedef struct WOLFSSL_DTLS_CTX {
* connected (connect() and bind() both called). * connected (connect() and bind() both called).
* This means that sendto and recvfrom do not need to * This means that sendto and recvfrom do not need to
* specify and store the peer address. */ * specify and store the peer address. */
#ifdef WOLFSSL_DTLS_CID
byte processingPendingRecord:1;
#endif
} WOLFSSL_DTLS_CTX; } WOLFSSL_DTLS_CTX;
@ -3712,6 +3720,7 @@ WOLFSSL_LOCAL int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input,
WOLFSSL_LOCAL void DtlsCIDOnExtensionsParsed(WOLFSSL* ssl); WOLFSSL_LOCAL void DtlsCIDOnExtensionsParsed(WOLFSSL* ssl);
WOLFSSL_LOCAL byte DtlsCIDCheck(WOLFSSL* ssl, const byte* input, WOLFSSL_LOCAL byte DtlsCIDCheck(WOLFSSL* ssl, const byte* input,
word16 inputSize); word16 inputSize);
WOLFSSL_LOCAL int Dtls13UnifiedHeaderCIDPresent(byte flags);
#endif /* WOLFSSL_DTLS_CID */ #endif /* WOLFSSL_DTLS_CID */
WOLFSSL_LOCAL byte DtlsGetCidTxSize(WOLFSSL* ssl); WOLFSSL_LOCAL byte DtlsGetCidTxSize(WOLFSSL* ssl);
WOLFSSL_LOCAL byte DtlsGetCidRxSize(WOLFSSL* ssl); WOLFSSL_LOCAL byte DtlsGetCidRxSize(WOLFSSL* ssl);
@ -5052,6 +5061,7 @@ struct Options {
#if defined(HAVE_DANE) #if defined(HAVE_DANE)
word16 useDANE:1; word16 useDANE:1;
#endif /* HAVE_DANE */ #endif /* HAVE_DANE */
word16 disableRead:1;
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
byte haveMcast; /* using multicast ? */ byte haveMcast; /* using multicast ? */
#endif #endif

View File

@ -1359,6 +1359,7 @@ WOLFSSL_API const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf,
int len); int len);
WOLFSSL_API const char* wolfSSL_get_curve_name(WOLFSSL* ssl); WOLFSSL_API const char* wolfSSL_get_curve_name(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_get_fd(const 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 */ /* 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_connect(WOLFSSL* ssl);
WOLFSSL_ABI WOLFSSL_API int wolfSSL_write( WOLFSSL_ABI WOLFSSL_API int wolfSSL_write(
@ -1366,6 +1367,7 @@ WOLFSSL_ABI WOLFSSL_API int wolfSSL_write(
WOLFSSL_ABI WOLFSSL_API int wolfSSL_read(WOLFSSL* ssl, void* data, int sz); 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_API int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz);
WOLFSSL_ABI WOLFSSL_API int wolfSSL_accept(WOLFSSL* ssl); 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_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req);
WOLFSSL_API int wolfSSL_mutual_auth(WOLFSSL* ssl, int req); WOLFSSL_API int wolfSSL_mutual_auth(WOLFSSL* ssl, int req);
@ -1733,8 +1735,16 @@ WOLFSSL_API int wolfSSL_dtls(WOLFSSL* ssl);
WOLFSSL_API void* wolfSSL_dtls_create_peer(int port, char* ip); 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_free_peer(void* addr);
WOLFSSL_API int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz); WOLFSSL_API int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer,
WOLFSSL_API int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz); 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) #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS)
WOLFSSL_API int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx); WOLFSSL_API int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx);
@ -4709,6 +4719,7 @@ WOLFSSL_API int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx);
#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) #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 /* notify user we parsed a verified ClientHello is done. This only has an effect
* on the server end. */ * on the server end. */
typedef int (*ClientHelloGoodCb)(WOLFSSL* ssl, void*); typedef int (*ClientHelloGoodCb)(WOLFSSL* ssl, void*);
@ -5844,11 +5855,15 @@ WOLFSSL_API int wolfSSL_dtls_cid_get_rx_size(WOLFSSL* ssl,
unsigned int* size); unsigned int* size);
WOLFSSL_API int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buffer, WOLFSSL_API int wolfSSL_dtls_cid_get_rx(WOLFSSL* ssl, unsigned char* buffer,
unsigned int bufferSz); 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, WOLFSSL_API int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl,
unsigned int* size); unsigned int* size);
WOLFSSL_API int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer, WOLFSSL_API int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer,
unsigned int bufferSz); 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 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) */ #endif /* defined(WOLFSSL_DTLS_CID) */
#ifdef WOLFSSL_DTLS_CH_FRAG #ifdef WOLFSSL_DTLS_CH_FRAG

View File

@ -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_CTX_SetIOSend(WOLFSSL_CTX *ctx, CallbackIOSend CBIOSend);
WOLFSSL_API void wolfSSL_SSLSetIORecv(WOLFSSL *ssl, CallbackIORecv CBIORecv); WOLFSSL_API void wolfSSL_SSLSetIORecv(WOLFSSL *ssl, CallbackIORecv CBIORecv);
WOLFSSL_API void wolfSSL_SSLSetIOSend(WOLFSSL *ssl, CallbackIOSend CBIOSend); 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 */ /* deprecated old name */
#define wolfSSL_SetIORecv wolfSSL_CTX_SetIORecv #define wolfSSL_SetIORecv wolfSSL_CTX_SetIORecv
#define wolfSSL_SetIOSend wolfSSL_CTX_SetIOSend #define wolfSSL_SetIOSend wolfSSL_CTX_SetIOSend