diff --git a/src/internal.c b/src/internal.c index 9321a840e..5c9ede255 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1956,6 +1956,10 @@ void FreeArrays(WOLFSSL* ssl, int keep) XMEMCPY(ssl->session.sessionID, ssl->arrays->sessionID, ID_LEN); ssl->session.sessionIDSz = ssl->arrays->sessionIDSz; } + if (ssl->arrays) { + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + } XFREE(ssl->arrays, ssl->heap, DYNAMIC_TYPE_CERT); ssl->arrays = NULL; } @@ -5259,16 +5263,73 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 totalSz) { - byte type; - word32 size; int ret = 0; WOLFSSL_ENTER("DoHandShakeMsg()"); - if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size, totalSz) != 0) - return PARSE_ERROR; + /* If there is a pending fragmented handshake message, + * pending message size will be non-zero. */ + if (ssl->arrays->pendingMsgSz == 0) { + byte type; + word32 size; - ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + if (GetHandShakeHeader(ssl,input, inOutIdx, &type, &size, totalSz) != 0) + return PARSE_ERROR; + + /* Cap the maximum size of a handshake message to something reasonable. + * By default is the maximum size of a certificate message assuming + * nine 2048-bit RSA certificates in the chain. */ + if (size > MAX_HANDSHAKE_SZ) { + WOLFSSL_MSG("Handshake message too large"); + return HANDSHAKE_SIZE_ERROR; + } + + /* size is the size of the certificate message payload */ + if (ssl->curSize < size) { + ssl->arrays->pendingMsgType = type; + ssl->arrays->pendingMsgSz = size + HANDSHAKE_HEADER_SZ; + ssl->arrays->pendingMsg = (byte*)XMALLOC(size + HANDSHAKE_HEADER_SZ, + ssl->heap, + DYNAMIC_TYPE_ARRAYS); + if (ssl->arrays->pendingMsg == NULL) + return MEMORY_E; + XMEMCPY(ssl->arrays->pendingMsg, + input + *inOutIdx - HANDSHAKE_HEADER_SZ, ssl->curSize); + ssl->arrays->pendingMsgOffset = ssl->curSize; + *inOutIdx += ssl->curSize - HANDSHAKE_HEADER_SZ; + return 0; + } + + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + } + else { + if (ssl->curSize + ssl->arrays->pendingMsgOffset + > ssl->arrays->pendingMsgSz) { + + return BUFFER_ERROR; + } + else { + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, + input + *inOutIdx, ssl->curSize); + ssl->arrays->pendingMsgOffset += ssl->curSize; + *inOutIdx += ssl->curSize; + } + + if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz) + { + word32 idx = 0; + ret = DoHandShakeMsgType(ssl, + ssl->arrays->pendingMsg + + HANDSHAKE_HEADER_SZ, + &idx, ssl->arrays->pendingMsgType, + ssl->arrays->pendingMsgSz + - HANDSHAKE_HEADER_SZ, + ssl->arrays->pendingMsgSz); + XFREE(ssl->arrays->pendingMsg, ssl->heap, DYNAMIC_TYPE_ARRAYS); + ssl->arrays->pendingMsg = NULL; + ssl->arrays->pendingMsgSz = 0; + } + } WOLFSSL_LEAVE("DoHandShakeMsg()", ret); return ret; @@ -8500,6 +8561,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case RSA_SIGN_FAULT: return "RSA Signature Fault Error"; + case HANDSHAKE_SIZE_ERROR: + return "Handshake message too large Error"; + default : return "unknown error number"; } diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 309be9eca..c3ff047fc 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -136,6 +136,7 @@ enum wolfSSL_ErrorCodes { DH_KEY_SIZE_E = -401, /* DH Key too small */ SNI_ABSENT_ERROR = -402, /* No SNI request. */ RSA_SIGN_FAULT = -403, /* RSA Sign fault */ + HANDSHAKE_SIZE_ERROR = -404, /* Handshake message too large */ /* add strings to SetErrorString !!!!! */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 99831e599..85afad61c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1016,6 +1016,19 @@ enum Misc { #define MAX_CHAIN_DEPTH 9 #endif +/* max size of a certificate message payload */ +/* assumes MAX_CHAIN_DEPTH number of certificates at 2kb per certificate */ +#ifndef MAX_CERTIFICATE_SZ + #define MAX_CERTIFICATE_SZ \ + CERT_HEADER_SZ + \ + (MAX_X509_SIZE + CERT_HEADER_SZ) * MAX_CHAIN_DEPTH +#endif + +/* max size of a handshake message, currently set to the certificate */ +#ifndef MAX_HANDSHAKE_SZ + #define MAX_HANDSHAKE_SZ MAX_CERTIFICATE_SZ +#endif + #ifndef SESSION_TICKET_LEN #define SESSION_TICKET_LEN 256 #endif @@ -2098,7 +2111,10 @@ typedef struct Options { } Options; typedef struct Arrays { + byte* pendingMsg; /* defrag buffer */ word32 preMasterSz; /* differs for DH, actual size */ + word32 pendingMsgSz; /* defrag buffer size */ + word32 pendingMsgOffset; /* current offset into defrag buffer */ #ifndef NO_PSK word32 psk_keySz; /* acutal size */ char client_identity[MAX_PSK_ID_LEN];