Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6667d9a

Browse files
committed
Re-allow SSL passphrase prompt at server start, but not thereafter.
Leave OpenSSL's default passphrase collection callback in place during the first call of secure_initialize() in server startup. Although that doesn't work terribly well in daemon contexts, some people feel we should not break it for anyone who was successfully using it before. We still block passphrase demands during SIGHUP, meaning that you can't adjust SSL configuration on-the-fly if you used a passphrase, but this is no worse than what it was before commit de41869. And we block passphrase demands during EXEC_BACKEND reloads; that behavior wasn't useful either, but at least now it's documented. Tweak some related log messages for more readability, and avoid issuing essentially duplicate messages about reload failure caused by a passphrase. Discussion: https://postgr.es/m/29982.1483412575@sss.pgh.pa.us
1 parent 0fad355 commit 6667d9a

File tree

6 files changed

+72
-53
lines changed

6 files changed

+72
-53
lines changed

doc/src/sgml/runtime.sgml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,8 +2159,13 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
21592159
</para>
21602160

21612161
<para>
2162-
The private key cannot be protected with a passphrase, as there is no
2163-
way to supply the passphrase to the server.
2162+
If the private key is protected with a passphrase, the
2163+
server will prompt for the passphrase and will not start until it has
2164+
been entered.
2165+
Using a passphrase also disables the ability to change the server's SSL
2166+
configuration without a server restart.
2167+
Furthermore, passphrase-protected private keys cannot be used at all
2168+
on Windows.
21642169
</para>
21652170

21662171
<para>
@@ -2293,9 +2298,9 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
22932298
<para>
22942299
If an error in these files is detected at server start, the server will
22952300
refuse to start. But if an error is detected during a configuration
2296-
reload, the files are ignored and the old values continue to be used.
2297-
On <systemitem class="osname">Windows</> systems, if an error in these
2298-
files is detected at backend start, that backend will be unable to
2301+
reload, the files are ignored and the old SSL configuration continues to
2302+
be used. On <systemitem class="osname">Windows</> systems, if an error in
2303+
these files is detected at backend start, that backend will be unable to
22992304
establish an SSL connection. In all these cases, the error condition is
23002305
reported in the server log.
23012306
</para>
@@ -2314,8 +2319,8 @@ openssl req -new -text -out server.req
23142319
you enter the local host name as <quote>Common Name</>; the challenge
23152320
password can be left blank. The program will generate a key that is
23162321
passphrase protected; it will not accept a passphrase that is less
2317-
than four characters long. To remove the passphrase again (as you must),
2318-
next run the commands:
2322+
than four characters long. To remove the passphrase again (as you must
2323+
if you want automatic start-up of the server), next run the commands:
23192324
<programlisting>
23202325
openssl rsa -in privkey.pem -out server.key
23212326
rm privkey.pem

src/backend/libpq/be-secure-openssl.c

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,14 @@ static DH *tmp_dh_cb(SSL *s, int is_export, int keylength);
7878
static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);
7979
static int verify_cb(int, X509_STORE_CTX *);
8080
static void info_cb(const SSL *ssl, int type, int args);
81-
static bool initialize_ecdh(SSL_CTX *context, bool failOnError);
81+
static bool initialize_ecdh(SSL_CTX *context, bool isServerStart);
8282
static const char *SSLerrmessage(unsigned long ecode);
8383

8484
static char *X509_NAME_to_cstring(X509_NAME *name);
8585

8686
static SSL_CTX *SSL_context = NULL;
8787
static bool SSL_initialized = false;
88+
static bool ssl_passwd_cb_called = false;
8889

8990
/* ------------------------------------------------------------ */
9091
/* Hardcoded values */
@@ -159,12 +160,12 @@ KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
159160
/*
160161
* Initialize global SSL context.
161162
*
162-
* If failOnError is true, report any errors as FATAL (so we don't return).
163-
* Otherwise, log errors at LOG level and return -1 to indicate trouble.
164-
* Returns 0 if OK.
163+
* If isServerStart is true, report any errors as FATAL (so we don't return).
164+
* Otherwise, log errors at LOG level and return -1 to indicate trouble,
165+
* preserving the old SSL state if any. Returns 0 if OK.
165166
*/
166167
int
167-
be_tls_init(bool failOnError)
168+
be_tls_init(bool isServerStart)
168169
{
169170
STACK_OF(X509_NAME) *root_cert_list = NULL;
170171
SSL_CTX *context;
@@ -192,7 +193,7 @@ be_tls_init(bool failOnError)
192193
context = SSL_CTX_new(SSLv23_method());
193194
if (!context)
194195
{
195-
ereport(failOnError ? FATAL : LOG,
196+
ereport(isServerStart ? FATAL : LOG,
196197
(errmsg("could not create SSL context: %s",
197198
SSLerrmessage(ERR_get_error()))));
198199
goto error;
@@ -205,16 +206,21 @@ be_tls_init(bool failOnError)
205206
SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
206207

207208
/*
208-
* Override OpenSSL's default handling of passphrase-protected files.
209+
* If reloading, override OpenSSL's default handling of
210+
* passphrase-protected files, because we don't want to prompt for a
211+
* passphrase in an already-running server. (Not that the default
212+
* handling is very desirable during server start either, but some people
213+
* insist we need to keep it.)
209214
*/
210-
SSL_CTX_set_default_passwd_cb(context, ssl_passwd_cb);
215+
if (!isServerStart)
216+
SSL_CTX_set_default_passwd_cb(context, ssl_passwd_cb);
211217

212218
/*
213219
* Load and verify server's certificate and private key
214220
*/
215221
if (SSL_CTX_use_certificate_chain_file(context, ssl_cert_file) != 1)
216222
{
217-
ereport(failOnError ? FATAL : LOG,
223+
ereport(isServerStart ? FATAL : LOG,
218224
(errcode(ERRCODE_CONFIG_FILE_ERROR),
219225
errmsg("could not load server certificate file \"%s\": %s",
220226
ssl_cert_file, SSLerrmessage(ERR_get_error()))));
@@ -223,7 +229,7 @@ be_tls_init(bool failOnError)
223229

224230
if (stat(ssl_key_file, &buf) != 0)
225231
{
226-
ereport(failOnError ? FATAL : LOG,
232+
ereport(isServerStart ? FATAL : LOG,
227233
(errcode_for_file_access(),
228234
errmsg("could not access private key file \"%s\": %m",
229235
ssl_key_file)));
@@ -232,22 +238,22 @@ be_tls_init(bool failOnError)
232238

233239
if (!S_ISREG(buf.st_mode))
234240
{
235-
ereport(failOnError ? FATAL : LOG,
241+
ereport(isServerStart ? FATAL : LOG,
236242
(errcode(ERRCODE_CONFIG_FILE_ERROR),
237243
errmsg("private key file \"%s\" is not a regular file",
238244
ssl_key_file)));
239245
goto error;
240246
}
241247

242248
/*
243-
* Refuse to load files owned by users other than us or root.
249+
* Refuse to load key files owned by users other than us or root.
244250
*
245251
* XXX surely we can check this on Windows somehow, too.
246252
*/
247253
#if !defined(WIN32) && !defined(__CYGWIN__)
248254
if (buf.st_uid != geteuid() && buf.st_uid != 0)
249255
{
250-
ereport(failOnError ? FATAL : LOG,
256+
ereport(isServerStart ? FATAL : LOG,
251257
(errcode(ERRCODE_CONFIG_FILE_ERROR),
252258
errmsg("private key file \"%s\" must be owned by the database user or root",
253259
ssl_key_file)));
@@ -270,7 +276,7 @@ be_tls_init(bool failOnError)
270276
if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
271277
(buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
272278
{
273-
ereport(failOnError ? FATAL : LOG,
279+
ereport(isServerStart ? FATAL : LOG,
274280
(errcode(ERRCODE_CONFIG_FILE_ERROR),
275281
errmsg("private key file \"%s\" has group or world access",
276282
ssl_key_file),
@@ -279,20 +285,31 @@ be_tls_init(bool failOnError)
279285
}
280286
#endif
281287

288+
/*
289+
* OK, try to load the private key file.
290+
*/
291+
ssl_passwd_cb_called = false;
292+
282293
if (SSL_CTX_use_PrivateKey_file(context,
283294
ssl_key_file,
284295
SSL_FILETYPE_PEM) != 1)
285296
{
286-
ereport(failOnError ? FATAL : LOG,
287-
(errcode(ERRCODE_CONFIG_FILE_ERROR),
288-
errmsg("could not load private key file \"%s\": %s",
289-
ssl_key_file, SSLerrmessage(ERR_get_error()))));
297+
if (ssl_passwd_cb_called)
298+
ereport(isServerStart ? FATAL : LOG,
299+
(errcode(ERRCODE_CONFIG_FILE_ERROR),
300+
errmsg("private key file \"%s\" cannot be reloaded because it requires a passphrase",
301+
ssl_key_file)));
302+
else
303+
ereport(isServerStart ? FATAL : LOG,
304+
(errcode(ERRCODE_CONFIG_FILE_ERROR),
305+
errmsg("could not load private key file \"%s\": %s",
306+
ssl_key_file, SSLerrmessage(ERR_get_error()))));
290307
goto error;
291308
}
292309

293310
if (SSL_CTX_check_private_key(context) != 1)
294311
{
295-
ereport(failOnError ? FATAL : LOG,
312+
ereport(isServerStart ? FATAL : LOG,
296313
(errcode(ERRCODE_CONFIG_FILE_ERROR),
297314
errmsg("check of private key failed: %s",
298315
SSLerrmessage(ERR_get_error()))));
@@ -306,13 +323,13 @@ be_tls_init(bool failOnError)
306323
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
307324

308325
/* set up ephemeral ECDH keys */
309-
if (!initialize_ecdh(context, failOnError))
326+
if (!initialize_ecdh(context, isServerStart))
310327
goto error;
311328

312329
/* set up the allowed cipher list */
313330
if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1)
314331
{
315-
ereport(failOnError ? FATAL : LOG,
332+
ereport(isServerStart ? FATAL : LOG,
316333
(errcode(ERRCODE_CONFIG_FILE_ERROR),
317334
errmsg("could not set the cipher list (no valid ciphers available)")));
318335
goto error;
@@ -330,7 +347,7 @@ be_tls_init(bool failOnError)
330347
if (SSL_CTX_load_verify_locations(context, ssl_ca_file, NULL) != 1 ||
331348
(root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL)
332349
{
333-
ereport(failOnError ? FATAL : LOG,
350+
ereport(isServerStart ? FATAL : LOG,
334351
(errcode(ERRCODE_CONFIG_FILE_ERROR),
335352
errmsg("could not load root certificate file \"%s\": %s",
336353
ssl_ca_file, SSLerrmessage(ERR_get_error()))));
@@ -366,7 +383,7 @@ be_tls_init(bool failOnError)
366383
}
367384
else
368385
{
369-
ereport(failOnError ? FATAL : LOG,
386+
ereport(isServerStart ? FATAL : LOG,
370387
(errcode(ERRCODE_CONFIG_FILE_ERROR),
371388
errmsg("could not load SSL certificate revocation list file \"%s\": %s",
372389
ssl_crl_file, SSLerrmessage(ERR_get_error()))));
@@ -1071,19 +1088,16 @@ tmp_dh_cb(SSL *s, int is_export, int keylength)
10711088
*
10721089
* If OpenSSL is told to use a passphrase-protected server key, by default
10731090
* it will issue a prompt on /dev/tty and try to read a key from there.
1074-
* That's completely no good for a postmaster SIGHUP cycle, not to mention
1075-
* SSL context reload in an EXEC_BACKEND postmaster child. So override it
1076-
* with this dummy function that just returns an empty passphrase,
1077-
* guaranteeing failure. Later we might think about collecting a passphrase
1078-
* at server start and feeding it to OpenSSL repeatedly, but we'd still
1079-
* need this callback for that.
1091+
* That's no good during a postmaster SIGHUP cycle, not to mention SSL context
1092+
* reload in an EXEC_BACKEND postmaster child. So override it with this dummy
1093+
* function that just returns an empty passphrase, guaranteeing failure.
10801094
*/
10811095
static int
10821096
ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
10831097
{
1084-
ereport(LOG,
1085-
(errcode(ERRCODE_CONFIG_FILE_ERROR),
1086-
errmsg("server's private key file requires a passphrase")));
1098+
/* Set flag to change the error message we'll report */
1099+
ssl_passwd_cb_called = true;
1100+
/* And return empty string */
10871101
Assert(size > 0);
10881102
buf[0] = '\0';
10891103
return 0;
@@ -1151,7 +1165,7 @@ info_cb(const SSL *ssl, int type, int args)
11511165
}
11521166

11531167
static bool
1154-
initialize_ecdh(SSL_CTX *context, bool failOnError)
1168+
initialize_ecdh(SSL_CTX *context, bool isServerStart)
11551169
{
11561170
#ifndef OPENSSL_NO_ECDH
11571171
EC_KEY *ecdh;
@@ -1160,7 +1174,7 @@ initialize_ecdh(SSL_CTX *context, bool failOnError)
11601174
nid = OBJ_sn2nid(SSLECDHCurve);
11611175
if (!nid)
11621176
{
1163-
ereport(failOnError ? FATAL : LOG,
1177+
ereport(isServerStart ? FATAL : LOG,
11641178
(errcode(ERRCODE_CONFIG_FILE_ERROR),
11651179
errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
11661180
return false;
@@ -1169,7 +1183,7 @@ initialize_ecdh(SSL_CTX *context, bool failOnError)
11691183
ecdh = EC_KEY_new_by_curve_name(nid);
11701184
if (!ecdh)
11711185
{
1172-
ereport(failOnError ? FATAL : LOG,
1186+
ereport(isServerStart ? FATAL : LOG,
11731187
(errcode(ERRCODE_CONFIG_FILE_ERROR),
11741188
errmsg("ECDH: could not create key")));
11751189
return false;

src/backend/libpq/be-secure.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,15 @@ bool SSLPreferServerCiphers;
6565
/*
6666
* Initialize global context.
6767
*
68-
* If failOnError is true, report any errors as FATAL (so we don't return).
69-
* Otherwise, log errors at LOG level and return -1 to indicate trouble.
70-
* Returns 0 if OK.
68+
* If isServerStart is true, report any errors as FATAL (so we don't return).
69+
* Otherwise, log errors at LOG level and return -1 to indicate trouble,
70+
* preserving the old SSL state if any. Returns 0 if OK.
7171
*/
7272
int
73-
secure_initialize(bool failOnError)
73+
secure_initialize(bool isServerStart)
7474
{
7575
#ifdef USE_SSL
76-
return be_tls_init(failOnError);
76+
return be_tls_init(isServerStart);
7777
#else
7878
return 0;
7979
#endif

src/backend/postmaster/postmaster.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2507,11 +2507,11 @@ SIGHUP_handler(SIGNAL_ARGS)
25072507
/* Reload authentication config files too */
25082508
if (!load_hba())
25092509
ereport(LOG,
2510-
(errmsg("pg_hba.conf not reloaded")));
2510+
(errmsg("pg_hba.conf was not reloaded")));
25112511

25122512
if (!load_ident())
25132513
ereport(LOG,
2514-
(errmsg("pg_ident.conf not reloaded")));
2514+
(errmsg("pg_ident.conf was not reloaded")));
25152515

25162516
#ifdef USE_SSL
25172517
/* Reload SSL configuration as well */
@@ -2521,7 +2521,7 @@ SIGHUP_handler(SIGNAL_ARGS)
25212521
LoadedSSL = true;
25222522
else
25232523
ereport(LOG,
2524-
(errmsg("SSL context not reloaded")));
2524+
(errmsg("SSL configuration was not reloaded")));
25252525
}
25262526
else
25272527
{
@@ -4772,7 +4772,7 @@ SubPostmasterMain(int argc, char *argv[])
47724772
LoadedSSL = true;
47734773
else
47744774
ereport(LOG,
4775-
(errmsg("SSL context could not be reloaded in child process")));
4775+
(errmsg("SSL configuration could not be loaded in child process")));
47764776
}
47774777
#endif
47784778

src/include/libpq/libpq-be.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ typedef struct Port
199199
* These functions are implemented by the glue code specific to each
200200
* SSL implementation (e.g. be-secure-openssl.c)
201201
*/
202-
extern int be_tls_init(bool failOnError);
202+
extern int be_tls_init(bool isServerStart);
203203
extern void be_tls_destroy(void);
204204
extern int be_tls_open_server(Port *port);
205205
extern void be_tls_close(Port *port);

src/include/libpq/libpq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ extern char *ssl_key_file;
8181
extern char *ssl_ca_file;
8282
extern char *ssl_crl_file;
8383

84-
extern int secure_initialize(bool failOnError);
84+
extern int secure_initialize(bool isServerStart);
8585
extern bool secure_loaded_verify_locations(void);
8686
extern void secure_destroy(void);
8787
extern int secure_open_server(Port *port);

0 commit comments

Comments
 (0)