OSDN Git Service

Attached are a revised set of SSL patches. Many of these patches
authorBruce Momjian <bruce@momjian.us>
Fri, 14 Jun 2002 03:56:47 +0000 (03:56 +0000)
committerBruce Momjian <bruce@momjian.us>
Fri, 14 Jun 2002 03:56:47 +0000 (03:56 +0000)
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

15 files changed:
src/backend/libpq/Makefile
src/backend/libpq/pqcomm.c
src/backend/postmaster/postmaster.c
src/bin/psql/startup.c
src/include/libpq/libpq-be.h
src/interfaces/libpq/Makefile
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/fe-misc.c
src/interfaces/libpq/fe-ssl.c [new file with mode: 0644]
src/interfaces/libpq/libpq-int.h
src/interfaces/ssl/client.conf [new file with mode: 0644]
src/interfaces/ssl/mkcert.sh [new file with mode: 0755]
src/interfaces/ssl/pgkeygen.sh [new file with mode: 0644]
src/interfaces/ssl/root.conf [new file with mode: 0644]
src/interfaces/ssl/server.conf [new file with mode: 0644]

index d0f05e8..55d2b8c 100644 (file)
@@ -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
index a82771d..5ece972 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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,
-                                                PQ_BUFFER_SIZE - PqRecvLength);
-               else
-#endif
-                       r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
-                                        PQ_BUFFER_SIZE - PqRecvLength, 0);
+               r = read_SSL(MyProcPort, PqRecvBuffer + PqRecvLength,
+                                        PQ_BUFFER_SIZE - PqRecvLength);
 
                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
index ca96a44..5b56ab3 100644 (file)
@@ -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
 
        /*
@@ -1114,13 +1115,9 @@ 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.
index fee8c98..1d8e3aa 100644 (file)
@@ -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
index ed8b4e9..d0e6a15 100644 (file)
@@ -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;
 
index 8b8f3c9..a9679e6 100644 (file)
@@ -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
index 9864aad..ac4a420 100644 (file)
@@ -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());
-                                       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 (initialize_ctx(NULL, NULL, conn) == -1)
+                               goto connect_errReturn;
+                       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)
 {
index 643c810..64a05c8 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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,
-                                                conn->inBufSize - conn->inEnd);
-       else
-#endif
-               nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
-                                        conn->inBufSize - conn->inEnd, 0);
+       nread = read_SSL(conn, conn->inBuffer + conn->inEnd,
+                                        conn->inBufSize - conn->inEnd);
        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,
-                                                conn->inBufSize - conn->inEnd);
-       else
-#endif
-               nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
-                                        conn->inBufSize - conn->inEnd, 0);
+       nread = read_SSL(conn, conn->inBuffer + conn->inEnd,
+                                        conn->inBufSize - conn->inEnd);
        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))
diff --git a/src/interfaces/libpq/fe-ssl.c b/src/interfaces/libpq/fe-ssl.c
new file mode 100644 (file)
index 0000000..dc05903
--- /dev/null
@@ -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 */
index 34308ae..a874d6b 100644 (file)
@@ -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 */
diff --git a/src/interfaces/ssl/client.conf b/src/interfaces/ssl/client.conf
new file mode 100644 (file)
index 0000000..48793dc
--- /dev/null
@@ -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
+
diff --git a/src/interfaces/ssl/mkcert.sh b/src/interfaces/ssl/mkcert.sh
new file mode 100755 (executable)
index 0000000..8728a3a
--- /dev/null
@@ -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
diff --git a/src/interfaces/ssl/pgkeygen.sh b/src/interfaces/ssl/pgkeygen.sh
new file mode 100644 (file)
index 0000000..a65bb0f
--- /dev/null
@@ -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
diff --git a/src/interfaces/ssl/root.conf b/src/interfaces/ssl/root.conf
new file mode 100644 (file)
index 0000000..d7ed143
--- /dev/null
@@ -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
diff --git a/src/interfaces/ssl/server.conf b/src/interfaces/ssl/server.conf
new file mode 100644 (file)
index 0000000..fe6cfe4
--- /dev/null
@@ -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
+