mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
libpq: Add support for dumping SSL key material to file
This adds a new connection parameter which instructs libpq to write out keymaterial clientside into a file in order to make connection debugging with Wireshark and similar tools possible. The file format used is the standardized NSS format. Author: Abhishek Chanda <abhishek.becs@gmail.com> Co-authored-by: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com> Discussion: https://postgr.es/m/CAKiP-K85C8uQbzXKWf5wHQPkuygGUGcufke713iHmYWOe9q2dA@mail.gmail.com
This commit is contained in:
parent
e4309f73f6
commit
2da74d8d64
2
configure
vendored
2
configure
vendored
@ -12931,7 +12931,7 @@ fi
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Function introduced in OpenSSL 1.1.1, not in LibreSSL.
|
# Function introduced in OpenSSL 1.1.1, not in LibreSSL.
|
||||||
for ac_func in X509_get_signature_info SSL_CTX_set_num_tickets
|
for ac_func in X509_get_signature_info SSL_CTX_set_num_tickets SSL_CTX_set_keylog_callback
|
||||||
do :
|
do :
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||||
|
@ -1382,7 +1382,7 @@ if test "$with_ssl" = openssl ; then
|
|||||||
# Function introduced in OpenSSL 1.0.2, not in LibreSSL.
|
# Function introduced in OpenSSL 1.0.2, not in LibreSSL.
|
||||||
AC_CHECK_FUNCS([SSL_CTX_set_cert_cb])
|
AC_CHECK_FUNCS([SSL_CTX_set_cert_cb])
|
||||||
# Function introduced in OpenSSL 1.1.1, not in LibreSSL.
|
# Function introduced in OpenSSL 1.1.1, not in LibreSSL.
|
||||||
AC_CHECK_FUNCS([X509_get_signature_info SSL_CTX_set_num_tickets])
|
AC_CHECK_FUNCS([X509_get_signature_info SSL_CTX_set_num_tickets SSL_CTX_set_keylog_callback])
|
||||||
AC_DEFINE([USE_OPENSSL], 1, [Define to 1 to build with OpenSSL support. (--with-ssl=openssl)])
|
AC_DEFINE([USE_OPENSSL], 1, [Define to 1 to build with OpenSSL support. (--with-ssl=openssl)])
|
||||||
elif test "$with_ssl" != no ; then
|
elif test "$with_ssl" != no ; then
|
||||||
AC_MSG_ERROR([--with-ssl must specify openssl])
|
AC_MSG_ERROR([--with-ssl must specify openssl])
|
||||||
|
@ -1918,6 +1918,30 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="libpq-connect-sslkeylogfile" xreflabel="sslkeylogfile">
|
||||||
|
<term><literal>sslkeylogfile</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
This parameter specifies the location where <literal>libpq</literal>
|
||||||
|
will log keys used in this SSL context. This is useful for debugging
|
||||||
|
<productname>PostgreSQL</productname> protocol interactions or client
|
||||||
|
connections using network inspection tools like
|
||||||
|
<productname>Wireshark</productname>. This parameter is ignored if an
|
||||||
|
SSL connection is not made, or if <productname>LibreSSL</productname>
|
||||||
|
is used (<productname>LibreSSL</productname> does not support key
|
||||||
|
logging). Keys are logged using the <productname>NSS</productname>
|
||||||
|
format.
|
||||||
|
<warning>
|
||||||
|
<para>
|
||||||
|
Key logging will expose potentially sensitive information in the
|
||||||
|
keylog file. Keylog files should be handled with the same care as
|
||||||
|
<xref linkend="libpq-connect-sslkey" /> files.
|
||||||
|
</para>
|
||||||
|
</warning>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="libpq-connect-sslpassword" xreflabel="sslpassword">
|
<varlistentry id="libpq-connect-sslpassword" xreflabel="sslpassword">
|
||||||
<term><literal>sslpassword</literal></term>
|
<term><literal>sslpassword</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -1479,6 +1479,7 @@ if sslopt in ['auto', 'openssl']
|
|||||||
# Function introduced in OpenSSL 1.1.1, not in LibreSSL.
|
# Function introduced in OpenSSL 1.1.1, not in LibreSSL.
|
||||||
['X509_get_signature_info'],
|
['X509_get_signature_info'],
|
||||||
['SSL_CTX_set_num_tickets'],
|
['SSL_CTX_set_num_tickets'],
|
||||||
|
['SSL_CTX_set_keylog_callback'],
|
||||||
]
|
]
|
||||||
|
|
||||||
are_openssl_funcs_complete = true
|
are_openssl_funcs_complete = true
|
||||||
|
@ -368,6 +368,9 @@
|
|||||||
/* Define to 1 if you have the `SSL_CTX_set_ciphersuites' function. */
|
/* Define to 1 if you have the `SSL_CTX_set_ciphersuites' function. */
|
||||||
#undef HAVE_SSL_CTX_SET_CIPHERSUITES
|
#undef HAVE_SSL_CTX_SET_CIPHERSUITES
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `SSL_CTX_set_keylog_callback' function. */
|
||||||
|
#undef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
|
||||||
|
|
||||||
/* Define to 1 if you have the `SSL_CTX_set_num_tickets' function. */
|
/* Define to 1 if you have the `SSL_CTX_set_num_tickets' function. */
|
||||||
#undef HAVE_SSL_CTX_SET_NUM_TICKETS
|
#undef HAVE_SSL_CTX_SET_NUM_TICKETS
|
||||||
|
|
||||||
|
@ -401,6 +401,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
|
|||||||
"OAuth-Scope", "", 15,
|
"OAuth-Scope", "", 15,
|
||||||
offsetof(struct pg_conn, oauth_scope)},
|
offsetof(struct pg_conn, oauth_scope)},
|
||||||
|
|
||||||
|
{"sslkeylogfile", NULL, NULL, NULL,
|
||||||
|
"SSL-Key-Log-File", "", 0, /* sizeof("") = 0 */
|
||||||
|
offsetof(struct pg_conn, sslkeylogfile)},
|
||||||
|
|
||||||
/* Terminating entry --- MUST BE LAST */
|
/* Terminating entry --- MUST BE LAST */
|
||||||
{NULL, NULL, NULL, NULL,
|
{NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, 0}
|
NULL, NULL, 0}
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
* include <wincrypt.h>, but some other Windows headers do.)
|
* include <wincrypt.h>, but some other Windows headers do.)
|
||||||
*/
|
*/
|
||||||
#include "common/openssl.h"
|
#include "common/openssl.h"
|
||||||
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/conf.h>
|
#include <openssl/conf.h>
|
||||||
#ifdef USE_SSL_ENGINE
|
#ifdef USE_SSL_ENGINE
|
||||||
#include <openssl/engine.h>
|
#include <openssl/engine.h>
|
||||||
@ -684,6 +685,49 @@ pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn,
|
|||||||
/* See pqcomm.h comments on OpenSSL implementation of ALPN (RFC 7301) */
|
/* See pqcomm.h comments on OpenSSL implementation of ALPN (RFC 7301) */
|
||||||
static unsigned char alpn_protos[] = PG_ALPN_PROTOCOL_VECTOR;
|
static unsigned char alpn_protos[] = PG_ALPN_PROTOCOL_VECTOR;
|
||||||
|
|
||||||
|
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
|
||||||
|
/*
|
||||||
|
* SSL Key Logging callback
|
||||||
|
*
|
||||||
|
* This callback lets the user store all key material to a file for debugging
|
||||||
|
* purposes. The file will be written using the NSS keylog format. LibreSSL
|
||||||
|
* 3.5 introduced stub function to set the callback for OpenSSL compatibility
|
||||||
|
* but the callback is never invoked.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
SSL_CTX_keylog_cb(const SSL *ssl, const char *line)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
mode_t old_umask;
|
||||||
|
ssize_t rc;
|
||||||
|
PGconn *conn = SSL_get_app_data(ssl);
|
||||||
|
|
||||||
|
if (conn == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
old_umask = umask(077);
|
||||||
|
fd = open(conn->sslkeylogfile, O_WRONLY | O_APPEND | O_CREAT, 0600);
|
||||||
|
umask(old_umask);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
libpq_append_conn_error(conn, "could not open ssl keylog file %s: %s",
|
||||||
|
conn->sslkeylogfile, pg_strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line is guaranteed by OpenSSL to be NUL terminated */
|
||||||
|
rc = write(fd, line, strlen(line));
|
||||||
|
if (rc < 0)
|
||||||
|
libpq_append_conn_error(conn, "could not write to ssl keylog file %s: %s",
|
||||||
|
conn->sslkeylogfile, pg_strerror(errno));
|
||||||
|
else
|
||||||
|
rc = write(fd, "\n", 1);
|
||||||
|
(void) rc; /* silence compiler warnings */
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create per-connection SSL object, and load the client certificate,
|
* Create per-connection SSL object, and load the client certificate,
|
||||||
* private key, and trusted CA certs.
|
* private key, and trusted CA certs.
|
||||||
@ -1000,6 +1044,20 @@ initialize_SSL(PGconn *conn)
|
|||||||
}
|
}
|
||||||
conn->ssl_in_use = true;
|
conn->ssl_in_use = true;
|
||||||
|
|
||||||
|
if (conn->sslkeylogfile && strlen(conn->sslkeylogfile) > 0)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
|
||||||
|
SSL_CTX_set_keylog_callback(SSL_context, SSL_CTX_keylog_cb);
|
||||||
|
#else
|
||||||
|
#ifdef LIBRESSL_VERSION_NUMBER
|
||||||
|
fprintf(stderr, libpq_gettext("WARNING: sslkeylogfile support requires OpenSSL\n"));
|
||||||
|
#else
|
||||||
|
fprintf(stderr, libpq_gettext("WARNING: libpq was not built with sslkeylogfile support\n"));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSL contexts are reference counted by OpenSSL. We can free it as soon
|
* SSL contexts are reference counted by OpenSSL. We can free it as soon
|
||||||
* as we have created the SSL object, and it will stick around for as long
|
* as we have created the SSL object, and it will stick around for as long
|
||||||
|
@ -426,6 +426,7 @@ struct pg_conn
|
|||||||
char *load_balance_hosts; /* load balance over hosts */
|
char *load_balance_hosts; /* load balance over hosts */
|
||||||
char *scram_client_key; /* base64-encoded SCRAM client key */
|
char *scram_client_key; /* base64-encoded SCRAM client key */
|
||||||
char *scram_server_key; /* base64-encoded SCRAM server key */
|
char *scram_server_key; /* base64-encoded SCRAM server key */
|
||||||
|
char *sslkeylogfile; /* where should the client write ssl keylogs */
|
||||||
|
|
||||||
bool cancelRequest; /* true if this connection is used to send a
|
bool cancelRequest; /* true if this connection is used to send a
|
||||||
* cancel request, instead of being a normal
|
* cancel request, instead of being a normal
|
||||||
|
@ -147,6 +147,33 @@ my $default_ssl_connstr =
|
|||||||
$common_connstr =
|
$common_connstr =
|
||||||
"$default_ssl_connstr user=ssltestuser dbname=trustdb hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
|
"$default_ssl_connstr user=ssltestuser dbname=trustdb hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
|
||||||
|
|
||||||
|
SKIP:
|
||||||
|
{
|
||||||
|
skip "Keylogging is not supported with LibreSSL", 5 if $libressl;
|
||||||
|
|
||||||
|
my $tempdir = PostgreSQL::Test::Utils::tempdir;
|
||||||
|
my @status;
|
||||||
|
|
||||||
|
# Properly escape backslashes in the path
|
||||||
|
$tempdir =~ s/\\/\\\\/g;
|
||||||
|
|
||||||
|
# Connect should work with a given sslkeylogfile
|
||||||
|
$node->connect_ok(
|
||||||
|
"$common_connstr sslrootcert=ssl/root+server_ca.crt sslkeylogfile=$tempdir/key.txt sslmode=require",
|
||||||
|
"connect with server root cert and sslkeylogfile=$tempdir/key.txt");
|
||||||
|
|
||||||
|
# Verify the key file exists
|
||||||
|
ok(-f "$tempdir/key.txt", "keylog file exists at: $tempdir/key.txt");
|
||||||
|
|
||||||
|
# Skip permission checks on Windows/Cygwin
|
||||||
|
skip "Permissions check not enforced on Windows", 2
|
||||||
|
if ($windows_os || $Config::Config{osname} eq 'cygwin');
|
||||||
|
|
||||||
|
ok( (@status = stat("$tempdir/key.txt")),
|
||||||
|
"keylog file exists and returned status");
|
||||||
|
ok(@status && !($status[2] & 0006), "keylog file is not world readable");
|
||||||
|
}
|
||||||
|
|
||||||
# The server should not accept non-SSL connections.
|
# The server should not accept non-SSL connections.
|
||||||
$node->connect_fails(
|
$node->connect_fails(
|
||||||
"$common_connstr sslmode=disable",
|
"$common_connstr sslmode=disable",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user