From e7ee68dda56028aa9e0e0cead3a0d3832cfb16db Mon Sep 17 00:00:00 2001 From: Rahim Kanji Date: Fri, 3 Apr 2026 18:10:57 +0500 Subject: [PATCH 1/3] Add SSL/TLS traffic decryption for PostgreSQL backend connections (#5281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the existing NSS keylog-based SSL decryption to PostgreSQL backend connections by patching libpq with a global PQsetSSLKeyLogCallback() API. When admin-ssl_keylog_file is configured, TLS secrets from all PgSQL backend SSL handshakes are written to the keylog file in NSS Key Log Format, enabling traffic decryption with Wireshark/tshark. Approach: - Patch libpq with global callback following the PQsslKeyPassHook pattern - Single startup call covers all backend paths (regular, monitor, kill, harvester) - No new admin variables — existing admin-ssl_keylog_file covers PgSQL backends - Zero changes to ProxySQL PgSQL connection code Includes 9 integration tests (pgsql-ssl_keylog-t) and user guide updates. --- deps/Makefile | 1 + deps/postgresql/sslkeylogfile.patch | 63 +++ doc/ssl_keylog/ssl_keylog_developer_guide.md | 425 ----------------- doc/ssl_keylog/ssl_keylog_user_guide.md | 51 ++- include/proxysql_sslkeylog.h | 15 + lib/ProxySQL_GloVars.cpp | 1 + lib/proxysql_sslkeylog.cpp | 17 + test/tap/groups/groups.json | 1 + test/tap/tests/pgsql-ssl_keylog-t.cpp | 458 +++++++++++++++++++ 9 files changed, 599 insertions(+), 433 deletions(-) create mode 100644 deps/postgresql/sslkeylogfile.patch delete mode 100644 doc/ssl_keylog/ssl_keylog_developer_guide.md create mode 100644 test/tap/tests/pgsql-ssl_keylog-t.cpp diff --git a/deps/Makefile b/deps/Makefile index bfb9421de..29be815d9 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -370,6 +370,7 @@ postgresql/postgresql/src/interfaces/libpq/libpq.a: cd postgresql/postgresql && patch -p0 < ../fmt_err_msg.patch cd postgresql/postgresql && patch -p0 < ../bind_fmt_text.patch cd postgresql/postgresql && patch -p0 < ../pqsendpipelinesync.patch + cd postgresql/postgresql && patch -p0 < ../sslkeylogfile.patch ifeq ($(UNAME_S),Darwin) cd postgresql/postgresql && LDFLAGS="-L$$(brew --prefix icu4c)/lib" CPPFLAGS="-I$$(brew --prefix icu4c)/include" PKG_CONFIG_PATH="$$(brew --prefix icu4c)/lib/pkgconfig:$$PKG_CONFIG_PATH" DYLD_LIBRARY_PATH="$(SSL_LDIR):$$DYLD_LIBRARY_PATH" ./configure --with-ssl=openssl --with-includes="$(SSL_IDIR)" --with-libraries="$(SSL_LDIR)" --without-readline --with-icu else diff --git a/deps/postgresql/sslkeylogfile.patch b/deps/postgresql/sslkeylogfile.patch new file mode 100644 index 000000000..5c4752b6e --- /dev/null +++ b/deps/postgresql/sslkeylogfile.patch @@ -0,0 +1,63 @@ +diff -ruN ../tmp/src/interfaces/libpq/fe-secure-openssl.c ./src/interfaces/libpq/fe-secure-openssl.c +--- ../tmp/src/interfaces/libpq/fe-secure-openssl.c 2025-08-11 21:06:43.000000000 +0000 ++++ ./src/interfaces/libpq/fe-secure-openssl.c 2026-04-03 00:00:00.000000000 +0000 +@@ -97,6 +97,8 @@ + + static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL; + static int ssl_protocol_version_to_openssl(const char *protocol); ++ ++static PQsslKeyLogCallback_type PQsslKeyLogCB = NULL; + + /* ------------------------------------------------------------ */ + /* Procedures common to all secure sessions */ +@@ -972,6 +974,10 @@ + /* Disable old protocol versions */ + SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + ++ /* Set SSL keylog callback if configured (for TLS traffic decryption) */ ++ if (PQsslKeyLogCB) ++ SSL_CTX_set_keylog_callback(SSL_context, (void(*)(const SSL*, const char*))PQsslKeyLogCB); ++ + /* Set the minimum and maximum protocol versions if necessary */ + if (conn->ssl_min_protocol_version && + strlen(conn->ssl_min_protocol_version) != 0) +@@ -1758,6 +1764,24 @@ + return NULL; + } + ++/* ++ * SSL Key Log callback support ++ * ++ * Global callback for writing TLS secrets to a keylog file. ++ * Follows the same pattern as PQsslKeyPassHook. ++ */ ++PQsslKeyLogCallback_type ++PQgetSSLKeyLogCallback(void) ++{ ++ return PQsslKeyLogCB; ++} ++ ++void ++PQsetSSLKeyLogCallback(PQsslKeyLogCallback_type cb) ++{ ++ PQsslKeyLogCB = cb; ++} ++ + const char *const * + PQsslAttributeNames(PGconn *conn) + { +diff -ruN ../tmp/src/interfaces/libpq/libpq-fe.h ./src/interfaces/libpq/libpq-fe.h +--- ../tmp/src/interfaces/libpq/libpq-fe.h 2025-08-11 21:06:43.000000000 +0000 ++++ ./src/interfaces/libpq/libpq-fe.h 2026-04-03 00:00:00.000000000 +0000 +@@ -669,6 +669,11 @@ + extern void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook); + extern int PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn); + ++/* Support for SSL key log callback (TLS traffic decryption) */ ++typedef void (*PQsslKeyLogCallback_type)(const void *ssl, const char *line); ++extern PQsslKeyLogCallback_type PQgetSSLKeyLogCallback(void); ++extern void PQsetSSLKeyLogCallback(PQsslKeyLogCallback_type cb); ++ + #ifdef __cplusplus + } + #endif diff --git a/doc/ssl_keylog/ssl_keylog_developer_guide.md b/doc/ssl_keylog/ssl_keylog_developer_guide.md deleted file mode 100644 index 51822579a..000000000 --- a/doc/ssl_keylog/ssl_keylog_developer_guide.md +++ /dev/null @@ -1,425 +0,0 @@ -# SSL/TLS Key Log Feature - Developer Guide - -## Overview - -ProxySQL implements SSL/TLS key logging to enable decryption of encrypted traffic for debugging purposes. This feature writes TLS secrets to a file in the NSS Key Log Format, which can be used by tools like Wireshark to decrypt and analyze TLS traffic. - -**PR Reference:** #4236 - "Added support for SSLKEYLOGFILE" - ---- - -## Variable Naming Convention - -ProxySQL variables belong to **modules**. This is important for understanding how variables are referenced: - -| Context | Variable Name | Module | -|---------|---------------|--------| -| **Internal code** | `ssl_keylog_file` | Admin | -| **SQL interface** | `admin-ssl_keylog_file` | Admin (with prefix) | -| **Config file** | `ssl_keylog_file` | Admin (in `admin_variables` section) | - -**Code Location:** `include/proxysql_admin.h` - the variable is defined as `char* ssl_keylog_file` within the admin variables struct. - -**SQL Registration:** `lib/ProxySQL_Admin.cpp` - registered as `"ssl_keylog_file"` in the `admin_variables` array. - -When users set this variable via SQL, they must use the module prefix: -```sql -SET admin-ssl_keylog_file = '/path/to/file.txt'; -``` - ---- - -## Architecture - -### Component Diagram - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ ProxySQL Process │ -│ │ -│ ┌────────────────┐ ┌─────────────────────────────────┐ │ -│ | ProxySQL_Admin |────────>| Global Variables │ │ -│ | │ | .ssl_keylog_file = "/path/..." │ │ -│ └────────────────┘ └─────────────────────────────────┘ │ -│ │ │ -│ | SET admin-ssl_keylog_file='/path/keylog.txt' │ -│ v │ -│ ┌──────────────────────────────────────────────────────────────┐ │ -│ | proxysql_sslkeylog module │ │ -│ │ │ │ -│ │ ┌──────────────┐ ┌──────────────────┐ ┌───────────────┐ │ │ -│ │ | keylog_init | | keylog_open | | keylog_close │ │ │ -│ │ └──────────────┘ └──────────────────┘ └───────────────┘ │ │ -│ │ │ │ -│ │ ┌──────────────────────────────────────────────────────────┐│ │ -│ │ | proxysql_keylog_attach_callback(SSL_CTX*) ││ │ -│ │ | ││ │ -│ │ | SSL_CTX_set_keylog_callback(ctx, write_line_callback) ││ │ -│ │ └──────────────────────────────────────────────────────────┘│ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ │ -│ │ Callback invoked by OpenSSL │ -│ v │ -│ ┌──────────────────────────────────────────────────────────────┐ │ -│ │ proxysql_keylog_write_line_callback(ssl, line) │ │ -│ │ │ │ -│ │ - Validate line length │ │ -│ │ - Acquire read lock (rwlock) │ │ -│ │ - Write to keylog file │ │ -│ │ - Release lock │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ │ -│ v │ -│ ┌──────────────────────────────────────────────────────────────┐ │ -│ │ keylog_file_fp (FILE*) │ │ -│ │ "/var/log/proxysql/sslkeys.txt" │ │ -│ │ │ │ -│ │ CLIENT_RANDOM 3a4b5c... <48-byte-secret> │ │ -│ │ CLIENT_HANDSHAKE_TRAFFIC_SECRET 3a4b... <32-byte-secret> │ │ -│ │ SERVER_HANDSHAKE_TRAFFIC_SECRET 3a4b... <32-byte-secret> │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ -└──────────────────────────────────────────────────────────────────────┘ -``` - -### Thread Safety Model - -The keylog subsystem uses a **pthread read-write lock** for concurrent access. - -**Key Points:** -- Multiple threads can write to the keylog file simultaneously during TLS handshakes -- File rotation (open/close) acquires exclusive lock -- Double-checked locking in `write_line_callback()` for performance - ---- - -## NSS Key Log Format - -### File Structure - -Each line in the keylog file has the following format: - -``` -