On 11/7/19 12:30 PM, Andrew Dunstan wrote: > On 11/4/19 4:43 PM, Thomas Munro wrote: >> It looks like the new declarations in libpq-be.h are ifdef'd out in a >> non-USE_SSL build, but then we still try to build the new test module >> and it fails: >> >> https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.64071 > > > I think this updated patch should fix things. > >
This time with a typo fixed to keep the cfbot happy. cheers andrew -- Andrew Dunstan https://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 629919cc6e..bf4493c94a 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -45,6 +45,9 @@ #include "utils/memutils.h" +ssl_passphrase_func_cb ssl_passphrase_function = NULL; +bool ssl_passphrase_function_supports_reload = false; + static int my_sock_read(BIO *h, char *buf, int size); static int my_sock_write(BIO *h, const char *buf, int size); static BIO_METHOD *my_BIO_s_socket(void); @@ -124,12 +127,16 @@ be_tls_init(bool isServerStart) */ if (isServerStart) { - if (ssl_passphrase_command[0]) + if (ssl_passphrase_function) + SSL_CTX_set_default_passwd_cb(context, ssl_passphrase_function); + else if (ssl_passphrase_command[0]) SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); } else { - if (ssl_passphrase_command[0] && ssl_passphrase_command_supports_reload) + if (ssl_passphrase_function && ssl_passphrase_function_supports_reload) + SSL_CTX_set_default_passwd_cb(context, ssl_passphrase_function); + else if (ssl_passphrase_command[0] && ssl_passphrase_command_supports_reload) SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); else diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 5f30359165..18dd8578d9 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -972,17 +972,6 @@ PostmasterMain(int argc, char *argv[]) */ LocalProcessControlFile(false); - /* - * Initialize SSL library, if specified. - */ -#ifdef USE_SSL - if (EnableSSL) - { - (void) secure_initialize(true); - LoadedSSL = true; - } -#endif - /* * Register the apply launcher. Since it registers a background worker, * it needs to be called before InitializeMaxBackends(), and it's probably @@ -996,6 +985,17 @@ PostmasterMain(int argc, char *argv[]) */ process_shared_preload_libraries(); + /* + * Initialize SSL library, if specified. + */ +#ifdef USE_SSL + if (EnableSSL) + { + (void) secure_initialize(true); + LoadedSSL = true; + } +#endif + /* * Now that loadable modules have had their chance to register background * workers, calculate MaxBackends. diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 541f970f99..dd2b5fc6c8 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -287,6 +287,17 @@ extern void be_tls_get_peer_serial(Port *port, char *ptr, size_t len); extern char *be_tls_get_certificate_hash(Port *port, size_t *len); #endif +/* + * ssl_passphrase_function can be filled in by a shared preloaded module + * to supply a passphrase for a key file, as can the flag noting whether the + * function supports reloading. + */ + +typedef int (* ssl_passphrase_func_cb) (char *buf, int size, int rwflag, + void *userdata); +extern ssl_passphrase_func_cb ssl_passphrase_function; +extern bool ssl_passphrase_function_supports_reload; + #endif /* USE_SSL */ #ifdef ENABLE_GSS diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index b2eaef3bff..5f975ebcba 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -25,4 +25,9 @@ SUBDIRS = \ unsafe_tests \ worker_spi +ifeq ($(with_openssl),yes) +SUBDIRS += ssl_passphrase_callback +endif + + $(recurse) diff --git a/src/test/modules/ssl_passphrase_callback/.gitignore b/src/test/modules/ssl_passphrase_callback/.gitignore new file mode 100644 index 0000000000..1dbadf7baf --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/.gitignore @@ -0,0 +1 @@ +tmp_check diff --git a/src/test/modules/ssl_passphrase_callback/Makefile b/src/test/modules/ssl_passphrase_callback/Makefile new file mode 100644 index 0000000000..685b3aed74 --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/Makefile @@ -0,0 +1,25 @@ +# ssl_passphrase Makefile + +export with_openssl + +MODULE_big = ssl_passphrase_func +OBJS = ssl_passphrase_func.o $(WIN32RES) +PGFILEDESC = "callback function to provide a passphrase" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/ssl_passphrase_callback +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +check: prove-check + +prove-check: ssl_passphrase_func$(DLSUFFIX) | temp-install + @echo running prove ... + $(prove_check) + diff --git a/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c new file mode 100644 index 0000000000..bdbf3a3671 --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------- + * + * ssl_passphrase_func.c + * + * Loadable PostgreSQL module fetch an ssl passphrase for the server cert. + * instead of calling an external program. This implementation just hands + * back the configured password rot13'd. + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include <float.h> +#include <stdio.h> + +#include "libpq/libpq-be.h" +#include "utils/guc.h" + +PG_MODULE_MAGIC; + +void _PG_init(void); +void _PG_fini(void); + +static char *ssl_passphrase = NULL; + +static int rot13_passphrase(char *buf, + int size, + int rwflag, + void *userdata); + +/* + * Module load callback + */ +void +_PG_init(void) +{ + /* Define custom GUC variable. */ + DefineCustomStringVariable("ssl_passphrase.passphrase", + "passphrase before transformation", + NULL, + &ssl_passphrase, + NULL, + PGC_SIGHUP, + 0, /* no flags required */ + NULL, + NULL, + NULL); + if (ssl_passphrase) + { + ssl_passphrase_function = rot13_passphrase; + ssl_passphrase_function_supports_reload = true; + } +} + +void +_PG_fini(void) +{ + /* do nothing yet */ +} + +static int +rot13_passphrase(char *buf, int size, int rwflag, void *userdata) +{ + + Assert(ssl_passphrase != NULL); + StrNCpy(buf, ssl_passphrase, size); + for (char *p = buf; *p; p++) + { + char c = *p; + + if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')) + *p = c + 13; + else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')) + *p = c - 13; + } + + return strlen(buf); + +} diff --git a/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl b/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl new file mode 100644 index 0000000000..ffdc9f1562 --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/t/001_testfunc.pl @@ -0,0 +1,67 @@ + +use strict; +use warnings; + +use File::Copy; + +use TestLib; +use Test::More; +use PostgresNode; + +unless ( ($ENV{with_openssl} || 'no') eq 'yes') +{ + plan skip_all => 'SSL not supported by this build'; +} + +my $clearpass = "FooBaR1"; +my $rot13pass = "SbbOnE1"; + +# create a self-signed cert +system('openssl req -new -x509 -days 365 -nodes -text -out server.crt -keyout server.ckey -subj "/CN=localhost"'); +# add the cleartext passphrase to the key, remove the unprotected key +system("openssl rsa -aes256 -in server.ckey -out server.key -passout pass:$clearpass"); +unlink "server.ckey"; + + +my $node = get_new_node('main'); +$node->init; +$node->append_conf('postgresql.conf', + "ssl_passphrase.passphrase = '$rot13pass'"); +$node->append_conf('postgresql.conf', + "shared_preload_libraries = 'ssl_passphrase_func'"); +$node->append_conf('postgresql.conf', + "listen_addresses = 'localhost'"); +$node->append_conf('postgresql.conf', + "ssl = 'on'"); + +my $ddir = $node->data_dir; + +# install certificate and protected key +move("server.crt", $ddir); +move("server.key", $ddir); +chmod 0600, "$ddir/server.key"; + +$node->start; + +# if the server is running we must had successfully transformed the passphrase +ok(-e "$ddir/postmaster.pid","postgres started"); + +$node->stop('fast'); + +# set the wrong passphrase +$node->append_conf('postgresql.conf', + "ssl_passphrase.passphrase = 'blurfl'"); + +# try to start the server again +my $ret = TestLib::system_log('pg_ctl', '-D', $node->data_dir, '-l', + $node->logfile, 'start'); + + +# with a bad passphrase the server should not start +ok($ret, "pg_ctl fails with bad passphrase"); +ok(! -e "$ddir/postmaster.pid","postgres not started with bad passphrase"); + +# just in case +$node->stop('fast'); + +done_testing(); diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 9a0963a050..0fd887b778 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -429,7 +429,7 @@ sub mkvcbuild if (!$solution->{options}->{openssl}) { - push @contrib_excludes, 'sslinfo'; + push @contrib_excludes, 'sslinfo', 'ssl_passphrase_callback'; } if (!$solution->{options}->{uuid})