Skip to content

Commit ea43116

Browse files
authored
Merge pull request #9367 from julek-wolfssl/wolfDTLS_accept_stateless-early-data
wolfDTLS_accept_stateless: Fix handling for early data
2 parents 8b3eaa0 + bd2cc5b commit ea43116

8 files changed

Lines changed: 324 additions & 10 deletions

File tree

doc/dox_comments/header_files/wolfio.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,51 @@ void wolfSSL_SSLDisableRead(WOLFSSL *ssl);
618618
\sa wolfSSL_SSLEnableRead
619619
*/
620620
void wolfSSL_SSLEnableRead(WOLFSSL *ssl);
621+
622+
/*!
623+
\brief Set a custom DTLS recvfrom callback for a WOLFSSL session.
624+
625+
This function allows you to specify a custom callback function for receiving
626+
datagrams (DTLS) using the `recvfrom`-style interface. The callback must match
627+
the WolfSSLRecvFrom function pointer type and is expected to behave like the
628+
POSIX `recvfrom()` function, including its return values and error handling.
629+
630+
\param ssl A pointer to a WOLFSSL structure, created using wolfSSL_new().
631+
\param recvFrom The custom callback function to use for DTLS datagram receive.
632+
633+
_Example_
634+
\code
635+
wolfSSL_SetRecvFrom(ssl, my_recvfrom_cb);
636+
\endcode
637+
638+
\sa WolfSSLRecvFrom
639+
\sa wolfSSL_SetSendTo
640+
\sa EmbedReceiveFrom
641+
\sa wolfSSL_CTX_SetIORecv
642+
\sa wolfSSL_SSLSetIORecv
643+
*/
644+
WOLFSSL_API void wolfSSL_SetRecvFrom(WOLFSSL* ssl, WolfSSLRecvFrom recvFrom);
645+
646+
/*!
647+
\brief Set a custom DTLS sendto callback for a WOLFSSL session.
648+
649+
This function allows you to specify a custom callback function for sending
650+
datagrams (DTLS) using the `sendto`-style interface. The callback must match
651+
the WolfSSLSento function pointer type and is expected to behave like the
652+
POSIX `sendto()` function, including its return values and error handling.
653+
654+
\param ssl A pointer to a WOLFSSL structure, created using wolfSSL_new().
655+
\param sendTo The custom callback function to use for DTLS datagram send.
656+
657+
_Example_
658+
\code
659+
wolfSSL_SetSendTo(ssl, my_sendto_cb);
660+
\endcode
661+
662+
\sa WolfSSLSento
663+
\sa wolfSSL_SetRecvFrom
664+
\sa EmbedSendTo
665+
\sa wolfSSL_CTX_SetIOSend
666+
\sa wolfSSL_SSLSetIOSend
667+
*/
668+
WOLFSSL_API void wolfSSL_SetSendTo(WOLFSSL* ssl, WolfSSLSento sendTo);

src/ssl.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11012,6 +11012,12 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
1101211012
FALL_THROUGH;
1101311013

1101411014
case ACCEPT_FIRST_REPLY_DONE :
11015+
if (ssl->options.returnOnGoodCh) {
11016+
/* Higher level in stack wants us to return. Simulate a
11017+
* WANT_WRITE to accomplish this. */
11018+
ssl->error = WANT_WRITE;
11019+
return WOLFSSL_FATAL_ERROR;
11020+
}
1101511021
if ( (ssl->error = SendServerHello(ssl)) != 0) {
1101611022
#ifdef WOLFSSL_CHECK_ALERT_ON_ERR
1101711023
ProcessReplyEx(ssl, 1); /* See if an alert was sent. */
@@ -11312,15 +11318,19 @@ int wolfDTLS_accept_stateless(WOLFSSL* ssl)
1131211318
if (wolfDTLS_SetChGoodCb(ssl, chGoodDisableReadCB, &cb) != WOLFSSL_SUCCESS)
1131311319
return WOLFSSL_FATAL_ERROR;
1131411320

11321+
ssl->options.returnOnGoodCh = 1;
1131511322
ret = wolfSSL_accept(ssl);
11323+
ssl->options.returnOnGoodCh = 0;
1131611324
/* restore user options */
1131711325
ssl->options.disableRead = disableRead;
1131811326
(void)wolfDTLS_SetChGoodCb(ssl, cb.userCb, cb.userCtx);
1131911327
if (ret == WOLFSSL_SUCCESS) {
1132011328
WOLFSSL_MSG("should not happen. maybe the user called "
1132111329
"wolfDTLS_accept_stateless instead of wolfSSL_accept");
1132211330
}
11323-
else if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) {
11331+
else if (ssl->error == WC_NO_ERR_TRACE(WANT_READ) ||
11332+
ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) {
11333+
ssl->error = 0;
1132411334
if (ssl->options.dtlsStateful)
1132511335
ret = WOLFSSL_SUCCESS;
1132611336
else

src/tls13.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14597,6 +14597,12 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
1459714597
FALL_THROUGH;
1459814598

1459914599
case TLS13_ACCEPT_SECOND_REPLY_DONE :
14600+
if (ssl->options.returnOnGoodCh) {
14601+
/* Higher level in stack wants us to return. Simulate a
14602+
* WANT_WRITE to accomplish this. */
14603+
ssl->error = WANT_WRITE;
14604+
return WOLFSSL_FATAL_ERROR;
14605+
}
1460014606

1460114607
if ((ssl->error = SendTls13ServerHello(ssl, server_hello)) != 0) {
1460214608
WOLFSSL_ERROR(ssl->error);

src/wolfio.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,18 @@ static int isDGramSock(int sfd)
638638
}
639639
}
640640

641+
void wolfSSL_SetRecvFrom(WOLFSSL* ssl, WolfSSLRecvFrom recvFrom)
642+
{
643+
if (ssl != NULL)
644+
ssl->buffers.dtlsCtx.recvfrom = recvFrom;
645+
}
646+
647+
void wolfSSL_SetSendTo(WOLFSSL* ssl, WolfSSLSento sendTo)
648+
{
649+
if (ssl != NULL)
650+
ssl->buffers.dtlsCtx.sendto = sendTo;
651+
}
652+
641653
/* The receive embedded callback
642654
* return : nb bytes read, or error
643655
*/
@@ -686,10 +698,6 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
686698
/* Store the peer address. It is used to calculate the DTLS cookie. */
687699
newPeer = dtlsCtx->peer.sa == NULL || !ssl->options.dtlsStateful;
688700
peer = &lclPeer;
689-
if (dtlsCtx->peer.sa != NULL) {
690-
XMEMCPY(peer, (SOCKADDR_S*)dtlsCtx->peer.sa, MIN(sizeof(lclPeer),
691-
dtlsCtx->peer.sz));
692-
}
693701
peerSz = sizeof(lclPeer);
694702
}
695703

@@ -785,8 +793,16 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
785793

786794
{
787795
XSOCKLENT inPeerSz = peerSz;
788-
recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz,
789-
ssl->rflags, (SOCKADDR*)peer, peer != NULL ? &inPeerSz : NULL);
796+
if (dtlsCtx->recvfrom == NULL) {
797+
recvd = (int)DTLS_RECVFROM_FUNCTION(sd, buf, (size_t)sz,
798+
ssl->rflags, (SOCKADDR*)peer,
799+
peer != NULL ? &inPeerSz : NULL);
800+
}
801+
else {
802+
recvd = (int)dtlsCtx->recvfrom(sd, buf, (size_t) sz,
803+
ssl->rflags, (SOCKADDR*) peer,
804+
peer != NULL ? &inPeerSz : NULL);
805+
}
790806
/* Truncate peerSz. From the RECV(2) man page
791807
* The returned address is truncated if the buffer provided is too
792808
* small; in this case, addrlen will return a value greater than was
@@ -856,6 +872,7 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
856872
/* Store size of saved address. Locking handled internally. */
857873
if (wolfSSL_dtls_set_peer(ssl, peer, peerSz) != WOLFSSL_SUCCESS)
858874
return WOLFSSL_CBIO_ERR_GENERAL;
875+
dtlsCtx->userSet = 0;
859876
}
860877
#ifndef WOLFSSL_PEER_ADDRESS_CHANGES
861878
else {
@@ -914,8 +931,14 @@ int EmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx)
914931
#endif
915932
}
916933

917-
sent = (int)DTLS_SENDTO_FUNCTION(sd, buf, (size_t)sz, ssl->wflags,
918-
(const SOCKADDR*)peer, peerSz);
934+
if (dtlsCtx->sendto == NULL) {
935+
sent = (int)DTLS_SENDTO_FUNCTION(sd, buf, (size_t)sz, ssl->wflags,
936+
(const SOCKADDR*)peer, peerSz);
937+
}
938+
else {
939+
sent = (int)dtlsCtx->sendto(sd, buf, (size_t)sz, ssl->wflags,
940+
(const SOCKADDR*)peer, peerSz);
941+
}
919942

920943
sent = TranslateIoReturnCode(sent, sd, SOCKET_SENDING);
921944

tests/api/test_dtls.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,3 +2049,211 @@ int test_dtls_certreq_order(void)
20492049
#endif
20502050
return EXPECT_RESULT();
20512051
}
2052+
2053+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS)
2054+
struct {
2055+
struct test_memio_ctx* test_ctx;
2056+
WOLFSSL* ssl_s;
2057+
int fd;
2058+
SOCKADDR_S peer_addr;
2059+
} test_memio_wolfio_ctx;
2060+
2061+
static ssize_t test_memio_wolfio_recvfrom(int sockfd, void* buf,
2062+
size_t len, int flags, void* src_addr, void* addrlen)
2063+
{
2064+
int ret;
2065+
(void)flags;
2066+
if (sockfd != test_memio_wolfio_ctx.fd) {
2067+
errno = EINVAL;
2068+
return -1;
2069+
}
2070+
ret = test_memio_read_cb(test_memio_wolfio_ctx.ssl_s,
2071+
(char*)buf, (int)len, test_memio_wolfio_ctx.test_ctx);
2072+
if (ret <= 0) {
2073+
if (ret == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_WANT_READ))
2074+
errno = EAGAIN;
2075+
else
2076+
errno = EINVAL;
2077+
return -1;
2078+
}
2079+
XMEMCPY(src_addr, &test_memio_wolfio_ctx.peer_addr,
2080+
MIN(sizeof(test_memio_wolfio_ctx.peer_addr),
2081+
*(word32*)addrlen));
2082+
*(word32*)addrlen = sizeof(test_memio_wolfio_ctx.peer_addr);
2083+
return ret;
2084+
}
2085+
2086+
static ssize_t test_memio_wolfio_sendto(int sockfd, const void* buf,
2087+
size_t len, int flags, const void* dest_addr, word32 addrlen)
2088+
{
2089+
int ret;
2090+
(void) flags;
2091+
(void) dest_addr;
2092+
(void) addrlen;
2093+
if (sockfd != test_memio_wolfio_ctx.fd) {
2094+
errno = EINVAL;
2095+
return -1;
2096+
}
2097+
if (dest_addr != NULL && addrlen != 0 &&
2098+
(sizeof(test_memio_wolfio_ctx.peer_addr) != addrlen ||
2099+
XMEMCMP(dest_addr, &test_memio_wolfio_ctx.peer_addr,
2100+
addrlen) != 0)) {
2101+
errno = EINVAL;
2102+
return -1;
2103+
}
2104+
ret = test_memio_write_cb(test_memio_wolfio_ctx.ssl_s, (char*)buf,
2105+
(int)len, test_memio_wolfio_ctx.test_ctx);
2106+
if (ret <= 0) {
2107+
if (ret == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_WANT_WRITE))
2108+
errno = EAGAIN;
2109+
else
2110+
errno = EINVAL;
2111+
return -1;
2112+
}
2113+
return ret;
2114+
}
2115+
#endif
2116+
2117+
/* Test stateless API with wolfio */
2118+
int test_dtls_memio_wolfio(void)
2119+
{
2120+
EXPECT_DECLS;
2121+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS)
2122+
size_t i;
2123+
struct {
2124+
method_provider client_meth;
2125+
method_provider server_meth;
2126+
} params[] = {
2127+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13)
2128+
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method },
2129+
#endif
2130+
#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_DTLS)
2131+
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method },
2132+
#endif
2133+
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_DTLS)
2134+
{ wolfDTLSv1_client_method, wolfDTLSv1_server_method },
2135+
#endif
2136+
};
2137+
XMEMSET(&test_memio_wolfio_ctx, 0, sizeof(test_memio_wolfio_ctx));
2138+
for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) {
2139+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
2140+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
2141+
struct test_memio_ctx test_ctx;
2142+
2143+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2144+
2145+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2146+
params[i].client_meth, params[i].server_meth), 0);
2147+
2148+
test_memio_wolfio_ctx.test_ctx = &test_ctx;
2149+
test_memio_wolfio_ctx.ssl_s = ssl_s;
2150+
/* Large number to error out if any syscalls are called with it */
2151+
test_memio_wolfio_ctx.fd = 6000;
2152+
XMEMSET(&test_memio_wolfio_ctx.peer_addr, 0,
2153+
sizeof(test_memio_wolfio_ctx.peer_addr));
2154+
test_memio_wolfio_ctx.peer_addr.ss_family = AF_INET;
2155+
2156+
wolfSSL_dtls_set_using_nonblock(ssl_s, 1);
2157+
wolfSSL_SetRecvFrom(ssl_s, test_memio_wolfio_recvfrom);
2158+
wolfSSL_SetSendTo(ssl_s, test_memio_wolfio_sendto);
2159+
/* Restore default functions */
2160+
wolfSSL_SSLSetIORecv(ssl_s, EmbedReceiveFrom);
2161+
wolfSSL_SSLSetIOSend(ssl_s, EmbedSendTo);
2162+
ExpectIntEQ(wolfSSL_set_fd(ssl_s, test_memio_wolfio_ctx.fd),
2163+
WOLFSSL_SUCCESS);
2164+
2165+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2166+
2167+
wolfSSL_free(ssl_s);
2168+
wolfSSL_free(ssl_c);
2169+
wolfSSL_CTX_free(ctx_s);
2170+
wolfSSL_CTX_free(ctx_c);
2171+
}
2172+
#endif
2173+
return EXPECT_RESULT();
2174+
}
2175+
2176+
/* DTLS using stateless API handling new addresses with wolfio */
2177+
int test_dtls_memio_wolfio_stateless(void)
2178+
{
2179+
EXPECT_DECLS;
2180+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS)
2181+
size_t i, j;
2182+
struct {
2183+
method_provider client_meth;
2184+
method_provider server_meth;
2185+
} params[] = {
2186+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13)
2187+
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method },
2188+
#endif
2189+
#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_DTLS)
2190+
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method },
2191+
#endif
2192+
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_DTLS)
2193+
{ wolfDTLSv1_client_method, wolfDTLSv1_server_method },
2194+
#endif
2195+
};
2196+
XMEMSET(&test_memio_wolfio_ctx, 0, sizeof(test_memio_wolfio_ctx));
2197+
for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) {
2198+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
2199+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
2200+
struct test_memio_ctx test_ctx;
2201+
char chBuf[1000];
2202+
int chSz = sizeof(chBuf);
2203+
2204+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2205+
2206+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2207+
params[i].client_meth, params[i].server_meth), 0);
2208+
2209+
test_memio_wolfio_ctx.test_ctx = &test_ctx;
2210+
test_memio_wolfio_ctx.ssl_s = ssl_s;
2211+
/* Large number to error out if any syscalls are called with it */
2212+
test_memio_wolfio_ctx.fd = 6000;
2213+
XMEMSET(&test_memio_wolfio_ctx.peer_addr, 0,
2214+
sizeof(test_memio_wolfio_ctx.peer_addr));
2215+
test_memio_wolfio_ctx.peer_addr.ss_family = AF_INET;
2216+
2217+
wolfSSL_dtls_set_using_nonblock(ssl_s, 1);
2218+
wolfSSL_SetRecvFrom(ssl_s, test_memio_wolfio_recvfrom);
2219+
/* Restore default functions */
2220+
wolfSSL_SSLSetIORecv(ssl_s, EmbedReceiveFrom);
2221+
ExpectIntEQ(wolfSSL_set_read_fd(ssl_s, test_memio_wolfio_ctx.fd),
2222+
WOLFSSL_SUCCESS);
2223+
2224+
/* start handshake, send first ClientHello */
2225+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
2226+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
2227+
ExpectIntEQ(test_memio_copy_message(&test_ctx, 0, chBuf, &chSz, 0), 0);
2228+
ExpectIntGT(chSz, 0);
2229+
test_memio_clear_buffer(&test_ctx, 0);
2230+
2231+
/* Send CH from different addresses */
2232+
for (j = 0; j < 10 && !EXPECT_FAIL(); j++,
2233+
(((SOCKADDR_IN*)&test_memio_wolfio_ctx.peer_addr))->sin_port++) {
2234+
const char* hrrBuf = NULL;
2235+
int hrrSz = 0;
2236+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, chBuf, chSz), 0);
2237+
ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0);
2238+
ExpectIntEQ(test_memio_get_message(&test_ctx, 1, &hrrBuf, &hrrSz, 0), 0);
2239+
ExpectNotNull(hrrBuf);
2240+
ExpectIntGT(hrrSz, 0);
2241+
test_memio_clear_buffer(&test_ctx, 0);
2242+
}
2243+
test_memio_clear_buffer(&test_ctx, 1);
2244+
ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1);
2245+
ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0);
2246+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
2247+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
2248+
ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 1);
2249+
2250+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2251+
2252+
wolfSSL_free(ssl_s);
2253+
wolfSSL_free(ssl_c);
2254+
wolfSSL_CTX_free(ctx_s);
2255+
wolfSSL_CTX_free(ctx_c);
2256+
}
2257+
#endif
2258+
return EXPECT_RESULT();
2259+
}

0 commit comments

Comments
 (0)