diff --git a/src/sniffer.c b/src/sniffer.c index 577d59110..bcef1f9c5 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -90,6 +90,7 @@ enum { EXT_TYPE_SZ = 2, /* Extension length */ MAX_INPUT_SZ = MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA + MTU_EXTRA, /* Max input sz of reassembly */ + EXT_MASTER_SECRET = 0x17, /* Extended Master Secret Extension ID */ TICKET_EXT_ID = 0x23 /* Session Ticket Extension ID */ }; @@ -329,6 +330,9 @@ typedef struct Flags { byte srvAckFault; /* server acked unseen data from client */ byte cliSkipPartial; /* client skips partial data to catch up */ byte srvSkipPartial; /* server skips partial data to catch up */ +#ifdef HAVE_EXTENDED_MASTER + byte expectEms; /* expect extended master secret */ +#endif } Flags; @@ -341,6 +345,27 @@ typedef struct FinCaputre { } FinCaputre; +typedef struct HsHashes { +#ifndef NO_OLD_TLS +#ifndef NO_SHA + Sha hashSha; +#endif +#ifndef NO_MD5 + Md5 hashMd5; +#endif +#endif +#ifndef NO_SHA256 + Sha256 hashSha256; +#endif +#ifdef WOLFSSL_SHA384 + Sha384 hashSha384; +#endif +#ifdef WOLFSSL_SHA512 + Sha512 hashSha512; +#endif +} HsHashes; + + /* Sniffer Session holds info for each client/server SSL/TLS session */ typedef struct SnifferSession { SnifferServer* context; /* server context */ @@ -363,6 +388,9 @@ typedef struct SnifferSession { word32 srvReassemblyMemory; /* server packet memory used */ struct SnifferSession* next; /* for hash table list */ byte* ticketID; /* mac ID of session ticket */ +#ifdef HAVE_EXTENDED_MASTER + HsHashes* hash; +#endif } SnifferSession; @@ -483,6 +511,9 @@ static void FreeSnifferSession(SnifferSession* session) FreePacketList(session->srvReassemblyList); free(session->ticketID); +#ifdef HAVE_EXTENDED_MASTER + free(session->hash); +#endif } free(session); } @@ -533,6 +564,102 @@ void ssl_FreeSniffer(void) } +#ifdef HAVE_EXTENDED_MASTER + +static int HashInit(HsHashes* hash) +{ + int ret = 0; + + XMEMSET(hash, 0, sizeof(HsHashes)); + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + if (ret == 0) + ret = wc_InitSha(&hash->hashSha); +#endif +#ifndef NO_MD5 + if (ret == 0) + wc_InitMd5(&hash->hashMd5); +#endif +#endif +#ifndef NO_SHA256 + if (ret == 0) + ret = wc_InitSha256(&hash->hashSha256); +#endif +#ifdef WOLFSSL_SHA384 + if (ret == 0) + ret = wc_InitSha384(&hash->hashSha384); +#endif +#ifdef WOLFSSL_SHA512 + if (ret == 0) + ret = wc_InitSha512(&hash->hashSha512); +#endif + + return ret; +} + + +static int HashUpdate(HsHashes* hash, const byte* input, int sz) +{ + int ret = 0; + + input -= HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + if (ret == 0) + ret = wc_ShaUpdate(&hash->hashSha, input, sz); +#endif +#ifndef NO_MD5 + if (ret == 0) + wc_Md5Update(&hash->hashMd5, input, sz); +#endif +#endif +#ifndef NO_SHA256 + if (ret == 0) + ret = wc_Sha256Update(&hash->hashSha256, input, sz); +#endif +#ifdef WOLFSSL_SHA384 + if (ret == 0) + ret = wc_Sha384Update(&hash->hashSha384, input, sz); +#endif +#ifdef WOLFSSL_SHA512 + if (ret == 0) + ret = wc_Sha512Update(&hash->hashSha512, input, sz); +#endif + + return ret; +} + + +static int HashCopy(HS_Hashes* d, HsHashes* s) +{ +#ifndef NO_OLD_TLS +#ifndef NO_SHA + XMEMCPY(&d->hashSha, &s->hashSha, sizeof(Sha)); +#endif +#ifndef NO_MD5 + XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(Md5)); +#endif +#endif + +#ifndef NO_SHA256 + XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(Sha256)); +#endif +#ifdef WOLFSSL_SHA384 + XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(Sha384)); +#endif +#ifdef WOLFSSL_SHA512 + XMEMCPY(&d->hashSha512, &s->hashSha512, sizeof(Sha512)); +#endif + + return 0; +} + +#endif + + /* Initialize a SnifferServer */ static void InitSnifferServer(SnifferServer* sniffer) { @@ -563,6 +690,9 @@ static void InitFlags(Flags* flags) flags->srvAckFault = 0; flags->cliSkipPartial = 0; flags->srvSkipPartial = 0; +#ifdef HAVE_EXTENDED_MASTER + flags->expectEms = 0; +#endif } @@ -600,6 +730,9 @@ static void InitSession(SnifferSession* session) InitFlags(&session->flags); InitFinCapture(&session->finCaputre); +#ifdef HAVE_EXTENDED_MASTER + session->hash = 0; +#endif } @@ -1483,13 +1616,17 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, /* Process Server Hello */ -static int ProcessServerHello(const byte* input, int* sslBytes, +static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, SnifferSession* session, char* error) { ProtocolVersion pv; byte b; int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; int doResume = 0; + int initialBytes = *sslBytes; + + (void)msgSz; + (void)initialBytes; /* make sure we didn't miss ClientHello */ if (session->flags.clientHello == 0) { @@ -1548,6 +1685,62 @@ static int ProcessServerHello(const byte* input, int* sslBytes, return -1; } +#ifdef HAVE_EXTENDED_MASTER + /* extensions */ + if ((initialBytes - *sslBytes) < msgSz) { + word16 len; + + /* skip extensions until extended master secret */ + /* make sure can read len */ + if (SUITE_LEN > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + len = (word16)((input[0] << 8) | input[1]); + input += SUITE_LEN; + *sslBytes -= SUITE_LEN; + /* make sure can read through all extensions */ + if (len > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + while (len >= EXT_TYPE_SZ + LENGTH_SZ) { + byte extType[EXT_TYPE_SZ]; + word16 extLen; + + extType[0] = input[0]; + extType[1] = input[1]; + input += EXT_TYPE_SZ; + *sslBytes -= EXT_TYPE_SZ; + + extLen = (word16)((input[0] << 8) | input[1]); + input += LENGTH_SZ; + *sslBytes -= LENGTH_SZ; + + /* make sure can read through individual extension */ + if (extLen > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + + if (extType[0] == 0x00 && extType[1] == EXT_MASTER_SECRET) { + session->flags.expectEms = 1; + } + + input += extLen; + *sslBytes -= extLen; + len -= extLen + EXT_TYPE_SZ + LENGTH_SZ; + } + } + + if (!session->flags.expectEms) { + free(session->hash); + session->hash = NULL; + } +#endif + if (session->sslServer->options.haveSessionId && XMEMCMP(session->sslServer->arrays->sessionID, session->sslClient->arrays->sessionID, ID_LEN) == 0) @@ -1758,7 +1951,7 @@ static int ProcessClientHello(const byte* input, int* sslBytes, return -1; } - while (len > EXT_TYPE_SZ + LENGTH_SZ) { + while (len >= EXT_TYPE_SZ + LENGTH_SZ) { byte extType[EXT_TYPE_SZ]; word16 extLen; @@ -1883,6 +2076,11 @@ static int DoHandShake(const byte* input, int* sslBytes, return -1; } +#ifdef HAVE_EXTENDED_MASTER + if (session->hash) + HashUpdate(session->hash, input, size); +#endif + switch (type) { case hello_verify_request: Trace(GOT_HELLO_VERIFY_STR); @@ -1896,7 +2094,7 @@ static int DoHandShake(const byte* input, int* sslBytes, break; case server_hello: Trace(GOT_SERVER_HELLO_STR); - ret = ProcessServerHello(input, sslBytes, session, error); + ret = ProcessServerHello(size, input, sslBytes, session, error); break; case certificate_request: Trace(GOT_CERT_REQ_STR); @@ -1923,6 +2121,16 @@ static int DoHandShake(const byte* input, int* sslBytes, break; case client_key_exchange: Trace(GOT_CLIENT_KEY_EX_STR); +#ifdef HAVE_EXTENDED_MASTER + if (session->flags.expectEms && session->hash != NULL) { + HashCopy(session->sslServer->hsHashes, session->hash); + HashCopy(session->sslClient->hsHashes, session->hash); + session->sslServer->options.haveEMS = 1; + session->sslClient->options.haveEMS = 1; + free(session->hash); + session->hash = NULL; + } +#endif ret = ProcessClientKeyExchange(input, sslBytes, session, error); break; case certificate_verify: @@ -2135,6 +2343,18 @@ static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, return 0; } InitSession(session); +#ifdef HAVE_EXTENDED_MASTER + { + HsHashes* newHash = (HsHashes*)malloc(sizeof(HsHashes)); + if (newHash == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + free(session); + return 0; + } + HashInit(newHash); + session->hash = newHash; + } +#endif session->server = ipInfo->dst; session->client = ipInfo->src; session->srvPort = (word16)tcpInfo->dstPort;