On Wed, Feb 19, 2020 at 7:10 AM Andrew Dunstan <andrew.duns...@2ndquadrant.com> wrote: > > On Tue, Feb 18, 2020 at 2:01 PM Thomas Munro <thomas.mu...@gmail.com> wrote: > > > > On Wed, Jan 22, 2020 at 8:02 PM Andrew Dunstan > > <andrew.duns...@2ndquadrant.com> wrote: > > > Not sure if the placement is what you want, but maybe something like this? > > > > Hi Andrew, FYI this failed here: > > > > t/001_testfunc.pl .. Bailout called. Further testing stopped: pg_ctl > > start failed > > FAILED--Further testing stopped: pg_ctl start failed > > Makefile:23: recipe for target 'prove-check' failed > > > > Unfortunately my robot is poorly trained and does not dump any of the > > interesting logs for this case, but it looks like it's failing that > > way every time. > > > > https://travis-ci.org/postgresql-cfbot/postgresql/builds/651756191 > > > Thanks for letting me know, I will investigate. >
This should fix the issue, it happened when I switched to using a pre-generated cert/key. 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 18d3fff068..b0a8816cff 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -45,6 +45,9 @@ #include "tcop/tcopprot.h" #include "utils/memutils.h" +/* default init hook can be overridden by a shared library */ +static void default_openssl_tls_init(SSL_CTX *context, bool isServerStart); +openssl_tls_init_hook_typ openssl_tls_init_hook = default_openssl_tls_init; static int my_sock_read(BIO *h, char *buf, int size); static int my_sock_write(BIO *h, const char *buf, int size); @@ -116,27 +119,10 @@ be_tls_init(bool isServerStart) SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); /* - * Set password callback + * Call init hook (usually to set password callback) */ - if (isServerStart) - { - 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) - SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); - else + (* openssl_tls_init_hook)(context, isServerStart); - /* - * If reloading and no external command is configured, override - * OpenSSL's default handling of passphrase-protected files, - * because we don't want to prompt for a passphrase in an - * already-running server. - */ - SSL_CTX_set_default_passwd_cb(context, dummy_ssl_passwd_cb); - } /* used by the callback */ ssl_is_server_start = isServerStart; @@ -1313,3 +1299,27 @@ ssl_protocol_version_to_openssl(int v, const char *guc_name, int loglevel) GetConfigOption(guc_name, false, false)))); return -1; } + + +static void +default_openssl_tls_init(SSL_CTX *context, bool isServerStart) +{ + if (isServerStart) + { + 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) + SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb); + else + /* + * If reloading and no external command is configured, override + * OpenSSL's default handling of passphrase-protected files, + * because we don't want to prompt for a passphrase in an + * already-running server. + */ + SSL_CTX_set_default_passwd_cb(context, dummy_ssl_passwd_cb); + } +} diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index b3986bee75..53776d6198 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 82e57afc64..90f80bb33a 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -287,6 +287,10 @@ 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 +/* init hook for SSL, the default sets the passwor callback if appropriate */ +typedef void(* openssl_tls_init_hook_typ)(SSL_CTX *context, bool isServerStart); +extern openssl_tls_init_hook_typ openssl_tls_init_hook; + #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..e2d19f131a --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/Makefile @@ -0,0 +1,24 @@ +# 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/server.crt b/src/test/modules/ssl_passphrase_callback/server.crt new file mode 100644 index 0000000000..292472a041 --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/server.crt @@ -0,0 +1,77 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 64:b5:b2:57:92:2b:e5:86:c6:c8:b1:6b:f5:79:4d:25:b2:05:91:45 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = localhost + Validity + Not Before: Feb 18 22:02:33 2020 GMT + Not After : Feb 15 22:02:33 2030 GMT + Subject: CN = localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:fb:01:2c:02:cd:15:49:85:ea:e0:95:57:13:7a: + 9c:88:ed:93:f8:11:bc:d4:b2:0a:57:8e:ab:b4:5e: + da:a9:24:b8:43:63:35:2c:df:a1:35:8d:49:11:1a: + f0:9c:0a:15:63:0f:4e:53:54:35:9f:8e:2d:0f:57: + 13:fd:b8:61:7f:e7:ff:44:aa:23:b9:3e:e6:59:71: + 2a:93:84:62:f9:1d:92:37:20:a0:38:c3:a0:bf:09: + 28:19:7a:87:90:89:31:b0:84:4f:8f:9e:ae:f5:73: + 11:41:ff:ea:12:1b:ab:bb:4c:4e:ba:b1:50:ff:37: + b1:35:3f:0d:aa:bb:a4:93:f1:0c:1d:bd:76:73:32: + 2d:22:1b:77:91:e7:c6:d4:b4:5e:d3:bf:02:6f:87: + 16:c4:08:6b:3e:a5:17:8a:bf:82:95:42:fb:2e:69: + 8f:26:0a:69:7d:c1:f6:8d:a7:ca:69:1d:81:95:ac: + 26:d6:b9:75:25:72:ec:13:c9:cf:82:fb:f3:39:90: + 22:7e:64:6b:c3:2f:ad:00:0e:e5:27:87:cf:60:aa: + ae:64:0a:e8:04:9b:8f:25:43:cc:9e:a8:10:62:5f: + 4c:3a:8d:95:13:bf:18:fa:6c:be:79:be:36:84:1d: + 00:ba:35:c6:06:d7:5b:1b:19:b6:ec:88:60:6c:58: + 1e:2f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 1D:8D:CB:C5:DE:70:22:7C:1F:47:91:6C:61:03:C3:AB:78:CA:66:26 + X509v3 Authority Key Identifier: + keyid:1D:8D:CB:C5:DE:70:22:7C:1F:47:91:6C:61:03:C3:AB:78:CA:66:26 + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + ae:3a:22:a5:bb:95:0f:7f:de:81:58:60:6f:ce:39:f3:39:09: + b3:0e:ff:f9:f1:fa:ce:9c:8c:d1:8b:39:b8:ce:ac:d8:b1:63: + 08:fd:bd:c9:a8:b7:59:68:14:f2:17:23:0a:c8:04:34:85:5f: + 05:ba:70:7c:b6:56:aa:aa:7b:86:23:93:27:4c:ac:8f:4e:3a: + 5f:c6:54:74:d7:d4:00:a7:e7:b8:76:6c:6f:02:62:f0:55:4f: + 49:35:d6:f1:63:ba:e4:3b:90:cd:cc:a1:2c:ca:f6:11:22:e7: + 23:74:98:ee:8e:35:c0:e7:58:2b:2b:c4:99:82:81:39:17:5b: + a5:b5:d8:df:ca:77:9c:f0:34:1e:d5:5b:ea:76:45:b0:0a:53: + 6d:94:8f:7a:01:b5:83:32:0b:97:75:3a:2f:dd:cb:0c:40:6f: + 8c:57:17:db:21:04:6b:72:bc:e1:eb:72:8c:d4:25:53:63:bb: + f5:22:0b:40:dc:d0:e3:7b:fc:52:da:c4:cd:44:c1:3e:60:ae: + 88:c1:01:5b:52:71:33:c2:e7:43:c6:bd:92:50:46:50:ea:2e: + d7:ae:2f:d4:35:1e:69:e3:75:e1:bc:e7:0a:a2:e5:cb:5b:da: + 5e:c5:92:55:df:a2:71:44:bc:93:3a:6d:e5:cd:48:40:e2:fb: + 72:09:c9:e3 +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUZLWyV5Ir5YbGyLFr9XlNJbIFkUUwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDIxODIyMDIzM1oXDTMwMDIx +NTIyMDIzM1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA+wEsAs0VSYXq4JVXE3qciO2T+BG81LIKV46rtF7aqSS4 +Q2M1LN+hNY1JERrwnAoVYw9OU1Q1n44tD1cT/bhhf+f/RKojuT7mWXEqk4Ri+R2S +NyCgOMOgvwkoGXqHkIkxsIRPj56u9XMRQf/qEhuru0xOurFQ/zexNT8Nqrukk/EM +Hb12czItIht3kefG1LRe078Cb4cWxAhrPqUXir+ClUL7LmmPJgppfcH2jafKaR2B +lawm1rl1JXLsE8nPgvvzOZAifmRrwy+tAA7lJ4fPYKquZAroBJuPJUPMnqgQYl9M +Oo2VE78Y+my+eb42hB0AujXGBtdbGxm27IhgbFgeLwIDAQABo1MwUTAdBgNVHQ4E +FgQUHY3Lxd5wInwfR5FsYQPDq3jKZiYwHwYDVR0jBBgwFoAUHY3Lxd5wInwfR5Fs +YQPDq3jKZiYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArjoi +pbuVD3/egVhgb8458zkJsw7/+fH6zpyM0Ys5uM6s2LFjCP29yai3WWgU8hcjCsgE +NIVfBbpwfLZWqqp7hiOTJ0ysj046X8ZUdNfUAKfnuHZsbwJi8FVPSTXW8WO65DuQ +zcyhLMr2ESLnI3SY7o41wOdYKyvEmYKBORdbpbXY38p3nPA0HtVb6nZFsApTbZSP +egG1gzILl3U6L93LDEBvjFcX2yEEa3K84etyjNQlU2O79SILQNzQ43v8UtrEzUTB +PmCuiMEBW1JxM8LnQ8a9klBGUOou164v1DUeaeN14bznCqLly1vaXsWSVd+icUS8 +kzpt5c1IQOL7cgnJ4w== +-----END CERTIFICATE----- diff --git a/src/test/modules/ssl_passphrase_callback/server.key b/src/test/modules/ssl_passphrase_callback/server.key new file mode 100644 index 0000000000..a8c69d237c --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/server.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,6C66380BB92F2E7A0B6CE1D5AF290071 + +7iu0jn3UasRUxYvSzozTybKZg6RBZtclJhSF/kYSrAu36rbPG4mO5lPBZq1wc+0q +PutAjbZikucjIrU+y8/S5B0Krqmp9HD/oQ9Um5Wrcw3OXSLhLqOBp7l+9qe0Y3BB +Efo85Ok0maaLfRWGrQ2Y2DNeNmhmVWFDxEGYTIJZQL7jQY2rfPBLA/Yin48upIUJ +6EtsVuQELwKaerf/PN5Xjig/vx01kR2Lset2uVeiy43ZcPeN6TSwEEj6bC1PFqCR +5MQTT+u3/HMZE6UKZ1qOuVt0Cm+QqjNWD2y9ueWvyZ2lW3U+tW1SKSbTOdujSysS +HWF0vwMt0Aeac3SUDAggVfPzrwPYFacKSUE3RQ28+3O8g5F7G6+R9KQ1VMFPuemk ++DSLZDyLkVYnO/iauzfivONOHHRNWaYdZxS+LxLw3PfoPLjSQG7M87asZXX/lSo8 +ka/4qsnBrMb3h0KDAuD6RmbEJNk8RK8a8X7+98weBVOh+IZkp/BH4q83IjiSQhmF +DZxuU1dH01B/3NXn7Vbk9J3V1v/GoZf5kvCnmmzC7M5ehYSXHY8NqMpM7KxI+vlw +YZS7HRD5+PHJv4YqlD9RiKAMQfri6GfV1AcVqO8maagmgSLVmPP9tKcKHPRrFpsY +9cd3hWDBKJ47ZUNPv1C9ibZehMJoHRDwim6KnhT1vY4ikNrlwwIOt7n5OAael3GD +sP7Oodrgnye8mM0JtET/DVEuBZsT5uS0tfpIQvJKP7gNRLv8sMxF9t2RRgaakryD +DPD/YbZxBY2qJnvdrLT1Co5MguOvBh+067SRtVvHFOLb4SPiO1wRLy5UvZmjCRJX +cfCivr4beBr+mN2+1xDVpq2MaEIlT4RQkHNk1odPhof36g16Abe6QVUr/5LSsHvX ++MbgdI0FkveYrF1RdH1/B5BBagDvgA6w3m/PhzdMXJAuElR0FY/Ypow7BP4tJVUt +wDuB8pQS9gOMxa70RHnGI9GXxpMdiwMtvZOYlw7WmezryEYSNZrBOYl8t9WTB2Dn +q7TIdRpqE8GMkKE9gurxl0WhN2YEODNICG9luoD0TzVGwVTFOeilANBcfHFqubVs +Z9fdKHK9Wdr96RQjRzXrCsoMTVoX3A98PGUoDPgd7NPfbH1ybc1775SryzV/C3ii +yi3hDBBEgxW1ydmSK1PPQdFXGiSM4Tqdg0sqE5vcYhTBe4CjUZaSiW3hrwqnf8cr +RmSlwSemzZHW3JpcH/F1H+oj2Kz+S/raD9tMVFZuiO4YcZ/1ZEkC3K7jO+G0cc8X +EJlt1j7Vu2ULECqhHGgd2RVDX06QCwM4ZmZVEmGvtRg9r/OKZhhR4Cjgw0UcFw9Z +POlSI7GN/Ae0WlmpdC1yj/BUvf99hcUuiPy/eVvEJQIcZPkh7AzmbGMvf6OJSQd+ +TXaDtt/A3khqkQFUBuRkh5OtJaCoh2e7Htsmb0Xf5rWpnBdDY1zs8kwjUaMP0e7r +IWbsby39Rrwh9nis9f8JwyHg0OZAAkyJPDbkIKOsHfbEWY5zCW54/2vX0S/7rn1u +kYmrzHRls/lfGI4l6I5zMKb7QHfsKcCRO9NGjNEQPt/q3/Cf9ZjAe2lK2/ROKf/y +-----END RSA PRIVATE KEY----- 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..0964ba3508 --- /dev/null +++ b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c @@ -0,0 +1,82 @@ +/*------------------------------------------------------------------------- + * + * 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; + +/* callback function */ +static int rot13_passphrase(char *buf, int size, int rwflag, void *userdata); +/* hook function to set the callback */ +static void set_rot13(SSL_CTX *context, bool isServerStart); +/* + * 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) + openssl_tls_init_hook = set_rot13; +} + +void +_PG_fini(void) +{ + /* do nothing yet */ +} + +static void +set_rot13(SSL_CTX *context, bool isServerStart) +{ + SSL_CTX_set_default_passwd_cb(context, rot13_passphrase); +} + +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..e146e09dd7 --- /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"; + +# self-signed cert was generated like this: +# system('openssl req -new -x509 -days 3650 -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 +copy("server.crt", $ddir); +copy("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 a43e31c60e..e1ad4f4052 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})