diff options
Diffstat (limited to 'client/wolfssl/src/sniffer.c')
| -rw-r--r-- | client/wolfssl/src/sniffer.c | 4611 |
1 files changed, 0 insertions, 4611 deletions
diff --git a/client/wolfssl/src/sniffer.c b/client/wolfssl/src/sniffer.c deleted file mode 100644 index 9087148..0000000 --- a/client/wolfssl/src/sniffer.c +++ /dev/null @@ -1,4611 +0,0 @@ -/* sniffer.c - * - * Copyright (C) 2006-2020 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <wolfssl/wolfcrypt/settings.h> - -#ifndef WOLFCRYPT_ONLY -#ifdef WOLFSSL_SNIFFER - -#include <assert.h> -#include <time.h> - -#ifndef _WIN32 - #include <arpa/inet.h> -#else - #include <WS2tcpip.h> -#endif - -#ifdef _WIN32 - #define SNPRINTF _snprintf -#else - #define SNPRINTF snprintf -#endif - -#include <wolfssl/openssl/ssl.h> -#include <wolfssl/internal.h> -#include <wolfssl/error-ssl.h> -#include <wolfssl/sniffer.h> -#include <wolfssl/sniffer_error.h> -#ifdef NO_INLINE - #include <wolfssl/wolfcrypt/misc.h> -#else - #define WOLFSSL_MISC_INCLUDED - #include <wolfcrypt/src/misc.c> -#endif - -#ifdef WOLF_CRYPTO_CB - #include <wolfssl/wolfcrypt/cryptocb.h> - #ifdef HAVE_INTEL_QA_SYNC - #include <wolfssl/wolfcrypt/port/intel/quickassist_sync.h> - #endif - #ifdef HAVE_CAVIUM_OCTEON_SYNC - #include <wolfssl/wolfcrypt/port/cavium/cavium_octeon_sync.h> - #endif -#endif - - -#ifndef WOLFSSL_SNIFFER_TIMEOUT - #define WOLFSSL_SNIFFER_TIMEOUT 900 - /* Cache unclosed Sessions for 15 minutes since last used */ -#endif - -/* Misc constants */ -enum { - MAX_SERVER_ADDRESS = 128, /* maximum server address length */ - MAX_SERVER_NAME = 128, /* maximum server name length */ - MAX_ERROR_LEN = 80, /* maximum error length */ - ETHER_IF_ADDR_LEN = 6, /* ethernet interface address length */ - LOCAL_IF_ADDR_LEN = 4, /* localhost interface address length, !windows */ - TCP_PROTO = 6, /* TCP_PROTOCOL */ - IP_HDR_SZ = 20, /* IPv4 header length, min */ - IP6_HDR_SZ = 40, /* IPv6 header length, min */ - TCP_HDR_SZ = 20, /* TCP header length, min */ - IPV4 = 4, /* IP version 4 */ - IPV6 = 6, /* IP version 6 */ - TCP_PROTOCOL = 6, /* TCP Protocol id */ - NO_NEXT_HEADER = 59, /* IPv6 no headers follow */ - TRACE_MSG_SZ = 80, /* Trace Message buffer size */ - HASH_SIZE = 499, /* Session Hash Table Rows */ - PSEUDO_HDR_SZ = 12, /* TCP Pseudo Header size in bytes */ - FATAL_ERROR_STATE = 1, /* SnifferSession fatal error state */ - TICKET_HINT_LEN = 4, /* Session Ticket Hint length */ - 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 */ -}; - - -#ifdef _WIN32 - -static HMODULE dllModule; /* for error string resources */ - -BOOL APIENTRY DllMain( HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) -{ - static int didInit = 0; - - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - if (didInit == 0) { - dllModule = hModule; - ssl_InitSniffer(); - didInit = 1; - } - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - if (didInit) { - ssl_FreeSniffer(); - didInit = 0; - } - break; - } - return TRUE; -} - -#endif /* _WIN32 */ - - -static WOLFSSL_GLOBAL int TraceOn = 0; /* Trace is off by default */ -static WOLFSSL_GLOBAL FILE* TraceFile = 0; - - -/* windows uses .rc table for this */ -#ifndef _WIN32 - -static const char* const msgTable[] = -{ - /* 1 */ - "Out of Memory", - "New SSL Sniffer Server Registered", - "Checking IP Header", - "SSL Sniffer Server Not Registered", - "Checking TCP Header", - - /* 6 */ - "SSL Sniffer Server Port Not Registered", - "RSA Private Decrypt Error", - "RSA Private Decode Error", - "Set Cipher Spec Error", - "Server Hello Input Malformed", - - /* 11 */ - "Couldn't Resume Session Error", - "Server Did Resumption", - "Client Hello Input Malformed", - "Client Trying to Resume", - "Handshake Input Malformed", - - /* 16 */ - "Got Hello Verify msg", - "Got Server Hello msg", - "Got Cert Request msg", - "Got Server Key Exchange msg", - "Got Cert msg", - - /* 21 */ - "Got Server Hello Done msg", - "Got Finished msg", - "Got Client Hello msg", - "Got Client Key Exchange msg", - "Got Cert Verify msg", - - /* 26 */ - "Got Unknown Handshake msg", - "New SSL Sniffer Session created", - "Couldn't create new SSL", - "Got a Packet to decode", - "No data present", - - /* 31 */ - "Session Not Found", - "Got an Old Client Hello msg", - "Old Client Hello Input Malformed", - "Old Client Hello OK", - "Bad Old Client Hello", - - /* 36 */ - "Bad Record Header", - "Record Header Input Malformed", - "Got a HandShake msg", - "Bad HandShake msg", - "Got a Change Cipher Spec msg", - - /* 41 */ - "Got Application Data msg", - "Bad Application Data", - "Got an Alert msg", - "Another msg to Process", - "Removing Session From Table", - - /* 46 */ - "Bad Key File", - "Wrong IP Version", - "Wrong Protocol type", - "Packet Short for header processing", - "Got Unknown Record Type", - - /* 51 */ - "Can't Open Trace File", - "Session in Fatal Error State", - "Partial SSL record received", - "Buffer Error, malformed input", - "Added to Partial Input", - - /* 56 */ - "Received a Duplicate Packet", - "Received an Out of Order Packet", - "Received an Overlap Duplicate Packet", - "Received an Overlap Reassembly Begin Duplicate Packet", - "Received an Overlap Reassembly End Duplicate Packet", - - /* 61 */ - "Missed the Client Hello Entirely", - "Got Hello Request msg", - "Got Session Ticket msg", - "Bad Input", - "Bad Decrypt Type", - - /* 66 */ - "Bad Finished Message Processing", - "Bad Compression Type", - "Bad DeriveKeys Error", - "Saw ACK for Missing Packet Error", - "Bad Decrypt Operation", - - /* 71 */ - "Decrypt Keys Not Set Up", - "Late Key Load Error", - "Got Certificate Status msg", - "RSA Key Missing Error", - "Secure Renegotiation Not Supported", - - /* 76 */ - "Get Session Stats Failure", - "Reassembly Buffer Size Exceeded", - "Dropping Lost Fragment", - "Dropping Partial Record", - "Clear ACK Fault", - - /* 81 */ - "Bad Decrypt Size", - "Extended Master Secret Hash Error", - "Handshake Message Split Across TLS Records", - "ECC Private Decode Error", - "ECC Public Decode Error", - - /* 86 */ - "Watch callback not set", - "Watch hash failed", - "Watch callback failed", - "Bad Certificate Message", - "Store data callback not set", - - /* 91 */ - "No data destination Error", - "Store data callback failed", - "Loading chain input" -}; - - -/* *nix version uses table above */ -static void GetError(int idx, char* str) -{ - XSTRNCPY(str, msgTable[idx - 1], MAX_ERROR_LEN-1); - str[MAX_ERROR_LEN-1] = '\0'; -} - - -#else /* _WIN32 */ - - -/* Windows version uses .rc table */ -static void GetError(int idx, char* buffer) -{ - if (!LoadStringA(dllModule, idx, buffer, MAX_ERROR_LEN)) - buffer[0] = 0; -} - - -#endif /* _WIN32 */ - - -/* Packet Buffer for reassembly list and ready list */ -typedef struct PacketBuffer { - word32 begin; /* relative sequence begin */ - word32 end; /* relative sequence end */ - byte* data; /* actual data */ - struct PacketBuffer* next; /* next on reassembly list or ready list */ -} PacketBuffer; - - -#ifdef HAVE_SNI - -/* NamedKey maps a SNI name to a specific private key */ -typedef struct NamedKey { - char name[MAX_SERVER_NAME]; /* server DNS name */ - word32 nameSz; /* size of server DNS name */ - byte* key; /* DER private key */ - word32 keySz; /* size of DER private key */ - struct NamedKey* next; /* for list */ -} NamedKey; - -#endif - - -typedef struct IpAddrInfo { - int version; - union { - word32 ip4; - byte ip6[16]; - }; -} IpAddrInfo; - - -/* Sniffer Server holds info for each server/port monitored */ -typedef struct SnifferServer { - SSL_CTX* ctx; /* SSL context */ - char address[MAX_SERVER_ADDRESS]; /* passed in server address */ - IpAddrInfo server; /* network order address */ - int port; /* server port */ -#ifdef HAVE_SNI - NamedKey* namedKeys; /* mapping of names and keys */ - wolfSSL_Mutex namedKeysMutex; /* mutex for namedKey list */ -#endif - struct SnifferServer* next; /* for list */ -} SnifferServer; - - -/* Session Flags */ -typedef struct Flags { - byte side; /* which end is current packet headed */ - byte serverCipherOn; /* indicates whether cipher is active */ - byte clientCipherOn; /* indicates whether cipher is active */ - byte resuming; /* did this session come from resumption */ - byte cached; /* have we cached this session yet */ - byte clientHello; /* processed client hello yet, for SSLv2 */ - byte finCount; /* get both FINs before removing */ - byte fatalError; /* fatal error state */ - byte cliAckFault; /* client acked unseen data from server */ - 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; - - -/* Out of Order FIN capture */ -typedef struct FinCaputre { - word32 cliFinSeq; /* client relative sequence FIN 0 is no */ - word32 srvFinSeq; /* server relative sequence FIN, 0 is no */ - byte cliCounted; /* did we count yet, detects duplicates */ - byte srvCounted; /* did we count yet, detects duplicates */ -} FinCaputre; - - -typedef struct HsHashes { -#ifndef NO_OLD_TLS -#ifndef NO_SHA - wc_Sha hashSha; -#endif -#ifndef NO_MD5 - wc_Md5 hashMd5; -#endif -#endif -#ifndef NO_SHA256 - wc_Sha256 hashSha256; -#endif -#ifdef WOLFSSL_SHA384 - wc_Sha384 hashSha384; -#endif -} HsHashes; - - -/* Sniffer Session holds info for each client/server SSL/TLS session */ -typedef struct SnifferSession { - SnifferServer* context; /* server context */ - SSL* sslServer; /* SSL server side decode */ - SSL* sslClient; /* SSL client side decode */ - IpAddrInfo server; /* server address in network byte order */ - IpAddrInfo client; /* client address in network byte order */ - word16 srvPort; /* server port */ - word16 cliPort; /* client port */ - word32 cliSeqStart; /* client start sequence */ - word32 srvSeqStart; /* server start sequence */ - word32 cliExpected; /* client expected sequence (relative) */ - word32 srvExpected; /* server expected sequence (relative) */ - FinCaputre finCaputre; /* retain out of order FIN s */ - Flags flags; /* session flags */ - time_t lastUsed; /* last used ticks */ - word32 keySz; /* size of the private key */ - PacketBuffer* cliReassemblyList; /* client out of order packets */ - PacketBuffer* srvReassemblyList; /* server out of order packets */ - word32 cliReassemblyMemory; /* client packet memory used */ - word32 srvReassemblyMemory; /* server packet memory used */ - struct SnifferSession* next; /* for hash table list */ - byte* ticketID; /* mac ID of session ticket */ -#ifdef HAVE_SNI - const char* sni; /* server name indication */ -#endif -#ifdef HAVE_EXTENDED_MASTER - HsHashes* hash; -#endif -} SnifferSession; - - -/* Sniffer Server List and mutex */ -static WOLFSSL_GLOBAL SnifferServer* ServerList = 0; -static WOLFSSL_GLOBAL wolfSSL_Mutex ServerListMutex; - - -/* Session Hash Table, mutex, and count */ -static WOLFSSL_GLOBAL SnifferSession* SessionTable[HASH_SIZE]; -static WOLFSSL_GLOBAL wolfSSL_Mutex SessionMutex; -static WOLFSSL_GLOBAL int SessionCount = 0; - -/* Recovery of missed data switches and stats */ -static WOLFSSL_GLOBAL wolfSSL_Mutex RecoveryMutex; /* for stats */ -static WOLFSSL_GLOBAL int RecoveryEnabled = 0; /* global switch */ -static WOLFSSL_GLOBAL int MaxRecoveryMemory = -1; - /* per session max recovery memory */ -static WOLFSSL_GLOBAL word32 MissedDataSessions = 0; - /* # of sessions with missed data */ - -/* Connection Info Callback */ -static WOLFSSL_GLOBAL SSLConnCb ConnectionCb; -static WOLFSSL_GLOBAL void* ConnectionCbCtx = NULL; - -#ifdef WOLFSSL_SNIFFER_STATS -/* Sessions Statistics */ -static WOLFSSL_GLOBAL SSLStats SnifferStats; -static WOLFSSL_GLOBAL wolfSSL_Mutex StatsMutex; -#endif - -#ifdef WOLFSSL_SNIFFER_WATCH -/* Watch Key Callback */ -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) -{ - wc_LockMutex(&RecoveryMutex); - MissedDataSessions += 1; - wc_UnLockMutex(&RecoveryMutex); -} - - -#ifdef WOLFSSL_SNIFFER_STATS -#define LOCK_STAT() do { wc_LockMutex(&StatsMutex); } while (0) -#define UNLOCK_STAT() do { wc_UnLockMutex(&StatsMutex); } while (0) -#define NOLOCK_ADD_TO_STAT(x,y) do { TraceStat(#x, y); x += y; } while (0) -#define NOLOCK_INC_STAT(x) NOLOCK_ADD_TO_STAT(x,1) -#define ADD_TO_STAT(x,y) do { LOCK_STAT(); \ - NOLOCK_ADD_TO_STAT(x,y); UNLOCK_STAT(); } while (0) -#define INC_STAT(x) do { LOCK_STAT(); \ - NOLOCK_INC_STAT(x); UNLOCK_STAT(); } while (0) -#endif - - -#ifdef WOLF_CRYPTO_CB - static WOLFSSL_GLOBAL int CryptoDeviceId = INVALID_DEVID; -#endif - - -/* Initialize overall Sniffer */ -void ssl_InitSniffer(void) -{ - wolfSSL_Init(); - wc_InitMutex(&ServerListMutex); - wc_InitMutex(&SessionMutex); - wc_InitMutex(&RecoveryMutex); -#ifdef WOLFSSL_SNIFFER_STATS - XMEMSET(&SnifferStats, 0, sizeof(SSLStats)); - wc_InitMutex(&StatsMutex); -#endif -#ifdef WOLF_CRYPTO_CB - #ifdef HAVE_INTEL_QA_SYNC - CryptoDeviceId = wc_CryptoCb_InitIntelQa(); - if (INVALID_DEVID == CryptoDeviceId) { - printf("Couldn't init the Intel QA\n"); - } - #endif - #ifdef HAVE_CAVIUM_OCTEON_SYNC - CryptoDeviceId = wc_CryptoCb_InitOcteon(); - if (INVALID_DEVID == CryptoDeviceId) { - printf("Couldn't init the Intel QA\n"); - } - #endif -#endif -} - - -#ifdef HAVE_SNI - -/* Free Named Key and the zero out the private key it holds */ -static void FreeNamedKey(NamedKey* in) -{ - if (in) { - if (in->key) { - ForceZero(in->key, in->keySz); - XFREE(in->key, NULL, DYNAMIC_TYPE_X509); - } - XFREE(in, NULL, DYNAMIC_TYPE_SNIFFER_NAMED_KEY); - } -} - - -static void FreeNamedKeyList(NamedKey* in) -{ - NamedKey* next; - - while (in) { - next = in->next; - FreeNamedKey(in); - in = next; - } -} - -#endif - - -/* Free Sniffer Server's resources/self */ -static void FreeSnifferServer(SnifferServer* srv) -{ - if (srv) { -#ifdef HAVE_SNI - wc_LockMutex(&srv->namedKeysMutex); - FreeNamedKeyList(srv->namedKeys); - wc_UnLockMutex(&srv->namedKeysMutex); - wc_FreeMutex(&srv->namedKeysMutex); -#endif - SSL_CTX_free(srv->ctx); - } - XFREE(srv, NULL, DYNAMIC_TYPE_SNIFFER_SERVER); -} - - -/* free PacketBuffer's resources/self */ -static void FreePacketBuffer(PacketBuffer* del) -{ - if (del) { - XFREE(del->data, NULL, DYNAMIC_TYPE_SNIFFER_PB_BUFFER); - XFREE(del, NULL, DYNAMIC_TYPE_SNIFFER_PB); - } -} - - -/* remove PacketBuffer List */ -static void FreePacketList(PacketBuffer* in) -{ - if (in) { - PacketBuffer* del; - PacketBuffer* packet = in; - - while (packet) { - del = packet; - packet = packet->next; - FreePacketBuffer(del); - } - } -} - - -/* Free Sniffer Session's resources/self */ -static void FreeSnifferSession(SnifferSession* session) -{ - if (session) { - SSL_free(session->sslClient); - SSL_free(session->sslServer); - - FreePacketList(session->cliReassemblyList); - FreePacketList(session->srvReassemblyList); - - XFREE(session->ticketID, NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID); -#ifdef HAVE_EXTENDED_MASTER - XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); -#endif - } - XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); -} - - -/* Free overall Sniffer */ -void ssl_FreeSniffer(void) -{ - SnifferServer* srv; - SnifferServer* removeServer; - SnifferSession* session; - SnifferSession* removeSession; - int i; - - wc_LockMutex(&ServerListMutex); - wc_LockMutex(&SessionMutex); - - srv = ServerList; - while (srv) { - removeServer = srv; - srv = srv->next; - FreeSnifferServer(removeServer); - } - - for (i = 0; i < HASH_SIZE; i++) { - session = SessionTable[i]; - while (session) { - removeSession = session; - session = session->next; - FreeSnifferSession(removeSession); - } - } - - wc_UnLockMutex(&SessionMutex); - wc_UnLockMutex(&ServerListMutex); - - wc_FreeMutex(&RecoveryMutex); - wc_FreeMutex(&SessionMutex); - wc_FreeMutex(&ServerListMutex); - -#ifdef WOLF_CRYPTO_CB -#ifdef HAVE_INTEL_QA_SYNC - wc_CryptoCb_CleanupIntelQa(&CryptoDeviceId); -#endif -#ifdef HAVE_CAVIUM_OCTEON_SYNC - wc_CryptoCb_CleanupOcteon(&CryptoDeviceId); -#endif -#endif - - if (TraceFile) { - TraceOn = 0; - fclose(TraceFile); - TraceFile = NULL; - } - - wolfSSL_Cleanup(); -} - - -#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) { - ret = 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 - - 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) { - ret = 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 - - return ret; -} - - -static int HashCopy(HS_Hashes* d, HsHashes* s) -{ -#ifndef NO_OLD_TLS -#ifndef NO_SHA - XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha)); -#endif -#ifndef NO_MD5 - XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5)); -#endif -#endif - -#ifndef NO_SHA256 - XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256)); -#endif -#ifdef WOLFSSL_SHA384 - XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384)); -#endif - - return 0; -} - -#endif - - -/* Initialize a SnifferServer */ -static void InitSnifferServer(SnifferServer* sniffer) -{ - XMEMSET(sniffer, 0, sizeof(SnifferServer)); -} - - -/* Initialize session flags */ -static void InitFlags(Flags* flags) -{ - XMEMSET(flags, 0, sizeof(Flags)); -} - - -/* Initialize FIN Capture */ -static void InitFinCapture(FinCaputre* cap) -{ - XMEMSET(cap, 0, sizeof(FinCaputre)); -} - - -/* Initialize a Sniffer Session */ -static void InitSession(SnifferSession* session) -{ - XMEMSET(session, 0, sizeof(SnifferSession)); - InitFlags(&session->flags); - InitFinCapture(&session->finCaputre); -} - - -/* IP Info from IP Header */ -typedef struct IpInfo { - int length; /* length of this header */ - int total; /* total length of fragment */ - IpAddrInfo src; /* network order source address */ - IpAddrInfo dst; /* network order destination address */ -} IpInfo; - - -/* TCP Info from TCP Header */ -typedef struct TcpInfo { - int srcPort; /* source port */ - int dstPort; /* source port */ - int length; /* length of this header */ - word32 sequence; /* sequence number */ - word32 ackNumber; /* ack number */ - byte fin; /* FIN set */ - byte rst; /* RST set */ - byte syn; /* SYN set */ - byte ack; /* ACK set */ -} TcpInfo; - - -/* Tcp Pseudo Header for Checksum calculation */ -typedef struct TcpPseudoHdr { - word32 src; /* source address */ - word32 dst; /* destination address */ - byte rsv; /* reserved, always 0 */ - byte protocol; /* IP protocol */ - word16 length; /* tcp header length + data length (doesn't include */ - /* pseudo header length) network order */ -} TcpPseudoHdr; - - -/* Password Setting Callback */ -static int SetPassword(char* passwd, int sz, int rw, void* userdata) -{ - (void)rw; - XSTRNCPY(passwd, (const char*)userdata, sz); - return (int)XSTRLEN((const char*)userdata); -} - - -/* Ethernet Header */ -typedef struct EthernetHdr { - byte dst[ETHER_IF_ADDR_LEN]; /* destination host address */ - byte src[ETHER_IF_ADDR_LEN]; /* source host address */ - word16 type; /* IP, ARP, etc */ -} EthernetHdr; - - -/* IPv4 Header */ -typedef struct IpHdr { - byte ver_hl; /* version/header length */ - byte tos; /* type of service */ - word16 length; /* total length */ - word16 id; /* identification */ - word16 offset; /* fragment offset field */ - byte ttl; /* time to live */ - byte protocol; /* protocol */ - word16 sum; /* checksum */ - word32 src; /* source address */ - word32 dst; /* destination address */ -} IpHdr; - - -/* IPv6 Header */ -typedef struct Ip6Hdr { - byte ver_hl; /* version/traffic class high */ - byte tc_fl; /* traffic class low/flow label high */ - word16 fl; /* flow label low */ - word16 length; /* payload length */ - byte next_header; /* next header (6 for TCP, any other skip) */ - byte hl; /* hop limit */ - byte src[16]; /* source address */ - byte dst[16]; /* destination address */ -} Ip6Hdr; - - -/* IPv6 extension header */ -typedef struct Ip6ExtHdr { - byte next_header; /* next header (6 for TCP, any other skip) */ - byte length; /* length in 8-octet units - 1 */ - byte reserved[6]; -} Ip6ExtHdr; - - -#define IP_HL(ip) ( (((ip)->ver_hl) & 0x0f) * 4) -#define IP_V(ip) ( ((ip)->ver_hl) >> 4) - -/* TCP Header */ -typedef struct TcpHdr { - word16 srcPort; /* source port */ - word16 dstPort; /* destination port */ - word32 sequence; /* sequence number */ - word32 ack; /* acknowledgment number */ - byte offset; /* data offset, reserved */ - byte flags; /* option flags */ - word16 window; /* window */ - word16 sum; /* checksum */ - word16 urgent; /* urgent pointer */ -} TcpHdr; - -#define TCP_LEN(tcp) ( (((tcp)->offset & 0xf0) >> 4) * 4) -#define TCP_FIN 0x01 -#define TCP_SYN 0x02 -#define TCP_RST 0x04 -#define TCP_ACK 0x10 - - - - - -/* Use platform specific GetError to write to trace file if tracing */ -static void Trace(int idx) -{ - if (TraceOn) { - char myBuffer[MAX_ERROR_LEN]; - GetError(idx, myBuffer); - fprintf(TraceFile, "\t%s\n", myBuffer); -#ifdef DEBUG_SNIFFER - fprintf(stderr, "\t%s\n", myBuffer); -#endif - } -} - - -/* Show TimeStamp for beginning of packet Trace */ -static void TraceHeader(void) -{ - if (TraceOn) { - time_t ticks = time(NULL); - fprintf(TraceFile, "\n%s", ctime(&ticks)); - } -} - - -/* Show Set Server info for Trace */ -static void TraceSetServer(const char* srv, int port, const char* keyFile) -{ - if (TraceOn) { - fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n"); - fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port, - keyFile); - } -} - - -#ifdef HAVE_SNI - -/* Show Set Named Server info for Trace */ -static void TraceSetNamedServer(const char* name, - const char* srv, int port, const char* keyFile) -{ - if (TraceOn) { - fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n"); - fprintf(TraceFile, "\tname: %s, server: %s, port: %d, keyFile: %s\n", - name, srv, port, keyFile); - } -} - -#endif - - -/* Trace got packet number */ -static void TracePacket(void) -{ - if (TraceOn) { - static word32 packetNumber = 0; - fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n", - ++packetNumber); - } -} - - -/* Convert network byte order address into human readable */ -static const char* IpToS(int version, void* src, char* dst) -{ - return inet_ntop(version, src, dst, TRACE_MSG_SZ); -} - - -/* Show destination and source address from Ip Hdr for packet Trace */ -static void TraceIP(IpHdr* iphdr) -{ - if (TraceOn) { - char src[TRACE_MSG_SZ]; - char dst[TRACE_MSG_SZ]; - fprintf(TraceFile, "\tdst:%s src:%s\n", - IpToS(AF_INET, &iphdr->dst, dst), - IpToS(AF_INET, &iphdr->src, src)); - } -} - - -/* Show destination and source address from Ip6Hdr for packet Trace */ -static void TraceIP6(Ip6Hdr* iphdr) -{ - if (TraceOn) { - char src[TRACE_MSG_SZ]; - char dst[TRACE_MSG_SZ]; - fprintf(TraceFile, "\tdst: %s src: %s\n", - IpToS(AF_INET6, iphdr->dst, dst), - IpToS(AF_INET6, iphdr->src, src)); - } -} - - -/* Show destination and source port from Tcp Hdr for packet Trace */ -static void TraceTcp(TcpHdr* tcphdr) -{ - if (TraceOn) { - fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort), - ntohs(tcphdr->srcPort)); - } -} - - -/* Show sequence and payload length for Trace */ -static void TraceSequence(word32 seq, int len) -{ - if (TraceOn) { - fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len); - } -} - - -/* Show sequence and payload length for Trace */ -static void TraceAck(word32 ack, word32 expected) -{ - if (TraceOn) { - fprintf(TraceFile, "\tAck:%u Expected:%u\n", ack, expected); - } -} - - -/* Show relative expected and relative received sequences */ -static void TraceRelativeSequence(word32 expected, word32 got) -{ - if (TraceOn) { - fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n", - expected, got); - } -} - - -/* Show server sequence startup from SYN */ -static void TraceServerSyn(word32 seq) -{ - if (TraceOn) { - fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq); - } -} - - -/* Show client sequence startup from SYN */ -static void TraceClientSyn(word32 seq) -{ - if (TraceOn) { - fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq); - } -} - - -/* Show client FIN capture */ -static void TraceClientFin(word32 finSeq, word32 relSeq) -{ - if (TraceOn) { - fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n", - finSeq, relSeq); - } -} - - -/* Show server FIN capture */ -static void TraceServerFin(word32 finSeq, word32 relSeq) -{ - if (TraceOn) { - fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n", - finSeq, relSeq); - } -} - - -/* Show number of SSL data bytes decoded, could be 0 (ok) */ -static void TraceGotData(int bytes) -{ - if (TraceOn) { - fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes); - } -} - - -/* Show bytes added to old SSL App data */ -static void TraceAddedData(int newBytes, int existingBytes) -{ - if (TraceOn) { - fprintf(TraceFile, - "\t%d bytes added to %d existing bytes in User Buffer\n", - newBytes, existingBytes); - } -} - - -/* Show Stale Session */ -static void TraceStaleSession(void) -{ - if (TraceOn) { - fprintf(TraceFile, "\tFound a stale session\n"); - } -} - - -/* Show Finding Stale Sessions */ -static void TraceFindingStale(void) -{ - if (TraceOn) { - fprintf(TraceFile, "\tTrying to find Stale Sessions\n"); - } -} - - -/* Show Removed Session */ -static void TraceRemovedSession(void) -{ - if (TraceOn) { - fprintf(TraceFile, "\tRemoved it\n"); - } -} - - -/* Show SSLInfo if provided and is valid. */ -static void TraceSessionInfo(SSLInfo* sslInfo) -{ - if (TraceOn) { - if (sslInfo != NULL && sslInfo->isValid) { - fprintf(TraceFile, - "\tver:(%u %u) suiteId:(%02x %02x) suiteName:(%s) " - #ifdef HAVE_SNI - "sni:(%s) " - #endif - "keySize:(%u)\n", - sslInfo->protocolVersionMajor, - sslInfo->protocolVersionMinor, - sslInfo->serverCipherSuite0, - sslInfo->serverCipherSuite, - sslInfo->serverCipherSuiteName, - #ifdef HAVE_SNI - sslInfo->serverNameIndication, - #endif - sslInfo->keySize); - } - } -} - - -#ifdef WOLFSSL_SNIFFER_STATS - -/* Show value added to a named statistic. */ -static void TraceStat(const char* name, int add) -{ - if (TraceOn) { - fprintf(TraceFile, "\tAdding %d to %s\n", add, name); - } -} - -#endif - - -/* Set user error string */ -static void SetError(int idx, char* error, SnifferSession* session, int fatal) -{ - GetError(idx, error); - Trace(idx); - if (session && fatal == FATAL_ERROR_STATE) - session->flags.fatalError = 1; -} - - -/* Compare IpAddrInfo structs */ -static WC_INLINE int MatchAddr(IpAddrInfo l, IpAddrInfo r) -{ - if (l.version == r.version) { - if (l.version == IPV4) - return (l.ip4 == r.ip4); - else if (l.version == IPV6) - return (0 == XMEMCMP(l.ip6, r.ip6, sizeof(l.ip6))); - } - return 0; -} - - -#ifndef WOLFSSL_SNIFFER_WATCH - -/* See if this IPV4 network order address has been registered */ -/* return 1 is true, 0 is false */ -static int IsServerRegistered(word32 addr) -{ - int ret = 0; /* false */ - SnifferServer* sniffer; - - wc_LockMutex(&ServerListMutex); - - sniffer = ServerList; - while (sniffer) { - if (sniffer->server.ip4 == addr) { - ret = 1; - break; - } - sniffer = sniffer->next; - } - - wc_UnLockMutex(&ServerListMutex); - - return ret; -} - - -/* See if this port has been registered to watch */ -/* See if this IPV4 network order address has been registered */ -/* return 1 is true, 0 is false */ -static int IsServerRegistered6(byte* addr) -{ - int ret = 0; /* false */ - SnifferServer* sniffer; - - wc_LockMutex(&ServerListMutex); - - sniffer = ServerList; - while (sniffer) { - if (sniffer->server.version == IPV6 && - 0 == XMEMCMP(sniffer->server.ip6, addr, sizeof(sniffer->server.ip6))) { - ret = 1; - break; - } - sniffer = sniffer->next; - } - - wc_UnLockMutex(&ServerListMutex); - - return ret; -} - - -/* See if this port has been registered to watch */ -/* return 1 is true, 0 is false */ -static int IsPortRegistered(word32 port) -{ - int ret = 0; /* false */ - SnifferServer* sniffer; - - wc_LockMutex(&ServerListMutex); - - sniffer = ServerList; - while (sniffer) { - if (sniffer->port == (int)port) { - ret = 1; - break; - } - sniffer = sniffer->next; - } - - wc_UnLockMutex(&ServerListMutex); - - return ret; -} - -#endif - - -/* Get SnifferServer from IP and Port */ -static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo) -{ - SnifferServer* sniffer; - - wc_LockMutex(&ServerListMutex); - - sniffer = ServerList; - -#ifndef WOLFSSL_SNIFFER_WATCH - while (sniffer) { - if (sniffer->port == tcpInfo->srcPort && - MatchAddr(sniffer->server, ipInfo->src)) - break; - if (sniffer->port == tcpInfo->dstPort && - MatchAddr(sniffer->server, ipInfo->dst)) - break; - - sniffer = sniffer->next; - } -#else - (void)ipInfo; - (void)tcpInfo; -#endif - - wc_UnLockMutex(&ServerListMutex); - - return sniffer; -} - - -/* Hash the Session Info, return hash row */ -static word32 SessionHash(IpInfo* ipInfo, TcpInfo* tcpInfo) -{ - word32 hash = 1; - - if (ipInfo->src.version == IPV4) { - hash *= ipInfo->src.ip4 * ipInfo->dst.ip4; - } - else if (ipInfo->src.version == IPV6) { - word32* x; - word32 y; - x = (word32*)ipInfo->src.ip6; - y = x[0] ^ x[1] ^ x[2] ^ x[3]; - hash *= y; - x = (word32*)ipInfo->dst.ip6; - y = x[0] ^ x[1] ^ x[2] ^ x[3]; - hash *= y; - } - hash *= tcpInfo->srcPort * tcpInfo->dstPort; - - return hash % HASH_SIZE; -} - - -/* Get Existing SnifferSession from IP and Port */ -static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo) -{ - SnifferSession* session; - time_t currTime = time(NULL); - word32 row = SessionHash(ipInfo, tcpInfo); - - assert(row <= HASH_SIZE); - - wc_LockMutex(&SessionMutex); - - session = SessionTable[row]; - while (session) { - if (MatchAddr(session->server, ipInfo->src) && - MatchAddr(session->client, ipInfo->dst) && - session->srvPort == tcpInfo->srcPort && - session->cliPort == tcpInfo->dstPort) - break; - - if (MatchAddr(session->client, ipInfo->src) && - MatchAddr(session->server, ipInfo->dst) && - session->cliPort == tcpInfo->srcPort && - session->srvPort == tcpInfo->dstPort) - break; - - session = session->next; - } - - if (session) - session->lastUsed= currTime; /* keep session alive, remove stale will */ - /* leave alone */ - wc_UnLockMutex(&SessionMutex); - - /* determine side */ - if (session) { - if (MatchAddr(ipInfo->dst, session->server) && - tcpInfo->dstPort == session->srvPort) { - - session->flags.side = WOLFSSL_SERVER_END; - } - else { - session->flags.side = WOLFSSL_CLIENT_END; - } - } - - return session; -} - - -#if defined(HAVE_SNI) || defined(WOLFSSL_SNIFFER_WATCH) - -static int LoadKeyFile(byte** keyBuf, word32* keyBufSz, - const char* keyFile, int typeKey, - const char* password) -{ - byte* loadBuf; - long fileSz = 0; - XFILE file; - int ret; - - if (keyBuf == NULL || keyBufSz == NULL || keyFile == NULL) { - return -1; - } - - file = XFOPEN(keyFile, "rb"); - if (file == XBADFILE) return -1; - if(XFSEEK(file, 0, XSEEK_END) != 0) { - XFCLOSE(file); - return -1; - } - fileSz = XFTELL(file); - if (fileSz > MAX_WOLFSSL_FILE_SIZE || fileSz < 0) { - XFCLOSE(file); - return -1; - } - XREWIND(file); - - loadBuf = (byte*)XMALLOC(fileSz, NULL, DYNAMIC_TYPE_FILE); - if (loadBuf == NULL) { - XFCLOSE(file); - return -1; - } - - ret = (int)XFREAD(loadBuf, 1, fileSz, file); - XFCLOSE(file); - - if (ret != fileSz) { - XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE); - return -1; - } - - if (typeKey == WOLFSSL_FILETYPE_PEM) { - byte* saveBuf = (byte*)XMALLOC(fileSz, NULL, DYNAMIC_TYPE_X509); - int saveBufSz = 0; - - ret = -1; - if (saveBuf != NULL) { - saveBufSz = wc_KeyPemToDer(loadBuf, (int)fileSz, - saveBuf, (int)fileSz, password); - if (saveBufSz < 0) { - saveBufSz = 0; - XFREE(saveBuf, NULL, DYNAMIC_TYPE_X509); - saveBuf = NULL; - } - else - ret = 0; - } - - ForceZero(loadBuf, (word32)fileSz); - XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE); - - if (saveBuf) { - *keyBuf = saveBuf; - *keyBufSz = (word32)saveBufSz; - } - } - else { - *keyBuf = loadBuf; - *keyBufSz = (word32)fileSz; - } - - if (ret < 0) { - return -1; - } - - return ret; -} - -#endif - - -#ifdef WOLFSSL_SNIFFER_WATCH - -static int CreateWatchSnifferServer(char* error) -{ - SnifferServer* sniffer; - - sniffer = (SnifferServer*)XMALLOC(sizeof(SnifferServer), NULL, - DYNAMIC_TYPE_SNIFFER_SERVER); - if (sniffer == NULL) { - SetError(MEMORY_STR, error, NULL, 0); - return -1; - } - InitSnifferServer(sniffer); - sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); - if (!sniffer->ctx) { - SetError(MEMORY_STR, error, NULL, 0); - FreeSnifferServer(sniffer); - return -1; - } -#ifdef WOLF_CRYPTO_CB - if (CryptoDeviceId != INVALID_DEVID) - wolfSSL_CTX_SetDevId(sniffer->ctx, CryptoDeviceId); -#endif - ServerList = sniffer; - - return 0; -} - -#endif - - -static int SetNamedPrivateKey(const char* name, const char* address, int port, - const char* keyFile, int typeKey, const char* password, char* error) -{ - SnifferServer* sniffer; - int ret; - int type = (typeKey == FILETYPE_PEM) ? WOLFSSL_FILETYPE_PEM : - WOLFSSL_FILETYPE_ASN1; - int isNew = 0; - IpAddrInfo serverIp; - -#ifdef HAVE_SNI - NamedKey* namedKey = NULL; -#endif - - (void)name; -#ifdef HAVE_SNI - if (name != NULL) { - namedKey = (NamedKey*)XMALLOC(sizeof(NamedKey), - NULL, DYNAMIC_TYPE_SNIFFER_NAMED_KEY); - if (namedKey == NULL) { - SetError(MEMORY_STR, error, NULL, 0); - return -1; - } - XMEMSET(namedKey, 0, sizeof(NamedKey)); - - namedKey->nameSz = (word32)XSTRLEN(name); - if (namedKey->nameSz > sizeof(namedKey->name)-1) - namedKey->nameSz = sizeof(namedKey->name)-1; - XSTRNCPY(namedKey->name, name, namedKey->nameSz); - namedKey->name[MAX_SERVER_NAME-1] = '\0'; - - ret = LoadKeyFile(&namedKey->key, &namedKey->keySz, - keyFile, type, password); - if (ret < 0) { - SetError(KEY_FILE_STR, error, NULL, 0); - FreeNamedKey(namedKey); - return -1; - } - } -#endif - - serverIp.version = IPV4; - serverIp.ip4 = inet_addr(address); - if (serverIp.ip4 == INADDR_NONE) { - if (inet_pton(AF_INET6, address, serverIp.ip6) == 1) { - serverIp.version = IPV6; - } - } - sniffer = ServerList; - while (sniffer != NULL && - (!MatchAddr(sniffer->server, serverIp) || sniffer->port != port)) { - sniffer = sniffer->next; - } - - if (sniffer == NULL) { - isNew = 1; - sniffer = (SnifferServer*)XMALLOC(sizeof(SnifferServer), - NULL, DYNAMIC_TYPE_SNIFFER_SERVER); - if (sniffer == NULL) { - SetError(MEMORY_STR, error, NULL, 0); -#ifdef HAVE_SNI - FreeNamedKey(namedKey); -#endif - return -1; - } - InitSnifferServer(sniffer); - - XSTRNCPY(sniffer->address, address, MAX_SERVER_ADDRESS-1); - sniffer->address[MAX_SERVER_ADDRESS-1] = '\0'; - sniffer->server = serverIp; - sniffer->port = port; - - sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); - if (!sniffer->ctx) { - SetError(MEMORY_STR, error, NULL, 0); -#ifdef HAVE_SNI - FreeNamedKey(namedKey); -#endif - FreeSnifferServer(sniffer); - return -1; - } - } - - if (name == NULL) { - if (password) { - #ifdef WOLFSSL_ENCRYPTED_KEYS - SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword); - SSL_CTX_set_default_passwd_cb_userdata( - sniffer->ctx, (void*)password); - #endif - } - ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); - if (ret != WOLFSSL_SUCCESS) { - SetError(KEY_FILE_STR, error, NULL, 0); - if (isNew) - FreeSnifferServer(sniffer); - return -1; - } - #ifdef WOLF_CRYPTO_CB - wolfSSL_CTX_SetDevId(sniffer->ctx, CryptoDeviceId); - #endif - } -#ifdef HAVE_SNI - else { - wc_LockMutex(&sniffer->namedKeysMutex); - namedKey->next = sniffer->namedKeys; - sniffer->namedKeys = namedKey; - wc_UnLockMutex(&sniffer->namedKeysMutex); - } -#endif - - if (isNew) { - sniffer->next = ServerList; - ServerList = sniffer; - } - - return 0; -} - - -#ifdef HAVE_SNI - -/* Sets the private key for a specific name, server and port */ -/* returns 0 on success, -1 on error */ -int ssl_SetNamedPrivateKey(const char* name, - const char* address, int port, - const char* keyFile, int typeKey, - const char* password, char* error) -{ - int ret; - - TraceHeader(); - TraceSetNamedServer(name, address, port, keyFile); - - wc_LockMutex(&ServerListMutex); - ret = SetNamedPrivateKey(name, address, port, keyFile, - typeKey, password, error); - wc_UnLockMutex(&ServerListMutex); - - if (ret == 0) - Trace(NEW_SERVER_STR); - - return ret; -} - -#endif - - -/* Sets the private key for a specific server and port */ -/* returns 0 on success, -1 on error */ -int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, - int typeKey, const char* password, char* error) -{ - int ret; - - TraceHeader(); - TraceSetServer(address, port, keyFile); - - wc_LockMutex(&ServerListMutex); - ret = SetNamedPrivateKey(NULL, address, port, keyFile, - typeKey, password, error); - wc_UnLockMutex(&ServerListMutex); - - if (ret == 0) - Trace(NEW_SERVER_STR); - - return ret; -} - - -/* Check IP Header for IPV6, TCP, and a registered server address */ -/* returns 0 on success, -1 on error */ -static int CheckIp6Hdr(Ip6Hdr* iphdr, IpInfo* info, int length, char* error) -{ - int version = IP_V(iphdr); - int exthdrsz = IP6_HDR_SZ; - - TraceIP6(iphdr); - Trace(IP_CHECK_STR); - - if (version != IPV6) { - SetError(BAD_IPVER_STR, error, NULL, 0); - return -1; - } - - /* Here, we need to move onto next header if not TCP. */ - if (iphdr->next_header != TCP_PROTOCOL) { - Ip6ExtHdr* exthdr = (Ip6ExtHdr*)((byte*)iphdr + IP6_HDR_SZ); - do { - int hdrsz = (exthdr->length + 1) * 8; - if (hdrsz > length - exthdrsz) { - SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); - return -1; - } - exthdrsz += hdrsz; - exthdr = (Ip6ExtHdr*)((byte*)exthdr + hdrsz); - } - while (exthdr->next_header != TCP_PROTOCOL && - exthdr->next_header != NO_NEXT_HEADER); - } - -#ifndef WOLFSSL_SNIFFER_WATCH - if (!IsServerRegistered6(iphdr->src) && !IsServerRegistered6(iphdr->dst)) { - SetError(SERVER_NOT_REG_STR, error, NULL, 0); - return -1; - } -#endif - - info->length = exthdrsz; - info->total = ntohs(iphdr->length) + info->length; - /* IPv6 doesn't include its own header size in the length like v4. */ - info->src.version = IPV6; - XMEMCPY(info->src.ip6, iphdr->src, sizeof(info->src.ip6)); - info->dst.version = IPV6; - XMEMCPY(info->dst.ip6, iphdr->dst, sizeof(info->dst.ip6)); - - return 0; -} - - -/* Check IP Header for IPV4, TCP, and a registered server address */ -/* If header IPv6, pass to CheckIp6Hdr(). */ -/* returns 0 on success, -1 on error */ -static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error) -{ - int version = IP_V(iphdr); - - if (version == IPV6) - return CheckIp6Hdr((Ip6Hdr*)iphdr, info, length, error); - - TraceIP(iphdr); - Trace(IP_CHECK_STR); - - if (version != IPV4) { - SetError(BAD_IPVER_STR, error, NULL, 0); - return -1; - } - - if (iphdr->protocol != TCP_PROTOCOL) { - SetError(BAD_PROTO_STR, error, NULL, 0); - return -1; - } - -#ifndef WOLFSSL_SNIFFER_WATCH - if (!IsServerRegistered(iphdr->src) && !IsServerRegistered(iphdr->dst)) { - SetError(SERVER_NOT_REG_STR, error, NULL, 0); - return -1; - } -#endif - - info->length = IP_HL(iphdr); - info->total = ntohs(iphdr->length); - info->src.version = IPV4; - info->src.ip4 = iphdr->src; - info->dst.version = IPV4; - info->dst.ip4 = iphdr->dst; - - if (info->total == 0) - info->total = length; /* reassembled may be off */ - - return 0; -} - - -/* Check TCP Header for a registered port */ -/* returns 0 on success, -1 on error */ -static int CheckTcpHdr(TcpHdr* tcphdr, TcpInfo* info, char* error) -{ - TraceTcp(tcphdr); - Trace(TCP_CHECK_STR); - info->srcPort = ntohs(tcphdr->srcPort); - info->dstPort = ntohs(tcphdr->dstPort); - info->length = TCP_LEN(tcphdr); - info->sequence = ntohl(tcphdr->sequence); - info->fin = tcphdr->flags & TCP_FIN; - info->rst = tcphdr->flags & TCP_RST; - info->syn = tcphdr->flags & TCP_SYN; - info->ack = tcphdr->flags & TCP_ACK; - if (info->ack) - info->ackNumber = ntohl(tcphdr->ack); - -#ifndef WOLFSSL_SNIFFER_WATCH - if (!IsPortRegistered(info->srcPort) && !IsPortRegistered(info->dstPort)) { - SetError(SERVER_PORT_NOT_REG_STR, error, NULL, 0); - return -1; - } -#else - (void)error; -#endif - - return 0; -} - - -/* Decode Record Layer Header */ -static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size) -{ - XMEMCPY(rh, input, RECORD_HEADER_SZ); - *size = (rh->length[0] << 8) | rh->length[1]; - - if (*size > (MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA)) - return LENGTH_ERROR; - - return 0; -} - - -/* Copies the session's information to the provided sslInfo. Skip copy if - * SSLInfo is not provided. */ -static void CopySessionInfo(SnifferSession* session, SSLInfo* sslInfo) -{ - if (NULL != sslInfo) { - XMEMSET(sslInfo, 0, sizeof(SSLInfo)); - - /* Pass back Session Info after we have processed the Server Hello. */ - if (0 != session->sslServer->options.cipherSuite) { - const char* pCipher; - - sslInfo->isValid = 1; - sslInfo->protocolVersionMajor = session->sslServer->version.major; - sslInfo->protocolVersionMinor = session->sslServer->version.minor; - sslInfo->serverCipherSuite0 = - session->sslServer->options.cipherSuite0; - sslInfo->serverCipherSuite = - session->sslServer->options.cipherSuite; - - pCipher = wolfSSL_get_cipher(session->sslServer); - if (NULL != pCipher) { - XSTRNCPY((char*)sslInfo->serverCipherSuiteName, pCipher, - sizeof(sslInfo->serverCipherSuiteName)); - sslInfo->serverCipherSuiteName - [sizeof(sslInfo->serverCipherSuiteName) - 1] = '\0'; - } - sslInfo->keySize = session->keySz; - #ifdef HAVE_SNI - if (NULL != session->sni) { - XSTRNCPY((char*)sslInfo->serverNameIndication, - session->sni, sizeof(sslInfo->serverNameIndication)); - sslInfo->serverNameIndication - [sizeof(sslInfo->serverNameIndication) - 1] = '\0'; - } - #endif - TraceSessionInfo(sslInfo); - } - } -} - - -/* Call the session connection start callback. */ -static void CallConnectionCb(SnifferSession* session) -{ - if (ConnectionCb != NULL) { - SSLInfo info; - CopySessionInfo(session, &info); - ConnectionCb((const void*)session, &info, ConnectionCbCtx); - } -} - - -/* Process Client Key Exchange, RSA or static ECDH */ -static int ProcessClientKeyExchange(const byte* input, int* sslBytes, - SnifferSession* session, char* error) -{ - word32 idx = 0; - int tryEcc = 0; - int ret; - - if (session->sslServer->buffers.key == NULL || - session->sslServer->buffers.key->buffer == NULL || - session->sslServer->buffers.key->length == 0) { - - SetError(RSA_KEY_MISSING_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - { - RsaKey key; - int length; - - ret = wc_InitRsaKey(&key, 0); - if (ret == 0) { - ret = wc_RsaPrivateKeyDecode( - session->sslServer->buffers.key->buffer, - &idx, &key, session->sslServer->buffers.key->length); - if (ret != 0) { - tryEcc = 1; - #ifndef HAVE_ECC - SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); - #else - /* If we can do ECC, this isn't fatal. Not loading an ECC - * key will be fatal, though. */ - SetError(RSA_DECODE_STR, error, session, 0); - #endif - } - } - - if (ret == 0) { - length = wc_RsaEncryptSize(&key); - if (IsTLS(session->sslServer)) { - input += 2; /* tls pre length */ - } - - if (length > *sslBytes) { - SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE); - ret = -1; - } - } - - #ifdef WC_RSA_BLINDING - if (ret == 0) { - ret = wc_RsaSetRNG(&key, session->sslServer->rng); - if (ret != 0) { - SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); - } - } - #endif - - if (ret == 0) { - session->keySz = length * WOLFSSL_BIT_SIZE; - /* length is the key size in bytes */ - session->sslServer->arrays->preMasterSz = SECRET_LEN; - - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &key.asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) { - ret = wc_RsaPrivateDecrypt(input, length, - session->sslServer->arrays->preMasterSecret, - session->sslServer->arrays->preMasterSz, &key); - } - } while (ret == WC_PENDING_E); - - if (ret != SECRET_LEN) { - SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); - } - } - - wc_FreeRsaKey(&key); - } - - if (tryEcc) { -#ifdef HAVE_ECC - ecc_key key; - ecc_key pubKey; - int length, keyInit = 0, pubKeyInit = 0; - - idx = 0; - ret = wc_ecc_init(&key); - if (ret == 0) { - keyInit = 1; - ret = wc_ecc_init(&pubKey); - } - if (ret == 0) { - pubKeyInit = 1; - ret = wc_EccPrivateKeyDecode( - session->sslServer->buffers.key->buffer, - &idx, &key, session->sslServer->buffers.key->length); - if (ret != 0) { - SetError(ECC_DECODE_STR, error, session, FATAL_ERROR_STATE); - } - } - - if (ret == 0) { - length = wc_ecc_size(&key) * 2 + 1; - /* The length should be 2 times the key size (x and y), plus 1 - * for the type byte. */ - if (IsTLS(session->sslServer)) { - input += 1; /* Don't include the TLS length for the key. */ - } - - if (length + 1 > *sslBytes) { - SetError(PARTIAL_INPUT_STR, - error, session, FATAL_ERROR_STATE); - ret = -1; - } - } - - if (ret == 0) { - ret = wc_ecc_import_x963_ex(input, length, &pubKey, ECC_CURVE_DEF); - if (ret != 0) { - SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE); - } - } - - if (ret == 0) { - session->keySz = ((length - 1) / 2) * WOLFSSL_BIT_SIZE; - /* Length is in bytes. Subtract 1 for the ECC key type. Divide - * by two as the key is in (x,y) coordinates, where x and y are - * the same size, the key size. Convert from bytes to bits. */ - session->sslServer->arrays->preMasterSz = ENCRYPT_LEN; - - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &key.asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) { - ret = wc_ecc_shared_secret(&key, &pubKey, - session->sslServer->arrays->preMasterSecret, - &session->sslServer->arrays->preMasterSz); - } - } while (ret == WC_PENDING_E); - } - -#ifdef WOLFSSL_SNIFFER_STATS - if (ret != 0) - INC_STAT(SnifferStats.sslKeyFails); -#endif - - if (keyInit) - wc_ecc_free(&key); - if (pubKeyInit) - wc_ecc_free(&pubKey); -#endif - } - - /* store for client side as well */ - XMEMCPY(session->sslClient->arrays->preMasterSecret, - session->sslServer->arrays->preMasterSecret, - session->sslServer->arrays->preMasterSz); - session->sslClient->arrays->preMasterSz = - session->sslServer->arrays->preMasterSz; - - #ifdef SHOW_SECRETS - { - word32 i; - printf("pre master secret: "); - for (i = 0; i < session->sslServer->arrays->preMasterSz; i++) - printf("%02x", session->sslServer->arrays->preMasterSecret[i]); - printf("\n"); - } - #endif - - if (SetCipherSpecs(session->sslServer) != 0) { - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - if (SetCipherSpecs(session->sslClient) != 0) { - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - ret = MakeMasterSecret(session->sslServer); - ret += MakeMasterSecret(session->sslClient); - ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); - ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); - - if (ret != 0) { - SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - -#ifdef SHOW_SECRETS - { - int i; - printf("server master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslServer->arrays->masterSecret[i]); - printf("\n"); - - printf("client master secret: "); - for (i = 0; i < SECRET_LEN; i++) - printf("%02x", session->sslClient->arrays->masterSecret[i]); - printf("\n"); - - printf("server suite = %d\n", session->sslServer->options.cipherSuite); - printf("client suite = %d\n", session->sslClient->options.cipherSuite); - } -#endif - - CallConnectionCb(session); - - return ret; -} - - -/* Process Session Ticket */ -static int ProcessSessionTicket(const byte* input, int* sslBytes, - SnifferSession* session, char* error) -{ - word16 len; - - /* make sure can read through hint and len */ - if (TICKET_HINT_LEN + LENGTH_SZ > *sslBytes) { - SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - input += TICKET_HINT_LEN; /* skip over hint */ - *sslBytes -= TICKET_HINT_LEN; - - len = (word16)((input[0] << 8) | input[1]); - input += LENGTH_SZ; - *sslBytes -= LENGTH_SZ; - - /* make sure can read through ticket */ - if (len > *sslBytes || len < ID_LEN) { - SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - /* store session with macID as sessionID */ - session->sslServer->options.haveSessionId = 1; - XMEMCPY(session->sslServer->arrays->sessionID, input + len - ID_LEN,ID_LEN); - - return 0; -} - - -/* Process Server Hello */ -static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, - SnifferSession* session, char* error) -{ - ProtocolVersion pv; - byte b, b0; - 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) { - SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - /* make sure can read through session len */ - if (toRead > *sslBytes) { - SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - XMEMCPY(&pv, input, VERSION_SZ); - input += VERSION_SZ; - *sslBytes -= VERSION_SZ; - - session->sslServer->version = pv; - session->sslClient->version = pv; - - XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN); - XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN); - input += RAN_LEN; - *sslBytes -= RAN_LEN; - - b = *input++; - *sslBytes -= 1; - - /* make sure can read through compression */ - if ( (b + SUITE_LEN + ENUM_LEN) > *sslBytes) { - SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - if (b) { - XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN); - session->sslServer->options.haveSessionId = 1; - } - input += b; - *sslBytes -= b; - - /* cipher suite */ - b0 = *input++; /* first byte, ECC or not */ - session->sslServer->options.cipherSuite0 = b0; - session->sslClient->options.cipherSuite0 = b0; - b = *input++; - session->sslServer->options.cipherSuite = b; - session->sslClient->options.cipherSuite = b; - *sslBytes -= SUITE_LEN; - -#ifdef WOLFSSL_SNIFFER_STATS - { - const CipherSuiteInfo* suites = GetCipherNames(); - int suitesSz = GetCipherNamesSize(); - int match = 0; - - while (suitesSz) { - if (b0 == suites->cipherSuite0 && b == suites->cipherSuite) { - match = 1; - break; - } - suites++; - suitesSz--; - } - if (!match) - INC_STAT(SnifferStats.sslCiphersUnsupported); - } -#endif /* WOLFSSL_SNIFFER_STATS */ - - /* compression */ - b = *input++; - *sslBytes -= ENUM_LEN; - - if (b) { - SetError(BAD_COMPRESSION_STR, error, session, FATAL_ERROR_STATE); - 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) { - XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); - session->hash = NULL; - } -#endif - - if (session->sslServer->options.haveSessionId) { - if (XMEMCMP(session->sslServer->arrays->sessionID, - session->sslClient->arrays->sessionID, ID_LEN) == 0) - doResume = 1; - } - else if (session->sslClient->options.haveSessionId == 0 && - session->sslServer->options.haveSessionId == 0 && - session->ticketID) - doResume = 1; - - if (session->ticketID && doResume) { - /* use ticketID to retrieve from session, prefer over sessionID */ - XMEMCPY(session->sslServer->arrays->sessionID,session->ticketID,ID_LEN); - session->sslServer->options.haveSessionId = 1; /* may not have - actual sessionID */ - } - - if (doResume ) { - int ret = 0; - SSL_SESSION* resume = GetSession(session->sslServer, - session->sslServer->arrays->masterSecret, 0); - if (resume == NULL) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslResumeMisses); -#endif - SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - /* make sure client has master secret too */ - XMEMCPY(session->sslClient->arrays->masterSecret, - session->sslServer->arrays->masterSecret, SECRET_LEN); - session->flags.resuming = 1; - - Trace(SERVER_DID_RESUMPTION_STR); -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslResumedConns); - INC_STAT(SnifferStats.sslResumptionValid); -#endif - if (SetCipherSpecs(session->sslServer) != 0) { - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - if (SetCipherSpecs(session->sslClient) != 0) { - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - if (session->sslServer->options.tls) { - ret = DeriveTlsKeys(session->sslServer); - ret += DeriveTlsKeys(session->sslClient); - } - else { - ret = DeriveKeys(session->sslServer); - ret += DeriveKeys(session->sslClient); - } - ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE); - ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE); - - if (ret != 0) { - SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - } - else { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslStandardConns); -#endif - } -#ifdef SHOW_SECRETS - { - int i; - printf("cipher suite = 0x%02x\n", - session->sslServer->options.cipherSuite); - printf("server random: "); - for (i = 0; i < RAN_LEN; i++) - printf("%02x", session->sslServer->arrays->serverRandom[i]); - printf("\n"); - } -#endif - return 0; -} - - -/* Process normal Client Hello */ -static int ProcessClientHello(const byte* input, int* sslBytes, - SnifferSession* session, char* error) -{ - byte bLen; - word16 len; - int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; - -#ifdef HAVE_SNI - { - byte name[MAX_SERVER_NAME]; - word32 nameSz = sizeof(name); - int ret; - - ret = wolfSSL_SNI_GetFromBuffer( - input - HANDSHAKE_HEADER_SZ - RECORD_HEADER_SZ, - *sslBytes + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ, - WOLFSSL_SNI_HOST_NAME, name, &nameSz); - - if (ret == WOLFSSL_SUCCESS) { - NamedKey* namedKey; - - if (nameSz > sizeof(name) - 1) - nameSz = sizeof(name) - 1; - name[nameSz] = 0; - wc_LockMutex(&session->context->namedKeysMutex); - namedKey = session->context->namedKeys; - while (namedKey != NULL) { - if (nameSz == namedKey->nameSz && - XSTRNCMP((char*)name, namedKey->name, nameSz) == 0) { - if (wolfSSL_use_PrivateKey_buffer(session->sslServer, - namedKey->key, namedKey->keySz, - WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) { - wc_UnLockMutex(&session->context->namedKeysMutex); - SetError(CLIENT_HELLO_LATE_KEY_STR, error, session, - FATAL_ERROR_STATE); - return -1; - } - session->sni = namedKey->name; - break; - } - else - namedKey = namedKey->next; - } - wc_UnLockMutex(&session->context->namedKeysMutex); - } - } -#endif - - session->flags.clientHello = 1; /* don't process again */ - - /* make sure can read up to session len */ - if (toRead > *sslBytes) { - SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - /* skip, get negotiated one from server hello */ - input += VERSION_SZ; - *sslBytes -= VERSION_SZ; - - XMEMCPY(session->sslServer->arrays->clientRandom, input, RAN_LEN); - XMEMCPY(session->sslClient->arrays->clientRandom, input, RAN_LEN); - - input += RAN_LEN; - *sslBytes -= RAN_LEN; - - /* store session in case trying to resume */ - bLen = *input++; - *sslBytes -= ENUM_LEN; - if (bLen) { - if (ID_LEN > *sslBytes) { - SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - Trace(CLIENT_RESUME_TRY_STR); - XMEMCPY(session->sslClient->arrays->sessionID, input, ID_LEN); - session->sslClient->options.haveSessionId = 1; - } -#ifdef SHOW_SECRETS - { - int i; - printf("client random: "); - for (i = 0; i < RAN_LEN; i++) - printf("%02x", session->sslServer->arrays->clientRandom[i]); - printf("\n"); - } -#endif - - input += bLen; - *sslBytes -= bLen; - - /* skip cipher suites */ - /* make sure can read len */ - if (SUITE_LEN > *sslBytes) { - SetError(CLIENT_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 suites + comp len */ - if (len + ENUM_LEN > *sslBytes) { - SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - input += len; - *sslBytes -= len; - - /* skip compression */ - bLen = *input++; - *sslBytes -= ENUM_LEN; - /* make sure can read len */ - if (bLen > *sslBytes) { - SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - input += bLen; - *sslBytes -= bLen; - - if (*sslBytes == 0) { - /* no extensions */ - return 0; - } - - /* skip extensions until session ticket */ - /* make sure can read len */ - if (SUITE_LEN > *sslBytes) { - SetError(CLIENT_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(CLIENT_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(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) { - - /* make sure can read through ticket if there is a non blank one */ - if (extLen && extLen < ID_LEN) { - SetError(CLIENT_HELLO_INPUT_STR, error, session, - FATAL_ERROR_STATE); - return -1; - } - - if (extLen) { - if (session->ticketID == 0) { - session->ticketID = (byte*)XMALLOC(ID_LEN, - NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID); - if (session->ticketID == 0) { - SetError(MEMORY_STR, error, session, - FATAL_ERROR_STATE); - return -1; - } - } - XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN); - } - } - - input += extLen; - *sslBytes -= extLen; - len -= extLen + EXT_TYPE_SZ + LENGTH_SZ; - } - - return 0; -} - - -#ifdef WOLFSSL_SNIFFER_WATCH - -/* Process Certificate */ -static int ProcessCertificate(const byte* input, int* sslBytes, - SnifferSession* session, char* error) -{ - Sha256 sha; - const byte* certChain; - word32 certChainSz; - word32 certSz; - int ret; - byte digest[SHA256_DIGEST_SIZE]; - - /* If the receiver is the server, this is the client certificate message, - * and it should be ignored at this point. */ - if (session->flags.side == WOLFSSL_SERVER_END) - return 0; - - if (WatchCb == NULL) { - SetError(WATCH_CB_MISSING_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - if (*sslBytes < CERT_HEADER_SZ) { - SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - ato24(input, &certChainSz); - *sslBytes -= CERT_HEADER_SZ; - input += CERT_HEADER_SZ; - - if (*sslBytes < (int)certChainSz) { - SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - certChain = input; - - ato24(input, &certSz); - input += OPAQUE24_LEN; - if (*sslBytes < (int)certSz) { - SetError(BAD_CERT_MSG_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - *sslBytes -= certChainSz; - - ret = wc_InitSha256(&sha); - if (ret == 0) - ret = wc_Sha256Update(&sha, input, certSz); - if (ret == 0) - ret = wc_Sha256Final(&sha, digest); - if (ret != 0) { - SetError(WATCH_HASH_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - ret = WatchCb((void*)session, digest, sizeof(digest), - certChain, certChainSz, WatchCbCtx, error); - if (ret != 0) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslKeysUnmatched); -#endif - SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - else { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslKeyMatches); -#endif - } - - return 0; -} - -#endif - - -/* Process Finished */ -static int ProcessFinished(const byte* input, int size, int* sslBytes, - SnifferSession* session, char* error) -{ - SSL* ssl; - word32 inOutIdx = 0; - int ret; - - if (session->flags.side == WOLFSSL_SERVER_END) - ssl = session->sslServer; - else - ssl = session->sslClient; - - ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes, - SNIFF); - *sslBytes -= (int)inOutIdx; - - if (ret < 0) { - SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE); - return ret; - } - - if (ret == 0 && session->flags.cached == 0) { - if (session->sslServer->options.haveSessionId) { - WOLFSSL_SESSION* sess = GetSession(session->sslServer, NULL, 0); - if (sess == NULL) { - AddSession(session->sslServer); /* don't re add */ -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslResumptionInserts); -#endif - } - session->flags.cached = 1; - } - } - - /* If receiving a finished message from one side, free the resources - * from the other side's tracker. */ - if (session->flags.side == WOLFSSL_SERVER_END) - FreeHandshakeResources(session->sslClient); - else - FreeHandshakeResources(session->sslServer); - - return ret; -} - - -/* Process HandShake input */ -static int DoHandShake(const byte* input, int* sslBytes, - SnifferSession* session, char* error) -{ - byte type; - int size; - int ret = 0; - int startBytes; - - if (*sslBytes < HANDSHAKE_HEADER_SZ) { - SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - type = input[0]; - size = (input[1] << 16) | (input[2] << 8) | input[3]; - - input += HANDSHAKE_HEADER_SZ; - *sslBytes -= HANDSHAKE_HEADER_SZ; - startBytes = *sslBytes; - - if (*sslBytes < size) { - Trace(SPLIT_HANDSHAKE_MSG_STR); - *sslBytes = 0; - return ret; - } - - /* A session's arrays are released when the handshake is completed. */ - if (session->sslServer->arrays == NULL && - session->sslClient->arrays == NULL) { - - SetError(NO_SECURE_RENEGOTIATION, error, session, FATAL_ERROR_STATE); - return -1; - } - -#ifdef HAVE_EXTENDED_MASTER - if (session->hash) { - if (HashUpdate(session->hash, input, size) != 0) { - SetError(EXTENDED_MASTER_HASH_STR, error, - session, FATAL_ERROR_STATE); - return -1; - } - } -#endif - - switch (type) { - case hello_verify_request: - Trace(GOT_HELLO_VERIFY_STR); - break; - case hello_request: - Trace(GOT_HELLO_REQUEST_STR); - break; - case session_ticket: - Trace(GOT_SESSION_TICKET_STR); - ret = ProcessSessionTicket(input, sslBytes, session, error); - break; - case server_hello: - Trace(GOT_SERVER_HELLO_STR); - ret = ProcessServerHello(size, input, sslBytes, session, error); - break; - case certificate_request: - Trace(GOT_CERT_REQ_STR); - break; - case server_key_exchange: -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslEphemeralMisses); -#endif - Trace(GOT_SERVER_KEY_EX_STR); - /* can't know temp key passively */ - SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); - ret = -1; - break; - case certificate: - Trace(GOT_CERT_STR); - if (session->flags.side == WOLFSSL_SERVER_END) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslClientAuthConns); -#endif - } -#ifdef WOLFSSL_SNIFFER_WATCH - ret = ProcessCertificate(input, sslBytes, session, error); -#endif - break; - case server_hello_done: - Trace(GOT_SERVER_HELLO_DONE_STR); - break; - case finished: - Trace(GOT_FINISHED_STR); - ret = ProcessFinished(input, size, sslBytes, session, error); - break; - case client_hello: - Trace(GOT_CLIENT_HELLO_STR); - ret = ProcessClientHello(input, sslBytes, session, error); - break; - case client_key_exchange: - Trace(GOT_CLIENT_KEY_EX_STR); -#ifdef HAVE_EXTENDED_MASTER - if (session->flags.expectEms && session->hash != NULL) { - if (HashCopy(session->sslServer->hsHashes, - session->hash) == 0 && - HashCopy(session->sslClient->hsHashes, - session->hash) == 0) { - - session->sslServer->options.haveEMS = 1; - session->sslClient->options.haveEMS = 1; - } - else { - SetError(EXTENDED_MASTER_HASH_STR, error, - session, FATAL_ERROR_STATE); - ret = -1; - } - XMEMSET(session->hash, 0, sizeof(HsHashes)); - XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES); - session->hash = NULL; - } - else { - session->sslServer->options.haveEMS = 0; - session->sslClient->options.haveEMS = 0; - } -#endif - if (ret == 0) - ret = ProcessClientKeyExchange(input, sslBytes, session, error); - break; - case certificate_verify: - Trace(GOT_CERT_VER_STR); - break; - case certificate_status: - Trace(GOT_CERT_STATUS_STR); - break; - default: - SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0); - return -1; - } - - *sslBytes = startBytes - size; /* actual bytes of full process */ - - return ret; -} - - -/* Decrypt input into plain output, 0 on success */ -static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) -{ - int ret = 0; - - (void)output; - (void)input; - (void)sz; - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_ARC4 - case wolfssl_rc4: - wc_Arc4Process(ssl->decrypt.arc4, output, input, sz); - break; - #endif - - #ifdef BUILD_DES3 - case wolfssl_triple_des: - ret = wc_Des3_CbcDecrypt(ssl->decrypt.des3, output, input, sz); - break; - #endif - - #ifdef BUILD_AES - case wolfssl_aes: - ret = wc_AesCbcDecrypt(ssl->decrypt.aes, output, input, sz); - break; - #endif - - #ifdef HAVE_HC128 - case wolfssl_hc128: - wc_Hc128_Process(ssl->decrypt.hc128, output, input, sz); - break; - #endif - - #ifdef BUILD_RABBIT - case wolfssl_rabbit: - wc_RabbitProcess(ssl->decrypt.rabbit, output, input, sz); - break; - #endif - - #ifdef HAVE_CAMELLIA - case wolfssl_camellia: - wc_CamelliaCbcDecrypt(ssl->decrypt.cam, output, input, sz); - break; - #endif - - #ifdef HAVE_IDEA - case wolfssl_idea: - wc_IdeaCbcDecrypt(ssl->decrypt.idea, output, input, sz); - break; - #endif - - #ifdef HAVE_AESGCM - case wolfssl_aes_gcm: - if (sz >= (word32)(AESGCM_EXP_IV_SZ + ssl->specs.aead_mac_size)) - { - /* scratch buffer, sniffer ignores auth tag*/ - byte authTag[WOLFSSL_MIN_AUTH_TAG_SZ]; - - byte nonce[AESGCM_NONCE_SZ]; - XMEMCPY(nonce, ssl->keys.aead_dec_imp_IV, AESGCM_IMP_IV_SZ); - XMEMCPY(nonce + AESGCM_IMP_IV_SZ, input, AESGCM_EXP_IV_SZ); - - if (wc_AesGcmEncrypt(ssl->decrypt.aes, - output, - input + AESGCM_EXP_IV_SZ, - sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, - nonce, AESGCM_NONCE_SZ, - authTag, sizeof(authTag), - NULL, 0) < 0) { - Trace(BAD_DECRYPT); - ret = -1; - } - ForceZero(nonce, AESGCM_NONCE_SZ); - } - else { - Trace(BAD_DECRYPT_SIZE); - ret = -1; - } - break; - #endif - - #ifdef HAVE_NULL_CIPHER - case wolfssl_cipher_null: - XMEMCPY(output, input, sz); - break; - #endif - - default: - Trace(BAD_DECRYPT_TYPE); - ret = -1; - break; - } - - return ret; -} - - -/* Decrypt input message into output, adjust output steam if needed */ -static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz, - byte* output, int* error, int* advance) -{ - int ivExtra = 0; - - int ret = Decrypt(ssl, output, input, sz); - if (ret != 0) { - *error = ret; - return NULL; - } - ssl->keys.encryptSz = sz; - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) { - output += ssl->specs.block_size; /* go past TLSv1.1 IV */ - ivExtra = ssl->specs.block_size; - *advance = ssl->specs.block_size; - } - - if (ssl->specs.cipher_type == aead) { - *advance = ssl->specs.aead_mac_size; - ssl->keys.padSz = ssl->specs.aead_mac_size; - } - else - ssl->keys.padSz = ssl->specs.hash_size; - - if (ssl->specs.cipher_type == block) - ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1; - - return output; -} - - -/* remove session from table, use rowHint if no info (means we have a lock) */ -static void RemoveSession(SnifferSession* session, IpInfo* ipInfo, - TcpInfo* tcpInfo, word32 rowHint) -{ - SnifferSession* previous = 0; - SnifferSession* current; - word32 row = rowHint; - int haveLock = 0; - - if (ipInfo && tcpInfo) - row = SessionHash(ipInfo, tcpInfo); - else - haveLock = 1; - - assert(row <= HASH_SIZE); - Trace(REMOVE_SESSION_STR); - - if (!haveLock) - wc_LockMutex(&SessionMutex); - - current = SessionTable[row]; - - while (current) { - if (current == session) { - if (previous) - previous->next = current->next; - else - SessionTable[row] = current->next; - FreeSnifferSession(session); - TraceRemovedSession(); - break; - } - previous = current; - current = current->next; - } - - if (!haveLock) - wc_UnLockMutex(&SessionMutex); -} - - -/* Remove stale sessions from the Session Table, have a lock */ -static void RemoveStaleSessions(void) -{ - word32 i; - SnifferSession* session; - - for (i = 0; i < HASH_SIZE; i++) { - session = SessionTable[i]; - while (session) { - SnifferSession* next = session->next; - if (time(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) { - TraceStaleSession(); - RemoveSession(session, NULL, NULL, i); - } - session = next; - } - } -} - - -/* Create a new Sniffer Session */ -static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, - char* error) -{ - SnifferSession* session = 0; - int row; - - Trace(NEW_SESSION_STR); - /* create a new one */ - session = (SnifferSession*)XMALLOC(sizeof(SnifferSession), - NULL, DYNAMIC_TYPE_SNIFFER_SESSION); - if (session == NULL) { - SetError(MEMORY_STR, error, NULL, 0); - return 0; - } - InitSession(session); -#ifdef HAVE_EXTENDED_MASTER - { - HsHashes* newHash = (HsHashes*)XMALLOC(sizeof(HsHashes), - NULL, DYNAMIC_TYPE_HASHES); - if (newHash == NULL) { - SetError(MEMORY_STR, error, NULL, 0); - XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); - return 0; - } - if (HashInit(newHash) != 0) { - SetError(EXTENDED_MASTER_HASH_STR, error, NULL, 0); - XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); - return 0; - } - session->hash = newHash; - } -#endif - session->server = ipInfo->dst; - session->client = ipInfo->src; - session->srvPort = (word16)tcpInfo->dstPort; - session->cliPort = (word16)tcpInfo->srcPort; - session->cliSeqStart = tcpInfo->sequence; - session->cliExpected = 1; /* relative */ - session->lastUsed= time(NULL); - session->keySz = 0; -#ifdef HAVE_SNI - session->sni = NULL; -#endif - - session->context = GetSnifferServer(ipInfo, tcpInfo); - if (session->context == NULL) { - SetError(SERVER_NOT_REG_STR, error, NULL, 0); - XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); - return 0; - } - - session->sslServer = SSL_new(session->context->ctx); - if (session->sslServer == NULL) { - SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); - XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); - return 0; - } - session->sslClient = SSL_new(session->context->ctx); - if (session->sslClient == NULL) { - SSL_free(session->sslServer); - session->sslServer = 0; - - SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); - XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); - return 0; - } - /* put server back into server mode */ - session->sslServer->options.side = WOLFSSL_SERVER_END; - - row = SessionHash(ipInfo, tcpInfo); - - /* add it to the session table */ - wc_LockMutex(&SessionMutex); - - session->next = SessionTable[row]; - SessionTable[row] = session; - - SessionCount++; - - if ( (SessionCount % HASH_SIZE) == 0) { - TraceFindingStale(); - RemoveStaleSessions(); - } - - wc_UnLockMutex(&SessionMutex); - - /* CreateSession is called in response to a SYN packet, we know this - * is headed to the server. Also we know the server is one we care - * about as we've passed the GetSnifferServer() successfully. */ - session->flags.side = WOLFSSL_SERVER_END; - - return session; -} - - -#ifdef OLD_HELLO_ALLOWED - -/* Process Old Client Hello Input */ -static int DoOldHello(SnifferSession* session, const byte* sslFrame, - int* rhSize, int* sslBytes, char* error) -{ - const byte* input = sslFrame; - byte b0, b1; - word32 idx = 0; - int ret; - - Trace(GOT_OLD_CLIENT_HELLO_STR); - session->flags.clientHello = 1; /* don't process again */ - b0 = *input++; - b1 = *input++; - *sslBytes -= 2; - *rhSize = ((b0 & 0x7f) << 8) | b1; - - if (*rhSize > *sslBytes) { - SetError(OLD_CLIENT_INPUT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - ret = ProcessOldClientHello(session->sslServer, input, &idx, *sslBytes, - (word16)*rhSize); - if (ret < 0 && ret != MATCH_SUITE_ERROR) { - SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - Trace(OLD_CLIENT_OK_STR); - XMEMCPY(session->sslClient->arrays->clientRandom, - session->sslServer->arrays->clientRandom, RAN_LEN); - - *sslBytes -= *rhSize; - return 0; -} - -#endif /* OLD_HELLO_ALLOWED */ - - -#if 0 -/* Calculate the TCP checksum, see RFC 1071 */ -/* return 0 for success, -1 on error */ -/* can be called from decode() with - TcpChecksum(&ipInfo, &tcpInfo, sslBytes, packet + ipInfo.length); - could also add a 64bit version if type available and using this -*/ -int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen, - const byte* packet) -{ - TcpPseudoHdr pseudo; - int count = PSEUDO_HDR_SZ; - const word16* data = (word16*)&pseudo; - word32 sum = 0; - word16 checksum; - - pseudo.src = ipInfo->src; - pseudo.dst = ipInfo->dst; - pseudo.rsv = 0; - pseudo.protocol = TCP_PROTO; - pseudo.length = htons(tcpInfo->length + dataLen); - - /* pseudo header sum */ - while (count >= 2) { - sum += *data++; - count -= 2; - } - - count = tcpInfo->length + dataLen; - data = (word16*)packet; - - /* main sum */ - while (count > 1) { - sum += *data++; - count -=2; - } - - /* get left-over, if any */ - packet = (byte*)data; - if (count > 0) { - sum += *packet; - } - - /* fold 32bit sum into 16 bits */ - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - checksum = (word16)~sum; - /* checksum should now equal 0, since included already calcd checksum */ - /* field, but tcp checksum offloading could negate calculation */ - if (checksum == 0) - return 0; - return -1; -} -#endif - - -/* Check IP and TCP headers, set payload */ -/* returns 0 on success, -1 on error */ -static int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet, - int length, const byte** sslFrame, int* sslBytes, char* error) -{ - TraceHeader(); - TracePacket(); - - /* ip header */ - if (length < IP_HDR_SZ) { - SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); - return -1; - } - if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0) - return -1; - - /* tcp header */ - if (length < (ipInfo->length + TCP_HDR_SZ)) { - SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); - return -1; - } - if (CheckTcpHdr((TcpHdr*)(packet + ipInfo->length), tcpInfo, error) != 0) - return -1; - - /* setup */ - *sslFrame = packet + ipInfo->length + tcpInfo->length; - if (*sslFrame > packet + length) { - SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); - return -1; - } - /* We only care about the data in the TCP/IP record. There may be extra - * data after the IP record for the FCS for Ethernet. */ - *sslBytes = (int)(packet + ipInfo->total - *sslFrame); - - return 0; -} - - -/* Create or Find existing session */ -/* returns 0 on success (continue), -1 on error, 1 on success (end) */ -static int CheckSession(IpInfo* ipInfo, TcpInfo* tcpInfo, int sslBytes, - SnifferSession** session, char* error) -{ - /* create a new SnifferSession on client SYN */ - if (tcpInfo->syn && !tcpInfo->ack) { - TraceClientSyn(tcpInfo->sequence); -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslEncryptedConns); -#endif - *session = CreateSession(ipInfo, tcpInfo, error); - if (*session == NULL) { - *session = GetSnifferSession(ipInfo, tcpInfo); - /* already had existing, so OK */ - if (*session) - return 1; - - SetError(MEMORY_STR, error, NULL, 0); - return -1; - } - return 1; - } - /* get existing sniffer session */ - else { - *session = GetSnifferSession(ipInfo, tcpInfo); - if (*session == NULL) { - /* don't worry about extraneous RST or duplicate FINs */ - if (tcpInfo->fin || tcpInfo->rst) - return 1; - /* don't worry about duplicate ACKs either */ - if (sslBytes == 0 && tcpInfo->ack) - return 1; - -#ifdef WOLFSSL_SNIFFER_STATS - LOCK_STAT(); - NOLOCK_INC_STAT(SnifferStats.sslDecryptedPackets); - NOLOCK_ADD_TO_STAT(SnifferStats.sslDecryptedBytes, sslBytes); - UNLOCK_STAT(); -#endif - - SetError(BAD_SESSION_STR, error, NULL, 0); - return -1; - } - } - return 0; -} - - -/* Create a Packet Buffer from *begin - end, adjust new *begin and bytesLeft */ -static PacketBuffer* CreateBuffer(word32* begin, word32 end, const byte* data, - int* bytesLeft) -{ - PacketBuffer* pb; - - int added = end - *begin + 1; - assert(*begin <= end); - - pb = (PacketBuffer*)XMALLOC(sizeof(PacketBuffer), - NULL, DYNAMIC_TYPE_SNIFFER_PB); - if (pb == NULL) return NULL; - - pb->next = 0; - pb->begin = *begin; - pb->end = end; - pb->data = (byte*)XMALLOC(added, NULL, DYNAMIC_TYPE_SNIFFER_PB_BUFFER); - - if (pb->data == NULL) { - XFREE(pb, NULL, DYNAMIC_TYPE_SNIFFER_PB); - return NULL; - } - XMEMCPY(pb->data, data, added); - - *bytesLeft -= added; - *begin = pb->end + 1; - - return pb; -} - - -/* Add sslFrame to Reassembly List */ -/* returns 1 (end) on success, -1, on error */ -static int AddToReassembly(byte from, word32 seq, const byte* sslFrame, - int sslBytes, SnifferSession* session, char* error) -{ - PacketBuffer* add; - PacketBuffer** front = (from == WOLFSSL_SERVER_END) ? - &session->cliReassemblyList: &session->srvReassemblyList; - PacketBuffer* curr = *front; - PacketBuffer* prev = curr; - - word32* reassemblyMemory = (from == WOLFSSL_SERVER_END) ? - &session->cliReassemblyMemory : &session->srvReassemblyMemory; - word32 startSeq = seq; - word32 added; - int bytesLeft = sslBytes; /* could be overlapping fragment */ - - /* if list is empty add full frame to front */ - if (!curr) { - if (MaxRecoveryMemory != -1 && - (int)(*reassemblyMemory + sslBytes) > MaxRecoveryMemory) { - SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft); - if (add == NULL) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - *front = add; - *reassemblyMemory += sslBytes; - return 1; - } - - /* add to front if before current front, up to next->begin */ - if (seq < curr->begin) { - word32 end = seq + sslBytes - 1; - - if (end >= curr->begin) - end = curr->begin - 1; - - if (MaxRecoveryMemory -1 && - (int)(*reassemblyMemory + sslBytes) > MaxRecoveryMemory) { - SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - add = CreateBuffer(&seq, end, sslFrame, &bytesLeft); - if (add == NULL) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - add->next = curr; - *front = add; - *reassemblyMemory += sslBytes; - } - - /* while we have bytes left, try to find a gap to fill */ - while (bytesLeft > 0) { - /* get previous packet in list */ - while (curr && (seq >= curr->begin)) { - prev = curr; - curr = curr->next; - } - - /* don't add duplicate data */ - if (prev->end >= seq) { - if ( (seq + bytesLeft - 1) <= prev->end) - return 1; - seq = prev->end + 1; - bytesLeft = startSeq + sslBytes - seq; - } - - if (!curr) - /* we're at the end */ - added = bytesLeft; - else - /* we're in between two frames */ - added = min((word32)bytesLeft, curr->begin - seq); - - /* data already there */ - if (added == 0) - continue; - - if (MaxRecoveryMemory != -1 && - (int)(*reassemblyMemory + added) > MaxRecoveryMemory) { - SetError(REASSEMBLY_MAX_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq], - &bytesLeft); - if (add == NULL) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - add->next = prev->next; - prev->next = add; - *reassemblyMemory += added; - } - return 1; -} - - -/* Add out of order FIN capture */ -/* returns 1 for success (end) */ -static int AddFinCapture(SnifferSession* session, word32 sequence) -{ - if (session->flags.side == WOLFSSL_SERVER_END) { - if (session->finCaputre.cliCounted == 0) - session->finCaputre.cliFinSeq = sequence; - } - else { - if (session->finCaputre.srvCounted == 0) - session->finCaputre.srvFinSeq = sequence; - } - return 1; -} - - -/* Adjust incoming sequence based on side */ -/* returns 0 on success (continue), -1 on error, 1 on success (end) */ -static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session, - int* sslBytes, const byte** sslFrame, char* error) -{ - word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? - session->cliSeqStart :session->srvSeqStart; - word32 real = tcpInfo->sequence - seqStart; - word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliExpected : &session->srvExpected; - PacketBuffer* reassemblyList = (session->flags.side == WOLFSSL_SERVER_END) ? - session->cliReassemblyList : session->srvReassemblyList; - byte skipPartial = (session->flags.side == WOLFSSL_SERVER_END) ? - session->flags.srvSkipPartial : - session->flags.cliSkipPartial; - - /* handle rollover of sequence */ - if (tcpInfo->sequence < seqStart) - real = 0xffffffffU - seqStart + tcpInfo->sequence; - - TraceRelativeSequence(*expected, real); - - if (real < *expected) { - Trace(DUPLICATE_STR); - if (real + *sslBytes > *expected) { - int overlap = *expected - real; - Trace(OVERLAP_DUPLICATE_STR); - - /* adjust to expected, remove duplicate */ - *sslFrame += overlap; - *sslBytes -= overlap; - - /* The following conditional block is duplicated below. It is the - * same action but for a different setup case. If changing this - * block be sure to also update the block below. */ - if (reassemblyList) { - word32 newEnd = *expected + *sslBytes; - - if (newEnd > reassemblyList->begin) { - Trace(OVERLAP_REASSEMBLY_BEGIN_STR); - - /* remove bytes already on reassembly list */ - *sslBytes -= newEnd - reassemblyList->begin; - } - if (newEnd > reassemblyList->end) { - Trace(OVERLAP_REASSEMBLY_END_STR); - - /* may be past reassembly list end (could have more on list) - so try to add what's past the front->end */ - AddToReassembly(session->flags.side, reassemblyList->end +1, - *sslFrame + reassemblyList->end - *expected + 1, - newEnd - reassemblyList->end, session, error); - } - } - } - else - return 1; - } - else if (real > *expected) { - Trace(OUT_OF_ORDER_STR); - if (*sslBytes > 0) { - int addResult = AddToReassembly(session->flags.side, real, - *sslFrame, *sslBytes, session, error); - if (skipPartial) { - *sslBytes = 0; - return 0; - } - else - return addResult; - } - else if (tcpInfo->fin) - return AddFinCapture(session, real); - } - else if (*sslBytes > 0) { - if (skipPartial) { - AddToReassembly(session->flags.side, real, - *sslFrame, *sslBytes, session, error); - *expected += *sslBytes; - *sslBytes = 0; - if (tcpInfo->fin) - *expected += 1; - return 0; - } - /* The following conditional block is duplicated above. It is the - * same action but for a different setup case. If changing this - * block be sure to also update the block above. */ - else if (reassemblyList) { - word32 newEnd = *expected + *sslBytes; - - if (newEnd > reassemblyList->begin) { - Trace(OVERLAP_REASSEMBLY_BEGIN_STR); - - /* remove bytes already on reassembly list */ - *sslBytes -= newEnd - reassemblyList->begin; - } - if (newEnd > reassemblyList->end) { - Trace(OVERLAP_REASSEMBLY_END_STR); - - /* may be past reassembly list end (could have more on list) - so try to add what's past the front->end */ - AddToReassembly(session->flags.side, reassemblyList->end +1, - *sslFrame + reassemblyList->end - *expected + 1, - newEnd - reassemblyList->end, session, error); - } - } - } - /* got expected sequence */ - *expected += *sslBytes; - if (tcpInfo->fin) - *expected += 1; - - return 0; -} - - -static int FindNextRecordInAssembly(SnifferSession* session, - const byte** sslFrame, int* sslBytes, - const byte** end, char* error) -{ - PacketBuffer** front = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliReassemblyList : - &session->srvReassemblyList; - PacketBuffer* curr = *front; - PacketBuffer* prev = NULL; - byte* skipPartial = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->flags.srvSkipPartial : - &session->flags.cliSkipPartial; - word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliReassemblyMemory : - &session->srvReassemblyMemory; - SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? - session->sslServer : - session->sslClient; - ProtocolVersion pv = ssl->version; - word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliExpected : - &session->srvExpected; - - while (curr != NULL) { - *expected = curr->end + 1; - - if (curr->data[0] == application_data && - curr->data[1] == pv.major && - curr->data[2] == pv.minor) { - - if (ssl->buffers.inputBuffer.length > 0) - Trace(DROPPING_PARTIAL_RECORD); - - *sslBytes = curr->end - curr->begin + 1; - if ( (word32)*sslBytes > ssl->buffers.inputBuffer.bufferSize) { - if (GrowInputBuffer(ssl, *sslBytes, 0) < 0) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - } - - XMEMCPY(ssl->buffers.inputBuffer.buffer, curr->data, *sslBytes); - - *front = curr->next; - *reassemblyMemory -= *sslBytes; - FreePacketBuffer(curr); - - ssl->buffers.inputBuffer.length = *sslBytes; - *sslFrame = ssl->buffers.inputBuffer.buffer; - *end = *sslFrame + *sslBytes; - *skipPartial = 0; - - return 0; - } - else if (ssl->specs.cipher_type == block) { - if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes) { -#ifdef BUILD_AES - wc_AesSetIV(ssl->decrypt.aes, - curr->data + curr->end - curr->begin - - ssl->specs.block_size + 1); -#endif - } - else if (ssl->specs.bulk_cipher_algorithm == wolfssl_triple_des) { -#ifdef BUILD_DES3 - wc_Des3_SetIV(ssl->decrypt.des3, - curr->data + curr->end - curr->begin - - ssl->specs.block_size + 1); -#endif - } - } - - Trace(DROPPING_LOST_FRAG_STR); -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslDecodeFails); -#endif - prev = curr; - curr = curr->next; - *reassemblyMemory -= (prev->end - prev->begin + 1); - FreePacketBuffer(prev); - } - - *front = curr; - - return 0; -} - - -static int FixSequence(TcpInfo* tcpInfo, SnifferSession* session) -{ - word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->srvExpected : &session->cliExpected; - PacketBuffer* list = (session->flags.side == WOLFSSL_SERVER_END) ? - session->srvReassemblyList : - session->cliReassemblyList; - byte* skipPartial = (session->flags.side != WOLFSSL_SERVER_END) ? - &session->flags.srvSkipPartial : - &session->flags.cliSkipPartial; - - *skipPartial = 1; - if (list != NULL) - *expected = list->begin; - else { - word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? - session->srvSeqStart : session->cliSeqStart; - word32 real = tcpInfo->ackNumber - seqStart; - - *expected = real; - } - - return 1; -} - - -/* Check latest ack number for missing packets - return 0 ok, <0 on error */ -static int CheckAck(TcpInfo* tcpInfo, SnifferSession* session) -{ - if (tcpInfo->ack) { - word32 seqStart = (session->flags.side == WOLFSSL_SERVER_END) ? - session->srvSeqStart :session->cliSeqStart; - word32 real = tcpInfo->ackNumber - seqStart; - word32 expected = (session->flags.side == WOLFSSL_SERVER_END) ? - session->srvExpected : session->cliExpected; - - /* handle rollover of sequence */ - if (tcpInfo->ackNumber < seqStart) - real = 0xffffffffU - seqStart + tcpInfo->ackNumber; - - TraceAck(real, expected); - - if (real > expected) - return -1; /* we missed a packet, ACKing data we never saw */ - } - return 0; -} - - -/* Check TCP Sequence status */ -/* returns 0 on success (continue), -1 on error, 1 on success (end) */ -static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo, - SnifferSession* session, int* sslBytes, - const byte** sslFrame, char* error) -{ - int actualLen; - byte* ackFault = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->flags.cliAckFault : - &session->flags.srvAckFault; - - /* init SEQ from server to client */ - if (tcpInfo->syn && tcpInfo->ack) { - session->srvSeqStart = tcpInfo->sequence; - session->srvExpected = 1; - TraceServerSyn(tcpInfo->sequence); - return 1; - } - - /* adjust potential ethernet trailer */ - actualLen = ipInfo->total - ipInfo->length - tcpInfo->length; - if (*sslBytes > actualLen) { - *sslBytes = actualLen; - } - - TraceSequence(tcpInfo->sequence, *sslBytes); - if (CheckAck(tcpInfo, session) < 0) { - if (!RecoveryEnabled) { - UpdateMissedDataSessions(); - SetError(ACK_MISSED_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - else { - SetError(ACK_MISSED_STR, error, session, 0); - if (*ackFault == 0) { - *ackFault = 1; - UpdateMissedDataSessions(); - } - return FixSequence(tcpInfo, session); - } - } - - if (*ackFault) { - Trace(CLEAR_ACK_FAULT); - *ackFault = 0; - } - - return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error); -} - - -/* Check Status before record processing */ -/* 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, - void* vChain, word32 chainSz, char* error) -{ - word32 length; - SSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ? - (*session)->sslServer : (*session)->sslClient; - byte skipPartial = ((*session)->flags.side == WOLFSSL_SERVER_END) ? - (*session)->flags.srvSkipPartial : - (*session)->flags.cliSkipPartial; - /* remove SnifferSession on 2nd FIN or RST */ - if (tcpInfo->fin || tcpInfo->rst) { - /* flag FIN and RST */ - if (tcpInfo->fin) - (*session)->flags.finCount += 1; - else if (tcpInfo->rst) - (*session)->flags.finCount += 2; - - if ((*session)->flags.finCount >= 2) { - RemoveSession(*session, ipInfo, tcpInfo, 0); - *session = NULL; - return 1; - } - } - - if ((*session)->flags.fatalError == FATAL_ERROR_STATE) { - SetError(FATAL_ERROR_STR, error, NULL, 0); - return -1; - } - - if (skipPartial) { - if (FindNextRecordInAssembly(*session, - sslFrame, sslBytes, end, error) < 0) { - return -1; - } - } - - if (*sslBytes == 0) { - Trace(NO_DATA_STR); - return 1; - } - - /* if current partial data, add to end of partial */ - /* if skipping, the data is already at the end of partial */ - if ( !skipPartial && (length = ssl->buffers.inputBuffer.length) ) { - Trace(PARTIAL_ADD_STR); - - if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) { - if (GrowInputBuffer(ssl, *sslBytes, length) < 0) { - SetError(MEMORY_STR, error, *session, FATAL_ERROR_STATE); - return -1; - } - } - if (vChain == NULL) { - XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], - *sslFrame, *sslBytes); - *sslBytes += length; - ssl->buffers.inputBuffer.length = *sslBytes; - *sslFrame = ssl->buffers.inputBuffer.buffer; - *end = *sslFrame + *sslBytes; - } - } - - if (vChain != NULL) { -#ifdef WOLFSSL_SNIFFER_CHAIN_INPUT - struct iovec* chain = (struct iovec*)vChain; - word32 i, offset, headerSz, qty, remainder; - - Trace(CHAIN_INPUT_STR); - headerSz = (word32)*sslFrame - (word32)chain[0].iov_base; - remainder = *sslBytes; - - if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) { - if (GrowInputBuffer(ssl, *sslBytes, length) < 0) { - SetError(MEMORY_STR, error, *session, FATAL_ERROR_STATE); - return -1; - } - } - - qty = min(*sslBytes, (word32)chain[0].iov_len - headerSz); - XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], - (byte*)chain[0].iov_base + headerSz, qty); - offset = length; - for (i = 1; i < chainSz; i++) { - offset += qty; - remainder -= qty; - - if (chain[i].iov_len > remainder) - qty = remainder; - else - qty = (word32)chain[i].iov_len; - XMEMCPY(ssl->buffers.inputBuffer.buffer + offset, - chain[i].iov_base, qty); - } - - *sslBytes += length; - ssl->buffers.inputBuffer.length = *sslBytes; - *sslFrame = ssl->buffers.inputBuffer.buffer; - *end = *sslFrame + *sslBytes; -#endif - (void)chainSz; - } - - 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]); - - if ((rhSize <= (*sslBytes - 2)) && - (*sslFrame)[2] == OLD_HELLO_ID && (*sslFrame)[3] == SSLv3_MAJOR) { -#ifdef OLD_HELLO_ALLOWED - int ret = DoOldHello(*session, *sslFrame, &rhSize, sslBytes, error); - if (ret < 0) - return -1; /* error already set */ - if (*sslBytes <= 0) - return 1; -#endif - } - else { -#ifdef STARTTLS_ALLOWED - if (ssl->buffers.inputBuffer.dynamicFlag) { - ssl->buffers.inputBuffer.length = 0; - ShrinkInputBuffer(ssl, NO_FORCED_FREE); - } - return 1; -#endif - } - } - - return 0; -} - - -/* See if input on the reassembly list is ready for consuming */ -/* returns 1 for TRUE, 0 for FALSE */ -static int HaveMoreInput(SnifferSession* session, const byte** sslFrame, - int* sslBytes, const byte** end, char* error) -{ - /* sequence and reassembly based on from, not to */ - int moreInput = 0; - PacketBuffer** front = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliReassemblyList : &session->srvReassemblyList; - word32* expected = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliExpected : &session->srvExpected; - /* buffer is on receiving end */ - word32* length = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->sslServer->buffers.inputBuffer.length : - &session->sslClient->buffers.inputBuffer.length; - byte** myBuffer = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->sslServer->buffers.inputBuffer.buffer : - &session->sslClient->buffers.inputBuffer.buffer; - word32* bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->sslServer->buffers.inputBuffer.bufferSize : - &session->sslClient->buffers.inputBuffer.bufferSize; - SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? - session->sslServer : session->sslClient; - word32* reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ? - &session->cliReassemblyMemory : &session->srvReassemblyMemory; - - while (*front && ((*front)->begin == *expected) ) { - word32 room = *bufferSize - *length; - word32 packetLen = (*front)->end - (*front)->begin + 1; - - if (packetLen > room && *bufferSize < MAX_INPUT_SZ) { - if (GrowInputBuffer(ssl, packetLen, *length) < 0) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return 0; - } - room = *bufferSize - *length; /* bufferSize is now bigger */ - } - - if (packetLen <= room) { - PacketBuffer* del = *front; - byte* buf = *myBuffer; - - XMEMCPY(&buf[*length], (*front)->data, packetLen); - *length += packetLen; - *expected += packetLen; - - /* remove used packet */ - *front = (*front)->next; - - *reassemblyMemory -= packetLen; - FreePacketBuffer(del); - - moreInput = 1; - } - else - break; - } - if (moreInput) { - *sslFrame = *myBuffer; - *sslBytes = *length; - *end = *myBuffer + *length; - } - return moreInput; -} - - - -/* Process Message(s) from 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, - void* ctx, char* error) -{ - const byte* sslBegin = sslFrame; - const byte* recordEnd; /* end of record indicator */ - const byte* inRecordEnd; /* indicator from input stream not decrypt */ - RecordLayerHeader rh; - int rhSize = 0; - int ret; - int errCode = 0; - int decoded = 0; /* bytes stored for user in data */ - int notEnough; /* notEnough bytes yet flag */ - int decrypted = 0; /* was current msg decrypted */ - SSL* ssl = (session->flags.side == WOLFSSL_SERVER_END) ? - session->sslServer : session->sslClient; -doMessage: - notEnough = 0; - if (sslBytes < 0) { - SetError(PACKET_HDR_SHORT_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - if (sslBytes >= RECORD_HEADER_SZ) { - if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) { - SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - } - else - notEnough = 1; - - if (notEnough || rhSize > (sslBytes - RECORD_HEADER_SZ)) { - /* don't have enough input yet to process full SSL record */ - Trace(PARTIAL_INPUT_STR); - - /* store partial if not there already or we advanced */ - if (ssl->buffers.inputBuffer.length == 0 || sslBegin != sslFrame) { - if (sslBytes > (int)ssl->buffers.inputBuffer.bufferSize) { - if (GrowInputBuffer(ssl, sslBytes, 0) < 0) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - } - XMEMMOVE(ssl->buffers.inputBuffer.buffer, sslFrame, sslBytes); - ssl->buffers.inputBuffer.length = sslBytes; - } - if (HaveMoreInput(session, &sslFrame, &sslBytes, &end, error)) - goto doMessage; - return decoded; - } - sslFrame += RECORD_HEADER_SZ; - sslBytes -= RECORD_HEADER_SZ; - recordEnd = sslFrame + rhSize; /* may have more than one record */ - inRecordEnd = recordEnd; - - /* decrypt if needed */ - if ((session->flags.side == WOLFSSL_SERVER_END && - session->flags.serverCipherOn) - || (session->flags.side == WOLFSSL_CLIENT_END && - session->flags.clientCipherOn)) { - int ivAdvance = 0; /* TLSv1.1 advance amount */ - if (ssl->decrypt.setup != 1) { - SetError(DECRYPT_KEYS_NOT_SETUP, error, session, FATAL_ERROR_STATE); - return -1; - } - if (CheckAvailableSize(ssl, rhSize) < 0) { - SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - sslFrame = DecryptMessage(ssl, sslFrame, rhSize, - ssl->buffers.outputBuffer.buffer, &errCode, - &ivAdvance); - recordEnd = sslFrame - ivAdvance + rhSize; /* sslFrame moved so - should recordEnd */ - decrypted = 1; - -#ifdef WOLFSSL_SNIFFER_STATS - if (errCode != 0) { - INC_STAT(SnifferStats.sslKeyFails); - } - else { - LOCK_STAT(); - NOLOCK_INC_STAT(SnifferStats.sslDecryptedPackets); - NOLOCK_ADD_TO_STAT(SnifferStats.sslDecryptedBytes, sslBytes); - UNLOCK_STAT(); - } -#endif - if (errCode != 0) { - SetError(BAD_DECRYPT, error, session, FATAL_ERROR_STATE); - return -1; - } - } - -doPart: - - switch ((enum ContentType)rh.type) { - case handshake: - { - int startIdx = sslBytes; - int used; - - Trace(GOT_HANDSHAKE_STR); - ret = DoHandShake(sslFrame, &sslBytes, session, error); - if (ret != 0) { - if (session->flags.fatalError == 0) - SetError(BAD_HANDSHAKE_STR, error, session, - FATAL_ERROR_STATE); - return -1; - } - - /* DoHandShake now fully decrements sslBytes to remaining */ - used = startIdx - sslBytes; - sslFrame += used; - if (decrypted) - sslFrame += ssl->keys.padSz; - } - break; - case change_cipher_spec: - if (session->flags.side == WOLFSSL_SERVER_END) - session->flags.serverCipherOn = 1; - else - session->flags.clientCipherOn = 1; - Trace(GOT_CHANGE_CIPHER_STR); - ssl->options.handShakeState = HANDSHAKE_DONE; - ssl->options.handShakeDone = 1; - - sslFrame += 1; - sslBytes -= 1; - - break; - case application_data: - Trace(GOT_APP_DATA_STR); - { - word32 inOutIdx = 0; - - ret = DoApplicationData(ssl, (byte*)sslFrame, &inOutIdx); - if (ret == 0) { - ret = ssl->buffers.clearOutputBuffer.length; - TraceGotData(ret); - if (ret) { /* may be blank message */ - 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 - } - TraceAddedData(ret, decoded); - decoded += ret; - ssl->buffers.clearOutputBuffer.length = 0; - } - } - else { - SetError(BAD_APP_DATA_STR, error,session,FATAL_ERROR_STATE); - return -1; - } - if (ssl->buffers.outputBuffer.dynamicFlag) - ShrinkOutputBuffer(ssl); - - sslFrame += inOutIdx; - sslBytes -= inOutIdx; - } - break; - case alert: - Trace(GOT_ALERT_STR); -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslAlerts); -#endif - sslFrame += rhSize; - sslBytes -= rhSize; - break; - case no_type: - default: - SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE); - return -1; - } - - /* do we have another msg in record ? */ - if (sslFrame < recordEnd) { - Trace(ANOTHER_MSG_STR); - goto doPart; - } - - /* back to input stream instead of potential decrypt buffer */ - recordEnd = inRecordEnd; - - /* do we have more records ? */ - if (recordEnd < end) { - Trace(ANOTHER_MSG_STR); - sslFrame = recordEnd; - sslBytes = (int)(end - recordEnd); - goto doMessage; - } - - /* clear used input */ - ssl->buffers.inputBuffer.length = 0; - - /* could have more input ready now */ - if (HaveMoreInput(session, &sslFrame, &sslBytes, &end, error)) - goto doMessage; - - if (ssl->buffers.inputBuffer.dynamicFlag) - ShrinkInputBuffer(ssl, NO_FORCED_FREE); - - return decoded; -} - - -/* See if we need to process any pending FIN captures */ -/* Return 0=normal, else = session removed */ -static int CheckFinCapture(IpInfo* ipInfo, TcpInfo* tcpInfo, - SnifferSession* session) -{ - int ret = 0; - if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <= - session->cliExpected) { - if (session->finCaputre.cliCounted == 0) { - session->flags.finCount += 1; - session->finCaputre.cliCounted = 1; - TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected); - } - } - - if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <= - session->srvExpected) { - if (session->finCaputre.srvCounted == 0) { - session->flags.finCount += 1; - session->finCaputre.srvCounted = 1; - TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected); - } - } - - if (session->flags.finCount >= 2) { - RemoveSession(session, ipInfo, tcpInfo, 0); - ret = 1; - } - return ret; -} - - -/* If session is in fatal error state free resources now - return true if removed, 0 otherwise */ -static int RemoveFatalSession(IpInfo* ipInfo, TcpInfo* tcpInfo, - SnifferSession* session, char* error) -{ - if (session && session->flags.fatalError == FATAL_ERROR_STATE) { - RemoveSession(session, ipInfo, tcpInfo, 0); - SetError(FATAL_ERROR_STR, error, NULL, 0); - return 1; - } - return 0; -} - - -/* 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) -{ - TcpInfo tcpInfo; - IpInfo ipInfo; - const byte* sslFrame; - const byte* end; - int sslBytes; /* ssl bytes unconsumed */ - 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; - - end = sslFrame + sslBytes; - - ret = CheckSession(&ipInfo, &tcpInfo, sslBytes, &session, error); - if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; - else if (ret == -1) return -1; - else if (ret == 1) { -#ifdef WOLFSSL_SNIFFER_STATS - if (sslBytes > 0) { - LOCK_STAT(); - NOLOCK_INC_STAT(SnifferStats.sslEncryptedPackets); - NOLOCK_ADD_TO_STAT(SnifferStats.sslEncryptedBytes, sslBytes); - UNLOCK_STAT(); - } - else - INC_STAT(SnifferStats.sslDecryptedPackets); -#endif - return 0; /* done for now */ - } - - ret = CheckSequence(&ipInfo, &tcpInfo, session, &sslBytes, &sslFrame,error); - if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; - else if (ret == -1) return -1; - else if (ret == 1) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslDecryptedPackets); -#endif - return 0; /* done for now */ - } - - ret = CheckPreRecord(&ipInfo, &tcpInfo, &sslFrame, &session, &sslBytes, - &end, vChain, chainSz, error); - if (RemoveFatalSession(&ipInfo, &tcpInfo, session, error)) return -1; - else if (ret == -1) return -1; - else if (ret == 1) { -#ifdef WOLFSSL_SNIFFER_STATS - INC_STAT(SnifferStats.sslDecryptedPackets); -#endif - return 0; /* done for now */ - } - -#ifdef WOLFSSL_SNIFFER_STATS - if (sslBytes > 0) { - LOCK_STAT(); - NOLOCK_INC_STAT(SnifferStats.sslEncryptedPackets); - NOLOCK_ADD_TO_STAT(SnifferStats.sslEncryptedBytes, sslBytes); - UNLOCK_STAT(); - } - else - INC_STAT(SnifferStats.sslDecryptedPackets); -#endif - - 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); - } - - return ret; -} - - -/* 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 */ -/* Also returns Session Info if available */ -int ssl_DecodePacketWithSessionInfo(const unsigned char* packet, int length, - unsigned char** data, SSLInfo* sslInfo, char* error) -{ - return ssl_DecodePacketInternal(packet, length, NULL, 0, data, sslInfo, - NULL, error); -} - - -/* 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 */ -int ssl_DecodePacket(const byte* packet, int length, byte** data, char* error) -{ - return ssl_DecodePacketInternal(packet, length, NULL, 0, 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, 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 - - -/* Deallocator for the decoded data buffer. */ -/* returns 0 on success, -1 on error */ -int ssl_FreeDecodeBuffer(byte** data, char* error) -{ - return ssl_FreeZeroDecodeBuffer(data, 0, error); -} - - -/* Deallocator for the decoded data buffer, zeros out buffer. */ -/* returns 0 on success, -1 on error */ -int ssl_FreeZeroDecodeBuffer(byte** data, int sz, char* error) -{ - (void)error; - - if (sz < 0) { - return -1; - } - - if (data != NULL) { - ForceZero(*data, (word32)sz); - XFREE(*data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - *data = NULL; - } - - return 0; -} - - -/* Enables (if traceFile)/ Disables debug tracing */ -/* returns 0 on success, -1 on error */ -int ssl_Trace(const char* traceFile, char* error) -{ - if (traceFile) { - /* Don't try to reopen the file */ - if (TraceFile == NULL) { - TraceFile = fopen(traceFile, "a"); - if (!TraceFile) { - SetError(BAD_TRACE_FILE_STR, error, NULL, 0); - return -1; - } - TraceOn = 1; - } - } - else - TraceOn = 0; - - return 0; -} - - -/* Enables/Disables Recovery of missed data if later packets allow - * maxMemory is number of bytes to use for reassembly buffering per session, - * -1 means unlimited - * returns 0 on success, -1 on error */ -int ssl_EnableRecovery(int onOff, int maxMemory, char* error) -{ - (void)error; - - RecoveryEnabled = onOff; - if (onOff) - MaxRecoveryMemory = maxMemory; - - return 0; -} - - - -#ifdef WOLFSSL_SESSION_STATS - -int ssl_GetSessionStats(unsigned int* active, unsigned int* total, - unsigned int* peak, unsigned int* maxSessions, - unsigned int* missedData, unsigned int* reassemblyMem, - char* error) -{ - int ret; - - if (missedData) { - wc_LockMutex(&RecoveryMutex); - *missedData = MissedDataSessions; - wc_UnLockMutex(&RecoveryMutex); - } - - if (reassemblyMem) { - SnifferSession* session; - int i; - - *reassemblyMem = 0; - wc_LockMutex(&SessionMutex); - for (i = 0; i < HASH_SIZE; i++) { - session = SessionTable[i]; - while (session) { - *reassemblyMem += session->cliReassemblyMemory; - *reassemblyMem += session->srvReassemblyMemory; - session = session->next; - } - } - wc_UnLockMutex(&SessionMutex); - } - - ret = wolfSSL_get_session_stats(active, total, peak, maxSessions); - - if (ret == WOLFSSL_SUCCESS) - return 0; - else { - SetError(BAD_SESSION_STATS, error, NULL, 0); - return -1; - } -} - -#endif - - - -int ssl_SetConnectionCb(SSLConnCb cb) -{ - ConnectionCb = cb; - return 0; -} - - - -int ssl_SetConnectionCtx(void* ctx) -{ - ConnectionCbCtx = ctx; - return 0; -} - - -#ifdef WOLFSSL_SNIFFER_STATS - -/* Resets the statistics tracking global structure. - * returns 0 on success, -1 on error */ -int ssl_ResetStatistics(void) -{ - wc_LockMutex(&StatsMutex); - XMEMSET(&SnifferStats, 0, sizeof(SSLStats)); - wc_UnLockMutex(&StatsMutex); - return 0; -} - - -/* Copies the SSL statistics into the provided stats record. - * returns 0 on success, -1 on error */ -int ssl_ReadStatistics(SSLStats* stats) -{ - if (stats == NULL) - return -1; - - LOCK_STAT(); - XMEMCPY(stats, &SnifferStats, sizeof(SSLStats)); - UNLOCK_STAT(); - return 0; -} - -/* Copies the SSL statistics into the provided stats record then - * resets the statistics tracking global structure. - * returns 0 on success, -1 on error */ -int ssl_ReadResetStatistics(SSLStats* stats) -{ - if (stats == NULL) - return -1; - - LOCK_STAT(); - XMEMCPY(stats, &SnifferStats, sizeof(SSLStats)); - XMEMSET(&SnifferStats, 0, sizeof(SSLStats)); - UNLOCK_STAT(); - return 0; -} - -#endif /* WOLFSSL_SNIFFER_STATS */ - - -#ifdef WOLFSSL_SNIFFER_WATCH - -int ssl_SetWatchKeyCallback_ex(SSLWatchCb cb, int devId, char* error) -{ - (void)devId; - WatchCb = cb; - return CreateWatchSnifferServer(error); -} - - -int ssl_SetWatchKeyCallback(SSLWatchCb cb, char* error) -{ - WatchCb = cb; - return CreateWatchSnifferServer(error); -} - - -int ssl_SetWatchKeyCtx(void* ctx, char* error) -{ - (void)error; - WatchCbCtx = ctx; - return 0; -} - - -int ssl_SetWatchKey_buffer(void* vSniffer, const byte* key, word32 keySz, - int keyType, char* error) -{ - SnifferSession* sniffer; - int ret; - - if (vSniffer == NULL) { - return -1; - } - if (key == NULL || keySz == 0) { - return -1; - } - - sniffer = (SnifferSession*)vSniffer; - /* Remap the keyType from what the user can use to - * what wolfSSL_use_PrivateKey_buffer expects. */ - keyType = (keyType == FILETYPE_PEM) ? WOLFSSL_FILETYPE_PEM : - WOLFSSL_FILETYPE_ASN1; - - ret = wolfSSL_use_PrivateKey_buffer(sniffer->sslServer, - key, keySz, keyType); - if (ret != WOLFSSL_SUCCESS) { - SetError(KEY_FILE_STR, error, sniffer, FATAL_ERROR_STATE); - return -1; - } - - return 0; -} - - -int ssl_SetWatchKey_file(void* vSniffer, const char* keyFile, int keyType, - const char* password, char* error) -{ - byte* keyBuf = NULL; - word32 keyBufSz = 0; - int ret; - - if (vSniffer == NULL) { - return -1; - } - if (keyFile == NULL) { - return -1; - } - - /* Remap the keyType from what the user can use to - * what LoadKeyFile expects. */ - keyType = (keyType == FILETYPE_PEM) ? WOLFSSL_FILETYPE_PEM : - WOLFSSL_FILETYPE_ASN1; - - ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, keyType, password); - if (ret < 0) { - SetError(KEY_FILE_STR, error, NULL, 0); - XFREE(keyBuf, NULL, DYNAMIC_TYPE_X509); - return -1; - } - - ret = ssl_SetWatchKey_buffer(vSniffer, keyBuf, keyBufSz, FILETYPE_DER, - error); - XFREE(keyBuf, NULL, DYNAMIC_TYPE_X509); - - return ret; -} - -#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 */ |