@@ -78,13 +78,14 @@ static DH *tmp_dh_cb(SSL *s, int is_export, int keylength);
7878static int ssl_passwd_cb (char * buf , int size , int rwflag , void * userdata );
7979static int verify_cb (int , X509_STORE_CTX * );
8080static 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 );
8282static const char * SSLerrmessage (unsigned long ecode );
8383
8484static char * X509_NAME_to_cstring (X509_NAME * name );
8585
8686static SSL_CTX * SSL_context = NULL ;
8787static 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 */
166167int
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 */
10811095static int
10821096ssl_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
11531167static 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;
0 commit comments