Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8a3d942

Browse files
committed
Add ssl_passphrase_command setting
This allows specifying an external command for prompting for orotherwise obtaining passphrases for SSL key files. This is usefulbecause in many cases there is no TTY easily available during servicestartup.Also add a setting ssl_passphrase_command_supports_reload, which allowssupporting SSL configuration reload even if SSL files need passphrases.Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
1 parent7a50bb6 commit8a3d942

File tree

13 files changed

+313
-20
lines changed

13 files changed

+313
-20
lines changed

‎doc/src/sgml/config.sgml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,66 @@ include_dir 'conf.d'
13131313
</para>
13141314
</listitem>
13151315
</varlistentry>
1316+
1317+
<varlistentry id="guc-ssl-passphrase-command" xreflabel="ssl_passphrase_command">
1318+
<term><varname>ssl_passphrase_command</varname> (<type>string</type>)
1319+
<indexterm>
1320+
<primary><varname>ssl_passphrase_command</varname> configuration parameter</primary>
1321+
</indexterm>
1322+
</term>
1323+
<listitem>
1324+
<para>
1325+
Sets an external command to be invoked when a passphrase for
1326+
decrypting an SSL file such as a private key needs to be obtained. By
1327+
default, this parameter is empty, which means the built-in prompting
1328+
mechanism is used.
1329+
</para>
1330+
<para>
1331+
The command must print the passphrase to the standard output and exit
1332+
with code 0. In the parameter value, <literal>%p</literal> is
1333+
replaced by a prompt string. (Write <literal>%%</literal> for a
1334+
literal <literal>%</literal>.) Note that the prompt string will
1335+
probably contain whitespace, so be sure to quote adequately. A single
1336+
newline is stripped from the end of the output if present.
1337+
</para>
1338+
<para>
1339+
The command does not actually have to prompt the user for a
1340+
passphrase. It can read it from a file, obtain it from a keychain
1341+
facility, or similar. It is up to the user to make sure the chosen
1342+
mechanism is adequately secure.
1343+
</para>
1344+
<para>
1345+
This parameter can only be set in the <filename>postgresql.conf</filename>
1346+
file or on the server command line.
1347+
</para>
1348+
</listitem>
1349+
</varlistentry>
1350+
1351+
<varlistentry id="guc-ssl-passphrase-command-supports-reload" xreflabel="ssl_passphrase_command_supports_reload">
1352+
<term><varname>ssl_passphrase_command_supports_reload</varname> (<type>boolean</type>)
1353+
<indexterm>
1354+
<primary><varname>ssl_passphrase_command_supports_reload</varname> configuration parameter</primary>
1355+
</indexterm>
1356+
</term>
1357+
<listitem>
1358+
<para>
1359+
This setting determines whether the passphrase command set by
1360+
<varname>ssl_passphrase_command</varname> will also be called during a
1361+
configuration reload if a key file needs a passphrase. If this
1362+
setting is false (the default), then
1363+
<varname>ssl_passphrase_command</varname> will be ignored during a
1364+
reload and the SSL configuration will not be reloaded if a passphrase
1365+
is needed. That setting is appropriate for a command that requires a
1366+
TTY for prompting, which might not be available when the server is
1367+
running. Setting this to true might be appropriate if the passphrase
1368+
is obtained from a file, for example.
1369+
</para>
1370+
<para>
1371+
This parameter can only be set in the <filename>postgresql.conf</filename>
1372+
file or on the server command line.
1373+
</para>
1374+
</listitem>
1375+
</varlistentry>
13161376
</variablelist>
13171377
</sect2>
13181378
</sect1>

‎src/backend/libpq/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global
1414

1515
# be-fsstubs is here for historical reasons, probably belongs elsewhere
1616

17-
OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ifaddr.o pqcomm.o\
17+
OBJS = be-fsstubs.o be-secure.obe-secure-common.oauth.o crypt.o hba.o ifaddr.o pqcomm.o\
1818
pqformat.o pqmq.o pqsignal.o auth-scram.o
1919

2020
ifeq ($(with_openssl),yes)

‎src/backend/libpq/be-secure-common.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* be-secure-common.c
4+
*
5+
* common implementation-independent SSL support code
6+
*
7+
* While be-secure.c contains the interfaces that the rest of the
8+
* communications code calls, this file contains support routines that are
9+
* used by the library-specific implementations such as be-secure-openssl.c.
10+
*
11+
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
12+
* Portions Copyright (c) 1994, Regents of the University of California
13+
*
14+
* IDENTIFICATION
15+
* src/backend/libpq/be-secure-common.c
16+
*
17+
*-------------------------------------------------------------------------
18+
*/
19+
20+
#include"postgres.h"
21+
22+
#include"libpq/libpq.h"
23+
#include"storage/fd.h"
24+
25+
/*
26+
* Run ssl_passphrase_command
27+
*
28+
* prompt will be substituted for %p. is_server_start determines the loglevel
29+
* of error messages.
30+
*
31+
* The result will be put in buffer buf, which is of size size. The return
32+
* value is the length of the actual result.
33+
*/
34+
int
35+
run_ssl_passphrase_command(constchar*prompt,boolis_server_start,char*buf,intsize)
36+
{
37+
intloglevel=is_server_start ?ERROR :LOG;
38+
StringInfoDatacommand;
39+
char*p;
40+
FILE*fh;
41+
intpclose_rc;
42+
size_tlen=0;
43+
44+
Assert(prompt);
45+
Assert(size>0);
46+
buf[0]='\0';
47+
48+
initStringInfo(&command);
49+
50+
for (p=ssl_passphrase_command;*p;p++)
51+
{
52+
if (p[0]=='%')
53+
{
54+
switch (p[1])
55+
{
56+
case'p':
57+
appendStringInfoString(&command,prompt);
58+
p++;
59+
break;
60+
case'%':
61+
appendStringInfoChar(&command,'%');
62+
p++;
63+
break;
64+
default:
65+
appendStringInfoChar(&command,p[0]);
66+
}
67+
}
68+
else
69+
appendStringInfoChar(&command,p[0]);
70+
}
71+
72+
fh=OpenPipeStream(command.data,"r");
73+
if (fh==NULL)
74+
{
75+
ereport(loglevel,
76+
(errcode_for_file_access(),
77+
errmsg("could not execute command \"%s\": %m",
78+
command.data)));
79+
gotoerror;
80+
}
81+
82+
if (!fgets(buf,size,fh))
83+
{
84+
if (ferror(fh))
85+
{
86+
ereport(loglevel,
87+
(errcode_for_file_access(),
88+
errmsg("could not read from command \"%s\": %m",
89+
command.data)));
90+
gotoerror;
91+
}
92+
}
93+
94+
pclose_rc=ClosePipeStream(fh);
95+
if (pclose_rc==-1)
96+
{
97+
ereport(loglevel,
98+
(errcode_for_file_access(),
99+
errmsg("could not close pipe to external command: %m")));
100+
gotoerror;
101+
}
102+
elseif (pclose_rc!=0)
103+
{
104+
ereport(loglevel,
105+
(errcode_for_file_access(),
106+
errmsg("command \"%s\" failed",
107+
command.data),
108+
errdetail_internal("%s",wait_result_to_str(pclose_rc))));
109+
gotoerror;
110+
}
111+
112+
/* strip trailing newline */
113+
len=strlen(buf);
114+
if (buf[len-1]=='\n')
115+
buf[len---1]='\0';
116+
117+
error:
118+
pfree(command.data);
119+
returnlen;
120+
}

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

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ static intmy_SSL_set_fd(Port *port, int fd);
5252

5353
staticDH*load_dh_file(char*filename,boolisServerStart);
5454
staticDH*load_dh_buffer(constchar*,size_t);
55-
staticintssl_passwd_cb(char*buf,intsize,intrwflag,void*userdata);
55+
staticintssl_external_passwd_cb(char*buf,intsize,intrwflag,void*userdata);
56+
staticintdummy_ssl_passwd_cb(char*buf,intsize,intrwflag,void*userdata);
5657
staticintverify_cb(int,X509_STORE_CTX*);
5758
staticvoidinfo_cb(constSSL*ssl,inttype,intargs);
5859
staticboolinitialize_dh(SSL_CTX*context,boolisServerStart);
@@ -63,7 +64,8 @@ static char *X509_NAME_to_cstring(X509_NAME *name);
6364

6465
staticSSL_CTX*SSL_context=NULL;
6566
staticboolSSL_initialized= false;
66-
staticboolssl_passwd_cb_called= false;
67+
staticbooldummy_ssl_passwd_cb_called= false;
68+
staticboolssl_is_server_start;
6769

6870

6971
/* ------------------------------------------------------------ */
@@ -111,14 +113,28 @@ be_tls_init(bool isServerStart)
111113
SSL_CTX_set_mode(context,SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
112114

113115
/*
114-
* If reloading, override OpenSSL's default handling of
115-
* passphrase-protected files, because we don't want to prompt for a
116-
* passphrase in an already-running server. (Not that the default
117-
* handling is very desirable during server start either, but some people
118-
* insist we need to keep it.)
116+
* Set password callback
119117
*/
120-
if (!isServerStart)
121-
SSL_CTX_set_default_passwd_cb(context,ssl_passwd_cb);
118+
if (isServerStart)
119+
{
120+
if (ssl_passphrase_command[0])
121+
SSL_CTX_set_default_passwd_cb(context,ssl_external_passwd_cb);
122+
}
123+
else
124+
{
125+
if (ssl_passphrase_command[0]&&ssl_passphrase_command_supports_reload)
126+
SSL_CTX_set_default_passwd_cb(context,ssl_external_passwd_cb);
127+
else
128+
/*
129+
* If reloading and no external command is configured, override
130+
* OpenSSL's default handling of passphrase-protected files,
131+
* because we don't want to prompt for a passphrase in an
132+
* already-running server.
133+
*/
134+
SSL_CTX_set_default_passwd_cb(context,dummy_ssl_passwd_cb);
135+
}
136+
/* used by the callback */
137+
ssl_is_server_start=isServerStart;
122138

123139
/*
124140
* Load and verify server's certificate and private key
@@ -138,13 +154,13 @@ be_tls_init(bool isServerStart)
138154
/*
139155
* OK, try to load the private key file.
140156
*/
141-
ssl_passwd_cb_called= false;
157+
dummy_ssl_passwd_cb_called= false;
142158

143159
if (SSL_CTX_use_PrivateKey_file(context,
144160
ssl_key_file,
145161
SSL_FILETYPE_PEM)!=1)
146162
{
147-
if (ssl_passwd_cb_called)
163+
if (dummy_ssl_passwd_cb_called)
148164
ereport(isServerStart ?FATAL :LOG,
149165
(errcode(ERRCODE_CONFIG_FILE_ERROR),
150166
errmsg("private key file \"%s\" cannot be reloaded because it requires a passphrase",
@@ -839,7 +855,21 @@ load_dh_buffer(const char *buffer, size_t len)
839855
}
840856

841857
/*
842-
*Passphrase collection callback
858+
*Passphrase collection callback using ssl_passphrase_command
859+
*/
860+
staticint
861+
ssl_external_passwd_cb(char*buf,intsize,intrwflag,void*userdata)
862+
{
863+
/* same prompt as OpenSSL uses internally */
864+
constchar*prompt="Enter PEM pass phrase:";
865+
866+
Assert(rwflag==0);
867+
868+
returnrun_ssl_passphrase_command(prompt,ssl_is_server_start,buf,size);
869+
}
870+
871+
/*
872+
* Dummy passphrase callback
843873
*
844874
* If OpenSSL is told to use a passphrase-protected server key, by default
845875
* it will issue a prompt on /dev/tty and try to read a key from there.
@@ -848,10 +878,10 @@ load_dh_buffer(const char *buffer, size_t len)
848878
* function that just returns an empty passphrase, guaranteeing failure.
849879
*/
850880
staticint
851-
ssl_passwd_cb(char*buf,intsize,intrwflag,void*userdata)
881+
dummy_ssl_passwd_cb(char*buf,intsize,intrwflag,void*userdata)
852882
{
853883
/* Set flag to change the error message we'll report */
854-
ssl_passwd_cb_called= true;
884+
dummy_ssl_passwd_cb_called= true;
855885
/* And return empty string */
856886
Assert(size>0);
857887
buf[0]='\0';

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ char *ssl_key_file;
4545
char*ssl_ca_file;
4646
char*ssl_crl_file;
4747
char*ssl_dh_params_file;
48+
char*ssl_passphrase_command;
49+
boolssl_passphrase_command_supports_reload;
4850

4951
#ifdefUSE_SSL
5052
boolssl_loaded_verify_locations= false;

‎src/backend/utils/misc/guc.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,15 @@ static struct config_bool ConfigureNamesBool[] =
988988
false,
989989
check_ssl,NULL,NULL
990990
},
991+
{
992+
{"ssl_passphrase_command_supports_reload",PGC_SIGHUP,CONN_AUTH_SSL,
993+
gettext_noop("Also use ssl_passphrase_command during server reload."),
994+
NULL
995+
},
996+
&ssl_passphrase_command_supports_reload,
997+
false,
998+
NULL,NULL,NULL
999+
},
9911000
{
9921001
{"ssl_prefer_server_ciphers",PGC_SIGHUP,CONN_AUTH_SSL,
9931002
gettext_noop("Give priority to server ciphersuite order."),
@@ -3655,6 +3664,16 @@ static struct config_string ConfigureNamesString[] =
36553664
NULL,NULL,NULL
36563665
},
36573666

3667+
{
3668+
{"ssl_passphrase_command",PGC_SIGHUP,CONN_AUTH_SSL,
3669+
gettext_noop("Command to obtain passphrases for SSL."),
3670+
NULL
3671+
},
3672+
&ssl_passphrase_command,
3673+
"",
3674+
NULL,NULL,NULL
3675+
},
3676+
36583677
{
36593678
{"application_name",PGC_USERSET,LOGGING_WHAT,
36603679
gettext_noop("Sets the application name to be reported in statistics and logs."),

‎src/backend/utils/misc/postgresql.conf.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
#ssl_prefer_server_ciphers = on
105105
#ssl_ecdh_curve = 'prime256v1'
106106
#ssl_dh_params_file = ''
107+
#ssl_passphrase_command = ''
108+
#ssl_passphrase_command_supports_reload = off
107109

108110

109111
#------------------------------------------------------------------------------

‎src/include/libpq/libpq.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ extern char *ssl_key_file;
8080
externchar*ssl_ca_file;
8181
externchar*ssl_crl_file;
8282
externchar*ssl_dh_params_file;
83+
externchar*ssl_passphrase_command;
84+
externboolssl_passphrase_command_supports_reload;
8385

8486
externintsecure_initialize(boolisServerStart);
8587
externboolsecure_loaded_verify_locations(void);
@@ -101,4 +103,10 @@ extern char *SSLCipherSuites;
101103
externchar*SSLECDHCurve;
102104
externboolSSLPreferServerCiphers;
103105

106+
/*
107+
* prototypes for functions in be-secure-common.c
108+
*/
109+
externintrun_ssl_passphrase_command(constchar*prompt,boolis_server_start,
110+
char*buf,intsize);
111+
104112
#endif/* LIBPQ_H */

‎src/test/ssl/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ CERTIFICATES := server_ca server-cn-and-alt-names \
2222
root_ca
2323

2424
SSLFILES :=$(CERTIFICATES:%=ssl/%.key)$(CERTIFICATES:%=ssl/%.crt)\
25+
ssl/server-password.key\
2526
ssl/client.crl ssl/server.crl ssl/root.crl\
2627
ssl/both-cas-1.crt ssl/both-cas-2.crt\
2728
ssl/root+server_ca.crt ssl/root+server.crl\
@@ -71,6 +72,10 @@ ssl/server-ss.crt: ssl/server-cn-only.key ssl/server-cn-only.crt server-cn-only.
7172
openssl x509 -req -days 10000 -in ssl/server-ss.csr -signkey ssl/server-cn-only.key -out ssl/server-ss.crt -extensions v3_req -extfile server-cn-only.config
7273
rm ssl/server-ss.csr
7374

75+
# Password-protected version of server-cn-only.key
76+
ssl/server-password.key: ssl/server-cn-only.key
77+
openssl rsa -des -in$< -out$@ -passout'pass:secret1'
78+
7479
# Client certificate, signed by the client CA:
7580
ssl/client.crt: ssl/client.key ssl/client_ca.crt
7681
openssl req -new -key ssl/client.key -out ssl/client.csr -config client.config

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp