Skip to content

Commit

Permalink
Merge pull request #8224 from julek-wolfssl/dtls-server-demux
Browse files Browse the repository at this point in the history
DTLS: Add server side stateless and CID QoL API
  • Loading branch information
JacobBarthelmeh authored Dec 23, 2024
2 parents 36d5342 + 9d3e477 commit 2409971
Show file tree
Hide file tree
Showing 15 changed files with 1,094 additions and 130 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/socat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,4 @@ jobs:
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH
export SHELL=/bin/bash
SOCAT=$GITHUB_WORKSPACE/socat-1.8.0.0/socat ./test.sh -t 0.5 --expect-fail 36,64,146,214,216,217,309,310,386,399,402,403,459,460,467,468,478,492,528,530
SOCAT=$GITHUB_WORKSPACE/socat-1.8.0.0/socat ./test.sh -t 0.5 --expect-fail 36,64,146,214,216,217,309,310,386,399,402,403,459,460,467,468,475,478,492,528,530
250 changes: 248 additions & 2 deletions doc/dox_comments/header_files/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -3856,12 +3927,53 @@ 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
Expand Down Expand Up @@ -3899,6 +4011,41 @@ 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
Expand Down Expand Up @@ -14138,6 +14285,39 @@ 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 This function is called to inject data into the WOLFSSL object. This
is useful when data needs to be read from a single place and demultiplexed
into multiple connections. The caller should then call wolfSSL_read() to
extract the plaintext data from the WOLFSSL object.
\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
Expand Down Expand Up @@ -14955,6 +15135,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
Expand All @@ -14967,6 +15148,26 @@ 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 set in cid.
\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.
Expand Down Expand Up @@ -14998,6 +15199,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
Expand All @@ -15008,6 +15210,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
Expand Down
43 changes: 43 additions & 0 deletions doc/dox_comments/header_files/wolfio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
2 changes: 1 addition & 1 deletion examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -2404,7 +2404,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
err_sys("provided connection ID is too big");
}
else {
strcpy(dtlsCID, myoptarg);
XSTRLCPY(dtlsCID, myoptarg, DTLS_CID_BUFFER_SIZE);
}
}
break;
Expand Down
2 changes: 1 addition & 1 deletion examples/server/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -2423,7 +2423,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
err_sys("provided connection ID is too big");
}
else {
strcpy(dtlsCID, myoptarg);
XSTRLCPY(dtlsCID, myoptarg, DTLS_CID_BUFFER_SIZE);
}
}
break;
Expand Down
Loading

0 comments on commit 2409971

Please sign in to comment.