Browse Source

Sniffer Chain Input
Add a new method for handling input records where the input is in the form of an iovec list.

John Safranek 4 years ago
parent
commit
dea5e73852
5 changed files with 166 additions and 13 deletions
  1. 90 7
      src/sniffer.c
  2. 63 6
      sslSniffer/sslSnifferTest/snifftest.c
  3. 11 0
      wolfssl/sniffer.h
  4. 1 0
      wolfssl/sniffer_error.h
  5. 1 0
      wolfssl/sniffer_error.rc

+ 90 - 7
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

+ 63 - 6
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;
+
+                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
 
-#ifndef WOLFSSL_SNIFFER_STORE_DATA_CB
-            ret = ssl_DecodePacketWithSessionInfo(packet, header.caplen, &data,
-                                                  &sslInfo, err);
-#else
+#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);

+ 11 - 0
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

+ 1 - 0
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 !!!! */
 
 

+ 1 - 0
wolfssl/sniffer_error.rc

@@ -111,5 +111,6 @@ STRINGTABLE
 
     91, "No data destination Error"
     92, "Store Data callback failed"
+    93, "Loading chain input"
 }