Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Keylog file with env variable SSLKEYLOGFILE (for openssl) #517

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/session_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <ctype.h>
#include <poll.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -43,6 +44,83 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>

#define SSLKEYLOGFILE_ENV "SSLKEYLOGFILE"
/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
static volatile FILE *keylog_file_fp = NULL;
static volatile uint32_t keylog_tls_sessions = 0;
static pthread_mutex_t keylog_mutex = PTHREAD_MUTEX_INITIALIZER;

static int
nc_tls_keylog_open(void)
{
char *keylog_file_name;

keylog_file_name = getenv(SSLKEYLOGFILE_ENV);

if (keylog_file_name) {
pthread_mutex_lock(&keylog_mutex);
keylog_tls_sessions++;
DBL(NULL, "TID %lu create tls session: number %d", (long unsigned int)pthread_self(), keylog_tls_sessions);
if (!keylog_file_fp) {
keylog_file_fp = fopen(keylog_file_name, "a");
DBL(NULL, "TID %lu open keylog file %s", (long unsigned int)pthread_self(), keylog_file_name);
if (keylog_file_fp) {
if (setvbuf((FILE *) keylog_file_fp, NULL, _IOLBF, 4096)) {
fclose((FILE *) keylog_file_fp);
keylog_file_fp = NULL;
}
}
}
pthread_mutex_unlock(&keylog_mutex);
}
return keylog_file_fp != NULL;
}

static void
nc_tls_keylog_close(void)
{
if (keylog_file_fp) {
pthread_mutex_lock(&keylog_mutex);
keylog_tls_sessions--;
DBL(NULL, "TID %lu remove tls session: number %d", (long unsigned int)pthread_self(), keylog_tls_sessions);
if (keylog_tls_sessions == 0) {
DBL(NULL, "TID %lu close keylog file", (long unsigned int)pthread_self());
fclose((FILE *) keylog_file_fp);
keylog_file_fp = NULL;
}
pthread_mutex_unlock(&keylog_mutex);
}
}

static void
nc_tls_keylog_write_line(const SSL *UNUSED(ssl), const char *line)
{
/* The current maximum valid keylog line length LF and NUL is 195. */
size_t linelen;
char buf[256];

if (!keylog_file_fp || !line) {
return;
}

linelen = strlen(line);
if ((linelen == 0) || (linelen > sizeof(buf) - 2)) {
/* Empty line or too big to fit in a LF and NUL. */
return;
}

memcpy(buf, line, linelen);
if (line[linelen - 1] != '\n') {
buf[linelen++] = '\n';
}
buf[linelen] = '\0';

/* Using fputs here instead of fprintf since libcurl's fprintf replacement
may not be thread-safe. */
fputs(buf, (FILE *)keylog_file_fp);
return;
}

void *
nc_tls_session_new_wrap(void *tls_cfg)
{
Expand All @@ -54,13 +132,19 @@ nc_tls_session_new_wrap(void *tls_cfg)
return NULL;
}

if (nc_tls_keylog_open()) {
SSL_CTX_set_keylog_callback(tls_cfg, nc_tls_keylog_write_line);
}

return session;
}

void
nc_tls_session_destroy_wrap(void *tls_session)
{
SSL_free(tls_session);

nc_tls_keylog_close();
}

void *
Expand Down
64 changes: 64 additions & 0 deletions tests/test_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

int TEST_PORT = 10050;
const char *TEST_PORT_STR = "10050";
const char *KEYLOG_FILE = "keylog.txt";

static void *
client_thread(void *arg)
Expand Down Expand Up @@ -54,6 +55,50 @@ client_thread(void *arg)
return NULL;
}

#ifndef HAVE_MBEDTLS

/** test keylog.txt file */
static void
assert_keylog_file()
{
FILE *file;
char line[256];
const char *lines_types[] = {
"SERVER_HANDSHAKE_TRAFFIC_SECRET",
"CLIENT_HANDSHAKE_TRAFFIC_SECRET",
"EXPORTER_SECRET",
"SERVER_TRAFFIC_SECRET_0",
"CLIENT_TRAFFIC_SECRET_0"
};
int lines_types_count[] = {0, 0, 0, 0, 0};

fprintf(stderr, "Checking keylog file\n");

if (!getenv("SSLKEYLOGFILE")) {
return;
}

file = fopen(KEYLOG_FILE, "r");
assert_non_null(file);

while (fgets(line, sizeof(line), file)) {
assert_true(strlen(line) > 32);
for (int i = 0; i < 5; i++) {
if (strncmp(line, lines_types[i], strlen(lines_types[i])) == 0) {
lines_types_count[i]++;
}
}
}
for (int i = 0; i < 5; i++) {
assert_int_equal(lines_types_count[i], 2);
}

fclose(file);
remove(KEYLOG_FILE);
}

#endif

static void
test_nc_tls(void **state)
{
Expand All @@ -70,6 +115,10 @@ test_nc_tls(void **state)
for (i = 0; i < 2; i++) {
pthread_join(tids[i], NULL);
}

#ifndef HAVE_MBEDTLS
assert_keylog_file();
#endif
}

static int
Expand Down Expand Up @@ -115,11 +164,25 @@ setup_f(void **state)
return 0;
}

static int
setup_f_with_keylog(void **state)
{
setenv("SSLKEYLOGFILE", KEYLOG_FILE, 1);
return setup_f(state);
}

static void
test_nc_tls_with_keylog(void **state)
{
test_nc_tls(state);
}

int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_nc_tls, setup_f, ln2_glob_test_teardown),
cmocka_unit_test_setup_teardown(test_nc_tls_with_keylog, setup_f_with_keylog, ln2_glob_test_teardown)
};

/* try to get ports from the environment, otherwise use the default */
Expand All @@ -128,5 +191,6 @@ main(void)
}

setenv("CMOCKA_TEST_ABORT", "1", 1);
setenv("SSLKEYLOGFILE", KEYLOG_FILE, 1);
return cmocka_run_group_tests(tests, NULL, NULL);
}
Loading