Index: azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/sniffer.c
===================================================================
--- azure_iot_hub_f767zi/trunk/wolfssl-4.4.0/src/sniffer.c	(revision 457)
+++ azure_iot_hub_f767zi/trunk/wolfssl-4.7.0/src/sniffer.c	(revision 464)
@@ -26,6 +26,42 @@
 
 #include <wolfssl/wolfcrypt/settings.h>
-
-#ifndef WOLFCRYPT_ONLY
+#include <wolfssl/wolfcrypt/wc_port.h>
+
+/* xctime */
+#ifndef XCTIME
+   #define XCTIME ctime
+#endif
+
+/* only in this file, to avoid confusing future ports leave
+ * these defines here. Do not move to wc_port.h */
+#ifdef USER_CUSTOM_SNIFFX
+    /* To be implemented in user_settings.h */
+#elif defined(FUSION_RTOS)
+    #include <fcl_network.h>
+    #define XINET_NTOA FNS_INET_NTOA
+    #define XINET_ATON FNS_INET_ATON
+    #define XINET_PTON(a,b,c,d) FNS_INET_PTON((a),(b),(c),(d),NULL)
+    #define XINET_NTOP(a,b,c,d) FNS_INET_NTOP((a),(b),(c),(d),NULL)
+    #define XINET_ADDR FNS_INET_ADDR
+    #define XHTONS FNS_HTONS
+    #define XNTOHS FNS_NTOHS
+    #define XHTONL FNS_HTONL
+    #define XNTOHL FNS_NTOHL
+    #define XINADDR_NONE FNS_INADDR_NONE
+#else
+    /* default */
+    #define XINET_NTOA inet_ntoa
+    #define XINET_ATON inet_aton
+    #define XINET_PTON(a,b,c) inet_pton((a),(b),(c))
+    #define XINET_NTOP inet_ntop
+    #define XINET_ADDR inet_addr
+    #define XHTONS htons
+    #define XNTOHS ntohs
+    #define XHTONL htonl
+    #define XNTOHL ntohl
+    #define XINADDR_NONE INADDR_NONE
+#endif
+
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_FILESYSTEM)
 #ifdef WOLFSSL_SNIFFER
 
@@ -33,8 +69,15 @@
 #include <time.h>
 
-#ifndef _WIN32
-  #include <arpa/inet.h>
+#ifdef FUSION_RTOS
+    #include <fns_inet.h>
+    #ifdef TCP_PROTOCOL
+        #undef TCP_PROTOCOL
+    #endif
 #else
-  #include <WS2tcpip.h>
+    #ifndef _WIN32
+        #include <arpa/inet.h>
+    #else
+        #include <WS2tcpip.h>
+    #endif
 #endif
 
@@ -45,5 +88,4 @@
 #endif
 
-#include <wolfssl/openssl/ssl.h>
 #include <wolfssl/internal.h>
 #include <wolfssl/error-ssl.h>
@@ -91,11 +133,34 @@
     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 */
+    FATAL_ERROR_STATE  = 1,   /* SnifferSession fatal error state */
     TICKET_HINT_LEN    = 4,   /* Session Ticket Hint length */
-    EXT_TYPE_SZ        = 2,   /* Extension length */
+    TICKET_HINT_AGE_LEN= 4,   /* Session Ticket Age add length */        
+    EXT_TYPE_SZ        = 2,   /* Extension type 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 */
+
+    /* TLS Extensions */
+    EXT_SERVER_NAME                = 0x0000, /* a.k.a. SNI  */
+    EXT_MAX_FRAGMENT_LENGTH        = 0x0001,
+    EXT_TRUSTED_CA_KEYS            = 0x0003,
+    EXT_TRUNCATED_HMAC             = 0x0004,
+    EXT_STATUS_REQUEST             = 0x0005, /* a.k.a. OCSP stapling   */
+    EXT_SUPPORTED_GROUPS           = 0x000a, /* a.k.a. Supported Curves */
+    EXT_EC_POINT_FORMATS           = 0x000b,
+    EXT_SIGNATURE_ALGORITHMS       = 0x000d,
+    EXT_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */
+    EXT_STATUS_REQUEST_V2          = 0x0011, /* a.k.a. OCSP stapling v2 */
+    EXT_ENCRYPT_THEN_MAC           = 0x0016, /* RFC 7366 */
+    EXT_MASTER_SECRET              = 0x0017, /* Extended Master Secret Extension ID */
+    EXT_TICKET_ID                  = 0x0023, /* Session Ticket Extension ID */
+    EXT_PRE_SHARED_KEY             = 0x0029,
+    EXT_EARLY_DATA                 = 0x002a,
+    EXT_SUPPORTED_VERSIONS         = 0x002b,
+    EXT_COOKIE                     = 0x002c,
+    EXT_PSK_KEY_EXCHANGE_MODES     = 0x002d,
+    EXT_POST_HANDSHAKE_AUTH        = 0x0031,
+    EXT_SIGNATURE_ALGORITHMS_CERT  = 0x0032,
+    EXT_KEY_SHARE                  = 0x0033,
+    EXT_RENEGOTIATION_INFO         = 0xff01
 };
 
@@ -139,5 +204,5 @@
 
 static WOLFSSL_GLOBAL int TraceOn = 0;         /* Trace is off by default */
-static WOLFSSL_GLOBAL FILE* TraceFile = 0;
+static WOLFSSL_GLOBAL XFILE TraceFile = 0;
 
 
@@ -276,5 +341,7 @@
     "No data destination Error",
     "Store data callback failed",
-    "Loading chain input"
+    "Loading chain input",
+    "Got encrypted extension",
+    "Got Hello Retry Request",
 };
 
@@ -319,4 +386,5 @@
     byte*            key;                        /* DER private key */
     word32           keySz;                      /* size of DER private key */
+    int              isEphemeralKey;
     struct NamedKey* next;                       /* for list */
 } NamedKey;
@@ -336,5 +404,5 @@
 /* Sniffer Server holds info for each server/port monitored */
 typedef struct SnifferServer {
-    SSL_CTX*       ctx;                          /* SSL context */
+    WOLFSSL_CTX*   ctx;                          /* SSL context */
     char           address[MAX_SERVER_ADDRESS];  /* passed in server address */
     IpAddrInfo     server;                       /* network order address */
@@ -365,14 +433,15 @@
     byte           expectEms;       /* expect extended master secret */
 #endif
+    byte           gotFinished;     /* processed finished */
 } Flags;
 
 
 /* Out of Order FIN capture */
-typedef struct FinCaputre {
+typedef struct FinCapture {
     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;
+} FinCapture;
 
 
@@ -385,5 +454,5 @@
     wc_Md5 hashMd5;
 #endif
-#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
     wc_Sha256 hashSha256;
@@ -393,4 +462,14 @@
 #endif
 } HsHashes;
+
+typedef struct KeyShareInfo {
+    word16      named_group;
+    int         key_len;
+    const byte* key;
+
+    /* additional info */
+    int         dh_key_bits;
+    int         curve_id;
+} KeyShareInfo;
 
 
@@ -398,6 +477,6 @@
 typedef struct SnifferSession {
     SnifferServer* context;         /* server context */
-    SSL*           sslServer;       /* SSL server side decode */
-    SSL*           sslClient;       /* SSL client side decode */
+    WOLFSSL*       sslServer;       /* SSL server side decode */
+    WOLFSSL*       sslClient;       /* SSL client side decode */
     IpAddrInfo     server;          /* server address in network byte order */
     IpAddrInfo     client;          /* client address in network byte order */
@@ -408,7 +487,7 @@
     word32         cliExpected;     /* client expected sequence (relative) */
     word32         srvExpected;     /* server expected sequence (relative) */
-    FinCaputre     finCaputre;      /* retain out of order FIN s */
+    FinCapture     finCapture;      /* retain out of order FIN s */
     Flags          flags;           /* session flags */
-    time_t         lastUsed;          /* last used ticks */
+    time_t         lastUsed;        /* last used ticks */
     word32         keySz;           /* size of the private key */
     PacketBuffer*  cliReassemblyList; /* client out of order packets */
@@ -416,11 +495,22 @@
     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 */
+    struct SnifferSession* next;    /* for hash table list */
+    byte*          ticketID;        /* mac ID of session ticket */
+#ifdef HAVE_MAX_FRAGMENT
+    byte*          tlsFragBuf;
+    word32         tlsFragOffset;
+    word32         tlsFragSize;
+#endif
 #ifdef HAVE_SNI
     const char*    sni;             /* server name indication */
 #endif
 #ifdef HAVE_EXTENDED_MASTER
-    HsHashes*       hash;
+    HsHashes*      hash;
+#endif
+#ifdef WOLFSSL_TLS13
+    byte*          cliKeyShare;
+    word32         cliKeyShareSz;
+    KeyShareInfo   srvKs;
+    KeyShareInfo   cliKs;
 #endif
 } SnifferSession;
@@ -559,5 +649,5 @@
         wc_FreeMutex(&srv->namedKeysMutex);
 #endif
-        SSL_CTX_free(srv->ctx);
+        wolfSSL_CTX_free(srv->ctx);
     }
     XFREE(srv, NULL, DYNAMIC_TYPE_SNIFFER_SERVER);
@@ -595,6 +685,6 @@
 {
     if (session) {
-        SSL_free(session->sslClient);
-        SSL_free(session->sslServer);
+        wolfSSL_free(session->sslClient);
+        wolfSSL_free(session->sslServer);
 
         FreePacketList(session->cliReassemblyList);
@@ -604,4 +694,14 @@
 #ifdef HAVE_EXTENDED_MASTER
         XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES);
+#endif
+#ifdef WOLFSSL_TLS13
+        if (session->cliKeyShare)
+            XFREE(session->cliKeyShare, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+#ifdef HAVE_MAX_FRAGMENT
+        if (session->tlsFragBuf) {
+            XFREE(session->tlsFragBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            session->tlsFragBuf = NULL;
+        }
 #endif
     }
@@ -622,11 +722,5 @@
     wc_LockMutex(&SessionMutex);
 
-    srv = ServerList;
-    while (srv) {
-        removeServer = srv;
-        srv = srv->next;
-        FreeSnifferServer(removeServer);
-    }
-
+    /* Free sessions (wolfSSL objects) first */
     for (i = 0; i < HASH_SIZE; i++) {
         session = SessionTable[i];
@@ -637,4 +731,14 @@
         }
     }
+    SessionCount = 0;
+
+    /* Then server (wolfSSL_CTX) */
+    srv = ServerList;
+    while (srv) {
+        removeServer = srv;
+        srv = srv->next;
+        FreeSnifferServer(removeServer);
+    }
+    ServerList = NULL;    
 
     wc_UnLockMutex(&SessionMutex);
@@ -656,5 +760,5 @@
     if (TraceFile) {
         TraceOn = 0;
-        fclose(TraceFile);
+        XFCLOSE(TraceFile);
         TraceFile = NULL;
     }
@@ -678,9 +782,8 @@
 #endif
 #ifndef NO_MD5
-    if (ret == 0) {
+    if (ret == 0)
         ret = wc_InitMd5(&hash->hashMd5);
-    }
-#endif
-#endif
+#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
     if (ret == 0)
@@ -694,5 +797,4 @@
     return ret;
 }
-
 
 static int HashUpdate(HsHashes* hash, const byte* input, int sz)
@@ -709,9 +811,8 @@
 #endif
 #ifndef NO_MD5
-    if (ret == 0) {
+    if (ret == 0)
         ret = wc_Md5Update(&hash->hashMd5, input, sz);
-    }
-#endif
-#endif
+#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
     if (ret == 0)
@@ -726,21 +827,19 @@
 }
 
-
 static int HashCopy(HS_Hashes* d, HsHashes* s)
 {
 #ifndef NO_OLD_TLS
 #ifndef NO_SHA
-        XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha));
+    XMEMCPY(&d->hashSha, &s->hashSha, sizeof(wc_Sha));
 #endif
 #ifndef NO_MD5
-        XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5));
-#endif
-#endif
-
+    XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(wc_Md5));
+#endif
+#endif /* !NO_OLD_TLS */
 #ifndef NO_SHA256
-        XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256));
+    XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(wc_Sha256));
 #endif
 #ifdef WOLFSSL_SHA384
-        XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384));
+    XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(wc_Sha384));
 #endif
 
@@ -766,7 +865,7 @@
 
 /* Initialize FIN Capture */
-static void InitFinCapture(FinCaputre* cap)
-{
-    XMEMSET(cap, 0, sizeof(FinCaputre));
+static void InitFinCapture(FinCapture* cap)
+{
+    XMEMSET(cap, 0, sizeof(FinCapture));
 }
 
@@ -777,5 +876,5 @@
     XMEMSET(session, 0, sizeof(SnifferSession));
     InitFlags(&session->flags);
-    InitFinCapture(&session->finCaputre);
+    InitFinCapture(&session->finCapture);
 }
 
@@ -900,7 +999,7 @@
         char myBuffer[MAX_ERROR_LEN];
         GetError(idx, myBuffer);
-        fprintf(TraceFile, "\t%s\n", myBuffer);
+        XFPRINTF(TraceFile, "\t%s\n", myBuffer);
 #ifdef DEBUG_SNIFFER
-        fprintf(stderr,    "\t%s\n", myBuffer);
+        XFPRINTF(stderr,    "\t%s\n", myBuffer);
 #endif
     }
@@ -912,6 +1011,6 @@
 {
     if (TraceOn) {
-        time_t ticks = time(NULL);
-        fprintf(TraceFile, "\n%s", ctime(&ticks));
+        time_t ticks = XTIME(NULL);
+        XFPRINTF(TraceFile, "\n%s", XCTIME(&ticks));
     }
 }
@@ -922,6 +1021,6 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n");
-        fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port,
+        XFPRINTF(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        XFPRINTF(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", srv, port,
                                                                     keyFile);
     }
@@ -936,7 +1035,10 @@
 {
     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);
+        XFPRINTF(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        XFPRINTF(TraceFile, "\tname: %s, server: %s, port: %d, keyFile: %s\n",
+		name ? name : "",
+		srv ? srv : "",
+		port,
+		keyFile ? keyFile : "");
     }
 }
@@ -950,5 +1052,5 @@
     if (TraceOn) {
         static word32 packetNumber = 0;
-        fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n",
+        XFPRINTF(TraceFile, "\tGot a Packet to decode, packet %u\n",
                 ++packetNumber);
     }
@@ -959,5 +1061,5 @@
 static const char* IpToS(int version, void* src, char* dst)
 {
-    return inet_ntop(version, src, dst, TRACE_MSG_SZ);
+    return XINET_NTOP(version, src, dst, TRACE_MSG_SZ);
 }
 
@@ -969,5 +1071,5 @@
         char src[TRACE_MSG_SZ];
         char dst[TRACE_MSG_SZ];
-        fprintf(TraceFile, "\tdst:%s src:%s\n",
+        XFPRINTF(TraceFile, "\tdst:%s src:%s\n",
                 IpToS(AF_INET, &iphdr->dst, dst),
                 IpToS(AF_INET, &iphdr->src, src));
@@ -982,5 +1084,5 @@
         char src[TRACE_MSG_SZ];
         char dst[TRACE_MSG_SZ];
-        fprintf(TraceFile, "\tdst: %s src: %s\n",
+        XFPRINTF(TraceFile, "\tdst: %s src: %s\n",
                 IpToS(AF_INET6, iphdr->dst, dst),
                 IpToS(AF_INET6, iphdr->src, src));
@@ -993,6 +1095,6 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort),
-                ntohs(tcphdr->srcPort));
+        XFPRINTF(TraceFile, "\tdstPort:%u srcPort:%u\n", XNTOHS(tcphdr->dstPort),
+                XNTOHS(tcphdr->srcPort));
     }
 }
@@ -1003,5 +1105,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len);
+        XFPRINTF(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len);
     }
 }
@@ -1012,5 +1114,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tAck:%u Expected:%u\n", ack, expected);
+        XFPRINTF(TraceFile, "\tAck:%u Expected:%u\n", ack, expected);
     }
 }
@@ -1021,5 +1123,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n",
+        XFPRINTF(TraceFile, "\tExpected sequence:%u, received sequence:%u\n",
                 expected, got);
     }
@@ -1031,5 +1133,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq);
+        XFPRINTF(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq);
     }
 }
@@ -1040,5 +1142,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq);
+        XFPRINTF(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq);
     }
 }
@@ -1049,5 +1151,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n",
+        XFPRINTF(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n",
                 finSeq, relSeq);
     }
@@ -1059,5 +1161,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n",
+        XFPRINTF(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n",
                 finSeq, relSeq);
     }
@@ -1069,5 +1171,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes);
+        XFPRINTF(TraceFile, "\t%d bytes of SSL App data processed\n", bytes);
     }
 }
@@ -1078,5 +1180,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile,
+        XFPRINTF(TraceFile,
                 "\t%d bytes added to %d existing bytes in User Buffer\n",
                 newBytes, existingBytes);
@@ -1089,5 +1191,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tFound a stale session\n");
+        XFPRINTF(TraceFile, "\tFound a stale session\n");
     }
 }
@@ -1098,5 +1200,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tTrying to find Stale Sessions\n");
+        XFPRINTF(TraceFile, "\tTrying to find Stale Sessions\n");
     }
 }
@@ -1107,5 +1209,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tRemoved it\n");
+        XFPRINTF(TraceFile, "\tRemoved it\n");
     }
 }
@@ -1117,5 +1219,5 @@
     if (TraceOn) {
         if (sslInfo != NULL && sslInfo->isValid) {
-            fprintf(TraceFile,
+            XFPRINTF(TraceFile,
                     "\tver:(%u %u) suiteId:(%02x %02x) suiteName:(%s) "
                     #ifdef HAVE_SNI
@@ -1143,5 +1245,5 @@
 {
     if (TraceOn) {
-        fprintf(TraceFile, "\tAdding %d to %s\n", add, name);
+        XFPRINTF(TraceFile, "\tAdding %d to %s\n", add, name);
     }
 }
@@ -1310,5 +1412,5 @@
 {
     SnifferSession* session;
-    time_t          currTime = time(NULL);
+    time_t          currTime = XTIME(NULL);
     word32          row = SessionHash(ipInfo, tcpInfo);
 
@@ -1358,5 +1460,5 @@
 
 static int LoadKeyFile(byte** keyBuf, word32* keyBufSz,
-                const char* keyFile, int typeKey,
+                const char* keyFile, int keySz, int typeKey,
                 const char* password)
 {
@@ -1364,5 +1466,5 @@
     long fileSz = 0;
     XFILE file;
-    int ret;
+    int ret = -1;
 
     if (keyBuf == NULL || keyBufSz == NULL || keyFile == NULL) {
@@ -1370,29 +1472,41 @@
     }
 
-    file = XFOPEN(keyFile, "rb");
-    if (file == XBADFILE) return -1;
-    if(XFSEEK(file, 0, XSEEK_END) != 0) {
+    if (keySz == 0) {
+        /* load from file */
+        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);
-        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 (ret != fileSz) {
+            XFREE(loadBuf, NULL, DYNAMIC_TYPE_FILE);
+            return -1;
+        }
+    }
+    else {
+        /* use buffer directly */
+        loadBuf = (byte*)XMALLOC(keySz, NULL, DYNAMIC_TYPE_FILE);
+        if (loadBuf == NULL) {
+            return -1;
+        }
+        fileSz = keySz;
+        XMEMCPY(loadBuf, keyFile, fileSz);        
     }
 
@@ -1450,5 +1564,5 @@
     }
     InitSnifferServer(sniffer);
-    sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method());
+    sniffer->ctx = wolfSSL_CTX_new(SSLv23_client_method());
     if (!sniffer->ctx) {
         SetError(MEMORY_STR, error, NULL, 0);
@@ -1469,5 +1583,6 @@
 
 static int SetNamedPrivateKey(const char* name, const char* address, int port,
-            const char* keyFile, int typeKey, const char* password, char* error)
+    const char* keyFile, int keySz, int typeKey, const char* password,
+    char* error, int isEphemeralKey)
 {
     SnifferServer* sniffer;
@@ -1498,7 +1613,7 @@
         XSTRNCPY(namedKey->name, name, namedKey->nameSz);
         namedKey->name[MAX_SERVER_NAME-1] = '\0';
-
+        namedKey->isEphemeralKey = isEphemeralKey;
         ret = LoadKeyFile(&namedKey->key, &namedKey->keySz,
-                          keyFile, type, password);
+                          keyFile, keySz, type, password);
         if (ret < 0) {
             SetError(KEY_FILE_STR, error, NULL, 0);
@@ -1510,7 +1625,12 @@
 
     serverIp.version = IPV4;
-    serverIp.ip4 = inet_addr(address);
-    if (serverIp.ip4 == INADDR_NONE) {
-        if (inet_pton(AF_INET6, address, serverIp.ip6) == 1) {
+    serverIp.ip4 = XINET_ADDR(address);
+    if (serverIp.ip4 == XINADDR_NONE) {
+    #ifdef FUSION_RTOS
+        if (XINET_PTON(AF_INET6, address, serverIp.ip6,
+                       sizeof(serverIp.ip4)) == 1) {
+    #else
+        if (XINET_PTON(AF_INET6, address, serverIp.ip6) == 1) {
+    #endif
             serverIp.version = IPV6;
         }
@@ -1540,5 +1660,5 @@
         sniffer->port = port;
 
-        sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method());
+        sniffer->ctx = wolfSSL_CTX_new(SSLv23_client_method());
         if (!sniffer->ctx) {
             SetError(MEMORY_STR, error, NULL, 0);
@@ -1554,10 +1674,30 @@
         if (password) {
     #ifdef WOLFSSL_ENCRYPTED_KEYS
-            SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
-            SSL_CTX_set_default_passwd_cb_userdata(
+            wolfSSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
+            wolfSSL_CTX_set_default_passwd_cb_userdata(
                                                  sniffer->ctx, (void*)password);
     #endif
         }
-        ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
+
+    #ifdef WOLFSSL_STATIC_EPHEMERAL
+        if (isEphemeralKey) {
+            /* auto detect key type with WC_PK_TYPE_NONE */
+            /* keySz == 0 mean load file */
+            ret = wolfSSL_CTX_set_ephemeral_key(sniffer->ctx, WC_PK_TYPE_NONE, 
+                keyFile, 0, type);
+            if (ret == 0)
+                ret = WOLFSSL_SUCCESS;
+        }
+        else
+    #endif
+        {
+            if (keySz == 0) {
+                ret = wolfSSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
+            }
+            else {
+                ret = wolfSSL_CTX_use_PrivateKey_buffer(sniffer->ctx,
+                                            (const byte*)keyFile, keySz, type);
+            }
+        }
         if (ret != WOLFSSL_SUCCESS) {
             SetError(KEY_FILE_STR, error, NULL, 0);
@@ -1589,5 +1729,4 @@
 
 #ifdef HAVE_SNI
-
 /* Sets the private key for a specific name, server and port  */
 /* returns 0 on success, -1 on error */
@@ -1603,6 +1742,6 @@
 
     wc_LockMutex(&ServerListMutex);
-    ret = SetNamedPrivateKey(name, address, port, keyFile,
-                             typeKey, password, error);
+    ret = SetNamedPrivateKey(name, address, port, keyFile, 0,
+                             typeKey, password, error, 0);
     wc_UnLockMutex(&ServerListMutex);
 
@@ -1613,11 +1752,31 @@
 }
 
-#endif
-
+int ssl_SetNamedPrivateKeyBuffer(const char* name,
+                                 const char* address, int port,
+                                 const char* keyBuf, int keySz, int typeKey, 
+                                 const char* password, char* error)
+{
+    int ret;
+
+    TraceHeader();
+    TraceSetNamedServer(name, address, port, NULL);
+
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(name, address, port, keyBuf, keySz,
+                             typeKey, password, error, 0);
+    wc_UnLockMutex(&ServerListMutex);
+
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+
+    return ret;
+}
+#endif /* HAVE_SNI */
 
 /* 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 ssl_SetPrivateKey(const char* address, int port, 
+                      const char* keyFile, int typeKey, 
+                      const char* password, char* error)
 {
     int ret;
@@ -1627,6 +1786,6 @@
 
     wc_LockMutex(&ServerListMutex);
-    ret = SetNamedPrivateKey(NULL, address, port, keyFile,
-                             typeKey, password, error);
+    ret = SetNamedPrivateKey(NULL, address, port, keyFile, 0,
+                             typeKey, password, error, 0);
     wc_UnLockMutex(&ServerListMutex);
 
@@ -1637,4 +1796,113 @@
 }
 
+int ssl_SetPrivateKeyBuffer(const char* address, int port,
+                            const char* keyBuf, int keySz, int typeKey, 
+                            const char* password, char* error)
+{
+    int ret;
+
+    TraceHeader();
+    TraceSetServer(address, port, "from buffer");
+
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(NULL, address, port, keyBuf, keySz,
+                             typeKey, password, error, 0);
+    wc_UnLockMutex(&ServerListMutex);
+
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+
+    return ret;
+}
+
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+#ifdef HAVE_SNI
+/* Sets the ephemeral key for a specific name, server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetNamedEphemeralKey(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, 0,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+
+int ssl_SetNamedEphemeralKeyBuffer(const char* name,
+                                   const char* address, int port,
+                                   const char* keyBuf, int keySz, int typeKey, 
+                                   const char* password, char* error)
+{
+    int ret;
+    
+    TraceHeader();
+    TraceSetNamedServer(name, address, port, NULL);
+    
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(name, address, port, keyBuf, keySz,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+#endif /* HAVE_SNI */
+
+/* Sets the ephemeral key for a specific server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetEphemeralKey(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, 0,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+
+int ssl_SetEphemeralKeyBuffer(const char* address, int port, 
+                              const char* keyBuf, int keySz, int typeKey, 
+                              const char* password, char* error)
+{
+    int ret;
+    
+    TraceHeader();
+    TraceSetServer(address, port, "from buffer");
+    
+    wc_LockMutex(&ServerListMutex);
+    ret = SetNamedPrivateKey(NULL, address, port, keyBuf, keySz,
+                             typeKey, password, error, 1);
+    wc_UnLockMutex(&ServerListMutex);
+    
+    if (ret == 0)
+        Trace(NEW_SERVER_STR);
+    
+    return ret;
+}
+#endif /* WOLFSSL_STATIC_EPHEMERAL */
 
 /* Check IP Header for IPV6, TCP, and a registered server address */
@@ -1677,6 +1945,6 @@
 
     info->length = exthdrsz;
-    info->total = ntohs(iphdr->length) + info->length;
-        /* IPv6 doesn't include its own header size in the length like v4. */
+    info->total = XNTOHS(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));
@@ -1693,5 +1961,5 @@
 static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error)
 {
-    int    version = IP_V(iphdr);
+    int version = IP_V(iphdr);
 
     if (version == IPV6)
@@ -1719,5 +1987,5 @@
 
     info->length  = IP_HL(iphdr);
-    info->total   = ntohs(iphdr->length);
+    info->total   = XNTOHS(iphdr->length);
     info->src.version = IPV4;
     info->src.ip4 = iphdr->src;
@@ -1738,8 +2006,8 @@
     TraceTcp(tcphdr);
     Trace(TCP_CHECK_STR);
-    info->srcPort   = ntohs(tcphdr->srcPort);
-    info->dstPort   = ntohs(tcphdr->dstPort);
+    info->srcPort   = XNTOHS(tcphdr->srcPort);
+    info->dstPort   = XNTOHS(tcphdr->dstPort);
     info->length    = TCP_LEN(tcphdr);
-    info->sequence  = ntohl(tcphdr->sequence);
+    info->sequence  = XNTOHL(tcphdr->sequence);
     info->fin       = tcphdr->flags & TCP_FIN;
     info->rst       = tcphdr->flags & TCP_RST;
@@ -1747,5 +2015,5 @@
     info->ack       = tcphdr->flags & TCP_ACK;
     if (info->ack)
-        info->ackNumber = ntohl(tcphdr->ack);
+        info->ackNumber = XNTOHL(tcphdr->ack);
 
 #ifndef WOLFSSL_SNIFFER_WATCH
@@ -1802,5 +2070,5 @@
             }
             sslInfo->keySize = session->keySz;
-            #ifdef HAVE_SNI
+        #ifdef HAVE_SNI
             if (NULL != session->sni) {
                 XSTRNCPY((char*)sslInfo->serverNameIndication,
@@ -1809,5 +2077,5 @@
                          [sizeof(sslInfo->serverNameIndication) - 1] = '\0';
             }
-            #endif
+        #endif
             TraceSessionInfo(sslInfo);
         }
@@ -1826,40 +2094,79 @@
 }
 
-
-/* Process Client Key Exchange, RSA or static ECDH */
-static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
-                                    SnifferSession* session, char* error)
+#ifdef SHOW_SECRETS
+static void PrintSecret(const char* desc, const byte* buf, int sz)
+{
+    int i;
+    printf("%s: ", desc);
+    for (i = 0; i < sz; i++) {
+        printf("%02x", buf[i]);
+    }
+    printf("\n");
+}
+
+static void ShowTlsSecrets(SnifferSession* session)
+{
+    PrintSecret("server master secret", session->sslServer->arrays->masterSecret, SECRET_LEN);
+    PrintSecret("client master secret", session->sslClient->arrays->masterSecret, SECRET_LEN);
+    printf("server suite = %d\n", session->sslServer->options.cipherSuite);
+    printf("client suite = %d\n", session->sslClient->options.cipherSuite);
+}
+#endif /* SHOW_SECRETS */
+
+
+/* Process Keys */
+
+/* contains static ephemeral keys */
+typedef struct {
+#ifndef NO_DH
+    DerBuffer* dhKey;
+#endif
+#ifdef HAVE_ECC
+    DerBuffer* ecKey;
+#endif
+#if !defined(NO_RSA) && defined(WOLFSSL_STATIC_RSA)
+    DerBuffer* rsaKey;
+#endif
+} KeyBuffers_t;
+
+static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, 
+    char* error, KeyShareInfo* ksInfo, KeyBuffers_t* keys)
 {
     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;
-    }
-
-    {
+    DerBuffer* keyBuf;
+#ifdef HAVE_ECC
+    int useEccCurveId = ECC_CURVE_DEF;
+    if (ksInfo && ksInfo->curve_id != 0)
+        useEccCurveId = ksInfo->curve_id;
+#endif
+
+#ifndef NO_RSA
+    /* Static RSA */
+    if (ksInfo == NULL && keys->rsaKey) {
         RsaKey key;
         int length;
 
+        keyBuf = keys->rsaKey;
+
         ret = wc_InitRsaKey(&key, 0);
         if (ret == 0) {
-            ret = wc_RsaPrivateKeyDecode(
-                    session->sslServer->buffers.key->buffer,
-                    &idx, &key, session->sslServer->buffers.key->length);
+            ret = wc_RsaPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->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
-            }
+            #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);
+                if (keys->ecKey == NULL)
+                    keys->ecKey = session->sslServer->buffers.key; /* try ECC */
+            #endif
+            }
+        #ifdef HAVE_ECC
+            else {
+                useEccCurveId = -1; /* don't try loading ECC */
+            }
+        #endif
         }
 
@@ -1909,11 +2216,104 @@
         wc_FreeRsaKey(&key);
     }
-
-    if (tryEcc) {
+#endif /* !NO_RSA */
+
+#if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA)
+    /* Static DH Key */
+    if (ksInfo && ksInfo->dh_key_bits != 0 && keys->dhKey) {
+        DhKey dhKey;
+        const DhParams* params;
+        word32 privKeySz;
+        byte privKey[52]; /* max for TLS */
+        
+        keyBuf = keys->dhKey;
+
+        /* get DH params */
+        switch (ksInfo->named_group) {
+        #ifdef HAVE_FFDHE_2048
+            case WOLFSSL_FFDHE_2048:
+                params = wc_Dh_ffdhe2048_Get();
+                privKeySz = 29;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+            case WOLFSSL_FFDHE_3072:
+                params = wc_Dh_ffdhe3072_Get();
+                privKeySz = 34;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+            case WOLFSSL_FFDHE_4096:
+                params = wc_Dh_ffdhe4096_Get();
+                privKeySz = 39;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+            case WOLFSSL_FFDHE_6144:
+                params = wc_Dh_ffdhe6144_Get();
+                privKeySz = 46;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_8192
+            case WOLFSSL_FFDHE_8192:
+                params = wc_Dh_ffdhe8192_Get();
+                privKeySz = 52;
+                break;
+        #endif
+            default:
+                return BAD_FUNC_ARG;
+        }
+
+        ret = wc_InitDhKey(&dhKey);
+        if (ret == 0) {
+            ret = wc_DhSetKey(&dhKey,
+                (byte*)params->p, params->p_len,
+                (byte*)params->g, params->g_len);
+            if (ret == 0) {
+                ret = wc_DhKeyDecode(keyBuf->buffer, &idx, &dhKey, 
+                    keyBuf->length);
+            }
+            if (ret == 0) {
+                ret = wc_DhExportKeyPair(&dhKey, privKey, &privKeySz, NULL, 
+                    NULL);
+            }
+
+            /* Derive secret from private key and peer's public key */
+            do {
+            #ifdef WOLFSSL_ASYNC_CRYPT
+                ret = wc_AsyncWait(ret, &dhPriv.asyncDev,
+                        WC_ASYNC_FLAG_CALL_AGAIN);
+            #endif
+                if (ret >= 0) {
+                    ret = wc_DhAgree(&dhKey,
+                        session->sslServer->arrays->preMasterSecret,
+                        &session->sslServer->arrays->preMasterSz,
+                        privKey, privKeySz,
+                        input, *sslBytes);
+                }
+            } while (ret == WC_PENDING_E);
+
+            wc_FreeDhKey(&dhKey);
+        
+            /* left-padded with zeros up to the size of the prime */
+            if (params->p_len > session->sslServer->arrays->preMasterSz) {
+                word32 diff = params->p_len - session->sslServer->arrays->preMasterSz;
+                XMEMMOVE(session->sslServer->arrays->preMasterSecret + diff,
+                        session->sslServer->arrays->preMasterSecret, 
+                        session->sslServer->arrays->preMasterSz);
+                XMEMSET(session->sslServer->arrays->preMasterSecret, 0, diff);
+                session->sslServer->arrays->preMasterSz = params->p_len;
+            }
+        }
+    }
+#endif /* !NO_DH && WOLFSSL_DH_EXTRA */
+
 #ifdef HAVE_ECC
+    /* Static ECC Key */
+    if (useEccCurveId >= ECC_CURVE_DEF && keys->ecKey) {
         ecc_key key;
         ecc_key pubKey;
         int length, keyInit = 0, pubKeyInit = 0;
 
+        keyBuf = keys->ecKey;
         idx = 0;
         ret = wc_ecc_init(&key);
@@ -1922,9 +2322,16 @@
             ret = wc_ecc_init(&pubKey);
         }
+
+    #if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
+        (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
+        !defined(HAVE_SELFTEST)
+        if (ret == 0) {
+            ret = wc_ecc_set_rng(&key, session->sslServer->rng);
+        }
+    #endif
+
         if (ret == 0) {
             pubKeyInit = 1;
-            ret = wc_EccPrivateKeyDecode(
-                    session->sslServer->buffers.key->buffer,
-                    &idx, &key, session->sslServer->buffers.key->length);
+            ret = wc_EccPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length);
             if (ret != 0) {
                 SetError(ECC_DECODE_STR, error, session, FATAL_ERROR_STATE);
@@ -1936,17 +2343,21 @@
             /* The length should be 2 times the key size (x and y), plus 1
              * for the type byte. */
-            if (IsTLS(session->sslServer)) {
+            if (!IsAtLeastTLSv1_3(session->sslServer->version)) {
                 input += 1; /* Don't include the TLS length for the key. */
             }
 
-            if (length + 1 > *sslBytes) {
-                SetError(PARTIAL_INPUT_STR,
-                        error, session, FATAL_ERROR_STATE);
+            if (length > *sslBytes) {
+                SetError(PARTIAL_INPUT_STR, error, session, FATAL_ERROR_STATE);
                 ret = -1;
             }
+
+            /* if curve not provided in key share data, then use private key curve */
+            if (useEccCurveId == ECC_CURVE_DEF && key.dp) {
+                useEccCurveId = key.dp->id;
+            }
         }
 
         if (ret == 0) {
-            ret = wc_ecc_import_x963_ex(input, length, &pubKey, ECC_CURVE_DEF);
+            ret = wc_ecc_import_x963_ex(input, length, &pubKey, useEccCurveId);
             if (ret != 0) {
                 SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE);
@@ -1983,6 +2394,6 @@
         if (pubKeyInit)
             wc_ecc_free(&pubKey);
-#endif
-    }
+    }
+#endif /* HAVE_ECC */
 
     /* store for client side as well */
@@ -1993,13 +2404,9 @@
         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
+#ifdef SHOW_SECRETS
+    PrintSecret("pre master secret", 
+                session->sslServer->arrays->preMasterSecret, 
+                session->sslServer->arrays->preMasterSz);
+#endif
 
     if (SetCipherSpecs(session->sslServer) != 0) {
@@ -2013,9 +2420,29 @@
     }
 
-    ret  = MakeMasterSecret(session->sslServer);
-    ret += MakeMasterSecret(session->sslClient);
-    ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
-    ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
-
+#ifdef WOLFSSL_TLS13
+    /* TLS v1.3 derive handshake key */
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        ret  = DeriveEarlySecret(session->sslServer);
+        ret += DeriveEarlySecret(session->sslClient);
+        ret += DeriveHandshakeSecret(session->sslServer);
+        ret += DeriveHandshakeSecret(session->sslClient);
+        ret += DeriveTls13Keys(session->sslServer, handshake_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+        ret += DeriveTls13Keys(session->sslClient, handshake_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+    #ifdef WOLFSSL_EARLY_DATA
+        ret += SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY);
+        ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY);
+    #else
+        ret += SetKeysSide(session->sslServer, ENCRYPT_AND_DECRYPT_SIDE);
+        ret += SetKeysSide(session->sslClient, ENCRYPT_AND_DECRYPT_SIDE);
+    #endif
+    }
+    else
+#endif
+    {
+        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);
@@ -2024,19 +2451,8 @@
 
 #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);
-    }
+    #ifdef WOLFSSL_TLS13
+    if (!IsAtLeastTLSv1_3(session->sslServer->version))
+    #endif
+        ShowTlsSecrets(session);
 #endif
 
@@ -2046,4 +2462,155 @@
 }
 
+/* Process Client Key Exchange, static RSA  */
+static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
+                            SnifferSession* session, char* error)
+{
+    KeyBuffers_t keys;
+
+    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;
+    }
+
+    XMEMSET(&keys, 0, sizeof(keys));
+#ifdef WOLFSSL_STATIC_EPHEMERAL
+    #ifndef NO_DH
+    keys.dhKey = session->sslServer->staticKE.dhKey;
+    #endif
+    #ifdef HAVE_ECC
+    keys.ecKey = session->sslServer->staticKE.ecKey;
+    #endif
+#endif
+    keys.rsaKey = session->sslServer->buffers.key;
+    return SetupKeys(input, sslBytes, session, error, NULL, &keys);
+}
+
+#ifdef WOLFSSL_TLS13
+static int ProcessKeyShare(KeyShareInfo* info, const byte* input, int len,
+    word16 filter_group)
+{
+    int index = 0;
+    while (index < len) {
+        /* clear info (reset dh_key_bits and curve_id) */
+        XMEMSET(info, 0, sizeof(KeyShareInfo));
+
+        /* Named group and public key */
+        info->named_group = (word16)((input[index] << 8) | input[index+1]);
+        index += OPAQUE16_LEN;
+        info->key_len = 0;
+        info->key = NULL;
+        /* If key was provided... (a hello_retry_request will not send a key) */
+        if (index + 2 <= len) {
+            info->key_len = (word16)((input[index] << 8) | input[index+1]);
+            index += OPAQUE16_LEN;
+            if (info->key_len == 0 || info->key_len > len - index) {
+                return -1;
+            }
+            info->key = &input[index];
+            index += info->key_len;
+        }
+
+        switch (info->named_group) {
+    #ifndef NO_DH
+        #ifdef HAVE_FFDHE_2048
+            case WOLFSSL_FFDHE_2048:
+                info->dh_key_bits = 2048;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_3072
+            case WOLFSSL_FFDHE_3072:
+                info->dh_key_bits = 3072;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_4096
+            case WOLFSSL_FFDHE_4096:
+                info->dh_key_bits = 4096;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_6144
+            case WOLFSSL_FFDHE_6144:
+                info->dh_key_bits = 6144;
+                break;
+        #endif
+        #ifdef HAVE_FFDHE_8192
+            case WOLFSSL_FFDHE_8192:
+                info->dh_key_bits = 8192;
+                break;
+        #endif
+    #endif /* !NO_DH */
+    #ifdef HAVE_ECC
+        #if !defined(NO_ECC256)  || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP256R1:
+                info->curve_id = ECC_SECP256R1;
+                break;
+            #endif /* !NO_ECC_SECP */
+        #endif
+        #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP384R1:
+                info->curve_id = ECC_SECP384R1;
+                break;
+            #endif /* !NO_ECC_SECP */
+        #endif
+        #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+            #ifndef NO_ECC_SECP
+            case WOLFSSL_ECC_SECP521R1:
+                info->curve_id = ECC_SECP521R1;
+                break;
+            #endif /* !NO_ECC_SECP */
+        #endif
+    #endif /* HAVE_ECC */
+        #ifdef HAVE_CURVE25519
+            case WOLFSSL_ECC_X25519:
+                info->curve_id = ECC_X25519;
+                break;
+        #endif
+        #ifdef HAVE_X448
+            case WOLFSSL_ECC_X448:
+                info->curve_id = ECC_X448;
+                break;
+        #endif
+            default:
+                /* do not throw error here, keep iterating the client key share */
+                break;
+        }
+
+        if (filter_group == 0 || filter_group == info->named_group) {
+            return 0;
+        }
+    }
+    return NO_PEER_KEY; /* unsupported key type */
+}
+
+static int ProcessServerKeyShare(SnifferSession* session, const byte* input, int len,
+    char* error)
+{
+    int ret;
+
+    if (session->cliKeyShare == NULL || session->cliKeyShareSz == 0) {
+        /* session->cliKeyShareSz could not be provided yet if the client_hello 
+            did not send a key share to force a hello_retry_request */
+        return 0;
+    }
+
+    /* Get server_hello key share (and key) */
+    ret = ProcessKeyShare(&session->srvKs, input, len, 0);
+    if (ret == 0 && session->srvKs.key_len > 0) {
+        /* Get client_hello key share */
+        ret = ProcessKeyShare(&session->cliKs, session->cliKeyShare,
+            session->cliKeyShareSz, session->srvKs.named_group);
+    }
+    if (ret != 0) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    return ret;
+} 
+#endif /* WOLFSSL_TLS13 */
 
 /* Process Session Ticket */
@@ -2053,30 +2620,200 @@
     word16 len;
 
-    /* make sure can read through hint and len */
-    if (TICKET_HINT_LEN + LENGTH_SZ > *sslBytes) {
+#ifdef WOLFSSL_TLS13
+    WOLFSSL* ssl;
+
+    if (session->flags.side == WOLFSSL_SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+#endif
+
+    /* make sure can read through hint len */
+    if (TICKET_HINT_LEN > *sslBytes) {
         SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
         return -1;
     }
-
-    input     += TICKET_HINT_LEN;  /* skip over hint */
+    input     += TICKET_HINT_LEN; /* skip over hint len */
     *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) {
+#ifdef WOLFSSL_TLS13
+    /* TLS v1.3 has hint age and nonce */
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        /* make sure can read through hint age and nonce len */
+        if (TICKET_HINT_AGE_LEN + 1 > *sslBytes) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        input     += TICKET_HINT_AGE_LEN; /* skip over hint age */
+        *sslBytes -= TICKET_HINT_AGE_LEN;
+
+        /* ticket nonce */
+        len = input[0];
+        if (len > MAX_TICKET_NONCE_SZ) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        input += OPAQUE8_LEN;
+        *sslBytes -= OPAQUE8_LEN;
+    #ifdef HAVE_SESSION_TICKET
+        /* store nonce in server for DeriveResumptionPSK */
+        session->sslServer->session.ticketNonce.len = len;
+        if (len > 0)
+            XMEMCPY(&session->sslServer->session.ticketNonce.data, input, len);
+    #endif
+        input += len;
+        *sslBytes -= len;
+    }
+#endif
+
+    /* make sure can read through len */
+    if (OPAQUE16_LEN > *sslBytes) {
         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);
+    len = (word16)((input[0] << 8) | input[1]);
+    input     += OPAQUE16_LEN;
+    *sslBytes -= OPAQUE16_LEN;
+
+    /* make sure can read through ticket */
+    if (len > *sslBytes) {
+        SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+#ifdef WOLFSSL_TLS13
+    /* TLS v1.3 has hint age and nonce */
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+    #ifdef HAVE_SESSION_TICKET
+        if (SetTicket(ssl, input, len) != 0) {
+            SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        /* set haveSessionId to use the wolfSession cache */
+        ssl->options.haveSessionId = 1;
+
+        /* Use the wolf Session cache to retain resumption secret */
+        if (session->flags.cached == 0) {
+            WOLFSSL_SESSION* sess = GetSession(ssl, NULL, 0);
+            if (sess == NULL) {
+                AddSession(ssl); /* don't re add */
+            #ifdef WOLFSSL_SNIFFER_STATS
+                INC_STAT(SnifferStats.sslResumptionInserts);
+            #endif
+            }
+            session->flags.cached = 1;
+        }
+    #endif /* HAVE_SESSION_TICKET */
+    }
+    else
+#endif /* WOLFSSL_TLS13 */
+    {
+        /* capture last part of sessionID as macID (32 bytes) */
+        if (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;
 }
 
+static int DoResume(SnifferSession* session, char* error)
+{
+    int ret = 0;
+    WOLFSSL_SESSION* resume;
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        resume = GetSession(session->sslServer, 
+                            session->sslServer->session.masterSecret, 0);
+    }
+    else
+#endif
+    {
+        resume = GetSession(session->sslServer,
+                            session->sslServer->arrays->masterSecret, 0);
+    }
+    if (resume == NULL) {
+        /* a session id without resume is okay with hello_retry_request */
+    #ifdef WOLFSSL_SNIFFER_STATS
+        INC_STAT(SnifferStats.sslStandardConns);
+    #endif
+        return 0;
+    }
+
+    /* make sure client has master secret too */
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        XMEMCPY(session->sslClient->session.masterSecret,
+                session->sslServer->session.masterSecret, SECRET_LEN);
+    }
+    else
+#endif
+    {
+        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;
+    }
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+    #ifdef HAVE_SESSION_TICKET
+        /* Resumption PSK is resumption master secret. */
+        session->sslServer->arrays->psk_keySz = session->sslServer->specs.hash_size;
+        session->sslClient->arrays->psk_keySz = session->sslClient->specs.hash_size;
+        ret  = DeriveResumptionPSK(session->sslServer, session->sslServer->session.ticketNonce.data, 
+            session->sslServer->session.ticketNonce.len, session->sslServer->arrays->psk_key);
+        /* Copy resumption PSK to client */
+        XMEMCPY(session->sslClient->arrays->psk_key, 
+            session->sslServer->arrays->psk_key,
+            session->sslServer->arrays->psk_keySz);
+    #endif
+        /* handshake key setup below and traffic keys done in SetupKeys */
+    }
+    else
+#endif
+    {
+        if (IsTLS(session->sslServer)) {
+            ret =  DeriveTlsKeys(session->sslServer);
+            ret += DeriveTlsKeys(session->sslClient);
+        }
+        else {
+#ifndef NO_OLD_TLS
+            ret =  DeriveKeys(session->sslServer);
+            ret += DeriveKeys(session->sslClient);
+#endif
+        }
+        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;
+    }
+
+    return ret;
+}
 
 /* Process Server Hello */
@@ -2084,17 +2821,18 @@
                               SnifferSession* session, char* error)
 {
+    int             ret = 0;
     ProtocolVersion pv;
     byte            b, b0;
     int             toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
-    int             doResume     = 0;
+    int             doResume = 0;
+    const byte*     inputHello = input;
     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;
+    if (session->flags.clientHello == 0 || session->sslClient->arrays == NULL) {
+        SetError(MISSED_CLIENT_HELLO_STR, error, session, 0);
+        return 0; /* do not throw error, just ignore packet */
     }
 
@@ -2111,8 +2849,12 @@
     session->sslServer->version = pv;
     session->sslClient->version = pv;
+    if (pv.minor >= TLSv1_MINOR) {
+        session->sslServer->options.tls = 1;
+        session->sslClient->options.tls = 1;
+    }
 
     XMEMCPY(session->sslServer->arrays->serverRandom, input, RAN_LEN);
     XMEMCPY(session->sslClient->arrays->serverRandom, input, RAN_LEN);
-    input    += RAN_LEN;
+    input     += RAN_LEN;
     *sslBytes -= RAN_LEN;
 
@@ -2126,4 +2868,7 @@
     }
     if (b) {
+    #ifdef WOLFSSL_TLS13
+        XMEMCPY(session->sslServer->session.sessionID, input, ID_LEN);
+    #endif
         XMEMCPY(session->sslServer->arrays->sessionID, input, ID_LEN);
         session->sslServer->options.haveSessionId = 1;
@@ -2169,5 +2914,4 @@
     }
 
-#ifdef HAVE_EXTENDED_MASTER
     /* extensions */
     if ((initialBytes - *sslBytes) < msgSz) {
@@ -2190,13 +2934,12 @@
 
         while (len >= EXT_TYPE_SZ + LENGTH_SZ) {
-            byte   extType[EXT_TYPE_SZ];
+            word16 extType;
             word16 extLen;
 
-            extType[0] = input[0];
-            extType[1] = input[1];
+            extType    = (word16)((input[0] << 8) | input[1]);
             input     += EXT_TYPE_SZ;
             *sslBytes -= EXT_TYPE_SZ;
 
-            extLen = (word16)((input[0] << 8) | input[1]);
+            extLen     = (word16)((input[0] << 8) | input[1]);
             input     += LENGTH_SZ;
             *sslBytes -= LENGTH_SZ;
@@ -2209,6 +2952,62 @@
             }
 
-            if (extType[0] == 0x00 && extType[1] == EXT_MASTER_SECRET) {
+            switch (extType) {
+        #ifdef WOLFSSL_TLS13
+            case EXT_KEY_SHARE:
+                ret = ProcessServerKeyShare(session, input, extLen, error);
+                if (ret != 0) {
+                    SetError(SERVER_HELLO_INPUT_STR, error, session, 
+                        FATAL_ERROR_STATE);
+                    return -1;
+                }
+                break;
+        #endif
+        #ifdef HAVE_SESSION_TICKET
+            case EXT_PRE_SHARED_KEY:
+                /* indicates we want to use resumption */
+                session->sslServer->options.resuming = 1;
+                session->sslClient->options.resuming = 1;
+            #ifdef WOLFSSL_TLS13
+                /* default nonce to len = 1, data = 0 */
+                session->sslServer->session.ticketNonce.len = 1;
+                session->sslServer->session.ticketNonce.data[0] = 0;
+                session->sslClient->session.ticketNonce.len = 1;
+                session->sslClient->session.ticketNonce.data[0] = 0;
+            #endif
+                break;
+        #endif
+        #ifdef HAVE_MAX_FRAGMENT
+            case EXT_MAX_FRAGMENT_LENGTH:
+            {
+                word16 max_fragment = MAX_RECORD_SIZE;
+                switch (input[0]) {
+                    case WOLFSSL_MFL_2_8 : max_fragment =  256; break;
+                    case WOLFSSL_MFL_2_9 : max_fragment =  512; break;
+                    case WOLFSSL_MFL_2_10: max_fragment = 1024; break;
+                    case WOLFSSL_MFL_2_11: max_fragment = 2048; break;
+                    case WOLFSSL_MFL_2_12: max_fragment = 4096; break;
+                    case WOLFSSL_MFL_2_13: max_fragment = 8192; break;
+                    default: break;
+                }
+                session->sslServer->max_fragment = max_fragment;
+                session->sslClient->max_fragment = max_fragment;
+                break;
+            }
+        #endif
+            case EXT_SUPPORTED_VERSIONS:
+                session->sslServer->version.major = input[0];
+                session->sslServer->version.minor = input[1];
+                session->sslClient->version.major = input[0];
+                session->sslClient->version.minor = input[1];
+                if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+                    /* The server side handshake encryption is on for future packets */
+                    session->flags.serverCipherOn = 1;
+                }
+                break;
+            case EXT_MASTER_SECRET:
+            #ifdef HAVE_EXTENDED_MASTER
                 session->flags.expectEms = 1;
+            #endif
+                break;
             }
 
@@ -2219,4 +3018,5 @@
     }
 
+#ifdef HAVE_EXTENDED_MASTER
     if (!session->flags.expectEms) {
         XFREE(session->hash, NULL, DYNAMIC_TYPE_HASHES);
@@ -2227,11 +3027,13 @@
     if (session->sslServer->options.haveSessionId) {
         if (XMEMCMP(session->sslServer->arrays->sessionID,
-                    session->sslClient->arrays->sessionID, ID_LEN) == 0)
+                session->sslClient->arrays->sessionID, ID_LEN) == 0) {
             doResume = 1;
-    }
+        }    
+    }        
     else if (session->sslClient->options.haveSessionId == 0 &&
              session->sslServer->options.haveSessionId == 0 &&
-             session->ticketID)
+             session->ticketID) {
         doResume = 1;
+    }
 
     if (session->ticketID && doResume) {
@@ -2242,49 +3044,34 @@
     }
 
-    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);
-
+#ifdef WOLFSSL_TLS13
+    /* Is TLS v1.3 hello_retry_request? */
+    if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len == 0) {
+        Trace(GOT_HELLO_RETRY_REQ_STR);
+
+        /* do not compute keys yet */
+        session->flags.serverCipherOn = 0;
+
+        /* make sure the mac and digest size are set */
+        SetCipherSpecs(session->sslServer);
+        SetCipherSpecs(session->sslClient);
+
+        /* reset hashes */
+        RestartHandshakeHash(session->sslServer);
+        RestartHandshakeHash(session->sslClient);
+
+        doResume = 0;
+    }
+#endif
+
+    /* hash server_hello */
+    HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, 
+        initialBytes + HANDSHAKE_HEADER_SZ);
+    HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, 
+        initialBytes + HANDSHAKE_HEADER_SZ);
+
+    if (doResume) {
+        ret = DoResume(session, error);
         if (ret != 0) {
-            SetError(BAD_DERIVE_STR, error, session, FATAL_ERROR_STATE);
-            return -1;
+            return ret;
         }
     }
@@ -2294,15 +3081,38 @@
 #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
+    printf("cipher suite = 0x%02x\n", session->sslServer->options.cipherSuite);
+    PrintSecret("server random", session->sslServer->arrays->serverRandom, RAN_LEN);
+#endif
+
+#ifdef WOLFSSL_TLS13
+    /* Setup handshake keys */
+    if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len > 0) {
+        KeyBuffers_t keys;
+        XMEMSET(&keys, 0, sizeof(keys));
+        keys.rsaKey = session->sslServer->buffers.key;
+    #ifdef WOLFSSL_STATIC_EPHEMERAL
+        #ifndef NO_DH
+        keys.dhKey = session->sslServer->staticKE.dhKey;
+        #endif
+        #ifdef HAVE_ECC
+        keys.ecKey = session->sslServer->staticKE.ecKey;
+        #endif
+    #endif
+        ret = SetupKeys(session->cliKs.key, &session->cliKs.key_len, 
+            session, error, &session->cliKs, &keys);
+        if (ret != 0) {
+            SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return ret;
+        }
+
+        if (session->flags.side == WOLFSSL_SERVER_END)
+            session->flags.serverCipherOn = 1;
+        else
+            session->flags.clientCipherOn = 1;
+    }
+#endif
+
     return 0;
 }
@@ -2313,7 +3123,12 @@
                               SnifferSession* session, char* error)
 {
+    int ret = 0;
     byte   bLen;
     word16 len;
     int    toRead = VERSION_SZ + RAN_LEN + ENUM_LEN;
+    const byte* inputHello = input;
+    int inputHelloSz = *sslBytes;
+    WOLFSSL* ssl = session->sslServer;
+    int didHash = 0;
 
 #ifdef HAVE_SNI
@@ -2321,5 +3136,4 @@
         byte name[MAX_SERVER_NAME];
         word32 nameSz = sizeof(name);
-        int ret;
 
         ret = wolfSSL_SNI_GetFromBuffer(
@@ -2339,7 +3153,21 @@
                 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) {
+                #ifdef WOLFSSL_STATIC_EPHEMERAL
+                    if (namedKey->isEphemeralKey) {
+                        /* auto detect key type with WC_PK_TYPE_NONE */
+                        ret = wolfSSL_set_ephemeral_key(ssl, 
+                            WC_PK_TYPE_NONE, (const char*)namedKey->key, 
+                            namedKey->keySz, WOLFSSL_FILETYPE_ASN1);
+                        if (ret == 0)
+                            ret = WOLFSSL_SUCCESS;
+                    }
+                    else
+                #endif
+                    {
+                        ret = wolfSSL_use_PrivateKey_buffer(ssl,
+                            namedKey->key, namedKey->keySz, 
+                            WOLFSSL_FILETYPE_ASN1);
+                    }
+                    if (ret != WOLFSSL_SUCCESS) {
                         wc_UnLockMutex(&session->context->namedKeysMutex);
                         SetError(CLIENT_HELLO_LATE_KEY_STR, error, session,
@@ -2355,4 +3183,9 @@
             wc_UnLockMutex(&session->context->namedKeysMutex);
         }
+        /* SSLv3 does not support the SNI TLS Extension and may return SNI_UNSUPPORTED */
+        if (ret > 0 || ret == SNI_UNSUPPORTED) {
+            /* make sure WOLFSSL_SUCCESS is converted to zero error code */
+            ret = 0;
+        }
     }
 #endif
@@ -2385,15 +3218,13 @@
         }
         Trace(CLIENT_RESUME_TRY_STR);
+#ifdef WOLFSSL_TLS13
+        XMEMCPY(session->sslClient->session.sessionID, input, ID_LEN);
+#endif
         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");
-    }
+    PrintSecret("client random", ssl->arrays->clientRandom, RAN_LEN);
 #endif
 
@@ -2450,13 +3281,12 @@
 
     while (len >= EXT_TYPE_SZ + LENGTH_SZ) {
-        byte   extType[EXT_TYPE_SZ];
+        word16 extType;
         word16 extLen;
 
-        extType[0] = input[0];
-        extType[1] = input[1];
+        extType    = (word16)((input[0] << 8) | input[1]);
         input     += EXT_TYPE_SZ;
         *sslBytes -= EXT_TYPE_SZ;
 
-        extLen = (word16)((input[0] << 8) | input[1]);
+        extLen     = (word16)((input[0] << 8) | input[1]);
         input     += LENGTH_SZ;
         *sslBytes -= LENGTH_SZ;
@@ -2468,6 +3298,88 @@
         }
 
-        if (extType[0] == 0x00 && extType[1] == TICKET_EXT_ID) {
-
+        switch (extType) {
+    #ifdef WOLFSSL_TLS13
+        case EXT_KEY_SHARE:
+        {
+            word16 ksLen = (word16)((input[0] << 8) | input[1]);
+            if (ksLen + OPAQUE16_LEN > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            /* cache key share data till server_hello */
+            session->cliKeyShareSz = ksLen;
+            session->cliKeyShare = (byte*)XMALLOC(ksLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (session->cliKeyShare == NULL) {
+                SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+                break;
+            }
+            XMEMCPY(session->cliKeyShare, &input[2], ksLen);
+            break;
+        }
+        #ifdef HAVE_SESSION_TICKET
+        case EXT_PRE_SHARED_KEY:
+        {
+            word16 idsLen, idLen, bindersLen, idx = 0;
+            word32 ticketAge;
+            const byte *identity, *binders;
+
+            idsLen = (word16)((input[idx] << 8) | input[idx+1]);
+            if (idsLen + OPAQUE16_LEN + idx > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            idx += OPAQUE16_LEN;
+
+            /* PSK identity */
+            idLen = (word16)((input[idx] << 8) | input[idx+1]);
+            if (idLen + OPAQUE16_LEN + idx > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            idx += OPAQUE16_LEN;
+            identity = &input[idx];
+            idx += idLen;
+
+            /* Obfuscated Ticket Age 32-bits */
+            ticketAge = (word32)((input[idx] << 24) | (input[idx+1] << 16) | 
+                                 (input[idx+2] << 8) | input[idx+3]);
+            (void)ticketAge; /* not used */
+            idx += OPAQUE32_LEN;
+
+            /* binders - all binders */
+            bindersLen = (word16)((input[idx] << 8) | input[idx+1]);
+            if (bindersLen + OPAQUE16_LEN + idx > extLen) {
+                SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            idx += OPAQUE16_LEN;
+            binders = &input[idx];
+            bindersLen += OPAQUE16_LEN; /* includes 2 bytes for total len */
+            (void)binders; /* not used */
+
+            /* Hash data up to binders for deriving binders in PSK extension. */
+            HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, 
+                inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ);
+            HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, 
+                inputHelloSz - bindersLen + HANDSHAKE_HEADER_SZ);
+
+            /* call to decrypt session ticket */
+            if (DoClientTicket(ssl, identity, idLen) != 0) {
+                /* we aren't decrypting the resumption, since we know the master secret */
+                /* ignore errors */
+            }
+            ssl->options.resuming  = 1;
+
+            /* Hash the rest of the ClientHello. */
+            HashRaw(session->sslServer, inputHello + inputHelloSz - bindersLen, bindersLen);
+            HashRaw(session->sslClient, inputHello + inputHelloSz - bindersLen, bindersLen);
+            didHash = 1;
+            break;
+        }
+        #endif /* HAVE_SESSION_TICKET */
+    #endif /* WOLFSSL_TLS13 */
+        case EXT_SUPPORTED_VERSIONS:
+            break;
+        case EXT_TICKET_ID:
             /* make sure can read through ticket if there is a non blank one */
             if (extLen && extLen < ID_LEN) {
@@ -2476,7 +3388,6 @@
                 return -1;
             }
-
             if (extLen) {
-                if (session->ticketID == 0) {
+                if (session->ticketID == NULL) {
                     session->ticketID = (byte*)XMALLOC(ID_LEN,
                             NULL, DYNAMIC_TYPE_SNIFFER_TICKET_ID);
@@ -2489,4 +3400,5 @@
                 XMEMCPY(session->ticketID, input + extLen - ID_LEN, ID_LEN);
             }
+            break;
         }
 
@@ -2496,9 +3408,57 @@
     }
 
-    return 0;
+    if (!didHash) {
+        HashRaw(session->sslServer, inputHello - HANDSHAKE_HEADER_SZ, 
+            inputHelloSz + HANDSHAKE_HEADER_SZ);
+        HashRaw(session->sslClient, inputHello - HANDSHAKE_HEADER_SZ, 
+            inputHelloSz + HANDSHAKE_HEADER_SZ);
+    }
+
+    (void)ssl;
+
+    return ret;
 }
 
 
 #ifdef WOLFSSL_SNIFFER_WATCH
+
+static int KeyWatchCall(SnifferSession* session, const byte* data, int dataSz,
+    char* error)
+{
+    int ret;
+    Sha256 sha;
+    byte digest[SHA256_DIGEST_SIZE];
+
+    if (WatchCb == NULL) {
+        SetError(WATCH_CB_MISSING_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    ret = wc_InitSha256(&sha);
+    if (ret == 0)
+        ret = wc_Sha256Update(&sha, data, dataSz);
+    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),
+            data, dataSz, WatchCbCtx, error);
+    if (ret != 0) {
+#ifdef WOLFSSL_SNIFFER_STATS
+        INC_STAT(SnifferStats.sslKeysUnmatched);
+#endif
+        SetError(WATCH_FAIL_STR, error, session, FATAL_ERROR_STATE);
+        ret = -1;
+    }
+    else {
+#ifdef WOLFSSL_SNIFFER_STATS
+        INC_STAT(SnifferStats.sslKeyMatches);
+#endif
+    }
+    return ret;
+}
 
 /* Process Certificate */
@@ -2506,10 +3466,6 @@
         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,
@@ -2518,13 +3474,17 @@
         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;
     }
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(session->sslServer->version)) {
+        /* skip 1 byte (Request context len) */
+        input += OPAQUE8_LEN;
+        *sslBytes -= OPAQUE8_LEN;
+    }
+#endif
+
     ato24(input, &certChainSz);
     *sslBytes -= CERT_HEADER_SZ;
@@ -2535,5 +3495,4 @@
         return -1;
     }
-    certChain = input;
 
     ato24(input, &certSz);
@@ -2546,30 +3505,5 @@
     *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;
+    return KeyWatchCall(session, input, certSz, error);
 }
 
@@ -2581,5 +3515,5 @@
                            SnifferSession* session, char* error)
 {
-    SSL*   ssl;
+    WOLFSSL* ssl;
     word32 inOutIdx = 0;
     int    ret;
@@ -2590,6 +3524,18 @@
         ssl = session->sslClient;
 
-    ret = DoFinished(ssl, input, &inOutIdx, (word32) size, (word32) *sslBytes,
-                                                                         SNIFF);
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        ret = DoTls13Finished(ssl, input, &inOutIdx, (word32)size, 
+            (word32)*sslBytes, SNIFF);
+
+        ssl->options.handShakeState = HANDSHAKE_DONE;
+        ssl->options.handShakeDone  = 1;
+    }
+    else
+#endif
+    {
+        ret = DoFinished(ssl, input, &inOutIdx, (word32)size, 
+            (word32)*sslBytes, SNIFF);
+    }
     *sslBytes -= (int)inOutIdx;
 
@@ -2612,4 +3558,60 @@
     }
 
+#ifdef WOLFSSL_TLS13
+    /* Derive TLS v1.3 traffic keys */
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        if (!session->flags.gotFinished) {
+            /* When either side gets "finished" derive master secret and keys */
+            ret  = DeriveMasterSecret(session->sslServer);
+            ret += DeriveMasterSecret(session->sslClient);
+        #ifdef WOLFSSL_EARLY_DATA
+            ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data);
+            ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, ssl->earlyData == no_early_data);
+        #else
+            ret += DeriveTls13Keys(session->sslServer, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+            ret += DeriveTls13Keys(session->sslClient, traffic_key, ENCRYPT_AND_DECRYPT_SIDE, 1);
+        #endif
+
+            if (ret != 0) {
+                SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+
+            session->flags.gotFinished = 1;
+        #ifdef SHOW_SECRETS
+            ShowTlsSecrets(session);    
+        #endif
+        }
+
+        if (session->flags.side == WOLFSSL_SERVER_END) {
+            /* finished from client to server */
+            ret  = SetKeysSide(session->sslServer, DECRYPT_SIDE_ONLY);
+            ret += SetKeysSide(session->sslClient, ENCRYPT_SIDE_ONLY);
+
+        #ifdef HAVE_SESSION_TICKET
+            /* derive resumption secret for next session - on finished (from client) */
+            ret += DeriveResumptionSecret(session->sslClient, session->sslClient->session.masterSecret);
+
+            /* copy resumption secret to server */
+            XMEMCPY(session->sslServer->session.masterSecret,
+                session->sslClient->session.masterSecret, SECRET_LEN);
+            #ifdef SHOW_SECRETS
+            PrintSecret("resumption secret", session->sslClient->session.masterSecret, SECRET_LEN);
+            #endif
+        #endif
+        }
+        else {
+            /* finished from server to client */
+            ret  = SetKeysSide(session->sslServer, ENCRYPT_SIDE_ONLY);
+            ret += SetKeysSide(session->sslClient, DECRYPT_SIDE_ONLY);
+        }
+
+        if (ret != 0) {
+            SetError(BAD_FINISHED_MSG, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+#endif
+
     /* If receiving a finished message from one side, free the resources
      * from the other side's tracker. */
@@ -2625,10 +3627,30 @@
 /* Process HandShake input */
 static int DoHandShake(const byte* input, int* sslBytes,
-                       SnifferSession* session, char* error)
+                       SnifferSession* session, char* error, word16 rhSize)
 {
     byte type;
     int  size;
     int  ret = 0;
-    int  startBytes;
+    WOLFSSL* ssl;
+    int startBytes;
+
+    (void)rhSize;
+
+#ifdef HAVE_MAX_FRAGMENT
+    if (session->tlsFragBuf) {
+        XMEMCPY(session->tlsFragBuf + session->tlsFragOffset, input, rhSize);
+        session->tlsFragOffset += rhSize;
+        *sslBytes -= rhSize;
+
+        if (session->tlsFragOffset < session->tlsFragSize) {
+            return 0;
+        }
+
+        /* reassembled complete fragment */
+        input = session->tlsFragBuf;
+        *sslBytes = session->tlsFragSize;
+        rhSize = session->tlsFragSize;
+    }
+#endif
 
     if (*sslBytes < HANDSHAKE_HEADER_SZ) {
@@ -2649,12 +3671,57 @@
     }
 
-    /* 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;
-    }
-
+    if (session->flags.side == WOLFSSL_SERVER_END)
+        ssl = session->sslServer;
+    else
+        ssl = session->sslClient;
+
+#ifdef HAVE_SECURE_RENEGOTIATION
+    if (!IsAtLeastTLSv1_3(ssl->version)) {
+        /* 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;
+        }
+    }
+#endif
+
+#ifdef HAVE_MAX_FRAGMENT
+    if (rhSize < size) {
+        /* partial fragment, let's reassemble */
+        if (session->tlsFragBuf == NULL) {
+            session->tlsFragOffset = 0;
+            session->tlsFragSize = size + HANDSHAKE_HEADER_SZ;
+            session->tlsFragBuf = (byte*)XMALLOC(session->tlsFragSize, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            if (session->tlsFragBuf == NULL) {
+                SetError(MEMORY_STR, error, NULL, 0);
+                return 0;
+            }
+
+            /* include the handshake header */
+            input -= HANDSHAKE_HEADER_SZ;
+            *sslBytes += HANDSHAKE_HEADER_SZ;
+        }
+
+        XMEMCPY(session->tlsFragBuf + session->tlsFragOffset, input, rhSize);
+        session->tlsFragOffset += rhSize;
+        *sslBytes -= rhSize;
+        return 0;
+    }
+#endif
+
+#ifdef WOLFSSL_TLS13
+    if (type != client_hello && type != server_hello) {
+        /* For resumption the hash is before / after client_hello PSK binder */
+        /* hash the packet including header */
+        /* TLS v1.3 requires the hash for the handshake and transfer key derivation */
+        /* we hash even for non TLS v1.3, since we don't know if its actually 
+            TLS v1.3 till later at EXT_SUPPORTED_VERSIONS in server_hello */
+        /* hello retry request restarts hash prior to server_hello hash calc */
+        HashRaw(session->sslServer, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ);
+        HashRaw(session->sslClient, input - HANDSHAKE_HEADER_SZ, size + HANDSHAKE_HEADER_SZ);
+    }
+#endif
 #ifdef HAVE_EXTENDED_MASTER
     if (session->hash) {
@@ -2662,5 +3729,6 @@
             SetError(EXTENDED_MASTER_HASH_STR, error,
                      session, FATAL_ERROR_STATE);
-            return -1;
+            ret = -1;
+            goto exit;
         }
     }
@@ -2694,4 +3762,8 @@
             ret = -1;
             break;
+        case encrypted_extensions:
+            Trace(GOT_ENC_EXT_STR);
+            ssl->msgsReceived.got_encrypted_extensions = 1;
+            break;
         case certificate:
             Trace(GOT_CERT_STR);
@@ -2753,6 +3825,17 @@
         default:
             SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0);
-            return -1;
-    }
+            ret = -1;
+            break;
+    }
+
+#ifdef HAVE_EXTENDED_MASTER
+exit:
+#endif
+#ifdef HAVE_MAX_FRAGMENT
+    if (session->tlsFragBuf) {
+        XFREE(session->tlsFragBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        session->tlsFragBuf = NULL;
+    }
+#endif
 
     *sslBytes = startBytes - size;  /* actual bytes of full process */
@@ -2763,5 +3846,5 @@
 
 /* Decrypt input into plain output, 0 on success */
-static int Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz)
+static int Decrypt(WOLFSSL* ssl, byte* output, const byte* input, word32 sz)
 {
     int ret = 0;
@@ -2814,16 +3897,25 @@
         #endif
 
-        #ifdef HAVE_AESGCM
+        #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
         case wolfssl_aes_gcm:
-            if (sz >= (word32)(AESGCM_EXP_IV_SZ + ssl->specs.aead_mac_size))
-            {
-                /* scratch buffer, sniffer ignores auth tag*/
+        case wolfssl_aes_ccm: /* GCM AEAD macros use same size as CCM */
+            if (sz >= (word32)(AESGCM_EXP_IV_SZ + ssl->specs.aead_mac_size)) {
+                /* scratch buffer, sniffer ignores auth tag */
+                wc_AesAuthEncryptFunc aes_auth_fn;
                 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,
+                /* use encrypt because we don't care about authtag */
+            #if defined(BUILD_AESGCM) && defined(HAVE_AESCCM)
+                aes_auth_fn = (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm)
+                                ? wc_AesGcmEncrypt : wc_AesCcmEncrypt;
+            #elif defined(BUILD_AESGCM)
+                aes_auth_fn = wc_AesGcmEncrypt;
+            #else
+                aes_auth_fn = wc_AesCcmEncrypt;
+            #endif
+                if (aes_auth_fn(ssl->decrypt.aes,
                             output,
                             input + AESGCM_EXP_IV_SZ,
@@ -2842,5 +3934,5 @@
             }
             break;
-         #endif
+        #endif
 
         #ifdef HAVE_NULL_CIPHER
@@ -2861,10 +3953,19 @@
 
 /* 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)
+static const byte* DecryptMessage(WOLFSSL* ssl, const byte* input, word32 sz,
+                byte* output, int* error, int* advance, RecordLayerHeader* rh)
 {
     int ivExtra = 0;
-
-    int ret = Decrypt(ssl, output, input, sz);
+    int ret;
+    
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        ret = DecryptTls13(ssl, output, input, sz, (byte*)rh, RECORD_HEADER_SZ);
+    }
+    else
+#endif
+    {
+        ret = Decrypt(ssl, output, input, sz);
+    }
     if (ret != 0) {
         *error = ret;
@@ -2873,5 +3974,5 @@
     ssl->keys.encryptSz = sz;
     if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) {
-        output += ssl->specs.block_size;     /* go past TLSv1.1 IV */
+        output += ssl->specs.block_size; /* go past TLSv1.1 IV */
         ivExtra = ssl->specs.block_size;
         *advance = ssl->specs.block_size;
@@ -2887,4 +3988,19 @@
     if (ssl->specs.cipher_type == block)
         ssl->keys.padSz += *(output + sz - ivExtra - 1) + 1;
+
+#ifdef WOLFSSL_TLS13
+    if (IsAtLeastTLSv1_3(ssl->version)) {
+        word16 i = (word16)(sz - ssl->keys.padSz);
+        /* Remove padding from end of plain text. */
+        for (--i; i > 0; i--) {
+            if (output[i] != 0)
+                break;
+        }
+        /* Get the real content type from the end of the data. */
+        rh->type = output[i];
+        ssl->keys.padSz = sz - i;
+    }
+#endif
+    (void)rh;
 
     return output;
@@ -2943,5 +4059,5 @@
         while (session) {
             SnifferSession* next = session->next;
-            if (time(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) {
+            if (XTIME(NULL) >= session->lastUsed + WOLFSSL_SNIFFER_TIMEOUT) {
                 TraceStaleSession();
                 RemoveSession(session, NULL, NULL, i);
@@ -2992,5 +4108,5 @@
     session->cliSeqStart = tcpInfo->sequence;
     session->cliExpected = 1;  /* relative */
-    session->lastUsed= time(NULL);
+    session->lastUsed= XTIME(NULL);
     session->keySz = 0;
 #ifdef HAVE_SNI
@@ -3005,5 +4121,5 @@
     }
 
-    session->sslServer = SSL_new(session->context->ctx);
+    session->sslServer = wolfSSL_new(session->context->ctx);
     if (session->sslServer == NULL) {
         SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
@@ -3011,7 +4127,7 @@
         return 0;
     }
-    session->sslClient = SSL_new(session->context->ctx);
+    session->sslClient = wolfSSL_new(session->context->ctx);
     if (session->sslClient == NULL) {
-        SSL_free(session->sslServer);
+        wolfSSL_free(session->sslServer);
         session->sslServer = 0;
 
@@ -3152,4 +4268,7 @@
                   int length, const byte** sslFrame, int* sslBytes, char* error)
 {
+    IpHdr* iphdr = (IpHdr*)packet;
+    int version;
+
     TraceHeader();
     TracePacket();
@@ -3160,4 +4279,15 @@
         return -1;
     }
+
+    version = IP_V(iphdr);
+    if (version != IPV6 && version != IPV4) {
+        /* Is this VLAN IEEE 802.1Q Frame? TPID = 0x8100 */
+        if (packet[2] == 0x81 && packet[3] == 0x00) {
+            /* trim VLAN header and try again */
+            packet += 8;
+            length -= 8;
+        }
+    }
+
     if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0)
         return -1;
@@ -3177,4 +4307,5 @@
         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. */
@@ -3372,10 +4503,10 @@
 {
     if (session->flags.side == WOLFSSL_SERVER_END) {
-        if (session->finCaputre.cliCounted == 0)
-            session->finCaputre.cliFinSeq = sequence;
+        if (session->finCapture.cliCounted == 0)
+            session->finCapture.cliFinSeq = sequence;
     }
     else {
-        if (session->finCaputre.srvCounted == 0)
-            session->finCaputre.srvFinSeq = sequence;
+        if (session->finCapture.srvCounted == 0)
+            session->finCapture.srvFinSeq = sequence;
     }
     return 1;
@@ -3513,5 +4644,5 @@
                                     &session->cliReassemblyMemory :
                                     &session->srvReassemblyMemory;
-    SSL*                 ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
+    WOLFSSL*             ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
                                     session->sslServer :
                                     session->sslClient;
@@ -3589,4 +4720,6 @@
     word32*   expected = (session->flags.side == WOLFSSL_SERVER_END) ?
                                 &session->srvExpected : &session->cliExpected;
+    word32    seqStart = (session->flags.side == WOLFSSL_SERVER_END) ?
+                                session->srvSeqStart : session->cliSeqStart;
     PacketBuffer* list = (session->flags.side == WOLFSSL_SERVER_END) ?
                                 session->srvReassemblyList :
@@ -3596,14 +4729,14 @@
                                 &session->flags.cliSkipPartial;
 
+    if (tcpInfo->ackNumber < seqStart) {
+        return -1; /* do not fix sequence - could be ack on unseen seq */
+    }
     *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;
-    }
+    else
+        *expected = tcpInfo->ackNumber - seqStart;
+
 
     return 1;
@@ -3646,6 +4779,6 @@
                         &session->flags.srvAckFault;
 
-    /* init SEQ from server to client */
-    if (tcpInfo->syn && tcpInfo->ack) {
+    /* init SEQ from server to client - if not ack fault */
+    if (tcpInfo->syn && tcpInfo->ack && !*ackFault) {
         session->srvSeqStart = tcpInfo->sequence;
         session->srvExpected = 1;
@@ -3694,5 +4827,5 @@
 {
     word32 length;
-    SSL*  ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
+    WOLFSSL* ssl = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
                                   (*session)->sslServer : (*session)->sslClient;
     byte  skipPartial = ((*session)->flags.side == WOLFSSL_SERVER_END) ?
@@ -3758,5 +4891,5 @@
 
         Trace(CHAIN_INPUT_STR);
-        headerSz = (word32)*sslFrame - (word32)chain[0].iov_base;
+        headerSz = (word32)((const byte*)*sslFrame - (const byte*)chain[0].iov_base);
         remainder = *sslBytes;
 
@@ -3833,5 +4966,5 @@
                                   &session->cliExpected : &session->srvExpected;
     /* buffer is on receiving end */
-    word32*        length = (session->flags.side == WOLFSSL_SERVER_END) ?
+    word32*          length = (session->flags.side == WOLFSSL_SERVER_END) ?
                                &session->sslServer->buffers.inputBuffer.length :
                                &session->sslClient->buffers.inputBuffer.length;
@@ -3839,8 +4972,8 @@
                                &session->sslServer->buffers.inputBuffer.buffer :
                                &session->sslClient->buffers.inputBuffer.buffer;
-    word32*       bufferSize = (session->flags.side == WOLFSSL_SERVER_END) ?
+    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) ?
+    WOLFSSL*           ssl  = (session->flags.side == WOLFSSL_SERVER_END) ?
                             session->sslServer : session->sslClient;
     word32*     reassemblyMemory = (session->flags.side == WOLFSSL_SERVER_END) ?
@@ -3904,6 +5037,6 @@
     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;
+    WOLFSSL*          ssl = (session->flags.side == WOLFSSL_SERVER_END) ?
+                            session->sslServer : session->sslClient;
 doMessage:
     notEnough = 0;
@@ -3951,4 +5084,9 @@
                                                session->flags.clientCipherOn)) {
         int ivAdvance = 0;  /* TLSv1.1 advance amount */
+
+        /* change_cipher_spec is not encrypted */
+        if (rh.type == change_cipher_spec) {
+            goto doPart;
+        }
         if (ssl->decrypt.setup != 1) {
             SetError(DECRYPT_KEYS_NOT_SETUP, error, session, FATAL_ERROR_STATE);
@@ -3959,7 +5097,8 @@
             return -1;
         }
+
         sslFrame = DecryptMessage(ssl, sslFrame, rhSize,
                                   ssl->buffers.outputBuffer.buffer, &errCode,
-                                  &ivAdvance);
+                                  &ivAdvance, &rh);
         recordEnd = sslFrame - ivAdvance + rhSize;  /* sslFrame moved so
                                                        should recordEnd */
@@ -3992,6 +5131,6 @@
 
                 Trace(GOT_HANDSHAKE_STR);
-                ret = DoHandShake(sslFrame, &sslBytes, session, error);
-                if (ret != 0) {
+                ret = DoHandShake(sslFrame, &sslBytes, session, error, rhSize);
+                if (ret != 0 || sslBytes > startIdx) {
                     if (session->flags.fatalError == 0)
                         SetError(BAD_HANDSHAKE_STR, error, session,
@@ -4008,6 +5147,15 @@
             break;
         case change_cipher_spec:
-            if (session->flags.side == WOLFSSL_SERVER_END)
-                session->flags.serverCipherOn = 1;
+            if (session->flags.side == WOLFSSL_SERVER_END) {
+            #ifdef WOLFSSL_TLS13
+                if (IsAtLeastTLSv1_3(session->sslServer->version) && session->srvKs.key_len == 0) {
+                    session->flags.serverCipherOn = 0;
+                }
+                else
+            #endif
+                {
+                    session->flags.serverCipherOn = 1;
+                }
+            }
             else
                 session->flags.clientCipherOn = 1;
@@ -4146,19 +5294,19 @@
 {
     int ret = 0;
-    if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <=
+    if (session->finCapture.cliFinSeq && session->finCapture.cliFinSeq <=
                                          session->cliExpected) {
-        if (session->finCaputre.cliCounted == 0) {
+        if (session->finCapture.cliCounted == 0) {
             session->flags.finCount += 1;
-            session->finCaputre.cliCounted = 1;
-            TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected);
-        }
-    }
-
-    if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <=
+            session->finCapture.cliCounted = 1;
+            TraceClientFin(session->finCapture.cliFinSeq, session->cliExpected);
+        }
+    }
+
+    if (session->finCapture.srvFinSeq && session->finCapture.srvFinSeq <=
                                          session->srvExpected) {
-        if (session->finCaputre.srvCounted == 0) {
+        if (session->finCapture.srvCounted == 0) {
             session->flags.finCount += 1;
-            session->finCaputre.srvCounted = 1;
-            TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected);
+            session->finCapture.srvCounted = 1;
+            TraceServerFin(session->finCapture.srvFinSeq, session->srvExpected);
         }
     }
@@ -4581,5 +5729,5 @@
                                           WOLFSSL_FILETYPE_ASN1;
 
-    ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, keyType, password);
+    ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, 0, keyType, password);
     if (ret < 0) {
         SetError(KEY_FILE_STR, error, NULL, 0);
