From 30752693264e90815bb36fa23d49b27d5cdd1833 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 28 Oct 2016 10:58:49 -0700 Subject: [PATCH 1/3] Replace the DTLS MsgPool for saving transmit handshake messages with the DTLS MsgList. --- src/internal.c | 381 +++++++++++++++++++++------------------------ src/ssl.c | 14 +- wolfssl/internal.h | 23 +-- 3 files changed, 189 insertions(+), 229 deletions(-) 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 From ffe905afbfbb9eed6a19b0759bc2e4252498bec0 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 31 Oct 2016 12:49:09 -0700 Subject: [PATCH 2/3] Moved the checks for the new session ticket and certificate verify messages from the change cipher spec handler to the sanity check handshake message function. It provides support for DTLS missing and duplicate messages. --- src/internal.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/internal.c b/src/internal.c index b8d90ba63..e82201d82 100755 --- a/src/internal.c +++ b/src/internal.c @@ -7503,6 +7503,16 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_MSG("No ServerHelloDone before ChangeCipher"); return OUT_OF_ORDER_E; } + #ifdef HAVE_SESSION_TICKET + if (ssl->expect_session_ticket) { + WOLFSSL_MSG("Expected session ticket missing"); + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + return OUT_OF_ORDER_E; + #endif + return SESSION_TICKET_EXPECT_E; + } + #endif } #endif #ifndef NO_WOLFSSL_SERVER @@ -7512,6 +7522,20 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type) WOLFSSL_MSG("No ClientKeyExchange before ChangeCipher"); return OUT_OF_ORDER_E; } + #ifndef NO_CERTS + if (ssl->options.verifyPeer && + ssl->options.havePeerCert) { + + if (!ssl->options.havePeerVerify) { + WOLFSSL_MSG("client didn't send cert verify"); + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + return OUT_OF_ORDER_E; + #endif + return NO_PEER_VERIFY; + } + } + #endif } #endif if (ssl->options.dtls) @@ -9538,14 +9562,6 @@ int ProcessReply(WOLFSSL* ssl) } } -#ifdef HAVE_SESSION_TICKET - if (ssl->options.side == WOLFSSL_CLIENT_END && - ssl->expect_session_ticket) { - WOLFSSL_MSG("Expected session ticket missing"); - return SESSION_TICKET_EXPECT_E; - } -#endif - if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) { ssl->buffers.inputBuffer.idx += ssl->keys.padSz; ssl->curSize -= (word16) ssl->buffers.inputBuffer.idx; @@ -9555,16 +9571,6 @@ int ProcessReply(WOLFSSL* ssl) WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg"); return LENGTH_ERROR; } - #ifndef NO_CERTS - if (ssl->options.side == WOLFSSL_SERVER_END && - ssl->options.verifyPeer && - ssl->options.havePeerCert) - if (!ssl->options.havePeerVerify) { - WOLFSSL_MSG("client didn't send cert verify"); - return NO_PEER_VERIFY; - } - #endif - ssl->buffers.inputBuffer.idx++; ssl->keys.encryptionOn = 1; From a3ea8378ec3fa078febb45df05ef580d22f713e0 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 1 Nov 2016 18:10:35 -0700 Subject: [PATCH 3/3] Cap the size of the transmit and receive DTLS message lists at 255. --- src/internal.c | 90 +++++++++++++++++++++++++++------------------ wolfssl/error-ssl.h | 1 + wolfssl/internal.h | 8 ++-- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/src/internal.c b/src/internal.c index e82201d82..f64b56dd4 100755 --- a/src/internal.c +++ b/src/internal.c @@ -3644,13 +3644,11 @@ void SSL_ResourceFree(WOLFSSL* ssl) if (ssl->buffers.outputBuffer.dynamicFlag) ShrinkOutputBuffer(ssl); #ifdef WOLFSSL_DTLS - 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; + DtlsMsgPoolReset(ssl); + if (ssl->dtls_rx_msg_list != NULL) { + DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); + ssl->dtls_rx_msg_list = NULL; + ssl->dtls_rx_msg_list_sz = 0; } XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); ssl->buffers.dtlsCtx.peer.sa = NULL; @@ -3813,10 +3811,10 @@ void FreeHandshakeResources(WOLFSSL* ssl) #ifdef WOLFSSL_DTLS /* DTLS_POOL */ if (ssl->options.dtls) { - 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; + DtlsMsgPoolReset(ssl); + DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); + ssl->dtls_rx_msg_list = NULL; + ssl->dtls_rx_msg_list_sz = 0; } #endif @@ -4230,10 +4228,9 @@ DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq) } -DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, +void DtlsMsgStore(WOLFSSL* ssl, word32 seq, const byte* data, word32 dataSz, byte type, word32 fragOffset, word32 fragSz, void* heap) { - /* See if seq exists in the list. If it isn't in the list, make * a new item of size dataSz, copy fragSz bytes from data to msg->msg * starting at offset fragOffset, and add fragSz to msg->fragSz. If @@ -4251,6 +4248,8 @@ DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, * belongs without overlaps. */ + DtlsMsg* head = ssl->dtls_rx_msg_list; + if (head != NULL) { DtlsMsg* cur = DtlsMsgFind(head, seq); if (cur == NULL) { @@ -4259,9 +4258,11 @@ DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, if (DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz, heap) < 0) { DtlsMsgDelete(cur, heap); - return head; } - head = DtlsMsgInsert(head, cur); + else { + ssl->dtls_rx_msg_list_sz++; + head = DtlsMsgInsert(head, cur); + } } } else { @@ -4273,11 +4274,14 @@ DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, head = DtlsMsgNew(dataSz, heap); if (DtlsMsgSet(head, seq, data, type, fragOffset, fragSz, heap) < 0) { DtlsMsgDelete(head, heap); - return NULL; + head = NULL; + } + else { + ssl->dtls_rx_msg_list_sz++; } } - return head; + ssl->dtls_rx_msg_list = head; } @@ -4318,6 +4322,9 @@ int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) DtlsMsg* item; int ret = 0; + if (ssl->dtls_tx_msg_list_sz > DTLS_POOL_SZ) + return DTLS_POOL_SZ_E; + item = DtlsMsgNew(dataSz, ssl->heap); if (item != NULL) { @@ -4334,6 +4341,7 @@ int DtlsMsgPoolSave(WOLFSSL* ssl, const byte* data, word32 dataSz) cur = cur->next; cur->next = item; } + ssl->dtls_tx_msg_list_sz++; } else ret = MEMORY_E; @@ -4358,9 +4366,12 @@ int DtlsMsgPoolTimeout(WOLFSSL* ssl) * 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; + if (ssl->dtls_tx_msg_list) { + DtlsMsgListDelete(ssl->dtls_tx_msg_list, ssl->heap); + ssl->dtls_tx_msg_list = NULL; + ssl->dtls_tx_msg_list_sz = 0; + ssl->dtls_timeout = ssl->dtls_timeout_init; + } } @@ -4368,7 +4379,7 @@ 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. + * to be used for triggering retransmission of whole DtlsMsgPool. * change cipher suite type is not verified here */ return ((fragOffset == 0) && @@ -7938,7 +7949,7 @@ static INLINE int DtlsUpdateWindow(WOLFSSL* ssl) static int DtlsMsgDrain(WOLFSSL* ssl) { - DtlsMsg* item = ssl->dtls_msg_list; + DtlsMsg* item = ssl->dtls_rx_msg_list; int ret = 0; /* While there is an item in the store list, and it is the expected @@ -7952,9 +7963,10 @@ static int DtlsMsgDrain(WOLFSSL* ssl) ssl->keys.dtls_expected_peer_handshake_number++; ret = DoHandShakeMsgType(ssl, item->msg, &idx, item->type, item->sz, item->sz); - ssl->dtls_msg_list = item->next; + ssl->dtls_rx_msg_list = item->next; DtlsMsgDelete(item, ssl->heap); - item = ssl->dtls_msg_list; + item = ssl->dtls_rx_msg_list; + ssl->dtls_rx_msg_list_sz--; } return ret; @@ -7998,10 +8010,11 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, * the client could be sending multiple new client hello messages * with newer and newer cookies.) */ if (type != client_hello) { - ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, - ssl->keys.dtls_peer_handshake_number, - input + *inOutIdx, size, type, - fragOffset, fragSz, ssl->heap); + if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) { + DtlsMsgStore(ssl, ssl->keys.dtls_peer_handshake_number, + input + *inOutIdx, size, type, + fragOffset, fragSz, ssl->heap); + } *inOutIdx += fragSz; ret = 0; } @@ -8030,16 +8043,18 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, } } else if (fragSz < size) { - /* Since this branch is in order, but fragmented, dtls_msg_list will be - * pointing to the message with this fragment in it. Check it to see + /* Since this branch is in order, but fragmented, dtls_rx_msg_list will + * be pointing to the message with this fragment in it. Check it to see * if it is completed. */ - ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, - ssl->keys.dtls_peer_handshake_number, input + *inOutIdx, - size, type, fragOffset, fragSz, ssl->heap); + if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) { + DtlsMsgStore(ssl, ssl->keys.dtls_peer_handshake_number, + input + *inOutIdx, size, type, + fragOffset, fragSz, ssl->heap); + } *inOutIdx += fragSz; ret = 0; - if (ssl->dtls_msg_list != NULL && - ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) + if (ssl->dtls_rx_msg_list != NULL && + ssl->dtls_rx_msg_list->fragSz >= ssl->dtls_rx_msg_list->sz) ret = DtlsMsgDrain(ssl); } else { @@ -8047,7 +8062,7 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); if (ret == 0) { ssl->keys.dtls_expected_peer_handshake_number++; - if (ssl->dtls_msg_list != NULL) { + if (ssl->dtls_rx_msg_list != NULL) { ret = DtlsMsgDrain(ssl); } } @@ -11626,6 +11641,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case EXT_MASTER_SECRET_NEEDED_E: return "Extended Master Secret must be enabled to resume EMS session"; + case DTLS_POOL_SZ_E: + return "Maximum DTLS pool size exceeded"; + default : return "unknown error number"; } diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index bf9861946..fded9efa8 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -150,6 +150,7 @@ enum wolfSSL_ErrorCodes { INPUT_SIZE_E = -412, /* input size too big error */ CTX_INIT_MUTEX_E = -413, /* initialize ctx mutex error */ EXT_MASTER_SECRET_NEEDED_E = -414, /* need EMS enabled to resume */ + DTLS_POOL_SZ_E = -415, /* exceeded DTLS pool size */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 31419e9d0..d89770443 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -952,7 +952,7 @@ enum Misc { DTLS_RECORD_EXTRA = 8, /* diff from normal */ DTLS_HANDSHAKE_SEQ_SZ = 2, /* handshake header sequence number */ DTLS_HANDSHAKE_FRAG_SZ = 3, /* fragment offset and length are 24 bit */ - DTLS_POOL_SZ = 5, /* buffers to hold in the retry pool */ + DTLS_POOL_SZ = 255,/* allowed number of list items in TX pool */ DTLS_EXPORT_PRO = 165,/* wolfSSL protocol for serialized session */ DTLS_EXPORT_VERSION = 2, /* wolfSSL version for serialized session */ DTLS_EXPORT_OPT_SZ = 57, /* amount of bytes used from Options */ @@ -2751,8 +2751,10 @@ struct WOLFSSL { int dtls_timeout_init; /* starting timeout value */ int dtls_timeout_max; /* maximum timeout value */ int dtls_timeout; /* current timeout value, changes */ + word32 dtls_tx_msg_list_sz; + word32 dtls_rx_msg_list_sz; DtlsMsg* dtls_tx_msg_list; - DtlsMsg* dtls_msg_list; + DtlsMsg* dtls_rx_msg_list; void* IOCB_CookieCtx; /* gen cookie ctx */ word32 dtls_expected_rx; wc_dtls_export dtls_export; /* export function for session */ @@ -3069,7 +3071,7 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); WOLFSSL_LOCAL int DtlsMsgSet(DtlsMsg*, word32, const byte*, byte, word32, word32, void*); WOLFSSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32); - WOLFSSL_LOCAL DtlsMsg* DtlsMsgStore(DtlsMsg*, word32, const byte*, word32, + WOLFSSL_LOCAL void DtlsMsgStore(WOLFSSL*, word32, const byte*, word32, byte, word32, word32, void*); WOLFSSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*);