diff --git a/cyassl/error-ssl.h b/cyassl/error-ssl.h index 94dec7e2f..de87d6a4d 100644 --- a/cyassl/error-ssl.h +++ b/cyassl/error-ssl.h @@ -124,6 +124,7 @@ enum CyaSSL_ErrorCodes { SCR_DIFFERENT_CERT_E = -391, /* SCR Different cert error */ SESSION_SECRET_CB_E = -392, /* Session secret Cb fcn failure */ NO_CHANGE_CIPHER_E = -393, /* Finished before change cipher */ + SANITY_MSG_E = -394, /* Sanity check on msg order error */ /* add strings to SetErrorString !!!!! */ diff --git a/cyassl/internal.h b/cyassl/internal.h index 180933821..4bc71f58e 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1956,6 +1956,24 @@ typedef struct DtlsMsg { #endif +/* Handshake messages recevied from peer (plus change cipher */ +typedef struct MsgsReceived { + word16 got_hello_request:1; + word16 got_client_hello:1; + word16 got_server_hello:1; + word16 got_hello_verify_request:1; + word16 got_session_ticket:1; + word16 got_certificate:1; + word16 got_server_key_exchange:1; + word16 got_certificate_request:1; + word16 got_server_hello_done:1; + word16 got_certificate_verify:1; + word16 got_client_key_exchange:1; + word16 got_finished:1; + word16 got_change_cipher:1; +} MsgsReceived; + + /* CyaSSL ssl type */ struct CYASSL { CYASSL_CTX* ctx; @@ -1970,6 +1988,7 @@ struct CYASSL { #endif CipherSpecs specs; Keys keys; + MsgsReceived msgsReceived; /* peer messages received */ int rfd; /* read file descriptor */ int wfd; /* write file descriptor */ int rflags; /* user read flags */ diff --git a/src/internal.c b/src/internal.c index 65b07667a..7fd3b7091 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1580,29 +1580,8 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->keys.dtls_state.nextSeq = 0; #endif -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - InitMd5(&ssl->hashMd5); -#endif -#ifndef NO_SHA - ret = InitSha(&ssl->hashSha); - if (ret != 0) { - return ret; - } -#endif -#endif -#ifndef NO_SHA256 - ret = InitSha256(&ssl->hashSha256); - if (ret != 0) { - return ret; - } -#endif -#ifdef CYASSL_SHA384 - ret = InitSha384(&ssl->hashSha384); - if (ret != 0) { - return ret; - } -#endif + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + #ifndef NO_RSA ssl->peerRsaKey = NULL; ssl->peerRsaKeyPresent = 0; @@ -1800,6 +1779,30 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) /* all done with init, now can return errors, call other stuff */ +#ifndef NO_OLD_TLS +#ifndef NO_MD5 + InitMd5(&ssl->hashMd5); +#endif +#ifndef NO_SHA + ret = InitSha(&ssl->hashSha); + if (ret != 0) { + return ret; + } +#endif +#endif +#ifndef NO_SHA256 + ret = InitSha256(&ssl->hashSha256); + if (ret != 0) { + return ret; + } +#endif +#ifdef CYASSL_SHA384 + ret = InitSha384(&ssl->hashSha384); + if (ret != 0) { + return ret; + } +#endif + /* increment CTX reference count */ if (LockMutex(&ctx->countMutex) != 0) { CYASSL_MSG("Couldn't lock CTX count mutex"); @@ -4686,6 +4689,129 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, word32 size, } +/* Make sure no duplicates, no fast forward, or other problems; 0 on success */ +static int SanityCheckMsgReceived(CYASSL* ssl, byte type) +{ + /* verify not a duplicate, mark received, check state */ + switch (type) { + + case hello_request: + if (ssl->msgsReceived.got_hello_request) { + CYASSL_MSG("Duplicate HelloRequest received"); + return -1; + } + ssl->msgsReceived.got_hello_request = 1; + + break; + + case client_hello: + if (ssl->msgsReceived.got_client_hello) { + CYASSL_MSG("Duplicate ClientHello received"); + return -1; + } + ssl->msgsReceived.got_client_hello = 1; + + break; + + case server_hello: + if (ssl->msgsReceived.got_server_hello) { + CYASSL_MSG("Duplicate ServerHello received"); + return -1; + } + ssl->msgsReceived.got_server_hello = 1; + + break; + + case hello_verify_request: + if (ssl->msgsReceived.got_hello_verify_request) { + CYASSL_MSG("Duplicate HelloVerifyRequest received"); + return -1; + } + ssl->msgsReceived.got_hello_verify_request = 1; + + break; + + case session_ticket: + if (ssl->msgsReceived.got_session_ticket) { + CYASSL_MSG("Duplicate SessionTicket received"); + return -1; + } + ssl->msgsReceived.got_session_ticket = 1; + + break; + + case certificate: + if (ssl->msgsReceived.got_certificate) { + CYASSL_MSG("Duplicate Certificate received"); + return -1; + } + ssl->msgsReceived.got_certificate = 1; + + break; + + case server_key_exchange: + if (ssl->msgsReceived.got_server_key_exchange) { + CYASSL_MSG("Duplicate ServerKeyExchange received"); + return -1; + } + ssl->msgsReceived.got_server_key_exchange = 1; + + break; + + case certificate_request: + if (ssl->msgsReceived.got_certificate_request) { + CYASSL_MSG("Duplicate CertificateRequest received"); + return -1; + } + ssl->msgsReceived.got_certificate_request = 1; + + break; + + case server_hello_done: + if (ssl->msgsReceived.got_server_hello_done) { + CYASSL_MSG("Duplicate ServerHelloDone received"); + return -1; + } + ssl->msgsReceived.got_server_hello_done = 1; + + break; + + case certificate_verify: + if (ssl->msgsReceived.got_certificate_verify) { + CYASSL_MSG("Duplicate CertificateVerify received"); + return -1; + } + ssl->msgsReceived.got_certificate_verify = 1; + + break; + + case client_key_exchange: + if (ssl->msgsReceived.got_client_key_exchange) { + CYASSL_MSG("Duplicate ClientKeyExchange received"); + return -1; + } + ssl->msgsReceived.got_client_key_exchange = 1; + + break; + + case finished: + if (ssl->msgsReceived.got_finished) { + CYASSL_MSG("Duplicate Finished received"); + return -1; + } + ssl->msgsReceived.got_finished = 1; + + break; + + default: + CYASSL_MSG("Unknown message type"); + return -1; + } + + return 0; +} + + static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, byte type, word32 size, word32 totalSz) { @@ -4698,6 +4824,12 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, if (*inOutIdx + size > totalSz) return INCOMPLETE_DATA; + /* sanity check msg received */ + if (SanityCheckMsgReceived(ssl, type) != 0) { + CYASSL_MSG("Sanity Check on handshake message type received failed"); + return SANITY_MSG_E; + } + /* hello_request not hashed */ if (type != hello_request) { ret = HashInput(ssl, input + *inOutIdx, size); @@ -7898,6 +8030,9 @@ const char* CyaSSL_ERR_reason_error_string(unsigned long e) case NO_CHANGE_CIPHER_E: return "Finished received from peer before Change Cipher Error"; + case SANITY_MSG_E: + return "Sanity Check on message order Error"; + default : return "unknown error number"; } diff --git a/src/ssl.c b/src/ssl.c index 9a1138fa0..74b324c3e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -779,6 +779,8 @@ int CyaSSL_Rehandshake(CYASSL* ssl) ssl->options.processReply = 0; /* TODO, move states in internal.h */ ssl->options.gotChangeCipher = 0; + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; #ifndef NO_OLD_TLS @@ -5313,6 +5315,8 @@ int CyaSSL_dtls_got_timeout(CYASSL* ssl) #ifdef CYASSL_DTLS if (ssl->options.dtls) { ssl->options.clientState = NULL_STATE; /* get again */ + /* reset messages received */ + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); /* re-init hashes, exclude first hello and verify request */ #ifndef NO_OLD_TLS InitMd5(&ssl->hashMd5);