Thread: SSL (patch 1)

SSL (patch 1)

From
Bear Giles
Date:
First of many patches on SSL code.  The first patch just sets
the groundwork for future patches by pulling all SSL-specific
(and by implication all secure session) code into two new files,
be-secure.c and fe-secure.c

These files also contain a temporary checklist of pending patches:

 * PATCH LEVEL
 *      milestone 1: fix basic coding errors
 *      [*] existing SSL code pulled out of existing files.
 *      [ ] SSL_get_error() after SSL_read() and SSL_write(),
 *          SSL_shutdown(), default to TLSv1.
 *
 *      milestone 2: provide endpoint authentication (server)
 *      [ ] client verifies server cert
 *      [ ] client verifies server hostname
 *
 *      milestone 3: improve confidentially, support perfect forward secrecy
 *      [ ] use 'random' file, read from '/dev/urandom?'
 *      [ ] emphermal DH keys, default values
 *
 *      milestone 4: provide endpoint authentication (client)
 *      [ ] server verifies client certificates
 *
 *      milestone 5: provide informational callbacks
 *      [ ] provide informational callbacks
 *
 *      other changes
 *      [ ] tcp-wrappers
 *      [ ] more informative psql

Finally, because of the large number of patches (instead of a
monoblock patch) I'm managing them with CVS.  Sorry about the
$Id$ and $Header$ in the diff....

Bear

Attachment

Re: SSL (patch 1)

From
Peter Eisentraut
Date:
Bear Giles writes:

> First of many patches on SSL code.  The first patch just sets
> the groundwork for future patches by pulling all SSL-specific
> (and by implication all secure session) code into two new files,
> be-secure.c and fe-secure.c

Looks like the right direction.  Specific comments below.

> Index: postgresql/src/backend/libpq/pqcomm.c

> ***************
> *** 80,85 ****
> --- 80,88 ----
>   #include "libpq/libpq.h"
>   #include "miscadmin.h"
>
> + extern void secure_close(Port *);
> + extern ssize_t secure_read(Port *, void *, size_t);
> + extern ssize_t secure_write(Port *, const void *, size_t);

Should be in a header file.  ssize_t is probably not portable.

> ***************
> *** 137,142 ****
> --- 140,146 ----
>   {
>       if (MyProcPort != NULL)
>       {
> +         secure_close(MyProcPort);
>           close(MyProcPort->sock);
>           /* make sure any subsequent attempts to do I/O fail cleanly */
>           MyProcPort->sock = -1;

Shouldn't secure_close() do all the other closing actions as well?  That's
how secure_read() etc. appear to work.

> Index: postgresql/src/backend/postmaster/be-secure.c

This file seems to be belong under backend/libpq.

> diff -c /dev/null postgresql/src/backend/postmaster/be-secure.c:1.1
> *** /dev/null    Fri May 24 12:50:07 2002
> --- postgresql/src/backend/postmaster/be-secure.c    Fri May 24 12:41:53 2002
> ***************
> *** 0 ****
> --- 1,327 ----
> + /*-------------------------------------------------------------------------
> +  *
> +  * be-connect.c
> +  *      functions related to setting up a secure connection to the frontend.
> +  *      Secure connections are expected to provide confidentiality,
> +  *      message integrity and endpoint authentication.
> +  *
> +  *
> +  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
> +  * Portions Copyright (c) 1994, Regents of the University of California
> +  *
> +  *
> +  * IDENTIFICATION
> +  *      $Header: /usr/local/cvsroot/postgresql/src/backend/postmaster/be-secure.c,v 1.1 2002/05/24 18:41:53 bear
Exp$ 
> +  *
> +  * PATCH LEVEL
> +  *      milestone 1: fix basic coding errors

I don't think we need to record that in a code file.

> + #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

There is no WIN32 in the backend.

> + extern void ExitPostmaster(int);
> + extern void postmaster_error(const char *fmt,...);
> +
> + int secure_initialize(void);
> + void secure_destroy(void);
> + int secure_open_server(Port *);
> + void secure_close(Port *);
> + ssize_t secure_read(Port *, void *ptr, size_t len);
> + ssize_t secure_write(Port *, const void *ptr, size_t len);

Header files...

> + #define PING()    elog(DEBUG,"%s, line %d, %s", __FILE__, __LINE__, __func__);

__func__ is definitely not portable.  Nor should there be unconditional
elog(DEBUG)'s in the code.  Actually, it should be elog(DEBUG[1-5]) now I
think.

> + /*
> +  * 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;
> + }

Should add some gettext() calls here?

> Index: postgresql/src/backend/postmaster/postmaster.c

>   #ifdef USE_SSL
> ! extern int secure_initialize(void);
> ! extern void secure_destroy(void);
> ! extern int secure_open_server(Port *);
> ! extern void secure_close(Port *);
> ! #endif /* USE_SSL */

Header files...

> Index: postgresql/src/interfaces/libpq/fe-connect.c

> ***************
> *** 61,69 ****
>   }
>   #endif
>
> -
>   #ifdef USE_SSL
> ! static SSL_CTX *SSL_context = NULL;
>   #endif
>
>   #define NOTIFYLIST_INITIAL_SIZE 10
> --- 61,72 ----
>   }
>   #endif
>
>   #ifdef USE_SSL
> ! extern int secure_initialize(PGconn *);
> ! extern void secure_destroy(void);
> ! extern int secure_open_client(PGconn *);
> ! extern void secure_close(PGconn *);
> ! extern SSL * PQgetssl(PGconn *);
>   #endif

These guys either need to be static or need to have less likely to
conflict names.  Keep in mind that this is a library.  Preprending pg_
should be OK.  And the gratuitous header file comment belongs here as
well.

> Index: postgresql/src/interfaces/libpq/fe-secure.c

> + 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;
> + }

Could also use some libpq_gettext() calls around the strings.  Also, you
shouldn't use fixed buffers for strings.  Or at least make it a lot bigger
in case someone translates it into Welsh. ;-)  Look at how the other error
messages are typically copied around.

--
Peter Eisentraut   peter_e@gmx.net



Re: SSL (patch 1)

From
Bear Giles
Date:
> > + extern void secure_close(Port *);
> > + extern ssize_t secure_read(Port *, void *, size_t);
> > + extern ssize_t secure_write(Port *, const void *, size_t);
>
> Should be in a header file.  ssize_t is probably not portable.

I agree, but I don't know enough about PosgreSQL layout policy to
know whether these prototypes should be in their own header file,
in libpq-XXX.h, or some place else.

> Shouldn't secure_close() do all the other closing actions as well?  That's
> how secure_read() etc. appear to work.

It could (should?).  At the moment it forces the *secure* connection
to terminate, but leaves the underlying insecure connection open.
This could be useful if the protocol provided a mechanism to enter
and exit a secure state.  But that probably breaks the 'principal of least
surprise.'

> > Index: postgresql/src/backend/postmaster/be-secure.c
>
> This file seems to be belong under backend/libpq.

See comments above regarding layout.  I put it into postmaster since
the bulk of the code came from postmaster.c.

> > +  * PATCH LEVEL
> > +  *      milestone 1: fix basic coding errors
>
> I don't think we need to record that in a code file.

That's for *you*, and were always meant to be temporary.  I knew there
would be about a dozen concurrent patches in play, and this helps
establish precedence if they don't go in in sequence.

>
> > + #define PING()    elog(DEBUG,"%s, line %d, %s", __FILE__, __LINE__, __func__);
>
> __func__ is definitely not portable.  Nor should there be unconditional
> elog(DEBUG)'s in the code.  Actually, it should be elog(DEBUG[1-5]) now I
> think.

That particular #define is debugging scaffolding.  As for DEBUG[1-5],
I'm using the conventions in the existing software.

> Could also use some libpq_gettext() calls around the strings.

(*cough*)  That code was copied verbatim from the existing software.

Since this is mostly stylistic, I'll put together a patch that runs
against the most recent set of code so that the rest of the patches
will run clean.  Renaming the file would probably best be handled on
your end to avoid unnecessary traffic.

Bear

Re: SSL (patch 1)

From
Tom Lane
Date:
Bear Giles <bgiles@coyotesong.com> writes:
> That's for *you*, and were always meant to be temporary.  I knew there
> would be about a dozen concurrent patches in play, and this helps
> establish precedence if they don't go in in sequence.

I'm a little uncomfortable with that whole approach to things, and was
intending to suggest that you submit the SSL changes as one big patch.
I feel that this is not letting me see the big picture ... quite aside
from the probability of breakage if patches get applied out-of-order.

            regards, tom lane

Re: SSL (patch 1)

From
Peter Eisentraut
Date:
Tom Lane writes:

> I'm a little uncomfortable with that whole approach to things, and was
> intending to suggest that you submit the SSL changes as one big patch.
> I feel that this is not letting me see the big picture ... quite aside
> >from the probability of breakage if patches get applied out-of-order.

I had suggested to Bear Giles in private mail that he resend his original
big patch as little pieces that preferrably change only one thing at a
time.  At least for me this makes it easier to see what is going on.

--
Peter Eisentraut   peter_e@gmx.net