diff --git a/src/internal.c b/src/internal.c index 4ce862173..b8d90ba63 100755 --- a/src/internal.c +++ b/src/internal.c @@ -3644,7 +3644,10 @@ void SSL_ResourceFree(WOLFSSL* ssl) if (ssl->buffers.outputBuffer.dynamicFlag) ShrinkOutputBuffer(ssl); #ifdef WOLFSSL_DTLS - DtlsPoolDelete(ssl); + if (ssl->dtls_tx_msg_list != NULL) { + DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); + ssl->dtls_tx_msg_list = NULL; + } if (ssl->dtls_msg_list != NULL) { DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap); ssl->dtls_msg_list = NULL; @@ -3810,7 +3813,8 @@ void FreeHandshakeResources(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS /* DTLS_POOL */ if (ssl->options.dtls) { - DtlsPoolDelete(ssl); + DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); + ssl->dtls_tx_msg_list = NULL; DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap); ssl->dtls_msg_list = NULL; } @@ -4033,183 +4037,6 @@ static INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out) #ifdef WOLFSSL_DTLS -int DtlsPoolInit(WOLFSSL* ssl) -{ - if (ssl->dtls_pool == NULL) { - DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool), - ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - if (pool == NULL) { - WOLFSSL_MSG("DTLS Buffer Pool Memory error"); - return MEMORY_E; - } - else { - int i; - - for (i = 0; i < DTLS_POOL_SZ; i++) { - pool->buf[i].length = 0; - pool->buf[i].buffer = NULL; - } - pool->used = 0; - ssl->dtls_pool = pool; - } - } - return 0; -} - - -int DtlsPoolSave(WOLFSSL* ssl, const byte *src, int sz) -{ - DtlsPool *pool = ssl->dtls_pool; - if (src == NULL) { - return BAD_FUNC_ARG; - } - if (pool != NULL && pool->used < DTLS_POOL_SZ) { - buffer *pBuf = &pool->buf[pool->used]; - pBuf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - if (pBuf->buffer == NULL) { - WOLFSSL_MSG("DTLS Buffer Memory error"); - return MEMORY_ERROR; - } - XMEMCPY(pBuf->buffer, src, sz); - pool->epoch[pool->used] = ssl->keys.dtls_epoch; - pBuf->length = (word32)sz; - pool->used++; - } - return 0; -} - - -void DtlsPoolReset(WOLFSSL* ssl) -{ - DtlsPool *pool = ssl->dtls_pool; - if (pool != NULL) { - buffer *pBuf; - int i, used; - - used = pool->used; - for (i = 0, pBuf = &pool->buf[0]; i < used; i++, pBuf++) { - XFREE(pBuf->buffer, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - pBuf->buffer = NULL; - pBuf->length = 0; - } - pool->used = 0; - } - ssl->dtls_timeout = ssl->dtls_timeout_init; -} - - -void DtlsPoolDelete(WOLFSSL* ssl) -{ - if (ssl->dtls_pool != NULL) { - DtlsPoolReset(ssl); - XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); - ssl->dtls_pool = NULL; - } -} - - -int DtlsPoolTimeout(WOLFSSL* ssl) -{ - int result = -1; - if (ssl->dtls_timeout < ssl->dtls_timeout_max) { - ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; - result = 0; - } - return result; -} - -int VerifyForDtlsPoolSend(WOLFSSL* ssl, byte type, word32 fragOffset) -{ - /** - * only the first message from previous flight should be valid - * to be used for triggering retransmission of whole DtlsPool. - * change cipher suite type is not verified here - */ - return ((fragOffset == 0) && - (((ssl->options.side == WOLFSSL_SERVER_END) && - ((type == client_hello) || - ((ssl->options.verifyPeer) && (type == certificate)) || - ((!ssl->options.verifyPeer) && (type == client_key_exchange)))) || - ((ssl->options.side == WOLFSSL_CLIENT_END) && - (type == server_hello)))); -} - -int DtlsPoolSend(WOLFSSL* ssl, byte sendOnlyFirstPacket) -{ - DtlsPool* pool = ssl->dtls_pool; - - if (pool != NULL && pool->used > 0) { - int ret = 0; - int i; - buffer* buf; - /** - * on server side, retranmission is being triggered only by sending - * first message of given flight, in order to trigger client - * to retransmit its whole flight. Sending the whole previous flight - * could lead to retranmission of previous client flight for each - * server message from previous flight. Therefore one message should be - * enough to do the trick. - */ - int maxPoolIndex = (((sendOnlyFirstPacket == 1) && - (ssl->options.side == WOLFSSL_SERVER_END) && - (pool->used >= 1)) ? 1 : pool->used); - - for (i = 0, buf = pool->buf; i < maxPoolIndex; i++, buf++) { - if (pool->epoch[i] == 0) { - DtlsRecordLayerHeader* dtls; - int epochOrder; - - dtls = (DtlsRecordLayerHeader*)buf->buffer; - /* If the stored record's epoch is 0, and the currently set - * epoch is 0, use the "current order" sequence number. - * If the stored record's epoch is 0 and the currently set - * epoch is not 0, the stored record is considered a "previous - * order" sequence number. */ - epochOrder = (ssl->keys.dtls_epoch == 0) ? - CUR_ORDER : PREV_ORDER; - - WriteSEQ(ssl, epochOrder, dtls->sequence_number); - DtlsSEQIncrement(ssl, epochOrder); - if ((ret = CheckAvailableSize(ssl, buf->length)) != 0) - return ret; - - XMEMCPY(ssl->buffers.outputBuffer.buffer, - buf->buffer, buf->length); - ssl->buffers.outputBuffer.idx = 0; - ssl->buffers.outputBuffer.length = buf->length; - } - else if (pool->epoch[i] == ssl->keys.dtls_epoch) { - byte* input; - byte* output; - int inputSz, sendSz; - - input = buf->buffer; - inputSz = buf->length; - sendSz = inputSz + MAX_MSG_EXTRA; - - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; - - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, - handshake, 0, 0); - if (sendSz < 0) - return BUILD_MSG_ERROR; - - ssl->buffers.outputBuffer.length += sendSz; - } - - ret = SendBuffered(ssl); - if (ret < 0) { - return ret; - } - } - } - return 0; -} - - /* functions for managing DTLS datagram reordering */ /* Need to allocate space for the handshake message header. The hashing @@ -4484,6 +4311,157 @@ DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item) return head; } + +/* DtlsMsgPoolSave() adds the message to the end of the stored transmit list. */ +int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) +{ + DtlsMsg* item; + int ret = 0; + + item = DtlsMsgNew(dataSz, ssl->heap); + + if (item != NULL) { + DtlsMsg* cur = ssl->dtls_tx_msg_list; + + XMEMCPY(item->buf, data, dataSz); + item->sz = dataSz; + item->seq = ssl->keys.dtls_epoch; + + if (cur == NULL) + ssl->dtls_tx_msg_list = item; + else { + while (cur->next) + cur = cur->next; + cur->next = item; + } + } + else + ret = MEMORY_E; + + return ret; +} + + +/* DtlsMsgPoolTimeout() updates the timeout time. */ +int DtlsMsgPoolTimeout(WOLFSSL* ssl) +{ + int result = -1; + if (ssl->dtls_timeout < ssl->dtls_timeout_max) { + ssl->dtls_timeout *= DTLS_TIMEOUT_MULTIPLIER; + result = 0; + } + return result; +} + + +/* DtlsMsgPoolReset() deletes the stored transmit list and resets the timeout + * value. */ +void DtlsMsgPoolReset(WOLFSSL* ssl) +{ + DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); + ssl->dtls_tx_msg_list = NULL; + ssl->dtls_timeout = ssl->dtls_timeout_init; +} + + +int VerifyForDtlsMsgPoolSend(WOLFSSL* ssl, byte type, word32 fragOffset) +{ + /** + * only the first message from previous flight should be valid + * to be used for triggering retransmission of whole DtlsPool. + * change cipher suite type is not verified here + */ + return ((fragOffset == 0) && + (((ssl->options.side == WOLFSSL_SERVER_END) && + ((type == client_hello) || + ((ssl->options.verifyPeer) && (type == certificate)) || + ((!ssl->options.verifyPeer) && (type == client_key_exchange)))) || + ((ssl->options.side == WOLFSSL_CLIENT_END) && + (type == server_hello)))); +} + + +/* DtlsMsgPoolSend() will send the stored transmit list. The stored list is + * updated with new sequence numbers, and will be re-encrypted if needed. */ +int DtlsMsgPoolSend(WOLFSSL* ssl, int sendOnlyFirstPacket) +{ + int ret = 0; + DtlsMsg* pool = ssl->dtls_tx_msg_list; + + if (pool != NULL) { + + while (pool != NULL) { + if (pool->seq == 0) { + DtlsRecordLayerHeader* dtls; + int epochOrder; + + dtls = (DtlsRecordLayerHeader*)pool->buf; + /* If the stored record's epoch is 0, and the currently set + * epoch is 0, use the "current order" sequence number. + * If the stored record's epoch is 0 and the currently set + * epoch is not 0, the stored record is considered a "previous + * order" sequence number. */ + epochOrder = (ssl->keys.dtls_epoch == 0) ? + CUR_ORDER : PREV_ORDER; + + WriteSEQ(ssl, epochOrder, dtls->sequence_number); + DtlsSEQIncrement(ssl, epochOrder); + if ((ret = CheckAvailableSize(ssl, pool->sz)) != 0) + return ret; + + XMEMCPY(ssl->buffers.outputBuffer.buffer, + pool->buf, pool->sz); + ssl->buffers.outputBuffer.idx = 0; + ssl->buffers.outputBuffer.length = pool->sz; + } + else if (pool->seq == ssl->keys.dtls_epoch) { + byte* input; + byte* output; + int inputSz, sendSz; + + input = pool->buf; + inputSz = pool->sz; + sendSz = inputSz + MAX_MSG_EXTRA; + + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, + handshake, 0, 0); + if (sendSz < 0) + return BUILD_MSG_ERROR; + + ssl->buffers.outputBuffer.length += sendSz; + } + + ret = SendBuffered(ssl); + if (ret < 0) { + return ret; + } + + /** + * on server side, retranmission is being triggered only by sending + * first message of given flight, in order to trigger client + * to retransmit its whole flight. Sending the whole previous flight + * could lead to retranmission of previous client flight for each + * server message from previous flight. Therefore one message should + * be enough to do the trick. + */ + if (sendOnlyFirstPacket && + ssl->options.side == WOLFSSL_SERVER_END) { + + pool = NULL; + } + else + pool = pool->next; + } + } + + return ret; +} + #endif /* WOLFSSL_DTLS */ #if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) @@ -4963,8 +4941,8 @@ retry: #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl) && !ssl->options.handShakeDone && - DtlsPoolTimeout(ssl) == 0 && - DtlsPoolSend(ssl, 0) == 0) { + DtlsMsgPoolTimeout(ssl) == 0 && + DtlsMsgPoolSend(ssl, 0) == 0) { goto retry; } @@ -8021,8 +7999,11 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, } *inOutIdx += ssl->keys.padSz; } - if (IsDtlsNotSctpMode(ssl) && VerifyForDtlsPoolSend(ssl, type, fragOffset)) - ret = DtlsPoolSend(ssl, 0); + if (IsDtlsNotSctpMode(ssl) && + VerifyForDtlsMsgPoolSend(ssl, type, fragOffset)) { + + ret = DtlsMsgPoolSend(ssl, 0); + } } else if (fragSz < size) { /* Since this branch is in order, but fragmented, dtls_msg_list will be @@ -9382,7 +9363,7 @@ int ProcessReply(WOLFSSL* ssl) ssl->buffers.inputBuffer.idx = 0; if (IsDtlsNotSctpMode(ssl) && ssl->options.dtlsHsRetain) { - ret = DtlsPoolSend(ssl, 0); + ret = DtlsMsgPoolSend(ssl, 0); if (ret != 0) return ret; } @@ -9541,7 +9522,7 @@ int ProcessReply(WOLFSSL* ssl) return ret; if (IsDtlsNotSctpMode(ssl)) { - ret = DtlsPoolSend(ssl, 1); + ret = DtlsMsgPoolSend(ssl, 1); if (ret != 0) return ret; } @@ -9594,7 +9575,7 @@ int ProcessReply(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { - DtlsPoolReset(ssl); + DtlsMsgPoolReset(ssl); ssl->keys.nextEpoch++; ssl->keys.nextSeq_lo = 0; ssl->keys.prevWindow = ssl->keys.window; @@ -9738,7 +9719,7 @@ int SendChangeCipher(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } #endif @@ -10185,7 +10166,7 @@ int SendFinished(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, input, headerSz + finishedSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, input, headerSz + finishedSz)) != 0) return ret; } #endif @@ -10436,7 +10417,7 @@ int SendCertificate(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } #endif @@ -10531,7 +10512,7 @@ int SendCertificateRequest(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } if (ssl->options.dtls) @@ -10637,7 +10618,7 @@ static int BuildCertificateStatus(WOLFSSL* ssl, byte type, buffer* status, #ifdef WOLFSSL_DTLS if (ret == 0 && IsDtlsNotSctpMode(ssl)) - ret = DtlsPoolSave(ssl, output, sendSz); + ret = DtlsMsgPoolSave(ssl, output, sendSz); #endif #ifdef WOLFSSL_CALLBACKS @@ -13076,7 +13057,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } #endif @@ -13111,7 +13092,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { - DtlsPoolReset(ssl); + DtlsMsgPoolReset(ssl); } #endif @@ -13429,7 +13410,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, } #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { - DtlsPoolReset(ssl); + DtlsMsgPoolReset(ssl); } #endif @@ -15602,7 +15583,7 @@ int SendClientKeyExchange(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) { goto exit_scke; } } @@ -16083,7 +16064,7 @@ int SendCertificateVerify(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - ret = DtlsPoolSave(ssl, output, sendSz); + ret = DtlsMsgPoolSave(ssl, output, sendSz); } #endif @@ -16379,7 +16360,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->buffers.outputBuffer.length += sendSz; #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; } @@ -17713,7 +17694,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) { goto exit_sske; } } @@ -18935,7 +18916,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return 0; } @@ -19157,7 +19138,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + if ((ret = DtlsMsgPoolSave(ssl, output, sendSz)) != 0) return ret; DtlsSEQIncrement(ssl, CUR_ORDER); diff --git a/src/ssl.c b/src/ssl.c index 3291d24af..3babee741 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -6750,7 +6750,7 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) int result = SSL_SUCCESS; if (!ssl->options.handShakeDone && - (DtlsPoolTimeout(ssl) < 0 || DtlsPoolSend(ssl, 0) < 0)) { + (DtlsMsgPoolTimeout(ssl) < 0 || DtlsMsgPoolSend(ssl, 0) < 0)) { result = SSL_FATAL_ERROR; } @@ -6923,12 +6923,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, ssl->options.dtls = 1; ssl->options.tls = 1; ssl->options.tls1_1 = 1; - - if (DtlsPoolInit(ssl) != 0) { - ssl->error = MEMORY_ERROR; - WOLFSSL_ERROR(ssl->error); - return SSL_FATAL_ERROR; - } } #endif @@ -7285,12 +7279,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, ssl->options.dtls = 1; ssl->options.tls = 1; ssl->options.tls1_1 = 1; - - if (DtlsPoolInit(ssl) != 0) { - ssl->error = MEMORY_ERROR; - WOLFSSL_ERROR(ssl->error); - return SSL_FATAL_ERROR; - } } #endif diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d51fb23a3..31419e9d0 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2584,13 +2584,6 @@ typedef struct DtlsRecordLayerHeader { } DtlsRecordLayerHeader; -typedef struct DtlsPool { - buffer buf[DTLS_POOL_SZ]; - word16 epoch[DTLS_POOL_SZ]; - int used; -} DtlsPool; - - typedef struct DtlsFrag { word32 begin; word32 end; @@ -2758,7 +2751,7 @@ struct WOLFSSL { int dtls_timeout_init; /* starting timeout value */ int dtls_timeout_max; /* maximum timeout value */ int dtls_timeout; /* current timeout value, changes */ - DtlsPool* dtls_pool; + DtlsMsg* dtls_tx_msg_list; DtlsMsg* dtls_msg_list; void* IOCB_CookieCtx; /* gen cookie ctx */ word32 dtls_expected_rx; @@ -3070,14 +3063,6 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); #endif /* NO_WOLFSSL_SERVER */ #ifdef WOLFSSL_DTLS - WOLFSSL_LOCAL int DtlsPoolInit(WOLFSSL*); - WOLFSSL_LOCAL int DtlsPoolSave(WOLFSSL*, const byte*, int); - WOLFSSL_LOCAL int DtlsPoolTimeout(WOLFSSL*); - WOLFSSL_LOCAL int DtlsPoolSend(WOLFSSL*, byte); - WOLFSSL_LOCAL int VerifyForDtlsPoolSend(WOLFSSL*, byte, word32); - WOLFSSL_LOCAL void DtlsPoolReset(WOLFSSL*); - WOLFSSL_LOCAL void DtlsPoolDelete(WOLFSSL*); - WOLFSSL_LOCAL DtlsMsg* DtlsMsgNew(word32, void*); WOLFSSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*); WOLFSSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*); @@ -3087,6 +3072,12 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); WOLFSSL_LOCAL DtlsMsg* DtlsMsgStore(DtlsMsg*, word32, const byte*, word32, byte, word32, word32, void*); WOLFSSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*); + + WOLFSSL_LOCAL int DtlsMsgPoolSave(WOLFSSL*, const byte*, word32); + WOLFSSL_LOCAL int DtlsMsgPoolTimeout(WOLFSSL*); + WOLFSSL_LOCAL int VerifyForDtlsMsgPoolSend(WOLFSSL*, byte, word32); + WOLFSSL_LOCAL void DtlsMsgPoolReset(WOLFSSL*); + WOLFSSL_LOCAL int DtlsMsgPoolSend(WOLFSSL*, int); #endif /* WOLFSSL_DTLS */ #ifndef NO_TLS