diff --git a/cyassl/internal.h b/cyassl/internal.h index 989947acd..146019236 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -599,7 +599,9 @@ enum Misc { COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ - OPAQUE16_LEN = 2, /* always 2 bytes */ + OPAQUE8_LEN = 1, /* 1 byte */ + OPAQUE16_LEN = 2, /* 2 bytes */ + OPAQUE24_LEN = 3, /* 3 bytes */ COMP_LEN = 1, /* compression length */ CURVE_LEN = 2, /* ecc named curve length */ SERVER_ID_LEN = 20, /* server session id length */ diff --git a/examples/client/client.c b/examples/client/client.c index ac6f935a8..807d7e91e 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -133,7 +133,7 @@ static void Usage(void) #ifdef HAVE_SNI printf("-S Use Host Name Indication\n"); #endif -#ifdef HAVE_MAXFRAGMENT +#ifdef HAVE_MAX_FRAGMENT printf("-L Use Maximum Fragment Length [1-5]\n"); #endif #ifdef HAVE_TRUNCATED_HMAC diff --git a/m4/ax_harden_compiler_flags.m4 b/m4/ax_harden_compiler_flags.m4 index 903bb9382..e977985a2 100644 --- a/m4/ax_harden_compiler_flags.m4 +++ b/m4/ax_harden_compiler_flags.m4 @@ -117,7 +117,7 @@ AX_APPEND_COMPILE_FLAGS([-Wno-pragmas],,[$ax_append_compile_cflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wall],,[$ax_append_compile_cflags_extra]) - AX_APPEND_COMPILE_FLAGS([-Wno-strict-aliasing],,,[$ax_append_compile_cflags_extra]) + AX_APPEND_COMPILE_FLAGS([-Wno-strict-aliasing],,[$ax_append_compile_cflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wextra],,[$ax_append_compile_cflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wunknown-pragmas],,[$ax_append_compile_cflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wthis-test-should-fail],,[$ax_append_compile_cflags_extra]) @@ -187,7 +187,7 @@ ]) AX_APPEND_COMPILE_FLAGS([-Wall],,[$ax_append_compile_cxxflags_extra]) - AX_APPEND_COMPILE_FLAGS([-Wno-strict-aliasing],,,[$ax_append_compile_cxxflags_extra]) + AX_APPEND_COMPILE_FLAGS([-Wno-strict-aliasing],,[$ax_append_compile_cxxflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wextra],,[$ax_append_compile_cxxflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wunknown-pragmas],,[$ax_append_compile_cxxflags_extra]) AX_APPEND_COMPILE_FLAGS([-Wthis-test-should-fail],,[$ax_append_compile_cxxflags_extra]) diff --git a/src/internal.c b/src/internal.c index 0e78e6a62..1fd2b6801 100644 --- a/src/internal.c +++ b/src/internal.c @@ -79,8 +79,7 @@ CYASSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS #ifndef NO_CYASSL_SERVER - static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32, - word32); + static int DoClientHello(CYASSL* ssl, const byte* input, word32*, word32); static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32*, word32); #if !defined(NO_RSA) || defined(HAVE_ECC) static int DoCertificateVerify(CYASSL* ssl, byte*, word32*, word32); @@ -3723,7 +3722,12 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, CYASSL_ENTER("DoHandShakeMsgType"); + /* make sure can read the message */ + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + HashInput(ssl, input + *inOutIdx, size); + #ifdef CYASSL_CALLBACKS /* add name later, add on record and handshake header part back on */ if (ssl->toInfoOn) { @@ -3820,12 +3824,12 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, #ifndef NO_CYASSL_SERVER case client_hello: CYASSL_MSG("processing client hello"); - ret = DoClientHello(ssl, input, inOutIdx, totalSz, size); + ret = DoClientHello(ssl, input, inOutIdx, size); break; case client_key_exchange: CYASSL_MSG("processing client key exchange"); - ret = DoClientKeyExchange(ssl, input, inOutIdx, totalSz); + ret = DoClientKeyExchange(ssl, input, inOutIdx, size); break; #if !defined(NO_RSA) || defined(HAVE_ECC) @@ -3840,6 +3844,7 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, default: CYASSL_MSG("Unknown handshake message type"); ret = UNKNOWN_HANDSHAKE_TYPE; + break; } CYASSL_LEAVE("DoHandShakeMsgType()", ret); @@ -3850,18 +3855,15 @@ static int DoHandShakeMsgType(CYASSL* ssl, byte* input, word32* inOutIdx, static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, word32 totalSz) { - byte type; + byte type; word32 size; - int ret = 0; + int ret = 0; CYASSL_ENTER("DoHandShakeMsg()"); if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0) return PARSE_ERROR; - if (*inOutIdx + size > totalSz) - return INCOMPLETE_DATA; - ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); CYASSL_LEAVE("DoHandShakeMsg()", ret); @@ -7461,29 +7463,38 @@ static void PickHashSigAlgo(CYASSL* ssl, static int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx, word32 helloSz) { - byte b; - byte compression; + byte b; ProtocolVersion pv; - word32 i = *inOutIdx; - word32 begin = i; + byte compression; + word32 i = *inOutIdx; + word32 begin = i; #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); #endif - XMEMCPY(&pv, input + i, sizeof(pv)); - i += (word32)sizeof(pv); + + /* protocol version, random and session id length check */ + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + /* protocol version */ + XMEMCPY(&pv, input + i, OPAQUE16_LEN); + i += OPAQUE16_LEN; + if (pv.minor > ssl->version.minor) { CYASSL_MSG("Server using higher version, fatal error"); return VERSION_ERROR; } else if (pv.minor < ssl->version.minor) { CYASSL_MSG("server using lower version"); + if (!ssl->options.downgrade) { CYASSL_MSG(" no downgrade allowed, fatal error"); return VERSION_ERROR; } - else if (pv.minor == SSLv3_MINOR) { + + if (pv.minor == SSLv3_MINOR) { /* turn off tls */ CYASSL_MSG(" downgrading to SSLv3"); ssl->options.tls = 0; @@ -7501,14 +7512,31 @@ static void PickHashSigAlgo(CYASSL* ssl, ssl->version.minor = TLSv1_1_MINOR; } } + + /* random */ XMEMCPY(ssl->arrays->serverRandom, input + i, RAN_LEN); i += RAN_LEN; + + /* session id */ b = input[i++]; - if (b) { + + if (b == ID_LEN) { + if ((i - begin) + ID_LEN > helloSz) + return BUFFER_ERROR; + XMEMCPY(ssl->arrays->sessionID, input + i, min(b, ID_LEN)); - i += b; + i += ID_LEN; ssl->options.haveSessionId = 1; } + else if (b) { + CYASSL_MSG("Invalid session ID size"); + return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } + + /* suite and compression */ + if ((i - begin) + OPAQUE16_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + ssl->options.cipherSuite0 = input[i++]; ssl->options.cipherSuite = input[i++]; compression = input[i++]; @@ -7519,17 +7547,23 @@ static void PickHashSigAlgo(CYASSL* ssl, } *inOutIdx = i; + + /* tls extensions */ if ( (i - begin) < helloSz) { #ifdef HAVE_TLS_EXTENSIONS if (IsTLS(ssl)) { - int ret = 0; + int ret = 0; word16 totalExtSz; Suites clSuites; /* just for compatibility right now */ + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + ato16(&input[i], &totalExtSz); - i += LENGTH_SZ; - if (totalExtSz > helloSz + begin - i) - return INCOMPLETE_DATA; + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; if ((ret = TLSX_Parse(ssl, (byte *) input + i, totalExtSz, 0, &clSuites))) @@ -7540,7 +7574,7 @@ static void PickHashSigAlgo(CYASSL* ssl, } else #endif - *inOutIdx = begin + helloSz; /* skip extensions */ + *inOutIdx = begin + helloSz; /* skip extensions */ } ssl->options.serverState = SERVER_HELLO_COMPLETE; @@ -7549,7 +7583,8 @@ static void PickHashSigAlgo(CYASSL* ssl, if (ssl->options.haveSessionId && XMEMCMP(ssl->arrays->sessionID, ssl->session.sessionID, ID_LEN) == 0) { if (SetCipherSpecs(ssl) == 0) { - int ret = -1; + int ret = -1; + XMEMCPY(ssl->arrays->masterSecret, ssl->session.masterSecret, SECRET_LEN); #ifdef NO_OLD_TLS @@ -7563,6 +7598,7 @@ static void PickHashSigAlgo(CYASSL* ssl, ret = DeriveKeys(ssl); #endif ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + return ret; } else { @@ -7580,6 +7616,7 @@ static void PickHashSigAlgo(CYASSL* ssl, DtlsPoolReset(ssl); } #endif + return SetCipherSpecs(ssl); } @@ -9986,7 +10023,7 @@ static void PickHashSigAlgo(CYASSL* ssl, static int DoClientHello(CYASSL* ssl, const byte* input, word32* inOutIdx, - word32 totalSz, word32 helloSz) + word32 helloSz) { byte b; ProtocolVersion pv; @@ -9999,12 +10036,8 @@ static void PickHashSigAlgo(CYASSL* ssl, if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); #endif - /* make sure can read the client hello */ - if (begin + helloSz > totalSz) - return INCOMPLETE_DATA; - /* protocol version, random and session id length check */ - if ((i - begin) + OPAQUE16_LEN + RAN_LEN + ENUM_LEN > helloSz) + if ((i - begin) + OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) return BUFFER_ERROR; /* protocol version */ @@ -10076,14 +10109,16 @@ static void PickHashSigAlgo(CYASSL* ssl, ssl->options.resuming = 1; /* client wants to resume */ CYASSL_MSG("Client wants to resume session"); } - else if (b) + else if (b) { + CYASSL_MSG("Invalid session ID size"); return BUFFER_ERROR; /* session ID nor 0 neither 32 bytes long */ + } #ifdef CYASSL_DTLS /* cookie */ if (ssl->options.dtls) { - if ((i - begin) + ENUM_LEN > helloSz) + if ((i - begin) + OPAQUE8_LEN > helloSz) return BUFFER_ERROR; b = input[i++]; @@ -10122,7 +10157,7 @@ static void PickHashSigAlgo(CYASSL* ssl, i += OPAQUE16_LEN; /* suites and compression length check */ - if ((i - begin) + clSuites.suiteSz + ENUM_LEN > helloSz) + if ((i - begin) + clSuites.suiteSz + OPAQUE8_LEN > helloSz) return BUFFER_ERROR; if (clSuites.suiteSz > MAX_SUITE_SZ) @@ -10512,18 +10547,19 @@ static void PickHashSigAlgo(CYASSL* ssl, } #endif - static int DoClientKeyExchange(CYASSL* ssl, byte* input, - word32* inOutIdx, word32 totalSz) + static int DoClientKeyExchange(CYASSL* ssl, byte* input, word32* inOutIdx, + word32 size) { int ret = 0; word32 length = 0; byte* out = NULL; + word32 begin = *inOutIdx; (void)length; /* shut up compiler warnings */ (void)out; (void)input; (void)inOutIdx; - (void)totalSz; + (void)size; if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { CYASSL_MSG("Client sending keyexchange at wrong time"); @@ -10552,15 +10588,12 @@ static void PickHashSigAlgo(CYASSL* ssl, { word32 idx = 0; RsaKey key; - byte* tmp = 0; byte doUserRsa = 0; #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - if (ssl->ctx->RsaDecCb) - doUserRsa = 1; - #endif /* NO_RSA */ - #endif /*HAVE_PK_CALLBACKS */ + if (ssl->ctx->RsaDecCb) + doUserRsa = 1; + #endif InitRsaKey(&key, ssl->heap); @@ -10576,28 +10609,31 @@ static void PickHashSigAlgo(CYASSL* ssl, if (ssl->options.tls) { word16 check; + + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + ato16(input + *inOutIdx, &check); - if ((word32)check != length) { + *inOutIdx += OPAQUE16_LEN; + + if ((word32) check != length) { CYASSL_MSG("RSA explicit size doesn't match"); FreeRsaKey(&key); return RSA_PRIVATE_ERROR; } - (*inOutIdx) += 2; } - tmp = input + *inOutIdx; - *inOutIdx += length; - if (*inOutIdx > totalSz) { + if ((*inOutIdx - begin) + length > size) { CYASSL_MSG("RSA message too big"); FreeRsaKey(&key); - return INCOMPLETE_DATA; + return BUFFER_ERROR; } if (doUserRsa) { #ifdef HAVE_PK_CALLBACKS #ifndef NO_RSA ret = ssl->ctx->RsaDecCb(ssl, - tmp, length, &out, + input + *inOutIdx, length, &out, ssl->buffers.key.buffer, ssl->buffers.key.length, ssl->RsaDecCtx); @@ -10605,9 +10641,12 @@ static void PickHashSigAlgo(CYASSL* ssl, #endif /*HAVE_PK_CALLBACKS */ } else { - ret = RsaPrivateDecryptInline(tmp, length, &out, &key); + ret = RsaPrivateDecryptInline(input + *inOutIdx, length, + &out, &key); } + *inOutIdx += length; + if (ret == SECRET_LEN) { XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN); if (ssl->arrays->preMasterSecret[0] != @@ -10633,36 +10672,46 @@ static void PickHashSigAlgo(CYASSL* ssl, byte* pms = ssl->arrays->preMasterSecret; word16 ci_sz; - ato16(&input[*inOutIdx], &ci_sz); - *inOutIdx += LENGTH_SZ; - if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR; + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; - XMEMCPY(ssl->arrays->client_identity, &input[*inOutIdx], ci_sz); + ato16(input + *inOutIdx, &ci_sz); + *inOutIdx += OPAQUE16_LEN; + + if (ci_sz > MAX_PSK_ID_LEN) + return CLIENT_ID_ERROR; + + if ((*inOutIdx - begin) + ci_sz > size) + return BUFFER_ERROR; + + XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz); *inOutIdx += ci_sz; - if (ci_sz < MAX_PSK_ID_LEN) - ssl->arrays->client_identity[ci_sz] = 0; - else - ssl->arrays->client_identity[MAX_PSK_ID_LEN-1] = 0; + ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0; ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, ssl->arrays->client_identity, ssl->arrays->psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) return PSK_KEY_ERROR; /* make psk pre master secret */ /* length of key + length 0s + length of key + key */ - c16toa((word16)ssl->arrays->psk_keySz, pms); - pms += 2; + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + XMEMSET(pms, 0, ssl->arrays->psk_keySz); pms += ssl->arrays->psk_keySz; - c16toa((word16)ssl->arrays->psk_keySz, pms); - pms += 2; + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; ret = MakeMasterSecret(ssl); + /* No further need for PSK */ XMEMSET(ssl->arrays->psk_key, 0, ssl->arrays->psk_keySz); ssl->arrays->psk_keySz = 0; @@ -10672,26 +10721,34 @@ static void PickHashSigAlgo(CYASSL* ssl, #ifdef HAVE_NTRU case ntru_kea: { - word32 rc; word16 cipherLen; word16 plainLen = sizeof(ssl->arrays->preMasterSecret); - byte* tmp; if (!ssl->buffers.key.buffer) return NO_PRIVATE_KEY; - ato16(&input[*inOutIdx], &cipherLen); - *inOutIdx += LENGTH_SZ; + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; + + ato16(input + *inOutIdx, &cipherLen); + *inOutIdx += OPAQUE16_LEN; + if (cipherLen > MAX_NTRU_ENCRYPT_SZ) return NTRU_KEY_ERROR; - tmp = input + *inOutIdx; - rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length, - ssl->buffers.key.buffer, cipherLen, tmp, &plainLen, - ssl->arrays->preMasterSecret); + if ((*inOutIdx - begin) + cipherLen > size) + return BUFFER_ERROR; - if (rc != NTRU_OK || plainLen != SECRET_LEN) + if (NTRU_OK != crypto_ntru_decrypt( + (word16) ssl->buffers.key.length, + ssl->buffers.key.buffer, cipherLen, + input + *inOutIdx, &plainLen, + ssl->arrays->preMasterSecret)) return NTRU_DECRYPT_ERROR; + + if (plainLen != SECRET_LEN) + return NTRU_DECRYPT_ERROR; + *inOutIdx += cipherLen; ssl->arrays->preMasterSz = plainLen; @@ -10702,18 +10759,23 @@ static void PickHashSigAlgo(CYASSL* ssl, #ifdef HAVE_ECC case ecc_diffie_hellman_kea: { - word32 size; - word32 bLength = input[*inOutIdx]; /* one byte length */ - *inOutIdx += 1; + if ((*inOutIdx - begin) + OPAQUE8_LEN > size) + return BUFFER_ERROR; - ret = ecc_import_x963(&input[*inOutIdx], - bLength, ssl->peerEccKey); - if (ret != 0) + length = input[*inOutIdx]; + *inOutIdx += OPAQUE8_LEN; + + if ((*inOutIdx - begin) + length > size) + return BUFFER_ERROR; + + if (ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey)) return ECC_PEERKEY_ERROR; - *inOutIdx += bLength; + + *inOutIdx += length; ssl->peerEccKeyPresent = 1; - size = sizeof(ssl->arrays->preMasterSecret); + length = sizeof(ssl->arrays->preMasterSecret); + if (ssl->specs.static_ecdh) { ecc_key staticKey; word32 i = 0; @@ -10721,17 +10783,21 @@ static void PickHashSigAlgo(CYASSL* ssl, ecc_init(&staticKey); ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, &staticKey, ssl->buffers.key.length); + if (ret == 0) ret = ecc_shared_secret(&staticKey, ssl->peerEccKey, - ssl->arrays->preMasterSecret, &size); + ssl->arrays->preMasterSecret, &length); + ecc_free(&staticKey); } - else + else ret = ecc_shared_secret(ssl->eccTempKey, ssl->peerEccKey, - ssl->arrays->preMasterSecret, &size); + ssl->arrays->preMasterSecret, &length); + if (ret != 0) return ECC_SHARED_ERROR; - ssl->arrays->preMasterSz = size; + + ssl->arrays->preMasterSz = length; ret = MakeMasterSecret(ssl); } break; @@ -10739,15 +10805,17 @@ static void PickHashSigAlgo(CYASSL* ssl, #ifdef OPENSSL_EXTRA case diffie_hellman_kea: { - byte* clientPub; word16 clientPubSz; DhKey dhKey; - ato16(&input[*inOutIdx], &clientPubSz); - *inOutIdx += LENGTH_SZ; + if ((*inOutIdx - begin) + OPAQUE16_LEN > size) + return BUFFER_ERROR; - clientPub = &input[*inOutIdx]; - *inOutIdx += clientPubSz; + ato16(input + *inOutIdx, &clientPubSz); + *inOutIdx += OPAQUE16_LEN; + + if ((*inOutIdx - begin) + clientPubSz > size) + return BUFFER_ERROR; InitDhKey(&dhKey); ret = DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, @@ -10759,8 +10827,11 @@ static void PickHashSigAlgo(CYASSL* ssl, &ssl->arrays->preMasterSz, ssl->buffers.serverDH_Priv.buffer, ssl->buffers.serverDH_Priv.length, - clientPub, clientPubSz); + input + *inOutIdx, clientPubSz); FreeDhKey(&dhKey); + + *inOutIdx += clientPubSz; + if (ret == 0) ret = MakeMasterSecret(ssl); } @@ -10773,6 +10844,7 @@ static void PickHashSigAlgo(CYASSL* ssl, } break; } + /* No further need for PMS */ XMEMSET(ssl->arrays->preMasterSecret, 0, ssl->arrays->preMasterSz); ssl->arrays->preMasterSz = 0; @@ -10789,5 +10861,3 @@ static void PickHashSigAlgo(CYASSL* ssl, } #endif /* NO_CYASSL_SERVER */ - - diff --git a/src/sniffer.c b/src/sniffer.c index b94eb503c..6779b4d8e 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -1782,7 +1782,7 @@ static int DoOldHello(SnifferSession* session, const byte* sslFrame, ret = ProcessOldClientHello(session->sslServer, input, &idx, *sslBytes, *rhSize); - if (ret < 0) { + if (ret < 0 && ret != MATCH_SUITE_ERROR) { SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE); return -1; }