Browse Source

First pass at TLS1.3 keylog file working

Brett Nicholas 8 months ago
parent
commit
15918d8ee6
5 changed files with 186 additions and 68 deletions
  1. 106 62
      src/sniffer.c
  2. 4 1
      src/tls.c
  3. 58 0
      src/tls13.c
  4. 4 5
      sslSniffer/README.md
  5. 14 0
      wolfssl/sniffer.h

+ 106 - 62
src/sniffer.c

@@ -662,13 +662,15 @@ static void UpdateMissedDataSessions(void)
 
 #if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
 static int addSecretNode(unsigned char* clientRandom,
+                         int type,
                          unsigned char* masterSecret,
                          char* error);
 static void hexToBin(const char* hex, unsigned char* bin, int binLength);
 static int parseKeyLogFile(const char* fileName, char* error);
-static unsigned char* findMasterSecret(unsigned char* clientRandom);
+static unsigned char* findSecret(unsigned char* clientRandom, int type);
 static void freeSecretList(void);
 static int snifferSecretCb(unsigned char* client_random,
+                           int type,
                            unsigned char* output_secret);
 static void setSnifferSecretCb(SnifferSession* session);
 static int addKeyLogSnifferServerHelper(const char* address,
@@ -7207,15 +7209,18 @@ int ssl_PollSniffer(WOLF_EVENT** events, int maxEvents, WOLF_EVENT_FLAG flags,
 
 #if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
 
-#define CLIENT_RANDOM_LABEL_LENGTH 13
-#define CLIENT_RANDOM_LENGTH 32
-#define MASTER_SECRET_LENGTH 48
-#define CLIENT_RANDOM_BITS ((CLIENT_RANDOM_LENGTH) * 8)
-
+/* Maximum length of the NSS Keylog prefix string */
+#define MAX_PREFIX_LENGTH (31)
+/* Maximum length (in bytes) required to store the binary representation of
+ * the "client random" value parsed from keylog file */
+#define CLIENT_RANDOM_LENGTH (32)
+/* Maximum length (in bytes) required to store the binary representation of the
+ * "secret" value parsed from keylog file */
+#define SECRET_LENGTH (48)
 
 typedef struct SecretNode {
     unsigned char clientRandom[CLIENT_RANDOM_LENGTH];
-    unsigned char masterSecret[MASTER_SECRET_LENGTH];
+    unsigned char secrets[SNIFFER_SECRET_NUM_SECRET_TYPES][SECRET_LENGTH];
     struct SecretNode* next;
 } SecretNode;
 
@@ -7233,7 +7238,6 @@ secretHashTable[WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE] = {NULL};
 static WOLFSSL_GLOBAL wolfSSL_Mutex secretListMutex;
 #endif
 
-
 static unsigned int secretHashFunction(unsigned char* clientRandom);
 
 #ifdef HAVE_C___ATOMIC
@@ -7253,9 +7257,10 @@ static unsigned int secretHashFunction(unsigned char* clientRandom)
 {
     int i = 0;
     unsigned int hash = 0;
+    const int CLIENT_RANDOM_NUM_BITS = CLIENT_RANDOM_LENGTH * 8;
 
     for (i = 0; i < CLIENT_RANDOM_LENGTH; i++) {
-        hash = (hash * CLIENT_RANDOM_BITS + clientRandom[i])
+        hash = (hash * CLIENT_RANDOM_NUM_BITS + clientRandom[i])
             % WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE;
     }
 
@@ -7263,62 +7268,67 @@ static unsigned int secretHashFunction(unsigned char* clientRandom)
 }
 
 
+/*
+ * Adds a new secret to the secret table, creating a new node based on the
+ * client random if necessary. If the client random is already present in the
+ * list, the requested secret will be updated.
+ */
 static int addSecretNode(unsigned char* clientRandom,
-                         unsigned char* masterSecret,
+                         int type,
+                         unsigned char* secret,
                          char* error)
 {
-    unsigned int index        = 0;
-    SecretNode* newSecretNode = NULL;
+    int index = 0;
+    int ret = 0;
+    SecretNode* node = NULL;
 
-    newSecretNode = (SecretNode*)XMALLOC(sizeof(SecretNode),
-                                         NULL,
-                                         DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
-    if (newSecretNode == NULL) {
-        SetError(MEMORY_STR, error, NULL, 0);
+    if (type >= SNIFFER_SECRET_NUM_SECRET_TYPES) {
         return WOLFSSL_SNIFFER_ERROR;
     }
 
-    XMEMCPY(newSecretNode->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH);
-    XMEMCPY(newSecretNode->masterSecret, masterSecret, MASTER_SECRET_LENGTH);
-
     LOCK_SECRET_LIST();
 
     index = secretHashFunction(clientRandom);
-    newSecretNode->next = NULL;
+    node = secretHashTable[index];
 
-    if (secretHashTable[index] == NULL) {
-        secretHashTable[index] = newSecretNode;
-    }
-    else {
-        SecretNode* current = secretHashTable[index];
-        while (current != NULL) {
-            if (memcmp(current->clientRandom,
-                       clientRandom,
-                       CLIENT_RANDOM_LENGTH) == 0) {
-                /* No need for a new node, since it already exists */
-                fprintf(stderr, "Found duplicate client random value in "
-                                "keylog file. Rejecting.\n");
-                XFREE(newSecretNode, NULL, DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
-                break;
-            }
-            if (current->next == NULL) {
-                current->next = newSecretNode;
-                break;
-            }
-            current = current->next;
+    while(node) {
+        /* Node already exists, so just add the requested secret */
+        if (XMEMCMP(node->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH)
+            == 0)
+        {
+            XMEMCPY(node->secrets[type], secret, SECRET_LENGTH);
+            ret = 0;
+            goto unlockReturn;
         }
+        node = node ->next;
     }
 
+    node = (SecretNode*)XMALLOC(sizeof(SecretNode),
+                                NULL,
+                                DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
+    if (node == NULL) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        ret = WOLFSSL_SNIFFER_ERROR;
+        goto unlockReturn;
+    }
+
+    XMEMCPY(node->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH);
+    XMEMCPY(node->secrets[type], secret, SECRET_LENGTH);
+    node->next = secretHashTable[index];
+    secretHashTable[index] = node;
+
+unlockReturn:
+
     UNLOCK_SECRET_LIST();
 
-    return 0;
+    return ret;
 }
 
 
 /*
  * Looks up a master secret for a given client random from the keylog file
  */
-static unsigned char* findMasterSecret(unsigned char* clientRandom)
+static unsigned char* findSecret(unsigned char* clientRandom, int type)
 {
     unsigned char* secret = NULL;
     SecretNode* node = NULL;
@@ -7332,7 +7342,7 @@ static unsigned char* findMasterSecret(unsigned char* clientRandom)
     while (node != NULL) {
         if (XMEMCMP(node->clientRandom,
                     clientRandom, CLIENT_RANDOM_LENGTH) == 0) {
-            secret = node->masterSecret;
+            secret = node->secrets[type];
             break;
         }
         node = node->next;
@@ -7348,23 +7358,25 @@ static void hexToBin(const char* hex, unsigned char* bin, int binLength)
 {
     int i = 0;
     for (i = 0; i < binLength; i++) {
-        sscanf(hex + 2 * i, "%02hhx", &bin[i]);
+        sscanf(hex + 2*i, "%02hhx", &bin[i]);
     }
 }
 
-
+/*
+ * Helper function to parse secrets from the keylog file into the secret table
+ */
 static int parseKeyLogFile(const char* fileName, char* error)
 {
-    const char CLIENT_RANDOM_LABEL_STR[] = "CLIENT_RANDOM";
     unsigned char clientRandom[CLIENT_RANDOM_LENGTH];
-    unsigned char masterSecret[MASTER_SECRET_LENGTH];
+    unsigned char secret[SECRET_LENGTH];
     FILE* file = NULL;
     int ret = 0;
+    int  type = 0;
     /* +1 for null terminator */
-    char clientRandomLabel[CLIENT_RANDOM_LABEL_LENGTH + 1] = {0};
+    char prefix[MAX_PREFIX_LENGTH + 1] = {0};
     /* 2 chars for Hexadecimal representation, plus null terminator */
     char clientRandomHex[2 * CLIENT_RANDOM_LENGTH + 1] = {0};
-    char masterSecretHex[2 * MASTER_SECRET_LENGTH + 1] = {0};
+    char secretHex[2 * SECRET_LENGTH + 1] = {0};
 
 
     file = fopen(fileName, "r");
@@ -7374,16 +7386,43 @@ static int parseKeyLogFile(const char* fileName, char* error)
         return WOLFSSL_SNIFFER_ERROR;
     }
 
-    while (fscanf(file, "%13s %64s %96s",
-                  clientRandomLabel, clientRandomHex, masterSecretHex) == 3) {
-        if (XSTRCMP(clientRandomLabel, CLIENT_RANDOM_LABEL_STR) == 0) {
-            hexToBin(clientRandomHex, clientRandom, CLIENT_RANDOM_LENGTH);
-            hexToBin(masterSecretHex, masterSecret, MASTER_SECRET_LENGTH);
-            ret = addSecretNode(clientRandom, masterSecret, error);
-            if (ret != 0) {
-                fclose(file);
-                return ret;
-            }
+    /* Format specifiers for each column should be:
+     * MAX_PREFIX_LENGTH, 2*CLIENT_RANDOM_LENGTH, and 2*SECRET_LENGTH */
+    while (fscanf(file, "%31s %64s %96s", prefix, clientRandomHex, secretHex)
+            == 3) {
+
+        if (XSTRCMP(prefix, "CLIENT_RANDOM") == 0) {
+            type = SNIFFER_SECRET_TLS12_MASTER_SECRET;
+        }
+#if defined(WOLFSSL_TLS13)
+        else if (XSTRCMP(prefix, "CLIENT_EARLY_TRAFFIC_SECRET") == 0) {
+            type = SNIFFER_SECRET_CLIENT_EARLY_TRAFFIC_SECRET;
+        }
+        else if (XSTRCMP(prefix, "CLIENT_HANDSHAKE_TRAFFIC_SECRET") == 0) {
+            type = SNIFFER_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET;
+        }
+        else if (XSTRCMP(prefix, "SERVER_HANDSHAKE_TRAFFIC_SECRET") == 0) {
+            type = SNIFFER_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET;
+        }
+        else if (XSTRCMP(prefix, "CLIENT_TRAFFIC_SECRET_0") == 0) {
+            type = SNIFFER_SECRET_CLIENT_TRAFFIC_SECRET;
+        }
+        else if (XSTRCMP(prefix, "SERVER_TRAFFIC_SECRET_0") == 0) {
+            type = SNIFFER_SECRET_SERVER_TRAFFIC_SECRET;
+        }
+#endif /* WOLFSSL_TLS13 */
+        else {
+            fprintf(stderr, "unrecognized prefix: %s\n", prefix);
+            continue;
+        }
+
+        hexToBin(clientRandomHex, clientRandom, CLIENT_RANDOM_LENGTH);
+        hexToBin(secretHex, secret, SECRET_LENGTH);
+        ret = addSecretNode(clientRandom, type, secret, error);
+
+        if (ret != 0) {
+            fclose(file);
+            return ret;
         }
     }
     fclose(file);
@@ -7418,6 +7457,7 @@ static void freeSecretList(void)
  * Looks up secret based on client random and copies it to output_secret
  */
 static int snifferSecretCb(unsigned char* client_random,
+                           int type,
                            unsigned char* output_secret)
 {
     unsigned char* secret = NULL;
@@ -7426,10 +7466,14 @@ static int snifferSecretCb(unsigned char* client_random,
         return WOLFSSL_SNIFFER_FATAL_ERROR;
     }
 
+    if (type >= SNIFFER_SECRET_NUM_SECRET_TYPES) {
+        return WOLFSSL_SNIFFER_FATAL_ERROR;
+    }
+
     /* get secret from secret table based on client random */
-    secret = findMasterSecret(client_random);
+    secret = findSecret(client_random, type);
     if (secret != NULL) {
-        XMEMCPY(output_secret, secret, MASTER_SECRET_LENGTH);
+        XMEMCPY(output_secret, secret, SECRET_LENGTH);
         return 0;
     }
 

+ 4 - 1
src/tls.c

@@ -520,7 +520,9 @@ int MakeTlsMasterSecret(WOLFSSL* ssl)
     /* If this is called from a sniffer session with keylog file support, obtain
      * the master secret from the callback */
     if (ssl->snifferSecretCb != NULL) {
-        ret = ssl->snifferSecretCb(ssl->arrays->clientRandom, ssl->arrays->masterSecret);
+        ret = ssl->snifferSecretCb(ssl->arrays->clientRandom,
+                                   SNIFFER_SECRET_TLS12_MASTER_SECRET,
+                                   ssl->arrays->masterSecret);
         if (ret != 0) {
             return ret;
         }
@@ -15227,4 +15229,5 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
 #endif /* NO_WOLFSSL_SERVER */
 
 #endif /* NO_TLS */
+
 #endif /* WOLFCRYPT_ONLY */

+ 58 - 0
src/tls13.c

@@ -414,6 +414,7 @@ int Tls13DeriveKey(WOLFSSL* ssl, byte* output, int outputLen,
     word32      protocolLen;
     int         digestAlg = 0;
 
+
     switch (hashAlgo) {
     #ifndef NO_SHA256
         case sha256_mac:
@@ -610,6 +611,17 @@ static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key, int side)
     if (ssl == NULL || ssl->arrays == NULL) {
         return BAD_FUNC_ARG;
     }
+
+#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
+    /* If this is called from a sniffer session with keylog file support,
+     * obtain the appropriate secret from the callback */
+    if (ssl->snifferSecretCb != NULL) {
+        return ssl->snifferSecretCb(ssl->arrays->clientRandom,
+                                    SNIFFER_SECRET_CLIENT_EARLY_TRAFFIC_SECRET,
+                                    key);
+    }
+#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
+
     ret = Tls13DeriveKey(ssl, key, -1, ssl->arrays->secret,
                     earlyTrafficLabel, EARLY_TRAFFIC_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1, side);
@@ -658,6 +670,16 @@ static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key)
         return BAD_FUNC_ARG;
     }
 
+#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
+    /* If this is called from a sniffer session with keylog file support,
+     * obtain the appropriate secret from the callback */
+    if (ssl->snifferSecretCb != NULL) {
+        return ssl->snifferSecretCb(ssl->arrays->clientRandom,
+                               SNIFFER_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET,
+                               key);
+    }
+#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
+
     ret = Tls13DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
                     clientHandshakeLabel, CLIENT_HANDSHAKE_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1, WOLFSSL_CLIENT_END);
@@ -703,9 +725,21 @@ static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key)
     if (ssl == NULL || ssl->arrays == NULL) {
         return BAD_FUNC_ARG;
     }
+
+#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
+    /* If this is called from a sniffer session with keylog file support,
+     * obtain the appropriate secret from the callback */
+    if (ssl->snifferSecretCb != NULL) {
+        return ssl->snifferSecretCb(ssl->arrays->clientRandom,
+                                SNIFFER_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET,
+                                key);
+    }
+#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
+
     ret = Tls13DeriveKey(ssl, key, -1, ssl->arrays->preMasterSecret,
                     serverHandshakeLabel, SERVER_HANDSHAKE_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1, WOLFSSL_SERVER_END);
+
 #ifdef HAVE_SECRET_CALLBACK
     if (ret == 0 && ssl->tls13SecretCb != NULL) {
         ret = ssl->tls13SecretCb(ssl, SERVER_HANDSHAKE_TRAFFIC_SECRET, key,
@@ -748,9 +782,21 @@ static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key)
     if (ssl == NULL || ssl->arrays == NULL) {
         return BAD_FUNC_ARG;
     }
+
+#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
+    /* If this is called from a sniffer session with keylog file support,
+     * obtain the appropriate secret from the callback */
+    if (ssl->snifferSecretCb != NULL) {
+        return ssl->snifferSecretCb(ssl->arrays->clientRandom,
+                                    SNIFFER_SECRET_CLIENT_TRAFFIC_SECRET,
+                                    key);
+    }
+#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
+
     ret = Tls13DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     clientAppLabel, CLIENT_APP_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1, WOLFSSL_CLIENT_END);
+
 #ifdef HAVE_SECRET_CALLBACK
     if (ret == 0 && ssl->tls13SecretCb != NULL) {
         ret = ssl->tls13SecretCb(ssl, CLIENT_TRAFFIC_SECRET, key,
@@ -793,9 +839,21 @@ static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key)
     if (ssl == NULL || ssl->arrays == NULL) {
         return BAD_FUNC_ARG;
     }
+
+#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_KEYLOGFILE)
+    /* If this is called from a sniffer session with keylog file support,
+     * obtain the appropriate secret from the callback */
+    if (ssl->snifferSecretCb != NULL) {
+        return ssl->snifferSecretCb(ssl->arrays->clientRandom,
+                                    SNIFFER_SECRET_SERVER_TRAFFIC_SECRET,
+                                    key);
+    }
+#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_KEYLOGFILE */
+
     ret = Tls13DeriveKey(ssl, key, -1, ssl->arrays->masterSecret,
                     serverAppLabel, SERVER_APP_LABEL_SZ,
                     ssl->specs.mac_algorithm, 1, WOLFSSL_SERVER_END);
+
 #ifdef HAVE_SECRET_CALLBACK
     if (ret == 0 && ssl->tls13SecretCb != NULL) {
         ret = ssl->tls13SecretCb(ssl, SERVER_TRAFFIC_SECRET, key,

+ 4 - 5
sslSniffer/README.md

@@ -39,8 +39,7 @@ The STARTTLS option allows the sniffer to receive and ignore plaintext before re
 
 `./configure --enable-sniffer CPPFLAGS=-DSTARTTLS_ALLOWED`
 
-The SSL KeyLog file option enables the sniffer to decrypt TLS traffic using the master secret obtained from a [NSS keylog file](https://web.archive.org/web/20220531072242/https://firefox-source-docs.mozilla.org/security/nss/legacy/key_log_format/index.html). This allows the sniffer to decrypt all TLS traffic, even for TLS connections using ephemeral cipher suites. Currently, sniffer keylog file support is limited to TLSv1.2 traffic. WolfSSL can be configured to export a keylog file using the `-DSHOW_SECRETS -DHAVE_SECRET_CALLBACK -DWOLFSSL_SSLKEYLOGFILE` macros, independently from the sniffer feature (NOTE: never do this in a production environment, as it is inherently insecure). To enable sniffer support for keylog files,
-use the following configure command line and build as before:
+The SSL Keylog file option enables the sniffer to decrypt TLS traffic using the master secret obtained from a [NSS keylog file](https://web.archive.org/web/20220531072242/https://firefox-source-docs.mozilla.org/security/nss/legacy/key_log_format/index.html). This allows the sniffer to decrypt all TLS traffic, even for TLS connections using ephemeral cipher suites. Keylog file sniffing is supported for TLS versions 1.2 and 1.3. WolfSSL can be configured to export a keylog file using the `--enable-keylog-export` configure option, independently from the sniffer feature (NOTE: never do this in a production environment, as it is inherently insecure). To enable sniffer support for keylog files, use the following configure command line and build as before:
 
 `./configure --enable-sniffer CPPFLAGS=-DWOLFSSL_SNIFFER_KEYLOGFILE`
 
@@ -326,7 +325,7 @@ int ssl_LoadSecretsFromKeyLogFile(const char* keylogfile, char* error)
 
 Loads secrets to decrypt TLS traffic from a keylog file. Only sniffer servers registered with `ssl_createKeyLogSnifferServer()` will be able to decrypt using these secrets
 
-This function requires that sniffer keylog file support (`WOLFSSL_SNIFFER_KEYLOGFILE`) is enabled in the build. Keylog file sniffing is only supported for TLS 1.2 traffic.
+This function requires that sniffer keylog file support (`WOLFSSL_SNIFFER_KEYLOGFILE`) is enabled in the build. Keylog file sniffing is supported for TLS versions 1.2 and 1.3.
 
 Return Values:
 * 0 on success
@@ -340,7 +339,7 @@ int ssl_CreateKeyLogSnifferServer(const char* address, int port, char* error)
 
 Creates a sniffer session based on `serverAddress` and `port`, and uses secrets obtained from a keylog file to decrypt traffic. Keylog files should be loaded using `ssl_LoadSecretsFromKeyLogFile()`.
 
-This function requires that sniffer keylog file support (`WOLFSSL_SNIFFER_KEYLOGFILE`) is enabled in the build. Keylog file sniffing is only supported for TLS 1.2 traffic.
+This function requires that sniffer keylog file support (`WOLFSSL_SNIFFER_KEYLOGFILE`) is enabled in the build. Keylog file sniffing is supported for TLS versions 1.2 and 1.3.
 
 Return Values:
 * 0 on success
@@ -680,7 +679,7 @@ Remember to always start the sniffing application before the server.  This is im
 
 ### Cipher Suite Limitations
 
-As a passive sniffer the wolfSSL sniffer will not be able to decode any SSL session that uses DHE (Ephemeral Diffie-Hellman) because it will not have access to the temporary key that the server generates.  You may need to disable DHE cipher suites on the server and/or client to prevent these cipher suites from being used.
+As a passive sniffer the wolfSSL sniffer will not be able to decode any SSL session that uses DHE (Ephemeral Diffie-Hellman) because it will not have access to the temporary key that the server generates. You may need to disable DHE cipher suites on the server and/or client to prevent these cipher suites from being used. The notable exception to this is if the sniffer session uses the keylog file feature, in which case any session using TLS 1.2 or 1.3 can be decoded.
 
 ### Thread Safety
 

+ 14 - 0
wolfssl/sniffer.h

@@ -315,6 +315,19 @@ SSL_SNIFFER_API int ssl_PollSniffer(WOLF_EVENT** events, int maxEvents,
 
 #ifdef WOLFSSL_SNIFFER_KEYLOGFILE
 
+typedef enum {
+    SNIFFER_SECRET_TLS12_MASTER_SECRET,
+#if defined(WOLFSSL_TLS13)
+    SNIFFER_SECRET_CLIENT_EARLY_TRAFFIC_SECRET,
+    SNIFFER_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET,
+    SNIFFER_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET,
+    SNIFFER_SECRET_CLIENT_TRAFFIC_SECRET,
+    SNIFFER_SECRET_SERVER_TRAFFIC_SECRET,
+#endif /* WOLFSSL_TLS13 */
+    SNIFFER_SECRET_NUM_SECRET_TYPES
+} SnifferSecretType;
+
+
 WOLFSSL_API
 SSL_SNIFFER_API int ssl_CreateKeyLogSnifferServer(const char* address,
                                                   int port,
@@ -325,6 +338,7 @@ SSL_SNIFFER_API int ssl_LoadSecretsFromKeyLogFile(const char* keylogfile,
                                                   char* error);
 
 typedef int (*SSLSnifferSecretCb)(unsigned char* client_random,
+                                  int type,
                                   unsigned char* output_secret);
 
 #endif /* WOLFSSL_SNIFFER_KEYLOGFILE */