Merge branch 'dtls'

Conflicts:
	cyassl/ctaocrypt/types.h
This commit is contained in:
John Safranek 2013-02-20 17:08:22 -08:00
commit 6ff39cffe4
4 changed files with 261 additions and 78 deletions

View File

@ -230,6 +230,7 @@ enum {
DYNAMIC_TYPE_LIBZ = 36,
DYNAMIC_TYPE_ECC = 37,
DYNAMIC_TYPE_TMP_BUFFER = 38,
DYNAMIC_TYPE_DTLS_MSG = 39,
DYNAMIC_TYPE_CAVIUM_TMP = 40,
DYNAMIC_TYPE_CAVIUM_RSA = 41
};

View File

@ -1280,9 +1280,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;
@ -1401,6 +1398,16 @@ typedef struct DtlsPool {
int used;
} DtlsPool;
typedef struct DtlsMsg {
struct DtlsMsg* next;
word32 seq; /* Handshake sequence number */
word32 sz; /* Length of whole mesage */
word32 fragSz; /* Length of fragments received */
byte type;
byte* buf;
byte* msg;
} DtlsMsg;
/* CyaSSL ssl type */
struct CYASSL {
@ -1473,6 +1480,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 */
@ -1696,6 +1704,16 @@ 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, void*);
CYASSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*);
CYASSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*);
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,
byte, word32, word32, void*);
CYASSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*);
#endif /* CYASSL_DTLS */
#ifndef NO_TLS

View File

@ -1219,6 +1219,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 */
@ -1266,9 +1267,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;
@ -1465,12 +1463,14 @@ 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);
}
if (ssl->dtls_msg_list != NULL) {
DtlsMsgListDelete(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
@ -1703,7 +1703,167 @@ int DtlsPoolSend(CYASSL* ssl)
return 0;
}
#endif
/* 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;
msg = (DtlsMsg*)XMALLOC(sizeof(DtlsMsg), heap, DYNAMIC_TYPE_DTLS_MSG);
if (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);
msg = NULL;
}
}
return msg;
}
void DtlsMsgDelete(DtlsMsg* item, void* heap)
{
(void)heap;
if (item != NULL) {
if (item->buf != NULL)
XFREE(item->buf, heap, DYNAMIC_TYPE_NONE);
XFREE(item, heap, DYNAMIC_TYPE_DTLS_MSG);
}
}
void DtlsMsgListDelete(DtlsMsg* head, void* heap)
{
DtlsMsg* next;
while (head) {
next = head->next;
DtlsMsgDelete(head, heap);
head = next;
}
}
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;
/* 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);
}
}
}
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, 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
* 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, type, fragOffset, fragSz);
head = DtlsMsgInsert(head, cur);
}
else {
DtlsMsgSet(cur, seq, data, type, fragOffset, fragSz);
}
}
else {
head = DtlsMsgNew(dataSz, heap);
DtlsMsgSet(head, seq, data, type, fragOffset, fragSz);
}
return head;
}
/* DtlsMsgInsert() is an in-order insert. */
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
@ -2186,7 +2346,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
@ -2204,7 +2366,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;
@ -2262,7 +2424,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;
}
@ -2991,6 +3152,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)
{
@ -3007,74 +3193,49 @@ 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.
*/
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;
/* 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 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)
ret = DtlsMsgDrain(ssl);
}
else {
if (ssl->keys.dtls_peer_handshake_number ==
ssl->keys.dtls_expected_peer_handshake_number) {
/* 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);
}
else {
*inOutIdx += size;
ret = 0;
}
}
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;
if (ret == 0 && ssl->dtls_msg_list != NULL)
ret = DtlsMsgDrain(ssl);
}
CYASSL_LEAVE("DoDtlsHandShakeMsg()", ret);
@ -4032,7 +4193,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;

View File

@ -2519,6 +2519,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;
}