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

Commit1957042

Browse files
committed
UPDATED PATCH:
Attached are a revised set of SSL patches. Many of these patchesare motivated by security concerns, it's not just bug fixes. The keydifferences (from stock 7.2.1) are:*) almost all code that directly uses the OpenSSL library is in two new files, src/interfaces/libpq/fe-ssl.c src/backend/postmaster/be-ssl.c in the long run, it would be nice to merge these two files.*) the legacy code to read and write network data have been encapsulated into read_SSL() and write_SSL(). These functions should probably be renamed - they handle both SSL and non-SSL cases. the remaining code should eliminate the problems identified earlier, albeit not very cleanly.*) both front- and back-ends will send a SSL shutdown via the new close_SSL() function. This is necessary for sessions to work properly. (Sessions are not yet fully supported, but by cleanly closing the SSL connection instead of just sending a TCP FIN packet other SSL tools will be much happier.)*) The client certificate and key are now expected in a subdirectory of the user's home directory. Specifically,- the directory .postgresql must be owned by the user, and allow no access by 'group' or 'other.'- the file .postgresql/postgresql.crt must be a regular file owned by the user.- the file .postgresql/postgresql.key must be a regular file owned by the user, and allow no access by 'group' or 'other'. At the current time encrypted private keys are not supported. There should also be a way to support multiple client certs/keys.*) the front-end performs minimal validation of the back-end cert. Self-signed certs are permitted, but the common name *must* match the hostname used by the front-end. (The cert itself should always use a fully qualified domain name (FDQN) in its common name field.) This means that psql -h eris db will fail, but psql -h eris.example.com db will succeed. At the current time this must be an exact match; future patches may support any FQDN that resolves to the address returned by getpeername(2). Another common "problem" is expiring certs. For now, it may be a good idea to use a very-long-lived self-signed cert. As a compile-time option, the front-end can specify a file containing valid root certificates, but it is not yet required.*) the back-end performs minimal validation of the client cert. It allows self-signed certs. It checks for expiration. It supports a compile-time option specifying a file containing valid root certificates.*) both front- and back-ends default to TLSv1, not SSLv3/SSLv2.*) both front- and back-ends support DSA keys. DSA keys are moderately more expensive on startup, but many people consider them preferable than RSA keys. (E.g., SSH2 prefers DSA keys.)*) if /dev/urandom exists, both client and server will read 16k of randomization data from it.*) the server can read empheral DH parameters from the files $DataDir/dh512.pem $DataDir/dh1024.pem $DataDir/dh2048.pem $DataDir/dh4096.pem if none are provided, the server will default to hardcoded parameter files provided by the OpenSSL project.Remaining tasks:*) the select() clauses need to be revisited - the SSL abstraction layer may need to absorb more of the current code to avoid rare deadlock conditions. This also touches on a true solution to the pg_eof() problem.*) the SIGPIPE signal handler may need to be revisited.*) support encrypted private keys.*) sessions are not yet fully supported. (SSL sessions can span multiple "connections," and allow the client and server to avoid costly renegotiations.)*) makecert - a script that creates back-end certs.*) pgkeygen - a tool that creates front-end certs.*) the whole protocol issue, SASL, etc. *) certs are fully validated - valid root certs must be available. This is a hassle, but it means that you *can* trust the identity of the server. *) the client library can handle hardcoded root certificates, to avoid the need to copy these files. *) host name of server cert must resolve to IP address, or be a recognized alias. This is more liberal than the previous iteration. *) the number of bytes transferred is tracked, and the session key is periodically renegotiated. *) basic cert generation scripts (mkcert.sh, pgkeygen.sh). The configuration files have reasonable defaults for each type of use.Bear Giles
1 parenteb43af3 commit1957042

File tree

9 files changed

+996
-211
lines changed

9 files changed

+996
-211
lines changed

‎src/backend/libpq/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Makefile for libpq subsystem (backend half of libpq interface)
55
#
66
# IDENTIFICATION
7-
# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.32 2002/06/14 04:09:36 momjian Exp $
7+
# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.33 2002/06/14 04:23:17 momjian Exp $
88
#
99
#-------------------------------------------------------------------------
1010

@@ -14,7 +14,8 @@ include $(top_builddir)/src/Makefile.global
1414

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

17-
OBJS = be-fsstubs.o auth.o crypt.o hba.o md5.o pqcomm.o pqformat.o pqsignal.o
17+
OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o md5.o pqcomm.o\
18+
pqformat.o pqsignal.o
1819

1920

2021
all: SUBSYS.o

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

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* be-connect.c
4+
* functions related to setting up a secure connection to the frontend.
5+
* Secure connections are expected to provide confidentiality,
6+
* message integrity and endpoint authentication.
7+
*
8+
*
9+
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
10+
* Portions Copyright (c) 1994, Regents of the University of California
11+
*
12+
*
13+
* IDENTIFICATION
14+
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.1 2002/06/14 04:23:17 momjian Exp $
15+
*
16+
* PATCH LEVEL
17+
* milestone 1: fix basic coding errors
18+
* [*] existing SSL code pulled out of existing files.
19+
* [*] SSL_get_error() after SSL_read() and SSL_write(),
20+
* SSL_shutdown(), default to TLSv1.
21+
*
22+
* milestone 2: provide endpoint authentication (server)
23+
* [*] client verifies server cert
24+
* [*] client verifies server hostname
25+
*
26+
* milestone 3: improve confidentially, support perfect forward secrecy
27+
* [ ] use 'random' file, read from '/dev/urandom?'
28+
* [ ] emphermal DH keys, default values
29+
* [ ] periodic renegotiation
30+
*
31+
* milestone 4: provide endpoint authentication (client)
32+
* [ ] server verifies client certificates
33+
*
34+
* milestone 5: provide informational callbacks
35+
* [ ] provide informational callbacks
36+
*
37+
* other changes
38+
* [ ] tcp-wrappers
39+
* [ ] more informative psql
40+
*
41+
*-------------------------------------------------------------------------
42+
*/
43+
44+
#include"postgres.h"
45+
46+
#include<sys/types.h>
47+
#include<signal.h>
48+
#include<fcntl.h>
49+
#include<errno.h>
50+
#include<ctype.h>
51+
52+
#include"libpq/libpq.h"
53+
#include"libpq/pqsignal.h"
54+
#include"miscadmin.h"
55+
56+
#ifdefWIN32
57+
#include"win32.h"
58+
#else
59+
#include<sys/socket.h>
60+
#include<unistd.h>
61+
#include<netdb.h>
62+
#include<netinet/in.h>
63+
#ifdefHAVE_NETINET_TCP_H
64+
#include<netinet/tcp.h>
65+
#endif
66+
#include<arpa/inet.h>
67+
#endif
68+
69+
70+
#ifndefHAVE_STRDUP
71+
#include"strdup.h"
72+
#endif
73+
74+
#ifdefUSE_SSL
75+
#include<openssl/ssl.h>
76+
#include<openssl/e_os.h>
77+
#endif
78+
79+
externvoidExitPostmaster(int);
80+
externvoidpostmaster_error(constchar*fmt,...);
81+
82+
intsecure_initialize(void);
83+
voidsecure_destroy(void);
84+
intsecure_open_server(Port*);
85+
voidsecure_close(Port*);
86+
ssize_tsecure_read(Port*,void*ptr,size_tlen);
87+
ssize_tsecure_write(Port*,constvoid*ptr,size_tlen);
88+
89+
#ifdefUSE_SSL
90+
staticintinitialize_SSL(void);
91+
staticvoiddestroy_SSL(void);
92+
staticintopen_server_SSL(Port*);
93+
staticvoidclose_SSL(Port*);
94+
staticconstchar*SSLerrmessage(void);
95+
#endif
96+
97+
#ifdefUSE_SSL
98+
staticSSL_CTX*SSL_context=NULL;
99+
#endif
100+
101+
/* ------------------------------------------------------------ */
102+
/* Procedures common to all secure sessions */
103+
/* ------------------------------------------------------------ */
104+
105+
/*
106+
*Initialize global context
107+
*/
108+
int
109+
secure_initialize (void)
110+
{
111+
intr=0;
112+
113+
#ifdefUSE_SSL
114+
r=initialize_SSL();
115+
#endif
116+
117+
returnr;
118+
}
119+
120+
/*
121+
*Destroy global context
122+
*/
123+
void
124+
secure_destroy (void)
125+
{
126+
#ifdefUSE_SSL
127+
destroy_SSL();
128+
#endif
129+
}
130+
131+
/*
132+
*Attempt to negotiate secure session.
133+
*/
134+
int
135+
secure_open_server (Port*port)
136+
{
137+
intr=0;
138+
139+
#ifdefUSE_SSL
140+
r=open_server_SSL(port);
141+
#endif
142+
143+
returnr;
144+
}
145+
146+
/*
147+
*Close secure session.
148+
*/
149+
void
150+
secure_close (Port*port)
151+
{
152+
#ifdefUSE_SSL
153+
if (port->ssl)
154+
close_SSL(port);
155+
#endif
156+
}
157+
158+
/*
159+
*Read data from a secure connection.
160+
*/
161+
ssize_t
162+
secure_read (Port*port,void*ptr,size_tlen)
163+
{
164+
ssize_tn;
165+
166+
#ifdefUSE_SSL
167+
if (port->ssl)
168+
{
169+
n=SSL_read(port->ssl,ptr,len);
170+
switch (SSL_get_error(port->ssl,n))
171+
{
172+
caseSSL_ERROR_NONE:
173+
break;
174+
caseSSL_ERROR_WANT_READ:
175+
break;
176+
caseSSL_ERROR_SYSCALL:
177+
errno=get_last_socket_error();
178+
elog(ERROR,"SSL SYSCALL error: %s",strerror(errno));
179+
break;
180+
caseSSL_ERROR_SSL:
181+
elog(ERROR,"SSL error: %s",SSLerrmessage());
182+
/* fall through */
183+
caseSSL_ERROR_ZERO_RETURN:
184+
secure_close(port);
185+
errno=ECONNRESET;
186+
n=-1;
187+
break;
188+
}
189+
}
190+
else
191+
#endif
192+
n=recv(port->sock,ptr,len,0);
193+
194+
returnn;
195+
}
196+
197+
/*
198+
*Write data to a secure connection.
199+
*/
200+
ssize_t
201+
secure_write (Port*port,constvoid*ptr,size_tlen)
202+
{
203+
ssize_tn;
204+
205+
#ifndefWIN32
206+
pqsigfuncoldsighandler=pqsignal(SIGPIPE,SIG_IGN);
207+
#endif
208+
209+
#ifdefUSE_SSL
210+
if (port->ssl)
211+
{
212+
n=SSL_write(port->ssl,ptr,len);
213+
switch (SSL_get_error(port->ssl,n))
214+
{
215+
caseSSL_ERROR_NONE:
216+
break;
217+
caseSSL_ERROR_WANT_WRITE:
218+
break;
219+
caseSSL_ERROR_SYSCALL:
220+
errno=get_last_socket_error();
221+
elog(ERROR,"SSL SYSCALL error: %s",strerror(errno));
222+
break;
223+
caseSSL_ERROR_SSL:
224+
elog(ERROR,"SSL error: %s",SSLerrmessage());
225+
/* fall through */
226+
caseSSL_ERROR_ZERO_RETURN:
227+
secure_close(port);
228+
errno=ECONNRESET;
229+
n=-1;
230+
break;
231+
}
232+
}
233+
else
234+
#endif
235+
n=send(port->sock,ptr,len,0);
236+
237+
#ifndefWIN32
238+
pqsignal(SIGPIPE,oldsighandler);
239+
#endif
240+
241+
returnn;
242+
}
243+
244+
/* ------------------------------------------------------------ */
245+
/* SSL specific code */
246+
/* ------------------------------------------------------------ */
247+
#ifdefUSE_SSL
248+
/*
249+
*Initialize global SSL context.
250+
*/
251+
staticint
252+
initialize_SSL (void)
253+
{
254+
charfnbuf[2048];
255+
256+
if (!SSL_context)
257+
{
258+
SSL_library_init();
259+
SSL_load_error_strings();
260+
SSL_context=SSL_CTX_new(TLSv1_method());
261+
if (!SSL_context)
262+
{
263+
postmaster_error("failed to create SSL context: %s",
264+
SSLerrmessage());
265+
ExitPostmaster(1);
266+
}
267+
268+
/*
269+
*Load and verify certificate and private key
270+
*/
271+
snprintf(fnbuf,sizeof(fnbuf),"%s/server.crt",DataDir);
272+
if (!SSL_CTX_use_certificate_file(SSL_context,fnbuf,SSL_FILETYPE_PEM))
273+
{
274+
postmaster_error("failed to load server certificate (%s): %s",
275+
fnbuf,SSLerrmessage());
276+
ExitPostmaster(1);
277+
}
278+
snprintf(fnbuf,sizeof(fnbuf),"%s/server.key",DataDir);
279+
if (!SSL_CTX_use_PrivateKey_file(SSL_context,fnbuf,SSL_FILETYPE_PEM))
280+
{
281+
postmaster_error("failed to load private key file (%s): %s",
282+
fnbuf,SSLerrmessage());
283+
ExitPostmaster(1);
284+
}
285+
if (!SSL_CTX_check_private_key(SSL_context))
286+
{
287+
postmaster_error("check of private key failed: %s",
288+
SSLerrmessage());
289+
ExitPostmaster(1);
290+
}
291+
}
292+
293+
return0;
294+
}
295+
296+
/*
297+
*Destroy global SSL context.
298+
*/
299+
staticvoid
300+
destroy_SSL (void)
301+
{
302+
if (SSL_context)
303+
{
304+
SSL_CTX_free(SSL_context);
305+
SSL_context=NULL;
306+
}
307+
}
308+
309+
/*
310+
*Attempt to negotiate SSL connection.
311+
*/
312+
staticint
313+
open_server_SSL (Port*port)
314+
{
315+
if (!(port->ssl=SSL_new(SSL_context))||
316+
!SSL_set_fd(port->ssl,port->sock)||
317+
SSL_accept(port->ssl) <=0)
318+
{
319+
elog(ERROR,"failed to initialize SSL connection: %s",SSLerrmessage());
320+
close_SSL(port);
321+
return-1;
322+
}
323+
324+
return0;
325+
}
326+
327+
/*
328+
*Close SSL connection.
329+
*/
330+
staticvoid
331+
close_SSL (Port*port)
332+
{
333+
if (port->ssl)
334+
{
335+
SSL_shutdown(port->ssl);
336+
SSL_free(port->ssl);
337+
port->ssl=NULL;
338+
}
339+
}
340+
341+
/*
342+
* Obtain reason string for last SSL error
343+
*
344+
* Some caution is needed here since ERR_reason_error_string will
345+
* return NULL if it doesn't recognize the error code. We don't
346+
* want to return NULL ever.
347+
*/
348+
staticconstchar*
349+
SSLerrmessage(void)
350+
{
351+
unsigned longerrcode;
352+
constchar*errreason;
353+
staticcharerrbuf[32];
354+
355+
errcode=ERR_get_error();
356+
if (errcode==0)
357+
return"No SSL error reported";
358+
errreason=ERR_reason_error_string(errcode);
359+
if (errreason!=NULL)
360+
returnerrreason;
361+
snprintf(errbuf,sizeof(errbuf),"SSL error code %lu",errcode);
362+
returnerrbuf;
363+
}
364+
365+
#endif/* USE_SSL */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp