Increment record layer sequence number when retransmitting DTLS packets (as per the RFC). Send the Finished message in the next epoch, but don't commit to using the next epoch until the other end indicates that the CCS message has been received.

Tested against an OpenSSL server, this change makes it a bit happier.
This commit is contained in:
Jonas Norling 2013-05-17 16:47:55 +02:00
parent 4dbb2d6d3b
commit 2051ee49b7

View File

@ -1830,6 +1830,19 @@ int DtlsPoolSend(CYASSL* ssl)
int sendResult;
buffer* buf = &pool->buf[i];
DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer;
word16 message_epoch;
ato16(dtls->epoch, &message_epoch);
if (message_epoch == ssl->keys.dtls_epoch) {
/* Increment record sequence number on retransmitted handshake messages */
c32to48(ssl->keys.dtls_sequence_number, dtls->sequence_number);
ssl->keys.dtls_sequence_number++;
}
else {
/* The Finished message is sent with the next epoch, keep its sequence number */
}
if ((ret = CheckAvailableSize(ssl, buf->length)) != 0)
return ret;
@ -3317,13 +3330,29 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff)
if (ssl->options.side == CLIENT_END) {
ssl->options.serverState = SERVER_FINISHED_COMPLETE;
if (!ssl->options.resuming)
if (!ssl->options.resuming) {
ssl->options.handShakeState = HANDSHAKE_DONE;
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
/* Other side has received our Finished, go to next epoch */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
}
}
else {
ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
if (ssl->options.resuming)
if (ssl->options.resuming) {
ssl->options.handShakeState = HANDSHAKE_DONE;
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
/* Other side has received our Finished, go to next epoch */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
}
}
*inOutIdx = idx;
@ -4994,17 +5023,21 @@ int SendFinished(CYASSL* ssl)
int headerSz = HANDSHAKE_HEADER_SZ;
/* check for available size */
if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0)
return ret;
#ifdef CYASSL_DTLS
word32 sequence_number = ssl->keys.dtls_sequence_number;
word16 epoch = ssl->keys.dtls_epoch;
if (ssl->options.dtls) {
/* Send Finished message with the next epoch, but don't commit that change
* until the other end confirms its reception. */
headerSz += DTLS_HANDSHAKE_EXTRA;
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */
}
#endif
/* check for available size */
if ((ret = CheckAvailableSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0)
return ret;
/* get ouput buffer */
output = ssl->buffers.outputBuffer.buffer +
@ -5017,24 +5050,50 @@ int SendFinished(CYASSL* ssl)
BuildFinished(ssl, hashes, ssl->options.side == CLIENT_END ? client :
server);
if ( (sendSz = BuildMessage(ssl, output, input, headerSz +
finishedSz, handshake)) < 0)
sendSz = BuildMessage(ssl, output, input, headerSz + finishedSz, handshake);
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
ssl->keys.dtls_epoch = epoch;
ssl->keys.dtls_sequence_number = sequence_number;
}
#endif
if (sendSz < 0)
return BUILD_MSG_ERROR;
if (!ssl->options.resuming) {
#ifndef NO_SESSION_CACHE
AddSession(ssl); /* just try */
#endif
if (ssl->options.side == CLIENT_END)
if (ssl->options.side == CLIENT_END) {
BuildFinished(ssl, &ssl->verifyHashes, server);
else
}
else {
ssl->options.handShakeState = HANDSHAKE_DONE;
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
/* Other side will soon receive our Finished, go to next epoch. */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
}
}
else {
if (ssl->options.side == CLIENT_END)
if (ssl->options.side == CLIENT_END) {
ssl->options.handShakeState = HANDSHAKE_DONE;
else
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {
/* Other side will soon receive our Finished, go to next epoch. */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
}
else {
BuildFinished(ssl, &ssl->verifyHashes, client);
}
}
#ifdef CYASSL_DTLS
if (ssl->options.dtls) {