From 982b72796e1ce74699976746e806ddb1ffb7e7c2 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 7 Feb 2013 11:26:02 -0800 Subject: [PATCH 1/6] added list for DTLS handshake datagram reordering --- cyassl/ctaocrypt/types.h | 3 +- cyassl/internal.h | 12 +++++++ src/internal.c | 76 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/cyassl/ctaocrypt/types.h b/cyassl/ctaocrypt/types.h index 82bbaec5b..f6a06e19e 100644 --- a/cyassl/ctaocrypt/types.h +++ b/cyassl/ctaocrypt/types.h @@ -228,7 +228,8 @@ enum { DYNAMIC_TYPE_SOCKADDR = 35, DYNAMIC_TYPE_LIBZ = 36, DYNAMIC_TYPE_ECC = 37, - DYNAMIC_TYPE_TMP_BUFFER = 38 + DYNAMIC_TYPE_TMP_BUFFER = 38, + DYNAMIC_TYPE_DTLS_MSG = 39 }; /* stack protection */ diff --git a/cyassl/internal.h b/cyassl/internal.h index a7d7bdad4..9a68f0faf 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1385,6 +1385,13 @@ typedef struct DtlsPool { int used; } DtlsPool; +typedef struct DtlsMsg { + struct DtlsMsg* next; + word32 seq; + word32 sz; + byte msg[1500]; +} DtlsMsg; + /* CyaSSL ssl type */ struct CYASSL { @@ -1457,6 +1464,7 @@ struct CYASSL { #ifdef CYASSL_DTLS int dtls_timeout; DtlsPool* dtls_pool; + DtlsMsg* dtls_msg_list; #endif #ifdef CYASSL_CALLBACKS HandShakeInfo handShakeInfo; /* info saved during handshake */ @@ -1677,6 +1685,10 @@ CYASSL_LOCAL int GrowInputBuffer(CYASSL* ssl, int size, int usedLength); CYASSL_LOCAL int DtlsPoolTimeout(CYASSL*); CYASSL_LOCAL int DtlsPoolSend(CYASSL*); CYASSL_LOCAL void DtlsPoolReset(CYASSL*); + CYASSL_LOCAL DtlsMsg* DtlsMsgNew(word32, byte*, word32, void*); + CYASSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*); + CYASSL_LOCAL void DtlsMsgListFree(DtlsMsg*, void*); + CYASSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*); #endif /* CYASSL_DTLS */ #ifndef NO_TLS diff --git a/src/internal.c b/src/internal.c index f4c34a648..ad596254d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1164,6 +1164,7 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->keys.dtls_expected_peer_epoch = 0; ssl->dtls_timeout = DTLS_DEFAULT_TIMEOUT; ssl->dtls_pool = NULL; + ssl->dtls_msg_list = NULL; #endif ssl->keys.encryptionOn = 0; /* initially off */ ssl->keys.decryptedCur = 0; /* initially off */ @@ -1412,6 +1413,10 @@ void SSL_ResourceFree(CYASSL* ssl) DtlsPoolReset(ssl); XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE); } + if (ssl->dtls_msg_list != NULL) { + DtlsMsgListFree(ssl->dtls_msg_list, ssl->heap); + ssl->dtls_msg_list = NULL; + } XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); ssl->buffers.dtlsCtx.peer.sa = NULL; #endif @@ -1644,7 +1649,76 @@ int DtlsPoolSend(CYASSL* ssl) return 0; } -#endif + +/* functions for managing DTLS datagram reordering */ + +DtlsMsg* DtlsMsgNew(word32 dataSz, byte* data, word32 seq, void* heap) +{ + DtlsMsg* msg = NULL; + + if (dataSz > 0) + msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); + + if (msg != NULL) { + msg->next = NULL; + msg->seq = seq; + msg->sz = dataSz; + XMEMCPY(msg->msg, data, dataSz); + } + + return msg; +} + + +void DtlsMsgDelete(DtlsMsg* msg, void* heap) +{ + (void)heap; + if (msg != NULL) + XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); +} + + +void DtlsMsgListFree(DtlsMsg* head, void* heap) +{ + DtlsMsg* next; + while (head) { + next = head->next; + DtlsMsgDelete(head, heap); + head = next; + } +} + + +DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item) +{ + if (head == NULL || item->seq < head->seq) { + item->next = head; + head = item; + } + else if (head->next == NULL) { + head->next = item; + } + else { + DtlsMsg* cur = head->next; + DtlsMsg* prev = head; + while (cur) { + if (item->seq < cur->seq) { + item->next = cur; + prev->next = item; + break; + } + prev = cur; + cur = cur->next; + } + if (cur == NULL) { + prev->next = item; + } + } + + return head; +} + +#endif /* CYASSL_DTLS */ #ifndef NO_OLD_TLS From 116f2403d0af2d1e3f1804244ec86089e3f18396 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 19 Feb 2013 12:51:02 -0800 Subject: [PATCH 2/6] updated the list for storing out of order messages --- cyassl/internal.h | 16 ++++--- src/internal.c | 103 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 99 insertions(+), 20 deletions(-) diff --git a/cyassl/internal.h b/cyassl/internal.h index 9a68f0faf..517035cbc 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1387,9 +1387,10 @@ typedef struct DtlsPool { typedef struct DtlsMsg { struct DtlsMsg* next; - word32 seq; - word32 sz; - byte msg[1500]; + word32 seq; /* Handshake sequence number */ + word32 sz; /* Length of whole mesage */ + word32 fragSz; /* Length of fragments received */ + byte* msg; } DtlsMsg; @@ -1685,9 +1686,14 @@ CYASSL_LOCAL int GrowInputBuffer(CYASSL* ssl, int size, int usedLength); CYASSL_LOCAL int DtlsPoolTimeout(CYASSL*); CYASSL_LOCAL int DtlsPoolSend(CYASSL*); CYASSL_LOCAL void DtlsPoolReset(CYASSL*); - CYASSL_LOCAL DtlsMsg* DtlsMsgNew(word32, byte*, word32, void*); + + CYASSL_LOCAL DtlsMsg* DtlsMsgNew(word32, void*); CYASSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*); - CYASSL_LOCAL void DtlsMsgListFree(DtlsMsg*, void*); + CYASSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*); + CYASSL_LOCAL void DtlsMsgSet(DtlsMsg*, word32, const byte*, word32, word32); + CYASSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32); + CYASSL_LOCAL DtlsMsg* DtlsMsgStore(DtlsMsg*, word32, const byte*, word32, + word32, word32, void*); CYASSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*); #endif /* CYASSL_DTLS */ diff --git a/src/internal.c b/src/internal.c index ad596254d..0a9078863 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1414,7 +1414,7 @@ void SSL_ResourceFree(CYASSL* ssl) XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE); } if (ssl->dtls_msg_list != NULL) { - DtlsMsgListFree(ssl->dtls_msg_list, ssl->heap); + DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap); ssl->dtls_msg_list = NULL; } XFREE(ssl->buffers.dtlsCtx.peer.sa, ssl->heap, DYNAMIC_TYPE_SOCKADDR); @@ -1652,33 +1652,43 @@ int DtlsPoolSend(CYASSL* ssl) /* functions for managing DTLS datagram reordering */ -DtlsMsg* DtlsMsgNew(word32 dataSz, byte* data, word32 seq, void* heap) +DtlsMsg* DtlsMsgNew(word32 sz, void* heap) { DtlsMsg* msg = NULL; - if (dataSz > 0) + if (sz > 0) msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); if (msg != NULL) { - msg->next = NULL; - msg->seq = seq; - msg->sz = dataSz; - XMEMCPY(msg->msg, data, dataSz); + msg->msg = (byte*)XMALLOC(sz, heap, DYNAMIC_TYPE_NONE); + if (msg->msg != NULL) { + msg->next = NULL; + msg->seq = 0; + msg->sz = sz; + msg->fragSz = 0; + } + else { + XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); + msg = NULL; + } } return msg; } - -void DtlsMsgDelete(DtlsMsg* msg, void* heap) +void DtlsMsgDelete(DtlsMsg* item, void* heap) { (void)heap; - if (msg != NULL) - XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); + + if (item != NULL) { + if (item->msg != NULL) + XFREE(item->msg, heap, DYNAMIC_TYPE_NONE); + XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG); + } } -void DtlsMsgListFree(DtlsMsg* head, void* heap) +void DtlsMsgListDelete(DtlsMsg* head, void* heap) { DtlsMsg* next; while (head) { @@ -1689,6 +1699,66 @@ void DtlsMsgListFree(DtlsMsg* head, void* heap) } +void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, + word32 fragOffset, word32 fragSz) +{ + if (msg != NULL && data != NULL && msg->fragSz <= msg->sz) { + msg->seq = seq; + msg->fragSz += fragSz; + XMEMCPY(&msg->msg[fragOffset], data, fragSz); + } +} + + +DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq) +{ + while (head != NULL && head->seq != seq) { + head = head->next; + } + return head; +} + + +DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, word32 dataSz, + 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 + * the seq is in the list and it isn't full, copy fragSz bytes from + * data to msg->msg starting at offset fragOffset, and add fragSz to + * msg->fragSz. The new item should be inserted into the list in its + * proper position. + * + * 1. Find seq in list, or where seq should go in list. If seq not in + * list, create new item and insert into list. Either case, keep + * pointer to item. + * 2. If msg->fragSz + fragSz < sz, copy data to msg->msg at offset + * fragOffset. Add fragSz to msg->fragSz. + */ + + if (head != NULL) { + DtlsMsg* cur = DtlsMsgFind(head, seq); + if (cur == NULL) { + cur = DtlsMsgNew(dataSz, heap); + DtlsMsgSet(cur, seq, data, fragOffset, fragSz); + head = DtlsMsgInsert(head, cur); + } + else { + DtlsMsgSet(cur, seq, data, fragOffset, fragSz); + } + } + else { + head = DtlsMsgNew(dataSz, heap); + DtlsMsgSet(head, seq, data, fragOffset, fragSz); + } + + return head; +} + + +/* DtlsMsgInsert() is an in-order insert. */ DtlsMsg* DtlsMsgInsert(DtlsMsg* head, DtlsMsg* item) { if (head == NULL || item->seq < head->seq) { @@ -2201,7 +2271,9 @@ static int GetRecordHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, return VERSION_ERROR; /* only use requested version */ } } - +#if 0 + /* Instead of this, check the datagram against the sliding window of + * received datagram goodness. */ #ifdef CYASSL_DTLS /* If DTLS, check the sequence number against expected. If out of * order, drop the record. Allows newer records in and resets the @@ -2219,7 +2291,7 @@ static int GetRecordHeader(CYASSL* ssl, const byte* input, word32* inOutIdx, } } #endif - +#endif /* record layer length check */ if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) return LENGTH_ERROR; @@ -4044,7 +4116,8 @@ int ProcessReply(CYASSL* ssl) &ssl->curRL, &ssl->curSize); #ifdef CYASSL_DTLS if (ssl->options.dtls && ret == SEQUENCE_ERROR) { - /* This message is out of order. Forget it ever happened. */ + /* This message is out of order. If we are handshaking, save + *it for later. Otherwise go ahead and process it. */ ssl->options.processReply = doProcessInit; ssl->buffers.inputBuffer.length = 0; ssl->buffers.inputBuffer.idx = 0; From bdadeab34282c7ee0596b0001602cd524bcfe161 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 19 Feb 2013 16:06:02 -0800 Subject: [PATCH 3/6] added storing of out-of-order and fragmented message, missing processing of the stored list --- cyassl/internal.h | 6 ++- src/internal.c | 115 +++++++++++++++++++++------------------------- src/ssl.c | 2 + 3 files changed, 58 insertions(+), 65 deletions(-) diff --git a/cyassl/internal.h b/cyassl/internal.h index 517035cbc..9f48d2f1f 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1390,6 +1390,7 @@ typedef struct DtlsMsg { word32 seq; /* Handshake sequence number */ word32 sz; /* Length of whole mesage */ word32 fragSz; /* Length of fragments received */ + byte type; byte* msg; } DtlsMsg; @@ -1690,10 +1691,11 @@ CYASSL_LOCAL int GrowInputBuffer(CYASSL* ssl, int size, int usedLength); CYASSL_LOCAL DtlsMsg* DtlsMsgNew(word32, void*); CYASSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*); CYASSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*); - CYASSL_LOCAL void DtlsMsgSet(DtlsMsg*, word32, const byte*, word32, word32); + CYASSL_LOCAL void DtlsMsgSet(DtlsMsg*, word32, const byte*, byte, + word32, word32); CYASSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32); CYASSL_LOCAL DtlsMsg* DtlsMsgStore(DtlsMsg*, word32, const byte*, word32, - word32, word32, void*); + byte, word32, word32, void*); CYASSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*); #endif /* CYASSL_DTLS */ diff --git a/src/internal.c b/src/internal.c index 0a9078863..bfd36042b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1699,11 +1699,12 @@ void DtlsMsgListDelete(DtlsMsg* head, void* heap) } -void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, +void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type, word32 fragOffset, word32 fragSz) { if (msg != NULL && data != NULL && msg->fragSz <= msg->sz) { msg->seq = seq; + msg->type = type; msg->fragSz += fragSz; XMEMCPY(&msg->msg[fragOffset], data, fragSz); } @@ -1719,8 +1720,8 @@ DtlsMsg* DtlsMsgFind(DtlsMsg* head, word32 seq) } -DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, word32 dataSz, - word32 fragOffset, word32 fragSz, void* heap) +DtlsMsg* DtlsMsgStore(DtlsMsg* head, 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 @@ -1742,16 +1743,16 @@ DtlsMsg* DtlsMsgStore(DtlsMsg* head, word32 seq, const byte* data, word32 dataSz DtlsMsg* cur = DtlsMsgFind(head, seq); if (cur == NULL) { cur = DtlsMsgNew(dataSz, heap); - DtlsMsgSet(cur, seq, data, fragOffset, fragSz); + DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz); head = DtlsMsgInsert(head, cur); } else { - DtlsMsgSet(cur, seq, data, fragOffset, fragSz); + DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz); } } else { head = DtlsMsgNew(dataSz, heap); - DtlsMsgSet(head, seq, data, fragOffset, fragSz); + DtlsMsgSet(head, seq, data, type, fragOffset, fragSz); } return head; @@ -2349,7 +2350,6 @@ static int GetDtlsHandShakeHeader(CYASSL* ssl, const byte* input, c24to32(input + idx, fragOffset); idx += DTLS_HANDSHAKE_FRAG_SZ; c24to32(input + idx, fragSz); - idx += DTLS_HANDSHAKE_FRAG_SZ; return 0; } @@ -3094,66 +3094,55 @@ static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, if (*inOutIdx + fragSz > totalSz) return INCOMPLETE_DATA; - if (fragSz < size) { - /* message is fragmented, knit back together */ - byte* buf = ssl->buffers.dtlsHandshake.buffer; - if (ssl->buffers.dtlsHandshake.length == 0) { - /* Need to add a header back into the data. The Hash is calculated - * as if this were a single message, not several fragments. */ - buf = (byte*)XMALLOC(size + DTLS_HANDSHAKE_HEADER_SZ, - ssl->heap, DYNAMIC_TYPE_NONE); - if (buf == NULL) - return MEMORY_ERROR; - - ssl->buffers.dtlsHandshake.length = size; - ssl->buffers.dtlsHandshake.buffer = buf; - ssl->buffers.dtlsUsed = 0; - ssl->buffers.dtlsType = type; - - /* Construct a new header for the reassembled message as if it - * were originally sent as one fragment for the hashing later. */ - XMEMCPY(buf, - input + *inOutIdx - DTLS_HANDSHAKE_HEADER_SZ, - DTLS_HANDSHAKE_HEADER_SZ - DTLS_HANDSHAKE_FRAG_SZ); - XMEMCPY(buf + DTLS_HANDSHAKE_HEADER_SZ - DTLS_HANDSHAKE_FRAG_SZ, - input + *inOutIdx - DTLS_HANDSHAKE_HEADER_SZ + ENUM_LEN, - DTLS_HANDSHAKE_FRAG_SZ); - } - /* readjust the buf pointer past the header */ - buf += DTLS_HANDSHAKE_HEADER_SZ; - - XMEMCPY(buf + fragOffset, input + *inOutIdx, fragSz); - ssl->buffers.dtlsUsed += fragSz; - *inOutIdx += fragSz; - - if (ssl->buffers.dtlsUsed != size) { - CYASSL_LEAVE("DoDtlsHandShakeMsg()", 0); - return 0; - } - else { - if (ssl->keys.dtls_peer_handshake_number == + /* Check the handshake sequence number first. If out of order, + * add the current message to the list. If the message is in order, + * but it is a fragment, add the current message to the list, then + * check the head of the list to see if it is complete, if so, pop + * it out as the current message. If the message is complete and in + * order, process it. Check the head of the list to see if it is in + * order, if so, process it. (Repeat until list exhausted.) If the + * head is out of order, return for more processing. + * NOTE: The hash is calculated on the data, not the header. In + * DoHandShakeMsgType(), HashInput starts with inOutIdx. + */ + if (ssl->keys.dtls_peer_handshake_number > ssl->keys.dtls_expected_peer_handshake_number) { - word32 idx = 0; - totalSz = size; - ssl->keys.dtls_expected_peer_handshake_number++; - ret = DoHandShakeMsgType(ssl, buf, &idx, type, size, totalSz); - } - else { - *inOutIdx += size; - ret = 0; - } + /* Current message is out of order. It will get stored in the list. + * Storing also takes care of defragmentation. */ + ssl->dtls_msg_list = DtlsMsgStore(ssl->dtls_msg_list, + ssl->keys.dtls_peer_handshake_number, input + *inOutIdx, + size, type, fragOffset, fragSz, ssl->heap); + *inOutIdx += fragSz; + ret = 0; + } + else if (ssl->keys.dtls_peer_handshake_number < + ssl->keys.dtls_expected_peer_handshake_number) { + /* Already saw this message and processed it. It can be ignored. */ + *inOutIdx += fragSz; + ret = 0; + } + else if (fragSz < size) { + /* Since this branch is in order, but fragmented, dtls_msg_list will be + * pointing the 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); + *inOutIdx += fragSz; + if (ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) { + DtlsMsg* item = ssl->dtls_msg_list; + word32 idx = 0; + 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; + DtlsMsgDelete(item, ssl->heap); } } else { - if (ssl->keys.dtls_peer_handshake_number == - ssl->keys.dtls_expected_peer_handshake_number) { - ssl->keys.dtls_expected_peer_handshake_number++; - ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); - } - else { - *inOutIdx += size; - ret = 0; - } + /* This branch is in order next, and a complete message. */ + ssl->keys.dtls_expected_peer_handshake_number++; + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); } if (ssl->buffers.dtlsHandshake.buffer != NULL) { diff --git a/src/ssl.c b/src/ssl.c index 97ef9682f..e5a3c9050 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2467,6 +2467,8 @@ int CyaSSL_dtls_got_timeout(CYASSL* ssl) { #ifdef CYASSL_DTLS int result = SSL_SUCCESS; + DtlsMsgListDelete(ssl->dtls_msg_list, ssl->heap); + ssl->dtls_msg_list = NULL; if (DtlsPoolTimeout(ssl) < 0 || DtlsPoolSend(ssl) < 0) { result = SSL_FATAL_ERROR; } From 2c1ed7c11cd4fb8b9430727d9f25263202d7cbca Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 20 Feb 2013 08:35:33 -0800 Subject: [PATCH 4/6] removed old defragmentation code. fixed new defragment code. --- cyassl/internal.h | 4 +--- src/internal.c | 51 ++++++++++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/cyassl/internal.h b/cyassl/internal.h index 9f48d2f1f..357db420e 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1264,9 +1264,6 @@ typedef struct Buffers { byte weOwnKey; /* SSL own key flag */ byte weOwnDH; /* SSL own dh (p,g) flag */ #ifdef CYASSL_DTLS - buffer dtlsHandshake; /* DTLS handshake defragment buf */ - word32 dtlsUsed; /* DTLS bytes used in buffer */ - byte dtlsType; /* DTLS handshake frag type */ CYASSL_DTLS_CTX dtlsCtx; /* DTLS connection context */ #endif } Buffers; @@ -1391,6 +1388,7 @@ typedef struct DtlsMsg { word32 sz; /* Length of whole mesage */ word32 fragSz; /* Length of fragments received */ byte type; + byte* buf; byte* msg; } DtlsMsg; diff --git a/src/internal.c b/src/internal.c index bfd36042b..4a703d9e9 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1212,9 +1212,6 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->buffers.weOwnDH = 0; #ifdef CYASSL_DTLS - ssl->buffers.dtlsHandshake.length = 0; - ssl->buffers.dtlsHandshake.buffer = NULL; - ssl->buffers.dtlsType = 0; ssl->buffers.dtlsCtx.fd = -1; ssl->buffers.dtlsCtx.peer.sa = NULL; ssl->buffers.dtlsCtx.peer.sz = 0; @@ -1407,8 +1404,6 @@ void SSL_ResourceFree(CYASSL* ssl) if (ssl->buffers.outputBuffer.dynamicFlag) ShrinkOutputBuffer(ssl); #ifdef CYASSL_DTLS - if (ssl->buffers.dtlsHandshake.buffer != NULL) - XFREE(ssl->buffers.dtlsHandshake.buffer, ssl->heap, DYNAMIC_TYPE_NONE); if (ssl->dtls_pool != NULL) { DtlsPoolReset(ssl); XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE); @@ -1652,6 +1647,11 @@ int DtlsPoolSend(CYASSL* ssl) /* functions for managing DTLS datagram reordering */ +/* Need to allocate space for the handshake message header. The hashing + * routines assume the message pointer is still within the buffer that + * has the headers, and will include those headers in the hash. The store + * routines need to take that into account as well. New will allocate + * extra space for the headers. */ DtlsMsg* DtlsMsgNew(word32 sz, void* heap) { DtlsMsg* msg = NULL; @@ -1660,12 +1660,14 @@ DtlsMsg* DtlsMsgNew(word32 sz, void* heap) msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); if (msg != NULL) { - msg->msg = (byte*)XMALLOC(sz, heap, DYNAMIC_TYPE_NONE); - if (msg->msg != NULL) { + msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ, + heap, DYNAMIC_TYPE_NONE); + if (msg->buf != NULL) { msg->next = NULL; msg->seq = 0; msg->sz = sz; msg->fragSz = 0; + msg->msg = msg->buf + DTLS_HANDSHAKE_HEADER_SZ; } else { XFREE(msg, heap, DYNAMIC_TYPE_DTLS_MSG); @@ -1681,8 +1683,8 @@ void DtlsMsgDelete(DtlsMsg* item, void* heap) (void)heap; if (item != NULL) { - if (item->msg != NULL) - XFREE(item->msg, heap, DYNAMIC_TYPE_NONE); + if (item->buf != NULL) + XFREE(item->buf, heap, DYNAMIC_TYPE_NONE); XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG); } } @@ -1706,7 +1708,21 @@ void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type, msg->seq = seq; msg->type = type; msg->fragSz += fragSz; - XMEMCPY(&msg->msg[fragOffset], data, fragSz); + /* If fragOffset is zero, this is either a full message that is out + * of order, or the first fragment of a fragmented message. Copy the + * handshake message header as well as the message data. */ + if (fragOffset == 0) + XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ, + fragSz + DTLS_HANDSHAKE_HEADER_SZ); + else { + /* If fragOffet is non-zero, this is an additional fragment that + * needs to be copied to its location in the message buffer. Also + * copy the total size of the message over the fragment size. The + * hash routines look at a defragmented message if it had actually + * come across as a single handshake message. */ + XMEMCPY(msg->msg + fragOffset, data, fragSz); + c32to24(msg->sz, msg->msg - DTLS_HANDSHAKE_FRAG_SZ); + } } } @@ -3123,18 +3139,19 @@ static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, } else if (fragSz < size) { /* Since this branch is in order, but fragmented, dtls_msg_list will be - * pointing the the message with this fragment in it. Check it to see + * 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); *inOutIdx += fragSz; + ret = 0; if (ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) { DtlsMsg* item = ssl->dtls_msg_list; word32 idx = 0; ssl->keys.dtls_expected_peer_handshake_number++; - ret = DoHandShakeMsgType(ssl, item->msg, &idx, - item->type, item->sz, item->sz); + ret = DoHandShakeMsgType(ssl, item->msg, + &idx, item->type, item->sz, item->sz); ssl->dtls_msg_list = item->next; DtlsMsgDelete(item, ssl->heap); } @@ -3145,14 +3162,6 @@ static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); } - if (ssl->buffers.dtlsHandshake.buffer != NULL) { - XFREE(ssl->buffers.dtlsHandshake.buffer, ssl->heap, DYNAMIC_TYPE_NONE); - ssl->buffers.dtlsHandshake.length = 0; - ssl->buffers.dtlsHandshake.buffer = NULL; - ssl->buffers.dtlsUsed = 0; - ssl->buffers.dtlsType = 0; - } - CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret); return ret; } From 598043dd6f26b41e723a6f6e5b1615630388dea8 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 20 Feb 2013 09:28:09 -0800 Subject: [PATCH 5/6] drains the DTLS message store once an in-order message is received. --- src/internal.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/internal.c b/src/internal.c index 4a703d9e9..35832648c 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3094,6 +3094,31 @@ static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, #ifdef CYASSL_DTLS +static int DtlsMsgDrain(CYASSL* ssl) +{ + DtlsMsg* item = ssl->dtls_msg_list; + int ret = 0; + word32 idx = 0; + + /* 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 messge... */ + while (item != NULL && + ssl->keys.dtls_expected_peer_handshake_number == item->seq && + item->fragSz == item->sz && + ret == 0) { + 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; + DtlsMsgDelete(item, ssl->heap); + item = ssl->dtls_msg_list; + } + + return ret; +} + + static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, word32 totalSz) { @@ -3118,8 +3143,6 @@ static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, * order, process it. Check the head of the list to see if it is in * order, if so, process it. (Repeat until list exhausted.) If the * head is out of order, return for more processing. - * NOTE: The hash is calculated on the data, not the header. In - * DoHandShakeMsgType(), HashInput starts with inOutIdx. */ if (ssl->keys.dtls_peer_handshake_number > ssl->keys.dtls_expected_peer_handshake_number) { @@ -3146,20 +3169,15 @@ static int DoDtlsHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, size, type, fragOffset, fragSz, ssl->heap); *inOutIdx += fragSz; ret = 0; - if (ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) { - DtlsMsg* item = ssl->dtls_msg_list; - word32 idx = 0; - 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; - DtlsMsgDelete(item, ssl->heap); - } + if (ssl->dtls_msg_list->fragSz >= ssl->dtls_msg_list->sz) + ret = DtlsMsgDrain(ssl); } else { /* This branch is in order next, and a complete message. */ ssl->keys.dtls_expected_peer_handshake_number++; ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + if (ret == 0 && ssl->dtls_msg_list != NULL) + ret = DtlsMsgDrain(ssl); } CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret); From ffc67892a4c648d9b96834cb3f1481f4e528bc87 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 20 Feb 2013 10:43:50 -0800 Subject: [PATCH 6/6] allow for 0 length handshake messages, still need to store the message header --- src/internal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index 35832648c..5dcc239f8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1656,8 +1656,7 @@ DtlsMsg* DtlsMsgNew(word32 sz, void* heap) { DtlsMsg* msg = NULL; - if (sz > 0) - msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); + msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG); if (msg != NULL) { msg->buf = (byte*)XMALLOC(sz + DTLS_HANDSHAKE_HEADER_SZ,