Replace the DTLS MsgPool for saving transmit handshake messages with

the DTLS MsgList.
This commit is contained in:
John Safranek
2016-10-28 10:58:49 -07:00
parent 3065bb2178
commit 3075269326
3 changed files with 189 additions and 229 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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