From 62ac388f55e3de526627c0ed0a4a3746c659c1dc Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 19 Aug 2019 15:33:43 -0700 Subject: [PATCH] Store Data Callback Added a callback and support to allow one to handle storing the data directly without reallocating the data buffer. Also added an example that uses this callback if the callback is enabled in the build. --- src/sniffer.c | 108 +++++++++++++++++++++----- sslSniffer/sslSnifferTest/snifftest.c | 44 +++++++++++ wolfssl/sniffer.h | 11 +++ wolfssl/sniffer_error.h | 4 + wolfssl/sniffer_error.rc | 4 + 5 files changed, 150 insertions(+), 21 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 156f400fb..8696c5945 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -261,7 +261,12 @@ static const char* const msgTable[] = "Watch callback not set", "Watch hash failed", "Watch callback failed", - "Bad Certificate Message" + "Bad Certificate Message", + "Store data callback not set", + + /* 91 */ + "No data destination Error", + "Store data callback failed" }; @@ -437,6 +442,11 @@ static WOLFSSL_GLOBAL SSLWatchCb WatchCb; static WOLFSSL_GLOBAL void* WatchCbCtx = NULL; #endif +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB +/* Store Data Callback */ +static WOLFSSL_GLOBAL SSLStoreDataCb StoreDataCb; +#endif + static void UpdateMissedDataSessions(void) { @@ -3707,7 +3717,7 @@ static int HaveMoreInput(SnifferSession* session, const byte** sslFrame, /* return Number of bytes on success, 0 for no data yet, and -1 on error */ static int ProcessMessage(const byte* sslFrame, SnifferSession* session, int sslBytes, byte** data, const byte* end, - char* error) + void* ctx, char* error) { const byte* sslBegin = sslFrame; const byte* recordEnd; /* end of record indicator */ @@ -3839,22 +3849,55 @@ doPart: ret = ssl->buffers.clearOutputBuffer.length; TraceGotData(ret); if (ret) { /* may be blank message */ - byte* tmpData; /* don't leak on realloc free */ - /* add an extra byte at end of allocation in case user - * wants to null terminate plaintext */ - tmpData = (byte*)XREALLOC(*data, decoded + ret + 1, - NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (tmpData == NULL) { - ForceZero(*data, decoded); - XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - *data = NULL; - SetError(MEMORY_STR, error, session, - FATAL_ERROR_STATE); - return -1; + if (data != NULL) { + byte* tmpData; /* don't leak on realloc free */ + /* add an extra byte at end of allocation in case + * user wants to null terminate plaintext */ + tmpData = (byte*)XREALLOC(*data, decoded + ret + 1, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmpData == NULL) { + ForceZero(*data, decoded); + XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *data = NULL; + SetError(MEMORY_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + *data = tmpData; + XMEMCPY(*data + decoded, + ssl->buffers.clearOutputBuffer.buffer, ret); + } + else { +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + if (StoreDataCb) { + const byte* buf; + word32 offset = 0; + word32 bufSz; + int stored; + + buf = ssl->buffers.clearOutputBuffer.buffer; + bufSz = ssl->buffers.clearOutputBuffer.length; + do { + stored = StoreDataCb(buf, bufSz, offset, + ctx); + if (stored <= 0) { + return -1; + } + offset += stored; + } while (offset < bufSz); + } + else { + SetError(STORE_DATA_CB_MISSING_STR, error, + session, FATAL_ERROR_STATE); + return -1; + } +#else + (void)ctx; + SetError(NO_DATA_DEST_STR, error, session, + FATAL_ERROR_STATE); + return -1; +#endif } - *data = tmpData; - XMEMCPY(*data + decoded, - ssl->buffers.clearOutputBuffer.buffer, ret); TraceAddedData(ret, decoded); decoded += ret; ssl->buffers.clearOutputBuffer.length = 0; @@ -3965,7 +4008,8 @@ 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, - byte** data, SSLInfo* sslInfo, char* error) + byte** data, SSLInfo* sslInfo, + void* ctx, char* error) { TcpInfo tcpInfo; IpInfo ipInfo; @@ -4028,7 +4072,7 @@ static int ssl_DecodePacketInternal(const byte* packet, int length, INC_STAT(SnifferStats.sslDecryptedPackets); #endif - ret = ProcessMessage(sslFrame, session, sslBytes, data, end, error); + ret = ProcessMessage(sslFrame, session, sslBytes, data, end, ctx, error); if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; if (CheckFinCapture(&ipInfo, &tcpInfo, session) == 0) { CopySessionInfo(session, sslInfo); @@ -4044,7 +4088,7 @@ 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, error); + return ssl_DecodePacketInternal(packet, length, data, sslInfo, NULL, error); } @@ -4052,10 +4096,21 @@ 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, error); + return ssl_DecodePacketInternal(packet, length, data, NULL, NULL, error); } +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + +int ssl_DecodePacketWithSessionInfoStoreData(const unsigned char* packet, + int length, void* ctx, SSLInfo* sslInfo, char* error) +{ + return ssl_DecodePacketInternal(packet, length, NULL, sslInfo, ctx, error); +} + +#endif + + /* Deallocator for the decoded data buffer. */ /* returns 0 on success, -1 on error */ int ssl_FreeDecodeBuffer(byte** data, char* error) @@ -4310,5 +4365,16 @@ int ssl_SetWatchKey_file(void* vSniffer, const char* keyFile, int keyType, #endif /* WOLFSSL_SNIFFER_WATCH */ + +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + +int ssl_SetStoreDataCallback(SSLStoreDataCb cb) +{ + StoreDataCb = cb; + return 0; +} + +#endif /* WOLFSSL_SNIFFER_STORE_DATA_CB */ + #endif /* WOLFSSL_SNIFFER */ #endif /* WOLFCRYPT_ONLY */ diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index 69757b7e4..67e942f03 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -214,6 +214,42 @@ static int myWatchCb(void* vSniffer, #endif +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + +static int myStoreDataCb(const unsigned char* decryptBuf, + unsigned int decryptBufSz, unsigned int decryptBufOffset, void* ctx) +{ + byte** data = (byte**)ctx; + unsigned int qty; + + if (data == NULL) + return -1; + + if (decryptBufSz < decryptBufOffset) + return -1; + + qty = (decryptBufSz - decryptBufOffset) < 32 ? + (decryptBufSz - decryptBufOffset) : 32; + + if (*data == NULL) { + byte* tmpData; + tmpData = (byte*)realloc(*data, decryptBufSz + 1); + if (tmpData == NULL) { + free(*data); + *data = NULL; + return -1; + } + *data = tmpData; + } + + memcpy(*data + decryptBufOffset, decryptBuf + decryptBufOffset, qty); + + return qty; +} + +#endif + + int main(int argc, char** argv) { int ret = 0; @@ -240,6 +276,9 @@ int main(int argc, char** argv) #ifdef WOLFSSL_SNIFFER_WATCH ssl_SetWatchKeyCallback(myWatchCb, err); #endif +#ifdef WOLFSSL_SNIFFER_STORE_DATA_CB + ssl_SetStoreDataCallback(myStoreDataCb); +#endif if (argc == 1) { /* normal case, user chooses device and port */ @@ -405,8 +444,13 @@ int main(int argc, char** argv) else continue; +#ifndef WOLFSSL_SNIFFER_STORE_DATA_CB ret = ssl_DecodePacketWithSessionInfo(packet, header.caplen, &data, &sslInfo, err); +#else + ret = ssl_DecodePacketWithSessionInfoStoreData(packet, + header.caplen, &data, &sslInfo, err); +#endif if (ret < 0) { printf("ssl_Decode ret = %d, %s\n", ret, err); hadBadPacket = 1; diff --git a/wolfssl/sniffer.h b/wolfssl/sniffer.h index fedab6c06..28e26ba4e 100644 --- a/wolfssl/sniffer.h +++ b/wolfssl/sniffer.h @@ -194,6 +194,17 @@ SSL_SNIFFER_API int ssl_SetWatchKey_file(void* vSniffer, const char* password, char* error); +typedef int (*SSLStoreDataCb)(const unsigned char* decryptBuf, + unsigned int decryptBufSz, unsigned int decryptBufOffset, void* ctx); + +WOLFSSL_API +SSL_SNIFFER_API int ssl_SetStoreDataCallback(SSLStoreDataCb cb); + +WOLFSSL_API +SSL_SNIFFER_API int ssl_DecodePacketWithSessionInfoStoreData( + const unsigned char* packet, int length, void* ctx, + SSLInfo* sslInfo, char* error); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index e3bc38b78..f3fe93ca4 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -125,6 +125,10 @@ #define WATCH_HASH_STR 87 #define WATCH_FAIL_STR 88 #define BAD_CERT_MSG_STR 89 +#define STORE_DATA_CB_MISSING_STR 90 + +#define NO_DATA_DEST_STR 91 +#define STORE_DATA_FAIL_STR 92 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index 336cf33e8..31e1317cc 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -107,5 +107,9 @@ STRINGTABLE 87, "Watch hash failed" 88, "Watch callback failed" 89, "Bad Certificate Message" + 90, "Store data callback not set" + + 91, "No data destination Error" + 92, "Store Data callback failed" }