SendCertificate fragments the message based on max_fragment setting for TLS and DTLS.

This commit is contained in:
John Safranek
2015-08-14 11:06:42 -07:00
parent 0f9f4ea7e0
commit d12308a053
3 changed files with 274 additions and 104 deletions

View File

@ -2277,7 +2277,7 @@ void DtlsMsgSet(DtlsMsg* msg, word32 seq, const byte* data, byte type,
XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ, XMEMCPY(msg->buf, data - DTLS_HANDSHAKE_HEADER_SZ,
fragSz + DTLS_HANDSHAKE_HEADER_SZ); fragSz + DTLS_HANDSHAKE_HEADER_SZ);
else { else {
/* If fragOffet is non-zero, this is an additional fragment that /* If fragOffset is non-zero, this is an additional fragment that
* needs to be copied to its location in the message buffer. Also * needs to be copied to its location in the message buffer. Also
* copy the total size of the message over the fragment size. The * copy the total size of the message over the fragment size. The
* hash routines look at a defragmented message if it had actually * hash routines look at a defragmented message if it had actually
@ -2535,6 +2535,45 @@ ProtocolVersion MakeDTLSv1_2(void)
#endif /* USE_WINDOWS_API */ #endif /* USE_WINDOWS_API */
static int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz)
{
#ifdef HAVE_FUZZER
if (ssl->fuzzerCb)
ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx);
#endif
#ifndef NO_OLD_TLS
#ifndef NO_SHA
wc_ShaUpdate(&ssl->hsHashes->hashSha, output, sz);
#endif
#ifndef NO_MD5
wc_Md5Update(&ssl->hsHashes->hashMd5, output, sz);
#endif
#endif
if (IsAtLeastTLSv1_2(ssl)) {
int ret;
#ifndef NO_SHA256
ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, output, sz);
if (ret != 0)
return ret;
#endif
#ifdef WOLFSSL_SHA384
ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, output, sz);
if (ret != 0)
return ret;
#endif
#ifdef WOLFSSL_SHA512
ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, output, sz);
if (ret != 0)
return ret;
#endif
}
return 0;
}
/* add output to md5 and sha handshake hashes, exclude record header */ /* add output to md5 and sha handshake hashes, exclude record header */
static int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) static int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz)
{ {
@ -2658,10 +2697,13 @@ static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl
/* add handshake header for message */ /* add handshake header for message */
static void AddHandShakeHeader(byte* output, word32 length, byte type, static void AddHandShakeHeader(byte* output, word32 length,
WOLFSSL* ssl) word32 fragOffset, word32 fragLength,
byte type, WOLFSSL* ssl)
{ {
HandShakeHeader* hs; HandShakeHeader* hs;
(void)fragOffset;
(void)fragLength;
(void)ssl; (void)ssl;
/* handshake header */ /* handshake header */
@ -2675,8 +2717,8 @@ static void AddHandShakeHeader(byte* output, word32 length, byte type,
/* dtls handshake header extensions */ /* dtls handshake header extensions */
dtls = (DtlsHandShakeHeader*)output; dtls = (DtlsHandShakeHeader*)output;
c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq); c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq);
c32to24(0, dtls->fragment_offset); c32to24(fragOffset, dtls->fragment_offset);
c32to24(length, dtls->fragment_length); c32to24(fragLength, dtls->fragment_length);
} }
#endif #endif
} }
@ -2685,16 +2727,37 @@ static void AddHandShakeHeader(byte* output, word32 length, byte type,
/* add both headers for handshake message */ /* add both headers for handshake message */
static void AddHeaders(byte* output, word32 length, byte type, WOLFSSL* ssl) static void AddHeaders(byte* output, word32 length, byte type, WOLFSSL* ssl)
{ {
if (!ssl->options.dtls) { word32 lengthAdj = HANDSHAKE_HEADER_SZ;
AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl); word32 outputAdj = RECORD_HEADER_SZ;
AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl);
}
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
else { if (ssl->options.dtls) {
AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl); lengthAdj += DTLS_HANDSHAKE_EXTRA;
AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl); outputAdj += DTLS_RECORD_EXTRA;
} }
#endif #endif
AddRecordHeader(output, length + lengthAdj, handshake, ssl);
AddHandShakeHeader(output + outputAdj, length, 0, length, type, ssl);
}
static void AddFragHeaders(byte* output, word32 fragSz, word32 fragOffset,
word32 length, byte type, WOLFSSL* ssl)
{
word32 lengthAdj = HANDSHAKE_HEADER_SZ;
word32 outputAdj = RECORD_HEADER_SZ;
(void)fragSz;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
lengthAdj += DTLS_HANDSHAKE_EXTRA;
outputAdj += DTLS_RECORD_EXTRA;
}
#endif
AddRecordHeader(output, fragSz + lengthAdj, handshake, ssl);
AddHandShakeHeader(output + outputAdj, length, fragOffset, fragSz, type, ssl);
} }
@ -4018,15 +4081,8 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
c24to32(input + *inOutIdx, &listSz); c24to32(input + *inOutIdx, &listSz);
*inOutIdx += OPAQUE24_LEN; *inOutIdx += OPAQUE24_LEN;
#ifdef HAVE_MAX_FRAGMENT
if (listSz > ssl->max_fragment) {
SendAlert(ssl, alert_fatal, record_overflow);
return BUFFER_E;
}
#else
if (listSz > MAX_RECORD_SIZE) if (listSz > MAX_RECORD_SIZE)
return BUFFER_E; return BUFFER_E;
#endif
if ((*inOutIdx - begin) + listSz != size) if ((*inOutIdx - begin) + listSz != size)
return BUFFER_ERROR; return BUFFER_ERROR;
@ -7281,7 +7337,7 @@ int SendFinished(WOLFSSL* ssl)
output = ssl->buffers.outputBuffer.buffer + output = ssl->buffers.outputBuffer.buffer +
ssl->buffers.outputBuffer.length; ssl->buffers.outputBuffer.length;
AddHandShakeHeader(input, finishedSz, finished, ssl); AddHandShakeHeader(input, finishedSz, 0, finishedSz, finished, ssl);
/* make finished hashes */ /* make finished hashes */
hashes = (Hashes*)&input[headerSz]; hashes = (Hashes*)&input[headerSz];
@ -7362,117 +7418,226 @@ int SendFinished(WOLFSSL* ssl)
return SendBuffered(ssl); return SendBuffered(ssl);
} }
#ifndef NO_CERTS #ifndef NO_CERTS
int SendCertificate(WOLFSSL* ssl) int SendCertificate(WOLFSSL* ssl)
{ {
int sendSz, length, ret = 0; int length, ret = 0;
word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; word32 certSz, certChainSz, headerSz, listSz, maxFragment, payloadSz;
word32 certSz, listSz;
byte* output = 0;
if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher)
return 0; /* not needed */ return 0; /* not needed */
if (ssl->options.sendVerify == SEND_BLANK_CERT) { if (ssl->options.sendVerify == SEND_BLANK_CERT) {
certSz = 0; certSz = 0;
certChainSz = 0;
headerSz = CERT_HEADER_SZ;
length = CERT_HEADER_SZ; length = CERT_HEADER_SZ;
listSz = 0; listSz = 0;
} }
else { else {
certSz = ssl->buffers.certificate.length; certSz = ssl->buffers.certificate.length;
headerSz = 2 * CERT_HEADER_SZ;
/* list + cert size */ /* list + cert size */
length = certSz + 2 * CERT_HEADER_SZ; length = certSz + headerSz;
listSz = certSz + CERT_HEADER_SZ; listSz = certSz + CERT_HEADER_SZ;
/* may need to send rest of chain, already has leading size(s) */ /* may need to send rest of chain, already has leading size(s) */
if (ssl->buffers.certChain.buffer) { if (certSz) {
length += ssl->buffers.certChain.length; certChainSz = ssl->buffers.certChain.length;
listSz += ssl->buffers.certChain.length; length += certChainSz;
listSz += certChainSz;
} }
} }
sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
payloadSz = length;
if (ssl->fragOffset != 0)
length -= (ssl->fragOffset + headerSz);
if (!ssl->options.dtls) {
maxFragment = MAX_RECORD_SIZE;
}
else {
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
if (ssl->options.dtls) { maxFragment = MAX_MTU - DTLS_RECORD_HEADER_SZ
sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - DTLS_HANDSHAKE_HEADER_SZ - 100;
i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; #endif /* WOLFSSL_DTLS */
}
#endif
if (ssl->keys.encryptionOn)
sendSz += MAX_MSG_EXTRA;
/* check for available size */
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
return ret;
/* get ouput buffer */
output = ssl->buffers.outputBuffer.buffer +
ssl->buffers.outputBuffer.length;
AddHeaders(output, length, certificate, ssl);
/* list total */
c32to24(listSz, output + i);
i += CERT_HEADER_SZ;
/* member */
if (certSz) {
c32to24(certSz, output + i);
i += CERT_HEADER_SZ;
XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz);
i += certSz;
/* send rest of chain? */
if (ssl->buffers.certChain.buffer) {
XMEMCPY(output + i, ssl->buffers.certChain.buffer,
ssl->buffers.certChain.length);
i += ssl->buffers.certChain.length;
}
} }
if (ssl->keys.encryptionOn) { #ifdef HAVE_MAX_FRAGMENT
byte* input; if (ssl->max_fragment != 0 && maxFragment >= ssl->max_fragment)
int inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */ maxFragment = ssl->max_fragment;
#endif /* HAVE_MAX_FRAGMENT */
input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); while (length > 0 && ret == 0) {
if (input == NULL) byte* output = NULL;
return MEMORY_E; word32 fragSz; /* How much of the certificate data are we copying? */
word32 i = RECORD_HEADER_SZ;
int sendSz = RECORD_HEADER_SZ;
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); if (!ssl->options.dtls) {
sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake); if (ssl->fragOffset == 0) {
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (headerSz + certSz + certChainSz <=
maxFragment - HANDSHAKE_HEADER_SZ) {
if (sendSz < 0) fragSz = headerSz + certSz + certChainSz;
return sendSz; }
} else { else {
ret = HashOutput(ssl, output, sendSz, 0); fragSz = maxFragment - HANDSHAKE_HEADER_SZ;
if (ret != 0) }
sendSz += fragSz + HANDSHAKE_HEADER_SZ;
i += HANDSHAKE_HEADER_SZ;
}
else {
fragSz = min(length, maxFragment);
sendSz += fragSz;
}
if (ssl->keys.encryptionOn)
sendSz += MAX_MSG_EXTRA;
}
else {
#ifdef WOLFSSL_DTLS
fragSz = min(length, maxFragment);
sendSz += fragSz + DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA
+ HANDSHAKE_HEADER_SZ;
i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA
+ HANDSHAKE_HEADER_SZ;
#endif
}
/* check for available size */
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
return ret; return ret;
/* get ouput buffer */
output = ssl->buffers.outputBuffer.buffer +
ssl->buffers.outputBuffer.length;
if (ssl->fragOffset == 0) {
if (!ssl->options.dtls) {
AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl);
HashOutputRaw(ssl, output + RECORD_HEADER_SZ,
HANDSHAKE_HEADER_SZ);
}
else {
#ifdef WOLFSSL_DTLS
AddHeaders(output, payloadSz, certificate, ssl);
HashOutputRaw(ssl,
output + RECORD_HEADER_SZ + DTLS_RECORD_EXTRA,
HANDSHAKE_HEADER_SZ + DTLS_HANDSHAKE_EXTRA);
/* Adding the headers increments these, decrement them for
* actual message header. */
ssl->keys.dtls_sequence_number--;
ssl->keys.dtls_handshake_number--;
AddFragHeaders(output, fragSz, 0, payloadSz, certificate, ssl);
ssl->keys.dtls_handshake_number--;
#endif /* WOLFSSL_DTLS */
}
/* list total */
c32to24(listSz, output + i);
HashOutputRaw(ssl, output + i, CERT_HEADER_SZ);
i += CERT_HEADER_SZ;
length -= CERT_HEADER_SZ;
fragSz -= CERT_HEADER_SZ;
if (certSz) {
c32to24(certSz, output + i);
HashOutputRaw(ssl, output + i, CERT_HEADER_SZ);
i += CERT_HEADER_SZ;
length -= CERT_HEADER_SZ;
fragSz -= CERT_HEADER_SZ;
HashOutputRaw(ssl, ssl->buffers.certificate.buffer, certSz);
if (certChainSz) {
HashOutputRaw(ssl,
ssl->buffers.certChain.buffer, certChainSz);
}
}
}
else {
if (!ssl->options.dtls) {
AddRecordHeader(output, fragSz, handshake, ssl);
}
else {
#ifdef WOLFSSL_DTLS
AddFragHeaders(output, fragSz, ssl->fragOffset + headerSz,
payloadSz, certificate, ssl);
ssl->keys.dtls_handshake_number--;
#endif /* WOLFSSL_DTLS */
}
}
/* member */
if (certSz && ssl->fragOffset < certSz) {
word32 copySz = min(certSz - ssl->fragOffset, fragSz);
XMEMCPY(output + i,
ssl->buffers.certificate.buffer + ssl->fragOffset, copySz);
i += copySz;
ssl->fragOffset += copySz;
length -= copySz;
fragSz -= copySz;
}
if (certChainSz && fragSz) {
word32 copySz = min(certChainSz + certSz - ssl->fragOffset, fragSz);
XMEMCPY(output + i,
ssl->buffers.certChain.buffer + ssl->fragOffset - certSz,
copySz);
i += copySz;
ssl->fragOffset += copySz;
length -= copySz;
fragSz -= copySz;
}
if (ssl->keys.encryptionOn) {
byte* input;
int inputSz = i - RECORD_HEADER_SZ; /* build msg adds rec hdr */
input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (input == NULL)
return MEMORY_E;
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake);
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (sendSz < 0)
return sendSz;
}
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
return ret;
}
#endif
#ifdef WOLFSSL_CALLBACKS
if (ssl->hsInfoOn)
AddPacketName("Certificate", &ssl->handShakeInfo);
if (ssl->toInfoOn)
AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
ssl->heap);
#endif
ssl->buffers.outputBuffer.length += sendSz;
if (!ssl->options.groupMessages)
ret = SendBuffered(ssl);
} }
#ifdef WOLFSSL_DTLS if (ret != WANT_WRITE) {
if (ssl->options.dtls) { /* Clean up the fragment offset. */
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) ssl->fragOffset = 0;
return ret; #ifdef WOLFSSL_DTLS
} if (ssl->options.dtls)
#endif ssl->keys.dtls_handshake_number++;
#endif
if (ssl->options.side == WOLFSSL_SERVER_END)
ssl->options.serverState = SERVER_CERT_COMPLETE;
}
#ifdef WOLFSSL_CALLBACKS return ret;
if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
if (ssl->toInfoOn)
AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
ssl->heap);
#endif
if (ssl->options.side == WOLFSSL_SERVER_END)
ssl->options.serverState = SERVER_CERT_COMPLETE;
ssl->buffers.outputBuffer.length += sendSz;
if (ssl->options.groupMessages)
return 0;
else
return SendBuffered(ssl);
} }

View File

@ -5408,8 +5408,10 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl)
if (ssl->buffers.outputBuffer.length > 0) { if (ssl->buffers.outputBuffer.length > 0) {
if ( (ssl->error = SendBuffered(ssl)) == 0) { if ( (ssl->error = SendBuffered(ssl)) == 0) {
ssl->options.connectState++; if (ssl->fragOffset == 0) {
WOLFSSL_MSG("connect state: Advanced from buffered send"); ssl->options.connectState++;
WOLFSSL_MSG("connect state: Advanced from buffered send");
}
} }
else { else {
WOLFSSL_ERROR(ssl->error); WOLFSSL_ERROR(ssl->error);
@ -5724,8 +5726,10 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl)
if (ssl->buffers.outputBuffer.length > 0) { if (ssl->buffers.outputBuffer.length > 0) {
if ( (ssl->error = SendBuffered(ssl)) == 0) { if ( (ssl->error = SendBuffered(ssl)) == 0) {
ssl->options.acceptState++; if (ssl->fragOffset == 0) {
WOLFSSL_MSG("accept state: Advanced from buffered send"); ssl->options.acceptState++;
WOLFSSL_MSG("accept state: Advanced from buffered send");
}
} }
else { else {
WOLFSSL_ERROR(ssl->error); WOLFSSL_ERROR(ssl->error);

View File

@ -2284,6 +2284,7 @@ struct WOLFSSL {
int rflags; /* user read flags */ int rflags; /* user read flags */
int wflags; /* user write flags */ int wflags; /* user write flags */
word32 timeout; /* session timeout */ word32 timeout; /* session timeout */
word32 fragOffset; /* fragment offset */
word16 curSize; word16 curSize;
RecordLayerHeader curRL; RecordLayerHeader curRL;
MsgsReceived msgsReceived; /* peer messages received */ MsgsReceived msgsReceived; /* peer messages received */