From dea5e73852b6641bf404031c0f11a82f5d03b21d Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 22 Aug 2019 15:57:27 -0700 Subject: [PATCH] Sniffer Chain Input Add a new method for handling input records where the input is in the form of an iovec list. --- src/sniffer.c | 97 +++++++++++++++++++++++++-- sslSniffer/sslSnifferTest/snifftest.c | 69 +++++++++++++++++-- wolfssl/sniffer.h | 11 +++ wolfssl/sniffer_error.h | 1 + wolfssl/sniffer_error.rc | 1 + 5 files changed, 166 insertions(+), 13 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 8696c5945..a4da757cd 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -266,7 +266,8 @@ static const char* const msgTable[] = /* 91 */ "No data destination Error", - "Store data callback failed" + "Store data callback failed", + "Loading chain input" }; @@ -3562,7 +3563,8 @@ static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo, /* returns 0 on success (continue), -1 on error, 1 on success (end) */ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte** sslFrame, SnifferSession** session, - int* sslBytes, const byte** end, char* error) + int* sslBytes, const byte** end, + void* vChain, word32 chainSz, char* error) { word32 length; SSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ? @@ -3604,7 +3606,7 @@ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, /* if current partial data, add to end of partial */ /* if skipping, the data is already at the end of partial */ - if ( !skipPartial && + if ( !skipPartial && !vChain && (length = ssl->buffers.inputBuffer.length) ) { Trace(PARTIAL_ADD_STR); @@ -3621,6 +3623,44 @@ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, *end = *sslFrame + *sslBytes; } + if (vChain != NULL) { +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + struct iovec* chain = (struct iovec*)vChain; + word32 i, offset, headerOffset, qty; + + Trace(CHAIN_INPUT_STR); + headerOffset = (word32)*sslFrame - (word32)chain[0].iov_base; + length = *sslBytes + headerOffset; + if (length > ssl->buffers.inputBuffer.bufferSize) { + if (GrowInputBuffer(ssl, length, 0) < 0) { + SetError(MEMORY_STR, error, *session, FATAL_ERROR_STATE); + return -1; + } + } + + offset = 0; + for (i = 0; i < chainSz; i++) { + /* In case there is extra data in the chain that isn't covered + * by the sizes in the TCP headers, don't copy too much. This + * case has been seen where there are 4 extra bytes in the + * packet capture than the TCP header indicates. */ + if (offset + chain[i].iov_len > length) + qty = length - offset; + else + qty = (word32)chain[i].iov_len; + XMEMCPY(ssl->buffers.inputBuffer.buffer + offset, + chain[i].iov_base, qty); + offset += qty; + } + + ssl->buffers.inputBuffer.length = length; + *sslFrame = ssl->buffers.inputBuffer.buffer + headerOffset; + *end = *sslFrame + *sslBytes; +#else + (void)chainSz; +#endif + } + if ((*session)->flags.clientHello == 0 && **sslFrame != handshake) { /* Sanity check the packet for an old style client hello. */ int rhSize = (((*sslFrame)[0] & 0x7f) << 8) | ((*sslFrame)[1]); @@ -3637,6 +3677,8 @@ static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, } else { #ifdef STARTTLS_ALLOWED + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); return 1; #endif } @@ -4008,6 +4050,7 @@ static int RemoveFatalSession(IpInfo* ipInfo, TcpInfo* tcpInfo, /* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */ /* returns Number of bytes on success, 0 for no data yet, and -1 on error */ static int ssl_DecodePacketInternal(const byte* packet, int length, + void* vChain, word32 chainSz, byte** data, SSLInfo* sslInfo, void* ctx, char* error) { @@ -4019,6 +4062,18 @@ static int ssl_DecodePacketInternal(const byte* packet, int length, int ret; SnifferSession* session = 0; +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + if (packet == NULL && vChain != NULL) { + struct iovec* chain = (struct iovec*)vChain; + word32 i; + + length = 0; + for (i = 0; i < chainSz; i++) + length += chain[i].iov_len; + packet = (const byte*)chain[0].iov_base; + } +#endif + if (CheckHeaders(&ipInfo, &tcpInfo, packet, length, &sslFrame, &sslBytes, error) != 0) return -1; @@ -4051,7 +4106,7 @@ static int ssl_DecodePacketInternal(const byte* packet, int length, } ret = CheckPreRecord(&ipInfo, &tcpInfo, &sslFrame, &session, &sslBytes, - &end, error); + &end, vChain, chainSz, error); if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; else if (ret == -1) return -1; else if (ret == 1) { @@ -4088,7 +4143,8 @@ static int ssl_DecodePacketInternal(const byte* packet, int length, int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length, unsigned char** data, SSLInfo* sslInfo, char* error) { - return ssl_DecodePacketInternal(packet, length, data, sslInfo, NULL, error); + return ssl_DecodePacketInternal(packet, length, NULL, 0, data, sslInfo, + NULL, error); } @@ -4096,7 +4152,8 @@ int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length, /* returns Number of bytes on success, 0 for no data yet, and -1 on error */ int ssl_DecodePacket(const byte* packet, int length, byte** data, char* error) { - return ssl_DecodePacketInternal(packet, length, data, NULL, NULL, error); + return ssl_DecodePacketInternal(packet, length, NULL, 0, data, NULL, NULL, + error); } @@ -4105,7 +4162,33 @@ int ssl_DecodePacket(const byte* packet, int length, byte** data, char* error) int ssl_DecodePacketWithSessionInfoStoreData(const unsigned char* packet, int length, void* ctx, SSLInfo* sslInfo, char* error) { - return ssl_DecodePacketInternal(packet, length, NULL, sslInfo, ctx, error); + return ssl_DecodePacketInternal(packet, length, NULL, 0, NULL, sslInfo, + ctx, error); +} + +#endif + + +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + +int ssl_DecodePacketWithChain(void* vChain, word32 chainSz, byte** data, + char* error) +{ + return ssl_DecodePacketInternal(NULL, 0, vChain, chainSz, data, NULL, NULL, + error); +} + +#endif + + +#if defined(WOLFSSL_SNIFFER_CHAIN_INPUT) && \ + defined(WOLFSSL_SNIFFER_STORE_DATA_CB) + +int ssl_DecodePacketWithChainSessionInfoStoreData(void* vChain, word32 chainSz, + void* ctx, SSLInfo* sslInfo, char* error) +{ + return ssl_DecodePacketInternal(NULL, 0, vChain, chainSz, NULL, sslInfo, + ctx, error); } #endif diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index 67e942f03..71781e160 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -72,6 +72,25 @@ enum { }; +/* A TLS record can be 16k and change. The chain is broken up into 2K chunks. + * This covers the TLS record, plus a chunk for TCP/IP headers. */ +#ifndef CHAIN_INPUT_CHUNK_SIZE + #define CHAIN_INPUT_CHUNK_SIZE 2048 +#elif (CHAIN_INPUT_CHUNK_SIZE < 256) + #undef CHAIN_INPUT_CHUNK_SIZE + #define CHAIN_INPUT_CHUNK_SIZE 256 +#elif (CHAIN_INPUT_CHUNK_SIZE > 16384) + #undef CHAIN_INPUT_CHUNK_SIZE + #define CHAIN_INPUT_CHUNK_SIZE 16384 +#endif +#define CHAIN_INPUT_COUNT ((16384 / CHAIN_INPUT_CHUNK_SIZE) + 1) + + +#ifndef STORE_DATA_BLOCK_SZ + #define STORE_DATA_BLOCK_SZ 1024 +#endif + + pcap_t* pcap = NULL; pcap_if_t* alldevs = NULL; @@ -170,6 +189,16 @@ static char* iptos(unsigned int addr) } +#if defined(WOLFSSL_SNIFFER_STORE_DATA_CB) || defined(WOLFSSL_SNIFFER_CHAIN_INPUT) + +static inline unsigned int min(unsigned int a, unsigned int b) +{ + return a > b ? b : a; +} + +#endif + + #ifdef WOLFSSL_SNIFFER_WATCH const byte rsaHash[] = { @@ -228,8 +257,7 @@ static int myStoreDataCb(const unsigned char* decryptBuf, if (decryptBufSz < decryptBufOffset) return -1; - qty = (decryptBufSz - decryptBufOffset) < 32 ? - (decryptBufSz - decryptBufOffset) : 32; + qty = min(decryptBufSz - decryptBufOffset, STORE_DATA_BLOCK_SZ); if (*data == NULL) { byte* tmpData; @@ -265,6 +293,10 @@ int main(int argc, char** argv) struct bpf_program fp; pcap_if_t *d; pcap_addr_t *a; +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + struct iovec chain[CHAIN_INPUT_COUNT]; + int chainSz; +#endif signal(SIGINT, sig_handler); @@ -443,13 +475,38 @@ int main(int argc, char** argv) } else continue; +#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT + { + unsigned int j = 0; + unsigned int remainder = header.caplen; -#ifndef WOLFSSL_SNIFFER_STORE_DATA_CB - ret = ssl_DecodePacketWithSessionInfo(packet, header.caplen, &data, - &sslInfo, err); -#else + chainSz = 0; + do { + unsigned int chunkSz; + + chunkSz = min(remainder, CHAIN_INPUT_CHUNK_SIZE); + chain[chainSz].iov_base = (void*)(packet + j); + chain[chainSz].iov_len = chunkSz; + j += chunkSz; + remainder -= chunkSz; + chainSz++; + } while (j < header.caplen); + } +#endif + +#if defined(WOLFSSL_SNIFFER_CHAIN_INPUT) && \ + defined(WOLFSSL_SNIFFER_STORE_DATA_CB) + ret = ssl_DecodePacketWithChainSessionInfoStoreData(chain, chainSz, + &data, &sslInfo, err); +#elif defined(WOLFSSL_SNIFFER_CHAIN_INPUT) + (void)sslInfo; + ret = ssl_DecodePacketWithChain(chain, chainSz, &data, err); +#elif defined(WOLFSSL_SNIFFER_STORE_DATA_CB) ret = ssl_DecodePacketWithSessionInfoStoreData(packet, header.caplen, &data, &sslInfo, err); +#else + ret = ssl_DecodePacketWithSessionInfo(packet, header.caplen, &data, + &sslInfo, err); #endif if (ret < 0) { printf("ssl_Decode ret = %d, %s\n", ret, err); diff --git a/wolfssl/sniffer.h b/wolfssl/sniffer.h index 28e26ba4e..7d11a7517 100644 --- a/wolfssl/sniffer.h +++ b/wolfssl/sniffer.h @@ -205,6 +205,17 @@ SSL_SNIFFER_API int ssl_DecodePacketWithSessionInfoStoreData( const unsigned char* packet, int length, void* ctx, SSLInfo* sslInfo, char* error); + +WOLFSSL_API +SSL_SNIFFER_API int ssl_DecodePacketWithChain(void* vChain, + unsigned int chainSz, unsigned char** data, char* error); + + +WOLFSSL_API +SSL_SNIFFER_API int ssl_DecodePacketWithChainSessionInfoStoreData( + void* vChain, unsigned int chainSz, void* ctx, SSLInfo* sslInfo, + char* error); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index f3fe93ca4..a63e1d015 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -129,6 +129,7 @@ #define NO_DATA_DEST_STR 91 #define STORE_DATA_FAIL_STR 92 +#define CHAIN_INPUT_STR 93 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index 31e1317cc..72fe36e9e 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -111,5 +111,6 @@ STRINGTABLE 91, "No data destination Error" 92, "Store Data callback failed" + 93, "Loading chain input" }