From d3e248855266e592e3edc5f4907f73a2c4fcb48c Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 5 Dec 2018 15:54:46 -0800 Subject: [PATCH 1/7] DTLS Resume Fix 1. In DTLS, when transmitting the Change Cipher Spec message increment the sequence number. 2. In DTLS, when client receives the CCS message, sanity check that the server hello has been received in the case of resume. --- src/internal.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/internal.c b/src/internal.c index 6a231e3063..ca7c0c78d8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10551,10 +10551,17 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) #ifndef NO_WOLFSSL_CLIENT if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (!ssl->options.resuming && - ssl->msgsReceived.got_server_hello_done == 0) { - WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); - return OUT_OF_ORDER_E; + if (!ssl->options.resuming) { + if (ssl->msgsReceived.got_server_hello_done == 0) { + WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); + return OUT_OF_ORDER_E; + } + } + else { + if (ssl->msgsReceived.got_server_hello == 0) { + WOLFSSL_MSG("No ServerHello before ChangeCipher on Resume"); + return OUT_OF_ORDER_E; + } } #ifdef HAVE_SESSION_TICKET if (ssl->expect_session_ticket) { @@ -13446,6 +13453,7 @@ int SendChangeCipher(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { + DtlsSEQIncrement(ssl, CUR_ORDER); if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } From 91d81ea691a00f4ecce7a21e7f274c2646225474 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 10 Dec 2018 16:51:43 -0800 Subject: [PATCH 2/7] Add some more debug logging for DTLS retransmission support. --- src/internal.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- src/ssl.c | 5 +++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/internal.c b/src/internal.c index ca7c0c78d8..3082e3bf58 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6003,8 +6003,12 @@ int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) DtlsMsg* item; int ret = 0; - if (ssl->dtls_tx_msg_list_sz > DTLS_POOL_SZ) + WOLFSSL_ENTER("DtlsMsgPoolSave()"); + + if (ssl->dtls_tx_msg_list_sz > DTLS_POOL_SZ) { + WOLFSSL_ERROR(DTLS_POOL_SZ_E); return DTLS_POOL_SZ_E; + } item = DtlsMsgNew(dataSz, ssl->heap); @@ -6027,6 +6031,7 @@ int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) else ret = MEMORY_E; + WOLFSSL_LEAVE("DtlsMsgPoolSave()", ret); return ret; } @@ -6039,6 +6044,7 @@ int DtlsMsgPoolTimeout(WOLFSSL* ssl) ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; result = 0; } + WOLFSSL_LEAVE("DtlsMsgPoolTimeout()", result); return result; } @@ -6047,6 +6053,7 @@ int DtlsMsgPoolTimeout(WOLFSSL* ssl) * value. */ void DtlsMsgPoolReset(WOLFSSL* ssl) { + WOLFSSL_ENTER("DtlsMsgPoolReset()"); if (ssl->dtls_tx_msg_list) { DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); ssl->dtls_tx_msg_list = NULL; @@ -6080,6 +6087,8 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) int ret = 0; DtlsMsg* pool = ssl->dtls_tx_msg_list; + WOLFSSL_ENTER("DtlsMsgPoolSend()"); + if (pool != NULL) { while (pool != NULL) { @@ -6098,8 +6107,10 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) WriteSEQ(ssl, epochOrder, dtls->sequence_number); DtlsSEQIncrement(ssl, epochOrder); - if ((ret = CheckAvailableSize(ssl, pool->sz)) != 0) + if ((ret = CheckAvailableSize(ssl, pool->sz)) != 0) { + WOLFSSL_ERROR(ret); return ret; + } XMEMCPY(ssl->buffers.outputBuffer.buffer, pool->buf, pool->sz); @@ -6115,21 +6126,26 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) inputSz = pool->sz; sendSz = inputSz + MAX_MSG_EXTRA; - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + WOLFSSL_ERROR(ret); return ret; + } output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.length; sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, handshake, 0, 0, 0); - if (sendSz < 0) + if (sendSz < 0) { + WOLFSSL_ERROR(BUILD_MSG_ERROR); return BUILD_MSG_ERROR; + } ssl->buffers.outputBuffer.length += sendSz; } ret = SendBuffered(ssl); if (ret < 0) { + WOLFSSL_ERROR(ret); return ret; } @@ -6151,6 +6167,7 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) } } + WOLFSSL_LEAVE("DtlsMsgPoolSend()", ret); return ret; } @@ -7094,6 +7111,7 @@ static int GetRecordHeader(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (IsDtlsNotSctpMode(ssl) && (!DtlsCheckWindow(ssl) || (ssl->options.handShakeDone && ssl->keys.curEpoch == 0))) { + WOLFSSL_LEAVE("GetRecordHeader()", SEQUENCE_ERROR); return SEQUENCE_ERROR; } #endif @@ -7186,8 +7204,10 @@ static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input, word32 idx = *inOutIdx; *inOutIdx += HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA; - if (*inOutIdx > totalSz) + if (*inOutIdx > totalSz) { + WOLFSSL_ERROR(BUFFER_E); return BUFFER_E; + } *type = input[idx++]; c24to32(input + idx, size); @@ -7203,8 +7223,10 @@ static int GetDtlsHandShakeHeader(WOLFSSL* ssl, const byte* input, if (ssl->curRL.pvMajor != ssl->version.major || ssl->curRL.pvMinor != ssl->version.minor) { - if (*type != client_hello && *type != hello_verify_request) + if (*type != client_hello && *type != hello_verify_request) { + WOLFSSL_ERROR(VERSION_ERROR); return VERSION_ERROR; + } else { WOLFSSL_MSG("DTLS Handshake ignoring hello or verify version"); } @@ -11247,6 +11269,8 @@ static int DtlsMsgDrain(WOLFSSL* ssl) DtlsMsg* item = ssl->dtls_rx_msg_list; int ret = 0; + WOLFSSL_ENTER("DtlsMsgDrain()"); + /* While there is an item in the store list, and it is the expected * message, and it is complete, and there hasn't been an error in the * last message... */ @@ -11270,6 +11294,7 @@ static int DtlsMsgDrain(WOLFSSL* ssl) ssl->dtls_rx_msg_list_sz--; } + WOLFSSL_LEAVE("DtlsMsgDrain()", ret); return ret; } @@ -11297,12 +11322,16 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* parse header */ if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, - &size, &fragOffset, &fragSz, totalSz) != 0) + &size, &fragOffset, &fragSz, totalSz) != 0) { + WOLFSSL_ERROR(PARSE_ERROR); return PARSE_ERROR; + } /* check that we have complete fragment */ - if (*inOutIdx + fragSz > totalSz) + if (*inOutIdx + fragSz > totalSz) { + WOLFSSL_ERROR(INCOMPLETE_DATA); return INCOMPLETE_DATA; + } /* Check the handshake sequence number first. If out of order, * add the current message to the list. If the message is in order, @@ -11347,6 +11376,7 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, *inOutIdx += fragSz; if(type == finished ) { if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); return BUFFER_E; } *inOutIdx += ssl->keys.padSz; @@ -13177,8 +13207,10 @@ int ProcessReply(WOLFSSL* ssl) ret = BUFFER_ERROR; #endif } - if (ret != 0) + if (ret != 0) { + WOLFSSL_ERROR(ret); return ret; + } break; case change_cipher_spec: diff --git a/src/ssl.c b/src/ssl.c index 0111613671..1757b3fa5a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8768,6 +8768,8 @@ int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) int timeout = 0; if (ssl) timeout = ssl->dtls_timeout; + + WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout()", timeout); return timeout; } @@ -8810,6 +8812,7 @@ int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) { int result = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_dtls_got_timeout()"); if (ssl == NULL) return WOLFSSL_FATAL_ERROR; @@ -8819,6 +8822,8 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) result = WOLFSSL_FATAL_ERROR; } + + WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout()", result); return result; } From 63f6c1d280228ac377c5cdd0bb53e14061e8dde9 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 13 Dec 2018 15:23:29 -0800 Subject: [PATCH 3/7] DTLS Nonblocking Updates 1. Add error code for trying to retransmit a flight when transmitting the flight hasn't finished. 2. Add function to retransmit the stored flight without updating the timeout count. --- src/internal.c | 3 +++ src/ssl.c | 21 +++++++++++++++++++++ wolfssl/error-ssl.h | 1 + wolfssl/ssl.h | 1 + 4 files changed, 26 insertions(+) diff --git a/src/internal.c b/src/internal.c index 3082e3bf58..dc3e0d7d68 100644 --- a/src/internal.c +++ b/src/internal.c @@ -15836,6 +15836,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case EXT_MISSING: return "Required TLS extension missing"; + case DTLS_RETX_OVER_TX: + return "DTLS interrupting flight transmit with retransmit"; + default : return "unknown error number"; } diff --git a/src/ssl.c b/src/ssl.c index 1757b3fa5a..755fe567aa 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -8827,6 +8827,27 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) return result; } + +/* retransmit all the saves messages, WOLFSSL_SUCCESS on ok */ +int wolfSSL_dtls_retransmit(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_retransmit()"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (!ssl->options.handShakeDone) { + int result = DtlsMsgPoolSend(ssl, 0); + if (result < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + } + + return 0; +} + #endif /* DTLS */ #endif /* LEANPSK */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 1fd9520f31..827ae0272c 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -163,6 +163,7 @@ enum wolfSSL_ErrorCodes { EXT_MISSING = -428, /* Required extension not found */ UNSUPPORTED_EXTENSION = -429, /* TLSX not requested by client */ PRF_MISSING = -430, /* PRF not compiled in */ + DTLS_RETX_OVER_TX = -431, /* Retransmit DTLS flight over */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 8986804534..75a4b95589 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -723,6 +723,7 @@ WOLFSSL_API int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int); WOLFSSL_API int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int); WOLFSSL_API int wolfSSL_dtls_got_timeout(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_dtls_retransmit(WOLFSSL*); WOLFSSL_API int wolfSSL_dtls(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_dtls_set_peer(WOLFSSL*, void*, unsigned int); From 8356c3d7e20ba153d65cbd9ba4789e19af1ef140 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 14 Dec 2018 11:30:03 -0800 Subject: [PATCH 4/7] DTLS Nonblocking Updates 1. Add a second select for tx. 2. Revised tcp_select to work for either rx or tx. 3. Updated client and server to use new tcp_select_tx() for checking the tx socket if the nonblocking connect/accept would block on transmit. --- examples/client/client.c | 20 +++++++++++++++----- examples/server/server.c | 19 ++++++++++++++----- wolfssl/test.h | 41 +++++++++++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 35a61f05c8..3aba5f4587 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -138,13 +138,16 @@ static int NonBlockingSSL_Connect(WOLFSSL* ssl) else #endif { - #ifdef WOLFSSL_DTLS - currTimeout = wolfSSL_dtls_get_current_timeout(ssl); - #endif - select_ret = tcp_select(sockfd, currTimeout); + if (error != WOLFSSL_ERROR_WANT_WRITE) { + #ifdef WOLFSSL_DTLS + currTimeout = wolfSSL_dtls_get_current_timeout(ssl); + #endif + select_ret = tcp_select(sockfd, currTimeout); + } } - if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_ERROR_READY) + if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_SEND_READY) + || (select_ret == TEST_ERROR_READY) #ifdef WOLFSSL_ASYNC_CRYPT || error == WC_PENDING_E #endif @@ -156,6 +159,13 @@ static int NonBlockingSSL_Connect(WOLFSSL* ssl) #endif error = wolfSSL_get_error(ssl, 0); elapsedSec = 0; /* reset elapsed */ + if (error == WOLFSSL_ERROR_WANT_WRITE) { + /* Do a send select here. */ + select_ret = tcp_select_tx(sockfd, 1); + if (select_ret == TEST_TIMEOUT) { + error = WOLFSSL_FATAL_ERROR; + } + } } else if (select_ret == TEST_TIMEOUT && !wolfSSL_dtls(ssl)) { error = WOLFSSL_ERROR_WANT_READ; diff --git a/examples/server/server.c b/examples/server/server.c index a64f2cfda4..1e8695fbbd 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -149,13 +149,16 @@ static int NonBlockingSSL_Accept(SSL* ssl) else #endif { - #ifdef WOLFSSL_DTLS - currTimeout = wolfSSL_dtls_get_current_timeout(ssl); - #endif - select_ret = tcp_select(sockfd, currTimeout); + if (error != WOLFSSL_ERROR_WANT_WRITE) { + #ifdef WOLFSSL_DTLS + currTimeout = wolfSSL_dtls_get_current_timeout(ssl); + #endif + select_ret = tcp_select(sockfd, currTimeout); + } } - if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_ERROR_READY) + if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_SEND_READY) + || (select_ret == TEST_ERROR_READY) #ifdef WOLFSSL_ASYNC_CRYPT || error == WC_PENDING_E #endif @@ -167,6 +170,12 @@ static int NonBlockingSSL_Accept(SSL* ssl) srvHandShakeCB, srvTimeoutCB, srvTo); #endif error = SSL_get_error(ssl, 0); + if (error == WOLFSSL_ERROR_WANT_WRITE) { + /* Do a select here. */ + select_ret = tcp_select_tx(sockfd, 1); + if (select_ret == TEST_TIMEOUT) + error = WOLFSSL_FATAL_ERROR; + } } else if (select_ret == TEST_TIMEOUT && !wolfSSL_dtls(ssl)) { error = WOLFSSL_ERROR_WANT_READ; diff --git a/wolfssl/test.h b/wolfssl/test.h index 1c61f23af7..a9cc4e8681 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -909,15 +909,18 @@ enum { TEST_SELECT_FAIL, TEST_TIMEOUT, TEST_RECV_READY, + TEST_SEND_READY, TEST_ERROR_READY }; #if !defined(WOLFSSL_MDK_ARM) && !defined(WOLFSSL_KEIL_TCP_NET) && \ !defined(WOLFSSL_TIRTOS) -static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) +static WC_INLINE int tcp_select_ex(SOCKET_T socketfd, int to_sec, int rx) { - fd_set recvfds, errfds; + fd_set fds, errfds; + fd_set* recvfds = NULL; + fd_set* sendfds = NULL; SOCKET_T nfds = socketfd + 1; #if !defined(__INTEGRITY) struct timeval timeout = {(to_sec > 0) ? to_sec : 0, 0}; @@ -926,32 +929,56 @@ static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) #endif int result; - FD_ZERO(&recvfds); - FD_SET(socketfd, &recvfds); + FD_ZERO(&fds); + FD_SET(socketfd, &fds); FD_ZERO(&errfds); FD_SET(socketfd, &errfds); + if (rx) + recvfds = &fds; + else + sendfds = &fds; + #if defined(__INTEGRITY) timeout.tv_sec = (long long)(to_sec > 0) ? to_sec : 0, 0; #endif - result = select(nfds, &recvfds, NULL, &errfds, &timeout); + result = select(nfds, recvfds, sendfds, &errfds, &timeout); if (result == 0) return TEST_TIMEOUT; else if (result > 0) { - if (FD_ISSET(socketfd, &recvfds)) - return TEST_RECV_READY; + if (FD_ISSET(socketfd, &fds)) { + if (rx) + return TEST_RECV_READY; + else + return TEST_SEND_READY; + } else if(FD_ISSET(socketfd, &errfds)) return TEST_ERROR_READY; } return TEST_SELECT_FAIL; } + +static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) +{ + return tcp_select_ex(socketfd, to_sec, 1); +} + +static WC_INLINE int tcp_select_tx(SOCKET_T socketfd, int to_sec) +{ + return tcp_select_ex(socketfd, to_sec, 0); +} + #elif defined(WOLFSSL_TIRTOS) || defined(WOLFSSL_KEIL_TCP_NET) static WC_INLINE int tcp_select(SOCKET_T socketfd, int to_sec) { return TEST_RECV_READY; } +static WC_INLINE int tcp_select_tx(SOCKET_T socketfd, int to_sec) +{ + return TEST_SEND_READY; +} #endif /* !WOLFSSL_MDK_ARM */ From aa4de6e17071f641a7d7aafb128c0128574b5334 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 17 Dec 2018 15:40:35 -0800 Subject: [PATCH 5/7] DTLS Nonblocking Updates Do not allow the DTLS message flight be retransmit without being finished. This can happen if a non-blocking transmit times out the response and the application tries to retransmit. --- src/internal.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/internal.c b/src/internal.c index dc3e0d7d68..5f5a56cb08 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6090,6 +6090,18 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) WOLFSSL_ENTER("DtlsMsgPoolSend()"); if (pool != NULL) { + if ((ssl->options.side == WOLFSSL_SERVER_END && + !(ssl->options.acceptState == SERVER_HELLO_DONE || + ssl->options.acceptState == ACCEPT_FINISHED_DONE)) || + (ssl->options.side == WOLFSSL_CLIENT_END && + !(ssl->options.connectState == CLIENT_HELLO_SENT || + ssl->options.connectState == HELLO_AGAIN_REPLY || + ssl->options.connectState == FINISHED_DONE))) { + + WOLFSSL_ERROR(DTLS_RETX_OVER_TX); + ssl->error = DTLS_RETX_OVER_TX; + return WOLFSSL_FATAL_ERROR; + } while (pool != NULL) { if (pool->seq == 0) { From cc3c2ef6836f2831a1125fc573ee57ffb5f9b9c5 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 18 Dec 2018 11:40:04 -0800 Subject: [PATCH 6/7] DTLS Nonblocking Updates Add command line option to the example server to fake a write block on a specified DTLS sequence number in epoch 0. --- examples/server/server.c | 171 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 3 deletions(-) diff --git a/examples/server/server.c b/examples/server/server.c index 1e8695fbbd..105ac547dd 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -115,6 +115,138 @@ static void err_sys_ex(int out, const char* msg) } } + +#ifdef WOLFSSL_DTLS + +/* Translates return codes returned from + * send() and recv() if need be. + */ +static WC_INLINE int TranslateReturnCode(int old, int sd) +{ + (void)sd; + +#if defined(FREESCALE_MQX) || defined(FREESCALE_KSDK_MQX) + if (old == 0) { + errno = SOCKET_EWOULDBLOCK; + return -1; /* convert to BSD style wouldblock as error */ + } + + if (old < 0) { + errno = RTCS_geterror(sd); + if (errno == RTCSERR_TCP_CONN_CLOSING) + return 0; /* convert to BSD style closing */ + if (errno == RTCSERR_TCP_CONN_RLSD) + errno = SOCKET_ECONNRESET; + if (errno == RTCSERR_TCP_TIMED_OUT) + errno = SOCKET_EAGAIN; + } +#endif + + return old; +} + +static WC_INLINE int wolfSSL_LastError(void) +{ +#ifdef USE_WINDOWS_API + return WSAGetLastError(); +#elif defined(EBSNET) + return xn_getlasterror(); +#else + return errno; +#endif +} + +/* wolfSSL Sock Addr */ +struct WOLFSSL_TEST_SOCKADDR { + unsigned int sz; /* sockaddr size */ + SOCKADDR_IN_T sa; /* pointer to the sockaddr_in or sockaddr_in6 */ +}; + +typedef struct WOLFSSL_TEST_DTLS_CTX { + struct WOLFSSL_TEST_SOCKADDR peer; + int rfd; + int wfd; + int failOnce; + word32 blockSeq; +} WOLFSSL_TEST_DTLS_CTX; + + +static WC_INLINE int PeekSeq(const char* buf, word32* seq) +{ + const char* c = buf + 3; + + if ((c[0] | c[1] | c[2] | c[3]) == 0) { + *seq = (c[4] << 24) | (c[5] << 16) | (c[6] << 8) | c[7]; + return 1; + } + + return 0; +} + + +/* The send embedded callback + * return : nb bytes sent, or error + */ +static int TestEmbedSendTo(WOLFSSL* ssl, char *buf, int sz, void *ctx) +{ + WOLFSSL_TEST_DTLS_CTX* dtlsCtx = (WOLFSSL_TEST_DTLS_CTX*)ctx; + int sd = dtlsCtx->wfd; + int sent; + int len = sz; + int err; + + (void)ssl; + + WOLFSSL_ENTER("TestEmbedSendTo()"); + + if (dtlsCtx->failOnce) { + word32 seq = 0; + + if (PeekSeq(buf, &seq) && seq == dtlsCtx->blockSeq) { + dtlsCtx->failOnce = 0; + WOLFSSL_MSG("Forcing WANT_WRITE"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + } + + sent = (int)sendto(sd, &buf[sz - len], len, 0, + (const SOCKADDR*)&dtlsCtx->peer.sa, + dtlsCtx->peer.sz); + + sent = TranslateReturnCode(sent, sd); + + if (sent < 0) { + err = wolfSSL_LastError(); + WOLFSSL_MSG("Embed Send To error"); + + if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { + WOLFSSL_MSG("\tWould Block"); + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + else if (err == SOCKET_ECONNRESET) { + WOLFSSL_MSG("\tConnection reset"); + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (err == SOCKET_EINTR) { + WOLFSSL_MSG("\tSocket interrupted"); + return WOLFSSL_CBIO_ERR_ISR; + } + else if (err == SOCKET_EPIPE) { + WOLFSSL_MSG("\tSocket EPIPE"); + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + WOLFSSL_MSG("\tGeneral error"); + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return sent; +} + +#endif /* WOLFSSL_DTLS */ + + static int NonBlockingSSL_Accept(SSL* ssl) { #ifndef WOLFSSL_CALLBACKS @@ -687,6 +819,9 @@ static void Usage(void) !defined(HAVE_SELFTEST) && !defined(WOLFSSL_OLD_PRIME_CHECK) printf("-2 Disable DH Prime check\n"); #endif +#ifdef WOLFSSL_DTLS + printf("-4 DTLS fake would-block for message seq\n"); +#endif #ifdef WOLFSSL_MULTICAST printf("%s", msg[++msgId]); /* -3 */ #endif @@ -728,6 +863,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) int dtlsUDP = 0; int dtlsSCTP = 0; int doMcast = 0; +#ifdef WOLFSSL_DTLS + int doBlockSeq = 0; + WOLFSSL_TEST_DTLS_CTX dtlsCtx; +#endif int needDH = 0; int useNtruKey = 0; int nonBlocking = 0; @@ -872,7 +1011,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) while ((ch = mygetopt(argc, argv, "?" "abc:defgijk:l:mnop:q:rstuv:wxy" "A:B:C:D:E:GH:IJKL:MNO:PQR:S:TUVYZ:" - "01:23:")) != -1) { + "01:23:4:")) != -1) { switch (ch) { case '?' : if(myoptarg!=NULL) { @@ -1228,6 +1367,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif break; + case '4' : + #ifdef WOLFSSL_DTLS + XMEMSET(&dtlsCtx, 0, sizeof(dtlsCtx)); + doBlockSeq = 1; + dtlsCtx.blockSeq = atoi(myoptarg); + #endif + break; + default: Usage(); XEXIT_T(MY_EX_USAGE); @@ -1607,6 +1754,14 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif } + if (doDTLS && dtlsUDP) { +#ifdef WOLFSSL_DTLS + if (doBlockSeq) { + wolfSSL_CTX_SetIOSend(ctx, TestEmbedSendTo); + } +#endif + } + #ifdef HAVE_PK_CALLBACKS if (pkCallbacks) SetupPkCallbacks(ctx); @@ -1816,12 +1971,22 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) /* For DTLS, peek at the next datagram so we can get the client's * address and set it into the ssl object later to generate the * cookie. */ - n = (int)recvfrom(sockfd, (char*)b, sizeof(b), MSG_PEEK, + n = (int)recvfrom(clientfd, (char*)b, sizeof(b), MSG_PEEK, (struct sockaddr*)&cliaddr, &len); if (n <= 0) err_sys_ex(runWithErrors, "recvfrom failed"); - wolfSSL_dtls_set_peer(ssl, &cliaddr, len); + if (doBlockSeq) { + XMEMCPY(&dtlsCtx.peer.sa, &cliaddr, len); + dtlsCtx.peer.sz = len; + dtlsCtx.wfd = clientfd; + dtlsCtx.failOnce = 1; + + wolfSSL_SetIOWriteCtx(ssl, &dtlsCtx); + } + else { + wolfSSL_dtls_set_peer(ssl, &cliaddr, len); + } } #endif if ((usePsk == 0 || usePskPlus) || useAnon == 1 || cipherList != NULL From c282f5b7263d28fc19d995932214707487321644 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 18 Dec 2018 16:19:52 -0800 Subject: [PATCH 7/7] DTLS Nonblocking Updates Modify the DtlsMsgPoolSend() function to keep track of the last message retransmit. If a write would block, it allows the retransmit pick up where it left off. --- src/internal.c | 6 +++++- wolfssl/internal.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 5f5a56cb08..4bf2cbe0f6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6057,6 +6057,7 @@ void DtlsMsgPoolReset(WOLFSSL* ssl) if (ssl->dtls_tx_msg_list) { DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); ssl->dtls_tx_msg_list = NULL; + ssl->dtls_tx_msg = NULL; ssl->dtls_tx_msg_list_sz = 0; ssl->dtls_timeout = ssl->dtls_timeout_init; } @@ -6085,10 +6086,12 @@ int VerifyForDtlsMsgPoolSend(WOLFSSL* ssl, byte type, word32 fragOffset) int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) { int ret = 0; - DtlsMsg* pool = ssl->dtls_tx_msg_list; + DtlsMsg* pool; WOLFSSL_ENTER("DtlsMsgPoolSend()"); + pool = ssl->dtls_tx_msg == NULL ? ssl->dtls_tx_msg_list : ssl->dtls_tx_msg; + if (pool != NULL) { if ((ssl->options.side == WOLFSSL_SERVER_END && !(ssl->options.acceptState == SERVER_HELLO_DONE || @@ -6176,6 +6179,7 @@ int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) } else pool = pool->next; + ssl->dtls_tx_msg = pool; } } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a03e86f8cb..a22c367023 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3741,6 +3741,7 @@ struct WOLFSSL { word32 dtls_tx_msg_list_sz; word32 dtls_rx_msg_list_sz; DtlsMsg* dtls_tx_msg_list; + DtlsMsg* dtls_tx_msg; DtlsMsg* dtls_rx_msg_list; void* IOCB_CookieCtx; /* gen cookie ctx */ word32 dtls_expected_rx;