Skip to content

Instantly share code, notes, and snippets.

@hlandau
Created September 10, 2023 10:13
Show Gist options
  • Save hlandau/f67b4065909913ed31da1500dc4a8719 to your computer and use it in GitHub Desktop.
Save hlandau/f67b4065909913ed31da1500dc4a8719 to your computer and use it in GitHub Desktop.
LD_PRELOAD implementation of SSLKEYLOGFILE in OpenSSL
/*
* ldkeylog.c - tool for dumping TLS keys from applications which
* dynamically link against OpenSSL on *nix systems
*
* Compile:
* cc -shared -fPIC -O3 -o ldkeylog.so ldkeylog.c
*
* Use:
* LD_PRELOAD=.../ldkeylog.so SSLKEYLOGFILE=.../keylog.txt \
* openssl s_client -connect www.google.com:443
*
* 2023 Hugo Landau <hlandau@devever.net>
* Released into the public domain.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
typedef void (*keylog_callback_t)(const void *ssl, const char *line);
typedef void *(*SSL_CTX_new_t)(const void *method);
typedef void *(*SSL_CTX_new_ex_t)(void *libctx, const char *propq, const void *method);
typedef void (*SSL_CTX_set_keylog_callback_t)(void *ctx, keylog_callback_t fp);
static pthread_once_t g_initOnce = PTHREAD_ONCE_INIT;
static SSL_CTX_new_t fp_SSL_CTX_new;
static SSL_CTX_new_ex_t fp_SSL_CTX_new_ex;
static SSL_CTX_set_keylog_callback_t fp_SSL_CTX_set_keylog_callback;
static int g_logFile = -1;
static void _Teardown(void)
{
close(g_logFile);
g_logFile = -1;
}
static void _InitActual(void)
{
fp_SSL_CTX_new = dlsym(RTLD_NEXT, "SSL_CTX_new");
fp_SSL_CTX_new_ex = dlsym(RTLD_NEXT, "SSL_CTX_new_ex");
fp_SSL_CTX_set_keylog_callback = dlsym(RTLD_NEXT, "SSL_CTX_set_keylog_callback");
if (!fp_SSL_CTX_set_keylog_callback)
return;
const char *klFilename = getenv("SSLKEYLOGFILE");
if (!klFilename || !*klFilename)
return;
g_logFile = open(klFilename, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0644);
if (g_logFile >= 0)
atexit(_Teardown);
}
static void _Init(void)
{
pthread_once(&g_initOnce, _InitActual);
}
static void _KeylogCallback(const void *ssl, const char *line)
{
struct iovec iov[2];
if (g_logFile < 0)
return;
iov[0].iov_base = (char *)line;
iov[0].iov_len = strlen(line);
iov[1].iov_base = "\n";
iov[1].iov_len = 1;
writev(g_logFile, iov, 2);
}
static void _ConfigureKeylog(void *ctx)
{
if (g_logFile < 0)
return;
fp_SSL_CTX_set_keylog_callback(ctx, _KeylogCallback);
}
void *SSL_CTX_new(const void *method)
{
_Init();
if (!fp_SSL_CTX_new)
abort();
void *p = fp_SSL_CTX_new(method);
if (p)
_ConfigureKeylog(p);
return p;
}
void *SSL_CTX_new_ex(void *libctx, const char *propq,
const void *method)
{
_Init();
if (!fp_SSL_CTX_new_ex)
abort();
void *p = fp_SSL_CTX_new_ex(libctx, propq, method);
if (p)
_ConfigureKeylog(p);
return p;
}
void SSL_CTX_set_keylog_callback(void *ctx, keylog_callback_t fp)
{
/* ignore */
}
ldkeylog.so: ldkeylog.c
gcc -Wall -shared -fPIC -O3 "$<" -o "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment