Skip to content

Commit 15918d8

Browse files
committed
First pass at TLS1.3 keylog file working
1 parent 3033371 commit 15918d8

5 files changed

Lines changed: 186 additions & 68 deletions

File tree

src/sniffer.c

Lines changed: 106 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -662,13 +662,15 @@ static void UpdateMissedDataSessions(void)
662662

663663
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
664664
static int addSecretNode(unsigned char* clientRandom,
665+
int type,
665666
unsigned char* masterSecret,
666667
char* error);
667668
static void hexToBin(const char* hex, unsigned char* bin, int binLength);
668669
static int parseKeyLogFile(const char* fileName, char* error);
669-
static unsigned char* findMasterSecret(unsigned char* clientRandom);
670+
static unsigned char* findSecret(unsigned char* clientRandom, int type);
670671
static void freeSecretList(void);
671672
static int snifferSecretCb(unsigned char* client_random,
673+
int type,
672674
unsigned char* output_secret);
673675
static void setSnifferSecretCb(SnifferSession* session);
674676
static int addKeyLogSnifferServerHelper(const char* address,
@@ -7207,15 +7209,18 @@ int ssl_PollSniffer(WOLF_EVENT** events, int maxEvents, WOLF_EVENT_FLAG flags,
72077209

72087210
#if defined(WOLFSSL_SNIFFER_KEYLOGFILE)
72097211

7210-
#define CLIENT_RANDOM_LABEL_LENGTH 13
7211-
#define CLIENT_RANDOM_LENGTH 32
7212-
#define MASTER_SECRET_LENGTH 48
7213-
#define CLIENT_RANDOM_BITS ((CLIENT_RANDOM_LENGTH) * 8)
7214-
7212+
/* Maximum length of the NSS Keylog prefix string */
7213+
#define MAX_PREFIX_LENGTH (31)
7214+
/* Maximum length (in bytes) required to store the binary representation of
7215+
* the "client random" value parsed from keylog file */
7216+
#define CLIENT_RANDOM_LENGTH (32)
7217+
/* Maximum length (in bytes) required to store the binary representation of the
7218+
* "secret" value parsed from keylog file */
7219+
#define SECRET_LENGTH (48)
72157220

72167221
typedef struct SecretNode {
72177222
unsigned char clientRandom[CLIENT_RANDOM_LENGTH];
7218-
unsigned char masterSecret[MASTER_SECRET_LENGTH];
7223+
unsigned char secrets[SNIFFER_SECRET_NUM_SECRET_TYPES][SECRET_LENGTH];
72197224
struct SecretNode* next;
72207225
} SecretNode;
72217226

@@ -7233,7 +7238,6 @@ secretHashTable[WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE] = {NULL};
72337238
static WOLFSSL_GLOBAL wolfSSL_Mutex secretListMutex;
72347239
#endif
72357240

7236-
72377241
static unsigned int secretHashFunction(unsigned char* clientRandom);
72387242

72397243
#ifdef HAVE_C___ATOMIC
@@ -7253,72 +7257,78 @@ static unsigned int secretHashFunction(unsigned char* clientRandom)
72537257
{
72547258
int i = 0;
72557259
unsigned int hash = 0;
7260+
const int CLIENT_RANDOM_NUM_BITS = CLIENT_RANDOM_LENGTH * 8;
72567261

72577262
for (i = 0; i < CLIENT_RANDOM_LENGTH; i++) {
7258-
hash = (hash * CLIENT_RANDOM_BITS + clientRandom[i])
7263+
hash = (hash * CLIENT_RANDOM_NUM_BITS + clientRandom[i])
72597264
% WOLFSSL_SNIFFER_KEYLOGFILE_HASH_TABLE_SIZE;
72607265
}
72617266

72627267
return hash;
72637268
}
72647269

72657270

7271+
/*
7272+
* Adds a new secret to the secret table, creating a new node based on the
7273+
* client random if necessary. If the client random is already present in the
7274+
* list, the requested secret will be updated.
7275+
*/
72667276
static int addSecretNode(unsigned char* clientRandom,
7267-
unsigned char* masterSecret,
7277+
int type,
7278+
unsigned char* secret,
72687279
char* error)
72697280
{
7270-
unsigned int index = 0;
7271-
SecretNode* newSecretNode = NULL;
7281+
int index = 0;
7282+
int ret = 0;
7283+
SecretNode* node = NULL;
72727284

7273-
newSecretNode = (SecretNode*)XMALLOC(sizeof(SecretNode),
7274-
NULL,
7275-
DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
7276-
if (newSecretNode == NULL) {
7277-
SetError(MEMORY_STR, error, NULL, 0);
7285+
if (type >= SNIFFER_SECRET_NUM_SECRET_TYPES) {
72787286
return WOLFSSL_SNIFFER_ERROR;
72797287
}
72807288

7281-
XMEMCPY(newSecretNode->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH);
7282-
XMEMCPY(newSecretNode->masterSecret, masterSecret, MASTER_SECRET_LENGTH);
7283-
72847289
LOCK_SECRET_LIST();
72857290

72867291
index = secretHashFunction(clientRandom);
7287-
newSecretNode->next = NULL;
7292+
node = secretHashTable[index];
72887293

7289-
if (secretHashTable[index] == NULL) {
7290-
secretHashTable[index] = newSecretNode;
7291-
}
7292-
else {
7293-
SecretNode* current = secretHashTable[index];
7294-
while (current != NULL) {
7295-
if (memcmp(current->clientRandom,
7296-
clientRandom,
7297-
CLIENT_RANDOM_LENGTH) == 0) {
7298-
/* No need for a new node, since it already exists */
7299-
fprintf(stderr, "Found duplicate client random value in "
7300-
"keylog file. Rejecting.\n");
7301-
XFREE(newSecretNode, NULL, DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
7302-
break;
7303-
}
7304-
if (current->next == NULL) {
7305-
current->next = newSecretNode;
7306-
break;
7307-
}
7308-
current = current->next;
7294+
while(node) {
7295+
/* Node already exists, so just add the requested secret */
7296+
if (XMEMCMP(node->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH)
7297+
== 0)
7298+
{
7299+
XMEMCPY(node->secrets[type], secret, SECRET_LENGTH);
7300+
ret = 0;
7301+
goto unlockReturn;
73097302
}
7303+
node = node ->next;
73107304
}
73117305

7306+
node = (SecretNode*)XMALLOC(sizeof(SecretNode),
7307+
NULL,
7308+
DYNAMIC_TYPE_SNIFFER_KEYLOG_NODE);
7309+
if (node == NULL) {
7310+
SetError(MEMORY_STR, error, NULL, 0);
7311+
ret = WOLFSSL_SNIFFER_ERROR;
7312+
goto unlockReturn;
7313+
}
7314+
7315+
XMEMCPY(node->clientRandom, clientRandom, CLIENT_RANDOM_LENGTH);
7316+
XMEMCPY(node->secrets[type], secret, SECRET_LENGTH);
7317+
node->next = secretHashTable[index];
7318+
secretHashTable[index] = node;
7319+
7320+
unlockReturn:
7321+
73127322
UNLOCK_SECRET_LIST();
73137323

7314-
return 0;
7324+
return ret;
73157325
}
73167326

73177327

73187328
/*
73197329
* Looks up a master secret for a given client random from the keylog file
73207330
*/
7321-
static unsigned char* findMasterSecret(unsigned char* clientRandom)
7331+
static unsigned char* findSecret(unsigned char* clientRandom, int type)
73227332
{
73237333
unsigned char* secret = NULL;
73247334
SecretNode* node = NULL;
@@ -7332,7 +7342,7 @@ static unsigned char* findMasterSecret(unsigned char* clientRandom)
73327342
while (node != NULL) {
73337343
if (XMEMCMP(node->clientRandom,
73347344
clientRandom, CLIENT_RANDOM_LENGTH) == 0) {
7335-
secret = node->masterSecret;
7345+
secret = node->secrets[type];
73367346
break;
73377347
}
73387348
node = node->next;
@@ -7348,23 +7358,25 @@ static void hexToBin(const char* hex, unsigned char* bin, int binLength)
73487358
{
73497359
int i = 0;
73507360
for (i = 0; i < binLength; i++) {
7351-
sscanf(hex + 2 * i, "%02hhx", &bin[i]);
7361+
sscanf(hex + 2*i, "%02hhx", &bin[i]);
73527362
}
73537363
}
73547364

7355-
7365+
/*
7366+
* Helper function to parse secrets from the keylog file into the secret table
7367+
*/
73567368
static int parseKeyLogFile(const char* fileName, char* error)
73577369
{
7358-
const char CLIENT_RANDOM_LABEL_STR[] = "CLIENT_RANDOM";
73597370
unsigned char clientRandom[CLIENT_RANDOM_LENGTH];
7360-
unsigned char masterSecret[MASTER_SECRET_LENGTH];
7371+
unsigned char secret[SECRET_LENGTH];
73617372
FILE* file = NULL;
73627373
int ret = 0;
7374+
int type = 0;
73637375
/* +1 for null terminator */
7364-
char clientRandomLabel[CLIENT_RANDOM_LABEL_LENGTH + 1] = {0};
7376+
char prefix[MAX_PREFIX_LENGTH + 1] = {0};
73657377
/* 2 chars for Hexadecimal representation, plus null terminator */
73667378
char clientRandomHex[2 * CLIENT_RANDOM_LENGTH + 1] = {0};
7367-
char masterSecretHex[2 * MASTER_SECRET_LENGTH + 1] = {0};
7379+
char secretHex[2 * SECRET_LENGTH + 1] = {0};
73687380

73697381

73707382
file = fopen(fileName, "r");
@@ -7374,16 +7386,43 @@ static int parseKeyLogFile(const char* fileName, char* error)
73747386
return WOLFSSL_SNIFFER_ERROR;
73757387
}
73767388

7377-
while (fscanf(file, "%13s %64s %96s",
7378-
clientRandomLabel, clientRandomHex, masterSecretHex) == 3) {
7379-
if (XSTRCMP(clientRandomLabel, CLIENT_RANDOM_LABEL_STR) == 0) {
7380-
hexToBin(clientRandomHex, clientRandom, CLIENT_RANDOM_LENGTH);
7381-
hexToBin(masterSecretHex, masterSecret, MASTER_SECRET_LENGTH);
7382-
ret = addSecretNode(clientRandom, masterSecret, error);
7383-
if (ret != 0) {
7384-
fclose(file);
7385-
return ret;
7386-
}
7389+
/* Format specifiers for each column should be:
7390+
* MAX_PREFIX_LENGTH, 2*CLIENT_RANDOM_LENGTH, and 2*SECRET_LENGTH */
7391+
while (fscanf(file, "%31s %64s %96s", prefix, clientRandomHex, secretHex)
7392+
== 3) {
7393+
7394+
if (XSTRCMP(prefix, "CLIENT_RANDOM") == 0) {
7395+
type = SNIFFER_SECRET_TLS12_MASTER_SECRET;
7396+
}
7397+
#if defined(WOLFSSL_TLS13)
7398+
else if (XSTRCMP(prefix, "CLIENT_EARLY_TRAFFIC_SECRET") == 0) {
7399+
type = SNIFFER_SECRET_CLIENT_EARLY_TRAFFIC_SECRET;
7400+
}
7401+
else if (XSTRCMP(prefix, "CLIENT_HANDSHAKE_TRAFFIC_SECRET") == 0) {
7402+
type = SNIFFER_SECRET_CLIENT_HANDSHAKE_TRAFFIC_SECRET;
7403+
}
7404+
else if (XSTRCMP(prefix, "SERVER_HANDSHAKE_TRAFFIC_SECRET") == 0) {
7405+
type = SNIFFER_SECRET_SERVER_HANDSHAKE_TRAFFIC_SECRET;
7406+
}
7407+
else if (XSTRCMP(prefix, "CLIENT_TRAFFIC_SECRET_0") == 0) {
7408+
type = SNIFFER_SECRET_CLIENT_TRAFFIC_SECRET;
7409+
}
7410+
else if (XSTRCMP(prefix, "SERVER_TRAFFIC_SECRET_0") == 0) {
7411+
type = SNIFFER_SECRET_SERVER_TRAFFIC_SECRET;
7412+
}
7413+
#endif /* WOLFSSL_TLS13 */
7414+
else {
7415+
fprintf(stderr, "unrecognized prefix: %s\n", prefix);
7416+
continue;
7417+
}
7418+
7419+
hexToBin(clientRandomHex, clientRandom, CLIENT_RANDOM_LENGTH);
7420+
hexToBin(secretHex, secret, SECRET_LENGTH);
7421+
ret = addSecretNode(clientRandom, type, secret, error);
7422+
7423+
if (ret != 0) {
7424+
fclose(file);
7425+
return ret;
73877426
}
73887427
}
73897428
fclose(file);
@@ -7418,6 +7457,7 @@ static void freeSecretList(void)
74187457
* Looks up secret based on client random and copies it to output_secret
74197458
*/
74207459
static int snifferSecretCb(unsigned char* client_random,
7460+
int type,
74217461
unsigned char* output_secret)
74227462
{
74237463
unsigned char* secret = NULL;
@@ -7426,10 +7466,14 @@ static int snifferSecretCb(unsigned char* client_random,
74267466
return WOLFSSL_SNIFFER_FATAL_ERROR;
74277467
}
74287468

7469+
if (type >= SNIFFER_SECRET_NUM_SECRET_TYPES) {
7470+
return WOLFSSL_SNIFFER_FATAL_ERROR;
7471+
}
7472+
74297473
/* get secret from secret table based on client random */
7430-
secret = findMasterSecret(client_random);
7474+
secret = findSecret(client_random, type);
74317475
if (secret != NULL) {
7432-
XMEMCPY(output_secret, secret, MASTER_SECRET_LENGTH);
7476+
XMEMCPY(output_secret, secret, SECRET_LENGTH);
74337477
return 0;
74347478
}
74357479

src/tls.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,9 @@ int MakeTlsMasterSecret(WOLFSSL* ssl)
520520
/* If this is called from a sniffer session with keylog file support, obtain
521521
* the master secret from the callback */
522522
if (ssl->snifferSecretCb != NULL) {
523-
ret = ssl->snifferSecretCb(ssl->arrays->clientRandom, ssl->arrays->masterSecret);
523+
ret = ssl->snifferSecretCb(ssl->arrays->clientRandom,
524+
SNIFFER_SECRET_TLS12_MASTER_SECRET,
525+
ssl->arrays->masterSecret);
524526
if (ret != 0) {
525527
return ret;
526528
}
@@ -15227,4 +15229,5 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1522715229
#endif /* NO_WOLFSSL_SERVER */
1522815230

1522915231
#endif /* NO_TLS */
15232+
1523015233
#endif /* WOLFCRYPT_ONLY */

0 commit comments

Comments
 (0)