Attached are a revised set of SSL patches. Many of these patches
are motivated by security concerns, it's not just bug fixes. The key differences (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
This commit is contained in:
parent
15378a53f8
commit
a9bd17616e
@ -4,7 +4,7 @@
|
||||
# Makefile for libpq subsystem (backend half of libpq interface)
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.30 2002/04/04 04:25:46 momjian Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.31 2002/06/14 03:56:46 momjian Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -14,7 +14,8 @@ include $(top_builddir)/src/Makefile.global
|
||||
|
||||
# be-fsstubs is here for historical reasons, probably belongs elsewhere
|
||||
|
||||
OBJS = be-fsstubs.o auth.o crypt.o hba.o md5.o pqcomm.o pqformat.o pqsignal.o
|
||||
OBJS = be-fsstubs.o be-ssl.o auth.o crypt.o hba.o md5.o pqcomm.o \
|
||||
pqformat.o pqsignal.o
|
||||
|
||||
|
||||
all: SUBSYS.o
|
||||
|
@ -29,7 +29,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.c,v 1.133 2002/05/05 00:03:28 tgl Exp $
|
||||
* $Id: pqcomm.c,v 1.134 2002/06/14 03:56:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -81,6 +81,14 @@
|
||||
#include "miscadmin.h"
|
||||
#include "storage/ipc.h"
|
||||
|
||||
/* these functions are misnamed - they handle both SSL and non-SSL case */
|
||||
extern ssize_t read_SSL(Port *, void *ptr, size_t len);
|
||||
extern ssize_t write_SSL(Port *, const void *ptr, size_t len);
|
||||
|
||||
#ifdef USE_SSL
|
||||
extern void close_SSL(Port *);
|
||||
#endif /* USE_SSL */
|
||||
|
||||
|
||||
static void pq_close(void);
|
||||
|
||||
@ -138,6 +146,9 @@ pq_close(void)
|
||||
{
|
||||
if (MyProcPort != NULL)
|
||||
{
|
||||
#ifdef USE_SSL
|
||||
close_SSL(MyProcPort);
|
||||
#endif /* USE_SSL */
|
||||
close(MyProcPort->sock);
|
||||
/* make sure any subsequent attempts to do I/O fail cleanly */
|
||||
MyProcPort->sock = -1;
|
||||
@ -416,6 +427,7 @@ StreamConnection(int server_fd, Port *port)
|
||||
void
|
||||
StreamClose(int sock)
|
||||
{
|
||||
/* FIXME - what about closing SSL connections? */
|
||||
close(sock);
|
||||
}
|
||||
|
||||
@ -457,14 +469,8 @@ pq_recvbuf(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (MyProcPort->ssl)
|
||||
r = SSL_read(MyProcPort->ssl, PqRecvBuffer + PqRecvLength,
|
||||
r = read_SSL(MyProcPort, PqRecvBuffer + PqRecvLength,
|
||||
PQ_BUFFER_SIZE - PqRecvLength);
|
||||
else
|
||||
#endif
|
||||
r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
|
||||
PQ_BUFFER_SIZE - PqRecvLength, 0);
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
@ -480,7 +486,11 @@ pq_recvbuf(void)
|
||||
elog(COMMERROR, "pq_recvbuf: recv() failed: %m");
|
||||
return EOF;
|
||||
}
|
||||
#ifdef USE_SSL
|
||||
if (r == 0 && !MyProcPort->ssl)
|
||||
#else /* USE_SSL */
|
||||
if (r == 0)
|
||||
#endif /* USE_SSL */
|
||||
{
|
||||
/* as above, only write to postmaster log */
|
||||
elog(COMMERROR, "pq_recvbuf: unexpected EOF on client connection");
|
||||
@ -651,14 +661,13 @@ pq_flush(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (MyProcPort->ssl)
|
||||
r = SSL_write(MyProcPort->ssl, bufptr, bufend - bufptr);
|
||||
else
|
||||
#endif
|
||||
r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
|
||||
r = write_SSL(MyProcPort, bufptr, bufend - bufptr);
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (r < 0 || (r == 0 && !MyProcPort->ssl))
|
||||
#else /* USE_SSL */
|
||||
if (r <= 0)
|
||||
#endif /* USE_SSL */
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue; /* Ok if we were interrupted */
|
||||
@ -703,8 +712,9 @@ int
|
||||
pq_eof(void)
|
||||
{
|
||||
char x;
|
||||
int res;
|
||||
int res = 1;
|
||||
|
||||
#ifndef USE_SSL /* not a good solution, but better than nothing */
|
||||
res = recv(MyProcPort->sock, &x, 1, MSG_PEEK);
|
||||
|
||||
if (res < 0)
|
||||
@ -713,6 +723,8 @@ pq_eof(void)
|
||||
elog(COMMERROR, "pq_eof: recv() failed: %m");
|
||||
return EOF;
|
||||
}
|
||||
#endif /* USE_SSL */
|
||||
|
||||
if (res == 0)
|
||||
return EOF;
|
||||
else
|
||||
|
@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.276 2002/06/11 13:40:51 wieck Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.277 2002/06/14 03:56:47 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@ -165,10 +165,6 @@ static int ServerSock_INET = INVALID_SOCK; /* stream socket server */
|
||||
static int ServerSock_UNIX = INVALID_SOCK; /* stream socket server */
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSL
|
||||
static SSL_CTX *SSL_context = NULL; /* Global SSL context */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set by the -o option
|
||||
*/
|
||||
@ -274,8 +270,10 @@ __attribute__((format(printf, 1, 2)));
|
||||
#define ShutdownDataBase() SSDataBase(BS_XLOG_SHUTDOWN)
|
||||
|
||||
#ifdef USE_SSL
|
||||
static void InitSSL(void);
|
||||
static const char *SSLerrmessage(void);
|
||||
extern int initialize_ctx(const char *, void (*err)(const char *fmt,...));
|
||||
extern void destroy_ctx(void);
|
||||
extern int open_SSL_server(Port *);
|
||||
extern void close_SSL(Port *);
|
||||
#endif
|
||||
|
||||
|
||||
@ -609,7 +607,10 @@ PostmasterMain(int argc, char *argv[])
|
||||
ExitPostmaster(1);
|
||||
}
|
||||
if (EnableSSL)
|
||||
InitSSL();
|
||||
{
|
||||
if (initialize_ctx(NULL, postmaster_error) == -1)
|
||||
ExitPostmaster(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -1115,12 +1116,8 @@ ProcessStartupPacket(Port *port, bool SSLdone)
|
||||
#ifdef USE_SSL
|
||||
if (SSLok == 'S')
|
||||
{
|
||||
if (!(port->ssl = SSL_new(SSL_context)) ||
|
||||
!SSL_set_fd(port->ssl, port->sock) ||
|
||||
SSL_accept(port->ssl) <= 0)
|
||||
if (open_SSL_server(port) != STATUS_OK)
|
||||
{
|
||||
elog(LOG, "failed to initialize SSL connection: %s (%m)",
|
||||
SSLerrmessage());
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
@ -1322,9 +1319,10 @@ static void
|
||||
ConnFree(Port *conn)
|
||||
{
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
SSL_free(conn->ssl);
|
||||
close_SSL(conn);
|
||||
#endif
|
||||
if (conn->sock != -1)
|
||||
close(conn->sock);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
@ -2424,72 +2422,6 @@ CountChildren(void)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#ifdef USE_SSL
|
||||
|
||||
/*
|
||||
* Initialize SSL library and structures
|
||||
*/
|
||||
static void
|
||||
InitSSL(void)
|
||||
{
|
||||
char fnbuf[2048];
|
||||
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
SSL_context = SSL_CTX_new(SSLv23_method());
|
||||
if (!SSL_context)
|
||||
{
|
||||
postmaster_error("failed to create SSL context: %s",
|
||||
SSLerrmessage());
|
||||
ExitPostmaster(1);
|
||||
}
|
||||
snprintf(fnbuf, sizeof(fnbuf), "%s/server.crt", DataDir);
|
||||
if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
|
||||
{
|
||||
postmaster_error("failed to load server certificate (%s): %s",
|
||||
fnbuf, SSLerrmessage());
|
||||
ExitPostmaster(1);
|
||||
}
|
||||
snprintf(fnbuf, sizeof(fnbuf), "%s/server.key", DataDir);
|
||||
if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
|
||||
{
|
||||
postmaster_error("failed to load private key file (%s): %s",
|
||||
fnbuf, SSLerrmessage());
|
||||
ExitPostmaster(1);
|
||||
}
|
||||
if (!SSL_CTX_check_private_key(SSL_context))
|
||||
{
|
||||
postmaster_error("check of private key failed: %s",
|
||||
SSLerrmessage());
|
||||
ExitPostmaster(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain reason string for last SSL error
|
||||
*
|
||||
* Some caution is needed here since ERR_reason_error_string will
|
||||
* return NULL if it doesn't recognize the error code. We don't
|
||||
* want to return NULL ever.
|
||||
*/
|
||||
static const char *
|
||||
SSLerrmessage(void)
|
||||
{
|
||||
unsigned long errcode;
|
||||
const char *errreason;
|
||||
static char errbuf[32];
|
||||
|
||||
errcode = ERR_get_error();
|
||||
if (errcode == 0)
|
||||
return "No SSL error reported";
|
||||
errreason = ERR_reason_error_string(errcode);
|
||||
if (errreason != NULL)
|
||||
return errreason;
|
||||
snprintf(errbuf, sizeof(errbuf), "SSL error code %lu", errcode);
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
#endif /* USE_SSL */
|
||||
|
||||
/*
|
||||
* Fire off a subprocess for startup/shutdown/checkpoint.
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.57 2002/05/14 04:20:15 ishii Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.58 2002/06/14 03:56:47 momjian Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
|
||||
@ -678,14 +678,33 @@ printSSLInfo(void)
|
||||
{
|
||||
int sslbits = -1;
|
||||
SSL *ssl;
|
||||
X509 *peer;
|
||||
char sn[256];
|
||||
long l;
|
||||
|
||||
ssl = PQgetssl(pset.db);
|
||||
if (!ssl)
|
||||
return; /* no SSL */
|
||||
|
||||
/* peer = pset.db.peer; */
|
||||
if ((peer = SSL_get_peer_certificate(ssl)) != NULL)
|
||||
{
|
||||
X509_NAME_oneline(X509_get_subject_name(peer), sn, sizeof sn);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(sn, "(anonymous)", sizeof sn);
|
||||
}
|
||||
printf(gettext("SSL connection\n"));
|
||||
printf(gettext("(host: %s)\n"), sn);
|
||||
|
||||
SSL_get_cipher_bits(ssl, &sslbits);
|
||||
printf(gettext("SSL connection (cipher: %s, bits: %i)\n\n"),
|
||||
printf(gettext("(protocol: %s)\n"), SSL_get_version(ssl)),
|
||||
printf(gettext("(cipher: %s, bits: %i)\n"),
|
||||
SSL_get_cipher(ssl), sslbits);
|
||||
l = SSL_get_default_timeout(ssl);
|
||||
printf(gettext("(timeout: %ld:%02ld:%02ld)\n\n"),
|
||||
l / 3600L, (l / 60L) % 60L, l % 60L);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-be.h,v 1.27 2001/11/12 05:43:25 tgl Exp $
|
||||
* $Id: libpq-be.h,v 1.28 2002/06/14 03:56:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -70,6 +70,7 @@ typedef struct Port
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
SSL *ssl;
|
||||
X509 *peer;
|
||||
#endif
|
||||
} Port;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.59 2001/09/22 22:54:32 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.60 2002/06/14 03:56:47 momjian Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -20,7 +20,7 @@ SO_MINOR_VERSION= 2
|
||||
override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"'
|
||||
|
||||
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
|
||||
pqexpbuffer.o dllist.o md5.o pqsignal.o \
|
||||
pqexpbuffer.o dllist.o md5.o pqsignal.o fe-ssl.o \
|
||||
$(INET_ATON) $(SNPRINTF) $(STRERROR)
|
||||
|
||||
ifdef MULTIBYTE
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.183 2002/04/15 23:34:17 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.184 2002/06/14 03:56:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -62,10 +62,6 @@ inet_aton(const char *cp, struct in_addr * inp)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_SSL
|
||||
static SSL_CTX *SSL_context = NULL;
|
||||
#endif
|
||||
|
||||
#define NOTIFYLIST_INITIAL_SIZE 10
|
||||
#define NOTIFYLIST_GROWBY 10
|
||||
|
||||
@ -186,8 +182,13 @@ static char *conninfo_getval(PQconninfoOption *connOptions,
|
||||
static void defaultNoticeProcessor(void *arg, const char *message);
|
||||
static int parseServiceInfo(PQconninfoOption *options,
|
||||
PQExpBuffer errorMessage);
|
||||
|
||||
#ifdef USE_SSL
|
||||
static const char *SSLerrmessage(void);
|
||||
extern int initialize_ctx(const char *passwd, void (*err)(const char *fmt,...), PGconn *);
|
||||
extern void destroy_ctx(PGconn *);
|
||||
extern int open_SSL_client(PGconn *);
|
||||
extern void close_SSL(PGconn *);
|
||||
extern SSL *PQgetssl(PGconn *);
|
||||
#endif
|
||||
|
||||
|
||||
@ -969,28 +970,10 @@ retry2:
|
||||
}
|
||||
if (SSLok == 'S')
|
||||
{
|
||||
if (!SSL_context)
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
SSL_context = SSL_CTX_new(SSLv23_method());
|
||||
if (!SSL_context)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not create SSL context: %s\n"),
|
||||
SSLerrmessage());
|
||||
if (initialize_ctx(NULL, NULL, conn) == -1)
|
||||
goto connect_errReturn;
|
||||
}
|
||||
}
|
||||
if (!(conn->ssl = SSL_new(SSL_context)) ||
|
||||
!SSL_set_fd(conn->ssl, conn->sock) ||
|
||||
SSL_connect(conn->ssl) <= 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not establish SSL connection: %s\n"),
|
||||
SSLerrmessage());
|
||||
if (open_SSL_client(conn) == -1)
|
||||
goto connect_errReturn;
|
||||
}
|
||||
/* SSL connection finished. Continue to send startup packet */
|
||||
}
|
||||
else if (SSLok == 'E')
|
||||
@ -1015,7 +998,7 @@ retry2:
|
||||
goto connect_errReturn;
|
||||
}
|
||||
}
|
||||
if (conn->require_ssl && !conn->ssl)
|
||||
if (conn->require_ssl && !PQgetssl(conn))
|
||||
{
|
||||
/* Require SSL, but server does not support/want it */
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
@ -1914,8 +1897,7 @@ freePGconn(PGconn *conn)
|
||||
return;
|
||||
pqClearAsyncResult(conn); /* deallocate result and curTuple */
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
SSL_free(conn->ssl);
|
||||
close_SSL(conn);
|
||||
#endif
|
||||
if (conn->sock >= 0)
|
||||
{
|
||||
@ -2641,35 +2623,6 @@ PQconninfoFree(PQconninfoOption *connOptions)
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_SSL
|
||||
|
||||
/*
|
||||
* Obtain reason string for last SSL error
|
||||
*
|
||||
* Some caution is needed here since ERR_reason_error_string will
|
||||
* return NULL if it doesn't recognize the error code. We don't
|
||||
* want to return NULL ever.
|
||||
*/
|
||||
static const char *
|
||||
SSLerrmessage(void)
|
||||
{
|
||||
unsigned long errcode;
|
||||
const char *errreason;
|
||||
static char errbuf[32];
|
||||
|
||||
errcode = ERR_get_error();
|
||||
if (errcode == 0)
|
||||
return "No SSL error reported";
|
||||
errreason = ERR_reason_error_string(errcode);
|
||||
if (errreason != NULL)
|
||||
return errreason;
|
||||
snprintf(errbuf, sizeof(errbuf), "SSL error code %lu", errcode);
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
#endif /* USE_SSL */
|
||||
|
||||
|
||||
/* =========== accessor functions for PGconn ========= */
|
||||
char *
|
||||
PQdb(const PGconn *conn)
|
||||
@ -2814,16 +2767,6 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSL
|
||||
SSL *
|
||||
PQgetssl(PGconn *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return NULL;
|
||||
return conn->ssl;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
PQtrace(PGconn *conn, FILE *debug_port)
|
||||
{
|
||||
|
@ -25,7 +25,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.70 2002/04/24 02:26:06 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.71 2002/06/14 03:56:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -55,6 +55,13 @@
|
||||
#include "mb/pg_wchar.h"
|
||||
#endif
|
||||
|
||||
/* these functions are misnamed - they handle both SSL and non-SSL case */
|
||||
extern ssize_t read_SSL (PGconn *, void *ptr, size_t);
|
||||
extern ssize_t write_SSL (PGconn *, const void *ptr, size_t);
|
||||
|
||||
#ifdef USE_SSL
|
||||
extern ssize_t close_SSL (PGconn *);
|
||||
#endif
|
||||
|
||||
#define DONOTICE(conn,message) \
|
||||
((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
|
||||
@ -477,14 +484,8 @@ pqReadData(PGconn *conn)
|
||||
|
||||
/* OK, try to read some data */
|
||||
retry3:
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
nread = SSL_read(conn->ssl, conn->inBuffer + conn->inEnd,
|
||||
nread = read_SSL(conn, conn->inBuffer + conn->inEnd,
|
||||
conn->inBufSize - conn->inEnd);
|
||||
else
|
||||
#endif
|
||||
nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
|
||||
conn->inBufSize - conn->inEnd, 0);
|
||||
if (nread < 0)
|
||||
{
|
||||
if (SOCK_ERRNO == EINTR)
|
||||
@ -563,14 +564,8 @@ retry3:
|
||||
* arrived.
|
||||
*/
|
||||
retry4:
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
nread = SSL_read(conn->ssl, conn->inBuffer + conn->inEnd,
|
||||
nread = read_SSL(conn, conn->inBuffer + conn->inEnd,
|
||||
conn->inBufSize - conn->inEnd);
|
||||
else
|
||||
#endif
|
||||
nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
|
||||
conn->inBufSize - conn->inEnd, 0);
|
||||
if (nread < 0)
|
||||
{
|
||||
if (SOCK_ERRNO == EINTR)
|
||||
@ -611,6 +606,9 @@ definitelyFailed:
|
||||
"\tThis probably means the server terminated abnormally\n"
|
||||
"\tbefore or while processing the request.\n"));
|
||||
conn->status = CONNECTION_BAD; /* No more connection to backend */
|
||||
#ifdef USE_SSL
|
||||
close_SSL(conn);
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
closesocket(conn->sock);
|
||||
#else
|
||||
@ -650,23 +648,9 @@ pqSendSome(PGconn *conn)
|
||||
/* while there's still data to send */
|
||||
while (len > 0)
|
||||
{
|
||||
/* Prevent being SIGPIPEd if backend has closed the connection. */
|
||||
#ifndef WIN32
|
||||
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
int sent;
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
sent = SSL_write(conn->ssl, ptr, len);
|
||||
else
|
||||
#endif
|
||||
sent = send(conn->sock, ptr, len, 0);
|
||||
|
||||
#ifndef WIN32
|
||||
pqsignal(SIGPIPE, oldsighandler);
|
||||
#endif
|
||||
sent = write_SSL(conn, ptr, len);
|
||||
|
||||
if (sent < 0)
|
||||
{
|
||||
@ -732,7 +716,7 @@ pqSendSome(PGconn *conn)
|
||||
*/
|
||||
#ifdef USE_SSL
|
||||
/* can't do anything for our SSL users yet */
|
||||
if (conn->ssl == NULL)
|
||||
if (PQgetssl(conn) == NULL)
|
||||
{
|
||||
#endif
|
||||
if (pqIsnonblocking(conn))
|
||||
|
785
src/interfaces/libpq/fe-ssl.c
Normal file
785
src/interfaces/libpq/fe-ssl.c
Normal file
@ -0,0 +1,785 @@
|
||||
#include "postgres_fe.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#include "libpq-int.h"
|
||||
#include "fe-auth.h"
|
||||
#include "pqsignal.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/e_os.h>
|
||||
|
||||
int initialize_ctx(const char *, void (*err)(const char *fmt,...), PGconn *);
|
||||
void destroy_ctx(void);
|
||||
int open_SSL_client(PGconn *);
|
||||
void close_SSL(PGconn *);
|
||||
SSL PGgetssl(PGconn *);
|
||||
static int clientCert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
|
||||
static int verify_cb(int, X509_STORE_CTX *);
|
||||
static void info_cb(SSL *ssl, int type, int args);
|
||||
static void load_hardcoded_certs(void);
|
||||
static X509 * load_cert_buffer(const char *buf, size_t len);
|
||||
static const char *SSLerrmessage(void);
|
||||
#endif
|
||||
|
||||
ssize_t read_SSL(PGconn *, void *, size_t);
|
||||
ssize_t write_SSL(PGconn *, const void *, size_t);
|
||||
|
||||
extern int h_error;
|
||||
|
||||
#ifdef USE_SSL
|
||||
static SSL_CTX *ctx = NULL;
|
||||
#endif
|
||||
|
||||
#define PING() fprintf(stderr,"%s, line %d, %s\n", __FILE__, __LINE__, __func__)
|
||||
|
||||
/*
|
||||
* Read data from network.
|
||||
*/
|
||||
ssize_t read_SSL (PGconn *conn, void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
{
|
||||
n = SSL_read(conn->ssl, ptr, len);
|
||||
switch (SSL_get_error(conn->ssl, n))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
SOCK_ERRNO = get_last_socket_error();
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
// log error...
|
||||
SOCK_ERRNO = ECONNRESET;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
SOCK_ERRNO = ECONNRESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* USE_SSL */
|
||||
n = recv(conn->sock, ptr, len, 0);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data to network.
|
||||
*/
|
||||
ssize_t write_SSL (PGconn *conn, const void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
/* prevent being SIGPIPEd if backend has closed the connection. */
|
||||
#ifndef WIN32
|
||||
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
{
|
||||
n = SSL_write(conn->ssl, ptr, len);
|
||||
switch (SSL_get_error(conn->ssl, n))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
SOCK_ERRNO = get_last_socket_error();
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
fprintf(stderr, "ssl error\n");
|
||||
// log error...
|
||||
SOCK_ERRNO = ECONNRESET;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
fprintf(stderr, "zero bytes\n");
|
||||
SOCK_ERRNO = ECONNRESET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
n = send(conn->sock, ptr, len, 0);
|
||||
|
||||
#ifndef WIN32
|
||||
pqsignal(SIGPIPE, oldsighandler);
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* Null authentication callback
|
||||
*/
|
||||
static int
|
||||
verify_cb (int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
char sn[256], buf[256];
|
||||
X509 *cert;
|
||||
int err, depth, n;
|
||||
BIO *bio;
|
||||
|
||||
cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth= X509_STORE_CTX_get_error_depth(ctx);
|
||||
|
||||
X509_NAME_oneline(X509_get_subject_name(cert), sn, sizeof sn);
|
||||
if (!ok)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
/* accept self-signed certs */
|
||||
// case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
// ok = 1;
|
||||
// break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "client cert %s: %s", sn,
|
||||
X509_verify_cert_error_string(err));
|
||||
}
|
||||
}
|
||||
|
||||
switch (ctx->error)
|
||||
{
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof buf);
|
||||
fprintf(stderr, "client cert %s: cannot find issuer %s", sn, buf);
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
ASN1_TIME_print(bio, X509_get_notBefore(cert));
|
||||
BIO_flush(bio);
|
||||
n = BIO_read(bio, buf, sizeof buf - 1);
|
||||
buf[n] = '\0';
|
||||
fprintf(stderr, "client cert %s: not valid until %s", sn, buf);
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
ASN1_TIME_print(bio, X509_get_notAfter(cert));
|
||||
BIO_flush(bio);
|
||||
n = BIO_read(bio, buf, sizeof buf - 1);
|
||||
buf[n] = '\0';
|
||||
fprintf(stderr, "client cert %s: not valid after %s\n", sn, buf);
|
||||
break;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback used by SSL to provide information messages.
|
||||
*/
|
||||
static void
|
||||
info_cb (SSL *ssl, int type, int args)
|
||||
{
|
||||
PGconn *conn = NULL;
|
||||
|
||||
conn = (PGconn *) SSL_get_app_data(ssl);
|
||||
if (conn == NULL || conn->Pfdebug == NULL)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SSL_CB_HANDSHAKE_START:
|
||||
fprintf(conn->Pfdebug, "Handshake start\n");
|
||||
break;
|
||||
case SSL_CB_HANDSHAKE_DONE:
|
||||
fprintf(conn->Pfdebug, "Handshake done\n");
|
||||
break;
|
||||
case SSL_CB_ACCEPT_LOOP:
|
||||
fprintf(conn->Pfdebug, "Accept loop...\n");
|
||||
break;
|
||||
case SSL_CB_ACCEPT_EXIT:
|
||||
fprintf(conn->Pfdebug, "Accept exit (%d)\n", args);
|
||||
break;
|
||||
case SSL_CB_CONNECT_LOOP:
|
||||
fprintf(conn->Pfdebug, "Connect loop...\n");
|
||||
break;
|
||||
case SSL_CB_CONNECT_EXIT:
|
||||
fprintf(conn->Pfdebug, "Connect exit (%d)\n", args);
|
||||
break;
|
||||
case SSL_CB_READ_ALERT:
|
||||
fprintf(conn->Pfdebug, "Read alert (0x%04x)\n", args);
|
||||
break;
|
||||
case SSL_CB_WRITE_ALERT:
|
||||
fprintf(conn->Pfdebug, "Write alert (0x%04x)\n", args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback used by SSL to load client cert and key.
|
||||
* At the current time we require the cert and key to be
|
||||
* located in the .postgresql directory under the user's
|
||||
* home directory, and the files must be named 'postgresql.crt'
|
||||
* and 'postgresql.key' respectively.
|
||||
*
|
||||
* returns 1 on success, 0 on no data, -1 on error.
|
||||
*/
|
||||
static int
|
||||
clientCert_cb (SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
||||
{
|
||||
uid_t uid;
|
||||
struct passwd *pwd;
|
||||
char fnbuf[2048];
|
||||
struct stat buf, buf1;
|
||||
FILE *fp;
|
||||
int (*cb)() = NULL;
|
||||
|
||||
if ((uid = getuid()) == -1)
|
||||
{
|
||||
fprintf(stderr, "can't get current uid\n");
|
||||
return -1;
|
||||
}
|
||||
if ((pwd = getpwuid(uid)) == NULL || !pwd->pw_dir)
|
||||
{
|
||||
fprintf(stderr, "can't get passwd entry\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* if $HOME/.postgresql does not exist, 'no data' case.
|
||||
* otherwise, it must be a directory, owned by current user,
|
||||
* and not group- or world-accessible.
|
||||
*/
|
||||
snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql", pwd->pw_dir);
|
||||
if (lstat(fnbuf, &buf) == -1)
|
||||
return 0;
|
||||
if (!S_ISDIR(buf.st_mode) || buf.st_uid != uid ||
|
||||
(buf.st_mode & (S_IRWXG | S_IRWXO)) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"$HOME/.postgresql directory has wrong ownership or permissions\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure $HOME/.postgresql/postgresql.crt file exists,
|
||||
* is regular file and owned by current user.
|
||||
*/
|
||||
snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/postgresql.crt",
|
||||
pwd->pw_dir);
|
||||
if (lstat(fnbuf, &buf) == -1)
|
||||
return 0;
|
||||
if (!S_ISREG(buf.st_mode) || buf.st_uid != uid)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"certificate file has wrong ownership or permissions\n");
|
||||
return -1;
|
||||
}
|
||||
if ((fp = fopen(fnbuf, "r")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "can't open certificate file (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
|
||||
{
|
||||
fprintf(stderr, "can't read certificate %s\n", SSLerrmessage());
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/*
|
||||
* make sure $HOME/.postgresql/postgresql.key file exists,
|
||||
* is regular file, owned by current user, and not group-
|
||||
* or world-accessable.
|
||||
*/
|
||||
snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/postgresql.key",
|
||||
pwd->pw_dir);
|
||||
if (lstat(fnbuf, &buf) == -1)
|
||||
{
|
||||
fprintf(stderr, "certificate file exists, but no private key\n");
|
||||
SSL_use_certificate(ssl, NULL);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISREG(buf.st_mode) || buf.st_uid != uid ||
|
||||
(buf.st_mode & (S_IRWXG | S_IRWXO)) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"private key file has wrong ownership or permissions\n");
|
||||
SSL_use_certificate(ssl, NULL);
|
||||
return -1;
|
||||
}
|
||||
if ((fp = fopen(fnbuf, "r")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "error opening private key file: %s\n",
|
||||
strerror(errno));
|
||||
SSL_use_certificate(ssl, NULL);
|
||||
return -1;
|
||||
}
|
||||
if (fstat(fileno(fp),&buf1) == -1 ||
|
||||
buf.st_dev != buf1.st_dev || buf.st_ino != buf1.st_ino)
|
||||
{
|
||||
fprintf(stderr, "private key changed under us!\n");
|
||||
fclose(fp);
|
||||
SSL_use_certificate(ssl, NULL);
|
||||
return -1;
|
||||
}
|
||||
if (PEM_read_PrivateKey(fp, pkey, cb, NULL) == NULL)
|
||||
{
|
||||
fprintf(stderr, "can't read private key %s\n", SSLerrmessage());
|
||||
fclose(fp);
|
||||
SSL_use_certificate(ssl, NULL);
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a root cert from a buffer. This allows us to avoid
|
||||
* needing to copy the root cert to deployed systems.
|
||||
*/
|
||||
static X509 *
|
||||
load_cert_buffer(const char *buf, size_t len)
|
||||
{
|
||||
BIO *bio;
|
||||
X509 *x;
|
||||
|
||||
bio = BIO_new_mem_buf((char *) buf, len);
|
||||
x = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize global SSL context.
|
||||
*
|
||||
* We want to use 'err' for errors, same as the corresponding
|
||||
* function on the server, but for now we use legacy error handler
|
||||
* in PGconn.
|
||||
*/
|
||||
int
|
||||
initialize_ctx (const char *password,
|
||||
void (*err)(const char * fmt,...), PGconn *conn)
|
||||
{
|
||||
SSL_METHOD *meth = NULL;
|
||||
struct stat buf;
|
||||
struct passwd *pwd;
|
||||
char fnbuf[2048];
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
// meth = SSLv23_method();
|
||||
meth = TLSv1_method();
|
||||
ctx = SSL_CTX_new(meth);
|
||||
|
||||
if (!ctx) {
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not create SSL context: %s\n"),
|
||||
SSLerrmessage());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* load any hard-coded root cert */
|
||||
load_hardcoded_certs();
|
||||
|
||||
/* load the CAs we trust */
|
||||
if ((pwd = getpwuid(getuid())) != NULL)
|
||||
{
|
||||
snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/root.crt", pwd->pw_dir);
|
||||
if (stat(fnbuf, &buf) != -1)
|
||||
{
|
||||
if (!SSL_CTX_load_verify_locations(ctx, fnbuf, 0))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not read CA list (%s): %s\n"),
|
||||
fnbuf, SSLerrmessage());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* load randomness */
|
||||
#ifdef RANDOM
|
||||
if (!RAND_load_file(RANDOM, 1024 * 1024))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not load randomness (%s): %s\n"),
|
||||
RANDOM, SSLerrmessage());
|
||||
return -1;
|
||||
}
|
||||
#else /* RANDOM */
|
||||
if (lstat("/dev/urandom", &buf) == 0 && S_ISCHR(buf.st_mode))
|
||||
{
|
||||
if (!RAND_load_file("/dev/urandom", 16 * 1024))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not load randomness (%s): %s\n"),
|
||||
"/dev/urandom", SSLerrmessage());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* RANDOM */
|
||||
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
|
||||
SSL_CTX_set_verify_depth(ctx, 1);
|
||||
|
||||
SSL_CTX_set_info_callback(ctx, info_cb);
|
||||
SSL_CTX_set_client_cert_cb(ctx, clientCert_cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the global SSL context.
|
||||
*/
|
||||
void destroy_ctx (void)
|
||||
{
|
||||
SSL_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a SSL connection.
|
||||
*/
|
||||
int
|
||||
open_SSL_client (PGconn *conn)
|
||||
{
|
||||
char peerName[256];
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in *sin1, *sin2;
|
||||
socklen_t len;
|
||||
struct hostent *h;
|
||||
const char *reason;
|
||||
char **s;
|
||||
int r;
|
||||
|
||||
if (!(conn->ssl = SSL_new(ctx)) ||
|
||||
!SSL_set_app_data(conn->ssl, conn) ||
|
||||
!SSL_set_fd(conn->ssl, conn->sock) ||
|
||||
SSL_connect(conn->ssl) <= 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not establish SSL connection: %s\n"),
|
||||
SSLerrmessage());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check the certificate chain */
|
||||
/* for now, we allow self-signed server certs */
|
||||
r = SSL_get_verify_result(conn->ssl);
|
||||
// if (r != X509_V_OK && r != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
|
||||
if (r != X509_V_OK)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
reason = "unable to get issuer cert";
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
||||
reason = "unable to get CRL";
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
||||
reason = "unable to decrypt cert signature";
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
|
||||
reason = "unable to decrypt CRL signature";
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
||||
reason = "unable to decode issuer public key";
|
||||
break;
|
||||
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
|
||||
reason = "cert signature failure";
|
||||
break;
|
||||
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
|
||||
reason = "CRL signature failure";
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
reason = "cert is not yet valid";
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
reason = "cert has expired";
|
||||
break;
|
||||
case X509_V_ERR_CRL_NOT_YET_VALID:
|
||||
reason = "CRL not yet valid";
|
||||
break;
|
||||
case X509_V_ERR_CRL_HAS_EXPIRED:
|
||||
reason = "CRL has expired";
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
reason = "error in cert notBefore field";
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
reason = "error in cert notAfter field";
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
||||
reason = "error in CRL last update field";
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
|
||||
reason = "error in CRL next update field";
|
||||
break;
|
||||
case X509_V_ERR_OUT_OF_MEM:
|
||||
reason = "out of memory";
|
||||
break;
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
reason = "depth zero self-signed cert";
|
||||
break;
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
reason = "self-signed cert in chain";
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||
reason = "unable to get issuer cert locally";
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
||||
reason = "unable to verify leaf signature";
|
||||
break;
|
||||
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
||||
reason = "cert chain too long";
|
||||
break;
|
||||
case X509_V_ERR_CERT_REVOKED:
|
||||
reason = "cert revoked";
|
||||
break;
|
||||
case X509_V_ERR_INVALID_CA:
|
||||
reason = "invalid CA";
|
||||
break;
|
||||
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
|
||||
reason = "path length exceeded";
|
||||
break;
|
||||
case X509_V_ERR_INVALID_PURPOSE:
|
||||
reason = "invalid purpose";
|
||||
break;
|
||||
case X509_V_ERR_CERT_UNTRUSTED:
|
||||
reason = "cert untrusted";
|
||||
break;
|
||||
case X509_V_ERR_CERT_REJECTED:
|
||||
reason = "cert rejected";
|
||||
break;
|
||||
/* These are 'informational' when looking for issuer cert */
|
||||
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
|
||||
reason = "cert issuer/issuer subject mismatch";
|
||||
break;
|
||||
case X509_V_ERR_AKID_SKID_MISMATCH:
|
||||
reason = "cert akid/issuer skid mismatch";
|
||||
break;
|
||||
case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
|
||||
reason = "cert akid/issuer serial mismatch";
|
||||
break;
|
||||
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
|
||||
reason = "keyusage no certsign";
|
||||
break;
|
||||
/* The application is not happy */
|
||||
case X509_V_ERR_APPLICATION_VERIFICATION:
|
||||
reason = "application-specific verification error";
|
||||
break;
|
||||
default:
|
||||
reason = "unknown reason";
|
||||
}
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("certificate could not be verified: %s (%d)\n"),
|
||||
reason, r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* do a reverse lookup on the server */
|
||||
len = sizeof(addr);
|
||||
if (getpeername(conn->sock, &addr, &len) == -1)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("error querying socket: %s\n"), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (addr.sa_family != AF_INET)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("not on IPv4 socket\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check the cert common name */
|
||||
conn->peer = SSL_get_peer_certificate(conn->ssl);
|
||||
X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
|
||||
NID_commonName, peerName, sizeof peerName);
|
||||
if ((h = gethostbyname2(peerName, addr.sa_family)) == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("error looking up address %s: %s\n"),
|
||||
peerName, hstrerror(h_errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check for a match on actual socket address */
|
||||
sin1 = (struct sockaddr_in *) &addr;
|
||||
for (s = h->h_addr_list; *s != NULL; s++)
|
||||
{
|
||||
sin2 = (struct sockaddr_in *) *s;
|
||||
if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr)
|
||||
break;
|
||||
}
|
||||
|
||||
/* if that failed, check for a match on alias */
|
||||
if (*s == NULL)
|
||||
{
|
||||
if (strcasecmp(peerName, conn->pghost) == 0)
|
||||
;
|
||||
else
|
||||
{
|
||||
for (s = h->h_aliases; *s != NULL; s++)
|
||||
{
|
||||
if (strcasecmp(peerName, *s) == 0)
|
||||
break;
|
||||
}
|
||||
if (*s == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext(
|
||||
"certificate name (%s) does not match peer address\n"),
|
||||
peerName);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a SSL connection.
|
||||
*/
|
||||
void
|
||||
close_SSL (PGconn *conn)
|
||||
{
|
||||
if (conn->ssl)
|
||||
{
|
||||
SSL_shutdown(conn->ssl);
|
||||
SSL_free(conn->ssl);
|
||||
conn->ssl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor function that retrieves SSL connection pointer.
|
||||
*/
|
||||
SSL *
|
||||
PQgetssl (PGconn *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return NULL;
|
||||
return conn->ssl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain reason string for last SSL error
|
||||
*
|
||||
* Some caution is needed here since ERR_reason_error_string will
|
||||
* return NULL if it doesn't recognize the error code. We don't
|
||||
* want to return NULL ever.
|
||||
*/
|
||||
static const char *
|
||||
SSLerrmessage(void)
|
||||
{
|
||||
unsigned long errcode;
|
||||
const char *errreason;
|
||||
static char errbuf[32];
|
||||
|
||||
errcode = ERR_get_error();
|
||||
if (errcode == 0)
|
||||
return "No SSL error reported";
|
||||
errreason = ERR_reason_error_string(errcode);
|
||||
if (errreason != NULL)
|
||||
return errreason;
|
||||
snprintf(errbuf, sizeof(errbuf), "SSL error code %lu", errcode);
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following conditional block shows how to embedded
|
||||
* one or more root certs into the libpq library. This
|
||||
* eliminates any need to copy the file to the clients, but
|
||||
* obviously must be done on a per-site basis.
|
||||
*/
|
||||
#if 0
|
||||
/*
|
||||
* The cert file, in PEM format, copied into a string buffer.
|
||||
*/
|
||||
static const char root1[] =
|
||||
"-----BEGIN CERTIFICATE-----\n\
|
||||
MIIEqDCCBGagAwIBAgIBADALBgcqhkjOOAQDBQAwgYwxEzARBgoJkiaJk/IsZAEZ\n\
|
||||
EwNjb20xGjAYBgoJkiaJk/IsZAEZEwpjb3lvdGVzb25nMRIwEAYDVQQKEwlTbmFr\n\
|
||||
ZSBPaWwxHTAbBgNVBAMTFFBvc3RncmVTUUwgUm9vdCBDZXJ0MSYwJAYJKoZIhvcN\n\
|
||||
AQkBFhdwb3N0Z3Jlc0Bjb3lvdGVzb25nLmNvbTAeFw0wMjA1MjEwMDE4MDZaFw0w\n\
|
||||
MjA2MjAwMDE4MDZaMIGMMRMwEQYKCZImiZPyLGQBGRMDY29tMRowGAYKCZImiZPy\n\
|
||||
LGQBGRMKY295b3Rlc29uZzESMBAGA1UEChMJU25ha2UgT2lsMR0wGwYDVQQDExRQ\n\
|
||||
b3N0Z3JlU1FMIFJvb3QgQ2VydDEmMCQGCSqGSIb3DQEJARYXcG9zdGdyZXNAY295\n\
|
||||
b3Rlc29uZy5jb20wggG2MIIBKwYHKoZIzjgEATCCAR4CgYEAxgmwTdzv7eSqUjcS\n\
|
||||
8fdT/3lm+On8LmHL+CkmF7IlvZKm2kwIiQqjcrG6JqgXBdBTIzeqSZV8cGrc0/f5\n\
|
||||
zMh6rDVxuSrEwCh8DtAC9LdwWyHp7Tw79z9khkZNTAlBonwOLvm0BJaroH5FLK9S\n\
|
||||
PvAHmjmLA1zd/2K8o+CqFFJasTkCFQDXfI1tnskPUtPXz/W88wRg5y5zpQKBgGwk\n\
|
||||
3a+tfWmw2mMDXh2sSHoGwVlzwqKZnDfk97I7Tz/zmGOLEGdA7s+2YqKKfW7F0S8p\n\
|
||||
Ho/cYDNE2lyaGqaxl2pscqdIhEmKYjJtjgaOOkQwfaYXs5GY0zkiSaxxtvJTj0WK\n\
|
||||
OQ+J/0iunsyyukYc3+TiosHENz4Y2ZgaGseJTMz0A4GEAAKBgFG5WK5/64gjuJ7D\n\
|
||||
D4RQ7QZtZ+wxP4s3oEqphz4hPGpGOPYlHdo2PhHMEAVrgMnX44yqUAnwmG5LT1RI\n\
|
||||
5KPCDwgyxBQVq2FDJrYoRb/AVbqMQ8cyJZ1etd7J1ies31b3fHp+uYSFHuCmLfFp\n\
|
||||
RO8wLplYM6XmJ5X5BF8zlclDxIj/o4IBVTCCAVEwHQYDVR0OBBYEFMO7rhIEVsrn\n\
|
||||
6k/gxKR5bCdEo8jZMIG5BgNVHSMEgbEwga6AFMO7rhIEVsrn6k/gxKR5bCdEo8jZ\n\
|
||||
oYGSpIGPMIGMMRMwEQYKCZImiZPyLGQBGRMDY29tMRowGAYKCZImiZPyLGQBGRMK\n\
|
||||
Y295b3Rlc29uZzESMBAGA1UEChMJU25ha2UgT2lsMR0wGwYDVQQDExRQb3N0Z3Jl\n\
|
||||
U1FMIFJvb3QgQ2VydDEmMCQGCSqGSIb3DQEJARYXcG9zdGdyZXNAY295b3Rlc29u\n\
|
||||
Zy5jb22CAQAwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEB\n\
|
||||
BAQDAgEGMCIGA1UdEQQbMBmBF3Bvc3RncmVzQGNveW90ZXNvbmcuY29tMCIGA1Ud\n\
|
||||
EgQbMBmBF3Bvc3RncmVzQGNveW90ZXNvbmcuY29tMAsGByqGSM44BAMFAAMvADAs\n\
|
||||
AhUAhcafaeM39bK2z2tgRD8OLbrr3fICEwdVqUy9ykb9Hc7SjcKB51lUJ9s=\n\
|
||||
-----END CERTIFICATE-----\n";
|
||||
|
||||
static void
|
||||
load_hardcoded_certs(void)
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509 *x;
|
||||
|
||||
store = SSL_CTX_get_cert_store(ctx);
|
||||
if (store != NULL)
|
||||
{
|
||||
x = load_cert_buffer(root1, sizeof (root1));
|
||||
X509_STORE_add_cert(store, x);
|
||||
X509_free(x);
|
||||
|
||||
/* repeat as necessary.... */
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void
|
||||
load_hardcoded_certs(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USE_SSL */
|
@ -12,7 +12,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-int.h,v 1.46 2002/03/05 06:07:27 momjian Exp $
|
||||
* $Id: libpq-int.h,v 1.47 2002/06/14 03:56:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -270,6 +270,7 @@ struct pg_conn
|
||||
bool allow_ssl_try; /* Allowed to try SSL negotiation */
|
||||
bool require_ssl; /* Require SSL to make connection */
|
||||
SSL *ssl; /* SSL status, if have SSL connection */
|
||||
X509 *peer; /* server certificate */
|
||||
#endif
|
||||
|
||||
/* Buffer for current error message */
|
||||
|
120
src/interfaces/ssl/client.conf
Normal file
120
src/interfaces/ssl/client.conf
Normal file
@ -0,0 +1,120 @@
|
||||
#
|
||||
# PostgreSQL sample configuration for *client* cert.
|
||||
# Contrast and compare with server.conf and root.conf.
|
||||
#
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 1024
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
#x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
# Passwords for private keys if not present they will be prompted for
|
||||
# input_password = secret
|
||||
# output_password = secret
|
||||
|
||||
# This sets a mask for permitted string types. There are several options.
|
||||
# default: PrintableString, T61String, BMPString.
|
||||
# pkix : PrintableString, BMPString.
|
||||
# utf8only: only UTF8Strings.
|
||||
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
|
||||
# MASK:XXXX a literal mask value.
|
||||
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
|
||||
# so use this option with caution!
|
||||
string_mask = nombstr
|
||||
|
||||
# req_extensions = v3_req # The extensions to add to a certificate request
|
||||
|
||||
[ req_distinguished_name ]
|
||||
0.domainComponent = domain name (TLD)
|
||||
0.domainComponent_default = com
|
||||
0.domainComponent_min = 2
|
||||
0.domainComponent_max = 3
|
||||
|
||||
1.domainComponent = domain name
|
||||
1.domainComponent_default = example
|
||||
1.domainComponent_min = 1
|
||||
1.domainComponent_max = 64
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = Snake Oil
|
||||
|
||||
# we can do this but it is not needed normally :-)
|
||||
#1.organizationName = Second Organization Name (eg, company)
|
||||
#1.organizationName_default = World Wide Web Pty Ltd
|
||||
|
||||
#organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default =
|
||||
|
||||
commonName = Your name
|
||||
commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 40
|
||||
|
||||
# SET-ex3 = SET extension number 3
|
||||
|
||||
[ req_attributes ]
|
||||
pgName = PostgreSQL user name
|
||||
pgName_min = 1
|
||||
pgName_max = 12
|
||||
|
||||
[ usr_cert ]
|
||||
|
||||
# These extensions are added when 'ca' signs a request.
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
# nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
#nsComment = "OpenSSL Generated Certificate"
|
||||
nsComment = "PostgreSQL/OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer:always
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
subjectAltName=email:copy
|
||||
subjectAltName=pgName
|
||||
|
||||
# Copy subject details
|
||||
issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
# Extensions to add to a certificate request
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
114
src/interfaces/ssl/mkcert.sh
Executable file
114
src/interfaces/ssl/mkcert.sh
Executable file
@ -0,0 +1,114 @@
|
||||
#!/bin/sh
|
||||
|
||||
# === FIRST DRAFT ===
|
||||
|
||||
PG_HOME=/var/lib/postgres
|
||||
PG_DATA=$PG_HOME/data
|
||||
|
||||
# default password for CA key
|
||||
PASSWORD=postgresql
|
||||
|
||||
#
|
||||
# this script creates the root (CA) certificate and
|
||||
# server cert for PostgreSQL. The OpenSSL applications
|
||||
# must be in the path.
|
||||
#
|
||||
|
||||
if [ $PG_HOME"." = "." -o $PG_DATA"." = "." ]
|
||||
then
|
||||
/bin/echo You must define \$PG_HOME and \$PG_DATA before running this program.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# generate DSA parameters file used for keys, if one does
|
||||
# not already exist.
|
||||
#
|
||||
if [ ! -f $PG_HOME/dsa1024.pem -o -z $PG_HOME/dsa1024.pem ]
|
||||
then
|
||||
openssl dsaparam -out $PG_HOME/dsa1024.pem 1024
|
||||
fi
|
||||
|
||||
#
|
||||
# generate CA directory tree and contents, if it does not already
|
||||
# exist.
|
||||
#
|
||||
if [ ! -d $PG_HOME/CA ]
|
||||
then
|
||||
/bin/mkdir $PG_HOME/CA;
|
||||
fi
|
||||
if [ ! -d $PG_HOME/CA/certs ]
|
||||
then
|
||||
/bin/mkdir $PG_HOME/CA/certs
|
||||
fi
|
||||
if [ ! -d $PG_HOME/CA/crl ]
|
||||
then
|
||||
/bin/mkdir $PG_HOME/CA/crl
|
||||
fi
|
||||
if [ ! -d $PG_HOME/CA/newcerts ]
|
||||
then
|
||||
/bin/mkdir $PG_HOME/CA/newcerts
|
||||
fi
|
||||
if [ ! -d $PG_HOME/CA/private ]
|
||||
then
|
||||
/bin/mkdir $PG_HOME/CA/private
|
||||
/bin/chmod 0700 $PG_HOME/CA/private
|
||||
fi
|
||||
if [ ! -f $PG_HOME/CA/index.txt ]
|
||||
then
|
||||
/usr/bin/touch $PG_HOME/CA/index.txt
|
||||
fi
|
||||
if [ ! -f $PG_HOME/CA/serial ]
|
||||
then
|
||||
/bin/echo 01 > $PG_HOME/CA/serial
|
||||
fi
|
||||
|
||||
#
|
||||
# generate root key, if one does not already exist.
|
||||
#
|
||||
if [ ! -f $PG_HOME/CA/private/cakey.pem -o -z $PG_HOME/CA/private/cakey.pem ]
|
||||
then
|
||||
openssl gendsa $PG_HOME/dsa1024.pem |\
|
||||
openssl pkcs8 -topk8 -v2 bf -out $PG_HOME/CA/private/cakey.pem
|
||||
/bin/chmod 0700 $PG_HOME/CA/private/cakey.pem
|
||||
fi
|
||||
|
||||
#
|
||||
# generate self-signed root certificate, if one does not already exist
|
||||
#
|
||||
if [ ! -f $PG_HOME/CA/cacert.pem -o -z $PG_HOME/CA/cacert.pem ]
|
||||
then
|
||||
/bin/echo "Creating the root certificate...."
|
||||
/bin/echo ""
|
||||
openssl req -new -x509 -out $PG_HOME/CA/cacert.pem \
|
||||
-key $PG_HOME/CA/private/cakey.pem \
|
||||
-config $PG_HOME/root.conf
|
||||
link -s $PG_HOME/CA/cacert.pem $PG_DATA/root.crt
|
||||
fi
|
||||
|
||||
#
|
||||
# generate server key, if one does not already exist.
|
||||
#
|
||||
if [ ! -f $PG_DATA/server.key -o -z $PG_DATA/server.key ]
|
||||
then
|
||||
openssl gendsa -out $PG_DATA/server.key $PG_HOME/dsa1024.pem
|
||||
/bin/chmod 0700 $PG_HOME/CA/private/cakey.pem
|
||||
fi
|
||||
|
||||
#
|
||||
# generate server certificate, if one does not already exist.
|
||||
#
|
||||
if [ ! -f $PG_DATA/server.crt -o -z $PG_DATA/server.crt ]
|
||||
then
|
||||
/bin/echo "Creating the PostgreSQL server certificate...."
|
||||
/bin/echo ""
|
||||
openssl req -new -x509 -out $PG_DATA/server.self \
|
||||
-key $PG_DATA/server.key \
|
||||
-config $PG_HOME/server.conf
|
||||
if [ -f $PG_DATA/server.self ]
|
||||
then
|
||||
openssl ca -out $PG_DATA/server.crt -ss_cert $PG_DATA/server.self \
|
||||
-config $PG_HOME/root.conf -extensions svr_cert
|
||||
/bin/rm -f $PG_DATA/server.self
|
||||
fi
|
||||
fi
|
54
src/interfaces/ssl/pgkeygen.sh
Normal file
54
src/interfaces/ssl/pgkeygen.sh
Normal file
@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo \$HOME = $HOME
|
||||
|
||||
CLIENTDIR=$HOME/.postgresql
|
||||
|
||||
#
|
||||
# copy root certificate, if necessary
|
||||
#
|
||||
if [ ! -f $CLIENTDIR/root.crt -o -z $CLIENTDIR/root.crt ]
|
||||
then
|
||||
if [ -f /etc/postgresql/root.crt ]
|
||||
then
|
||||
/bin/cp -p /etc/postgresql/root.crt $CLIENTDIR
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# generate client key, if one does not already exist.
|
||||
#
|
||||
if [ ! -f $CLIENTDIR/postgresql.key -o -z $CLIENTDIR/postgresql.key ]
|
||||
then
|
||||
if [ ! -f /etc/postgresql/dsa1024.pem -o -z /etc/postgresql/dsa1024.pem ]
|
||||
then
|
||||
/bin/echo "You must get the dsa1024.pem file from your DBA."
|
||||
exit 0
|
||||
fi
|
||||
openssl gendsa /etc/postgresql/dsa1024.pem |\
|
||||
openssl pkcs8 -topk8 -v2 bf -out $CLIENTDIR/postgresql.key
|
||||
/bin/chmod 0600 $CLIENTDIR/postgresql.key
|
||||
fi
|
||||
|
||||
#
|
||||
# generate client SS certificate, if one does not already exist.
|
||||
#
|
||||
if [ ! -f $CLIENTDIR/postgresql.crt -o -z $CLIENTDIR/postgresql.crt ]
|
||||
then
|
||||
if [ ! -f $CLIENTDIR/postgresql.pem -o -z $CLIENTDIR/postgresql.pem ]
|
||||
then
|
||||
/bin/echo "Creating client certificate...."
|
||||
/bin/echo ""
|
||||
openssl req -new -x509 -out $CLIENTDIR/postgresql.pem \
|
||||
-key $CLIENTDIR/postgresql.key -config /etc/postgresql/client.conf
|
||||
/bin/echo ""
|
||||
/bin/cat << EOM
|
||||
|
||||
You must now provide a copy of your ~/.postgresql/postgresql.pem file
|
||||
to your DBA for them to sign. When they have done so, you should rerun
|
||||
this application.
|
||||
EOM
|
||||
else
|
||||
cp -p $CLIENTDIR/postgresql.pem $CLIENTDIR/postgresql.crt
|
||||
fi
|
||||
fi
|
270
src/interfaces/ssl/root.conf
Normal file
270
src/interfaces/ssl/root.conf
Normal file
@ -0,0 +1,270 @@
|
||||
#
|
||||
# PostgreSQL sample configuration for *root* cert.
|
||||
# Contrast and compare with server.conf and client.conf.
|
||||
#
|
||||
|
||||
# define something in case $PG_HOME isn't defined.
|
||||
PG_HOME = /var/lib/postgres
|
||||
|
||||
####################################################################
|
||||
[ ca ]
|
||||
default_ca = CA_default # The default ca section
|
||||
|
||||
####################################################################
|
||||
[ CA_default ]
|
||||
|
||||
dir = $ENV::PG_HOME/CA # Where everything is kept
|
||||
certs = $dir/certs # Where the issued certs are kept
|
||||
crl_dir = $dir/crl # Where the issued crl are kept
|
||||
database = $dir/index.txt # database index file.
|
||||
new_certs_dir = $dir/newcerts # default place for new certs.
|
||||
|
||||
certificate = $dir/cacert.pem # The CA certificate
|
||||
serial = $dir/serial # The current serial number
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem# The private key
|
||||
RANDFILE = $dir/private/.rand # private random number file
|
||||
|
||||
x509_extensions = clnt_cert # The extentions to add to the cert
|
||||
|
||||
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
|
||||
# so this is commented out by default to leave a V1 CRL.
|
||||
# crl_extensions = crl_ext
|
||||
|
||||
default_days = 365 # how long to certify for
|
||||
default_crl_days= 30 # how long before next CRL
|
||||
default_md = sha1 # which md to use.
|
||||
preserve = no # keep passed DN ordering
|
||||
|
||||
# A few difference way of specifying how similar the request should look
|
||||
# For type CA, the listed attributes must be the same, and the optional
|
||||
# and supplied fields are just that :-)
|
||||
policy = policy_match
|
||||
|
||||
# For the CA policy
|
||||
[ policy_match ]
|
||||
domainComponent = match
|
||||
#1.domainComponent = match
|
||||
#organizationName = match
|
||||
#organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
# For the 'anything' policy
|
||||
# At this point in time, you must list all acceptable 'object'
|
||||
# types.
|
||||
[ policy_anything ]
|
||||
domainComponent = optional
|
||||
#1.domainComponent = optional
|
||||
#countryName = optional
|
||||
#stateOrProvinceName = optional
|
||||
#localityName = optional
|
||||
#organizationName = optional
|
||||
#organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 1024
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
# Passwords for private keys if not present they will be prompted for
|
||||
# input_password = secret
|
||||
# output_password = secret
|
||||
|
||||
# This sets a mask for permitted string types. There are several options.
|
||||
# default: PrintableString, T61String, BMPString.
|
||||
# pkix : PrintableString, BMPString.
|
||||
# utf8only: only UTF8Strings.
|
||||
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
|
||||
# MASK:XXXX a literal mask value.
|
||||
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
|
||||
# so use this option with caution!
|
||||
string_mask = nombstr
|
||||
|
||||
# req_extensions = v3_req # The extensions to add to a certificate request
|
||||
|
||||
[ req_distinguished_name ]
|
||||
0.domainComponent = domain name (TLD)
|
||||
0.domainComponent_default = com
|
||||
0.domainComponent_min = 2
|
||||
0.domainComponent_max = 3
|
||||
|
||||
1.domainComponent = domain name
|
||||
1.domainComponent_default = example
|
||||
1.domainComponent_min = 1
|
||||
1.domainComponent_max = 64
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = Snake Oil
|
||||
|
||||
# we can do this but it is not needed normally :-)
|
||||
#1.organizationName = Second Organization Name (eg, company)
|
||||
#1.organizationName_default = World Wide Web Pty Ltd
|
||||
|
||||
#organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default =
|
||||
|
||||
commonName = Common Name
|
||||
commonName_value = PostgreSQL Root Cert
|
||||
#commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_default = postgres@example.com
|
||||
emailAddress_max = 40
|
||||
|
||||
# SET-ex3 = SET extension number 3
|
||||
|
||||
[ req_attributes ]
|
||||
|
||||
[ svr_cert ]
|
||||
|
||||
# These extensions are added when 'ca' signs a request.
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
# nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
#nsComment = "OpenSSL Generated Certificate"
|
||||
nsComment = "PostgreSQL/OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer:always
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
subjectAltName=email:copy
|
||||
|
||||
# Copy subject details
|
||||
issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
[ clnt_cert ]
|
||||
|
||||
# These extensions are added when 'ca' signs a request.
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
# nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
#nsComment = "OpenSSL Generated Certificate"
|
||||
nsComment = "PostgreSQL/OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer:always
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
subjectAltName=email:copy
|
||||
|
||||
# Copy subject details
|
||||
issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
# Extensions to add to a certificate request
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
[ v3_ca ]
|
||||
|
||||
# Extensions for a typical CA
|
||||
|
||||
# PKIX recommendation.
|
||||
|
||||
subjectKeyIdentifier=hash
|
||||
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
||||
|
||||
# This is what PKIX recommends but some broken software chokes on critical
|
||||
# extensions.
|
||||
#basicConstraints = critical,CA:true
|
||||
# So we do this instead.
|
||||
basicConstraints = CA:true
|
||||
|
||||
# Key usage: this is typical for a CA certificate. However since it will
|
||||
# prevent it being used as an test self-signed certificate it is best
|
||||
# left out by default.
|
||||
keyUsage = cRLSign, keyCertSign
|
||||
|
||||
# Some might want this also
|
||||
nsCertType = sslCA, emailCA
|
||||
|
||||
# Include email address in subject alt name: another PKIX recommendation
|
||||
subjectAltName=email:copy
|
||||
# Copy issuer details
|
||||
issuerAltName=issuer:copy
|
||||
|
||||
# DER hex encoding of an extension: beware experts only!
|
||||
# obj=DER:02:03
|
||||
# Where 'obj' is a standard or added object
|
||||
# You can even override a supported extension:
|
||||
# basicConstraints= critical, DER:30:03:01:01:FF
|
||||
|
||||
[ crl_ext ]
|
||||
|
||||
# CRL extensions.
|
||||
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
|
||||
|
||||
# issuerAltName=issuer:copy
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
118
src/interfaces/ssl/server.conf
Normal file
118
src/interfaces/ssl/server.conf
Normal file
@ -0,0 +1,118 @@
|
||||
#
|
||||
# PostgreSQL sample configuration for *server* cert.
|
||||
# Contrast and compare with root.conf and client.conf.
|
||||
#
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 1024
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
#x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
# Passwords for private keys if not present they will be prompted for
|
||||
# input_password = secret
|
||||
# output_password = secret
|
||||
|
||||
# This sets a mask for permitted string types. There are several options.
|
||||
# default: PrintableString, T61String, BMPString.
|
||||
# pkix : PrintableString, BMPString.
|
||||
# utf8only: only UTF8Strings.
|
||||
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
|
||||
# MASK:XXXX a literal mask value.
|
||||
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
|
||||
# so use this option with caution!
|
||||
string_mask = nombstr
|
||||
|
||||
# req_extensions = v3_req # The extensions to add to a certificate request
|
||||
|
||||
[ req_distinguished_name ]
|
||||
0.domainComponent = domain name (TLD)
|
||||
0.domainComponent_default = com
|
||||
0.domainComponent_min = 2
|
||||
0.domainComponent_max = 3
|
||||
|
||||
1.domainComponent = domain name
|
||||
1.domainComponent_default = example
|
||||
1.domainComponent_min = 1
|
||||
1.domainComponent_max = 64
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = Snake Oil
|
||||
|
||||
# we can do this but it is not needed normally :-)
|
||||
#1.organizationName = Second Organization Name (eg, company)
|
||||
#1.organizationName_default = World Wide Web Pty Ltd
|
||||
|
||||
#organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default =
|
||||
|
||||
commonName = FQDN of server
|
||||
commonName_default = postgres.example.com
|
||||
commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_default = postgres@example.com
|
||||
emailAddress_max = 40
|
||||
|
||||
# SET-ex3 = SET extension number 3
|
||||
|
||||
[ req_attributes ]
|
||||
|
||||
[ usr_cert ]
|
||||
|
||||
# These extensions are added when 'ca' signs a request.
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
# nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
#nsComment = "OpenSSL Generated Certificate"
|
||||
nsComment = "PostgreSQL/OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer:always
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
subjectAltName=email:copy
|
||||
|
||||
# Copy subject details
|
||||
issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
# Extensions to add to a certificate request
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
Loading…
x
Reference in New Issue
Block a user