Thread: [PATCH] Automatic client certificate selection support for libpq v1

[PATCH] Automatic client certificate selection support for libpq v1

From
Seth Robertson
Date:
I had a situation where I needed to connect to multiple postgresql
servers in a variety of programs written in a variety of languages,
including some which connected to multiple servers at the same time.
As some of you might know, you cannot usefully put multiple
certificates or keys in the postgresql.crt/.key files.

I was pleased to see that 8.4 had sslcert/sslkey support and if it was
in 8.3, I *might* have done the painful work to update all of the
programs to use host-conditional environmental variables.  However,
since I had to modify my 8.3 postgresql anyway, I decided to go with
an automatic file-selection approach.  Essentially, before trying the
default postgresql.crt (and thus only if the sslcert option is not set
in 8.4), it appends the conn->pgname to the filename and checks to see
if that file exists.  It uses that host-specific file if it does,
otherwise it continues to use the previous default.  As such, it is a
low-impact change.

One possible problem is that as written it does not handle aliases
cleanly.  If the host-specific certificate is named
"postgresql.crt.db.example.com" you will be able to connect if you use
`psql -h db.example.com`.  However, if you use `psql -h db` you will
not match the file on disk (and thus fall back to postgresql.crt which
presumably will not contain the correct certificate).  This can be
manually ``solved'' by creating links or copies of the host specific
file to each needed alias.  If there is demand, the complexity of the
patch could be increased by using DNS to try and discover a canonical
name for the host.  Using the IP address is another option, but is
probably not preferred since it reduces flexibility.

I can provide an 8.3 patch if anyone desires.
                -Seth Robertson                 in-pgsql-hackers@baka.org

diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index ee0a91e..9a16996 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -599,7 +599,21 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)    if (conn->sslcert)        strncpy(fnbuf,
conn->sslcert,sizeof(fnbuf));    else
 
-        snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
+    {
+        fnbuf[0] = 0;
+
+        /* Check to see if there is a destination specific client certificate */
+        if (conn->pghost)
+        {
+            snprintf(fnbuf, sizeof(fnbuf), "%s/%s.%s", homedir, USER_CERT_FILE, conn->pghost);
+            if (access(fnbuf, R_OK) < 0)
+                fnbuf[0] = 0;    /* Cannot find one, try for default certificate */
+        }
+
+        /* Use default certificate file name if there was no hostname present, or host specific file did not exist */
+        if (!fnbuf[0])
+            snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
+    }    /*     * OpenSSL <= 0.9.8 lacks error stack handling, which means it's likely to
@@ -713,8 +727,20 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)    }    else    {
-        /* No PGSSLKEY specified, load default file */
-        snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
+        /* No PGSSLKEY specified, load default or host specific default file */
+        fnbuf[0] = 0;
+
+        /* Check to see if there is a destination specific client key */
+        if (conn->pghost)
+        {
+            snprintf(fnbuf, sizeof(fnbuf), "%s/%s.%s", homedir, USER_KEY_FILE, conn->pghost);
+            if (access(fnbuf, R_OK) < 0)
+                fnbuf[0] = 0;    /* Cannot find one, try for default key */
+        }
+
+        /* Use default key file name if there was no hostname present, or host specific file did not exist */
+        if (!fnbuf[0])
+            snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);    }    if (fnbuf[0] != '\0')


Seth Robertson <in-pgsql-hackers@baka.org> writes:
> I had a situation where I needed to connect to multiple postgresql
> servers in a variety of programs written in a variety of languages,
> including some which connected to multiple servers at the same time.
> As some of you might know, you cannot usefully put multiple
> certificates or keys in the postgresql.crt/.key files.

Hmm, shouldn't we fix *that* rather than inventing a hack like this?
        regards, tom lane


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
David Blewett
Date:
On Fri, May 8, 2009 at 12:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Seth Robertson <in-pgsql-hackers@baka.org> writes:
>> I had a situation where I needed to connect to multiple postgresql
>> servers in a variety of programs written in a variety of languages,
>> including some which connected to multiple servers at the same time.
>> As some of you might know, you cannot usefully put multiple
>> certificates or keys in the postgresql.crt/.key files.
>
> Hmm, shouldn't we fix *that* rather than inventing a hack like this?

Possibly a la SSH's authorized_keys or known_hosts formats?

David


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Seth Robertson
Date:
In message <8766.1241799013@sss.pgh.pa.us>, Tom Lane writes:
   Seth Robertson <in-pgsql-hackers@baka.org> writes:   > I had a situation where I needed to connect to multiple
postgresql  > servers in a variety of programs written in a variety of languages,   > including some which connected to
multipleservers at the same time.   > As some of you might know, you cannot usefully put multiple   > certificates or
keysin the postgresql.crt/.key files.      Hmm, shouldn't we fix *that* rather than inventing a hack like this?
 

I certainly agree that it would be ideal.  My understanding is that
OpenSSL does not really support certificate stores/wallets or other
methods of automatically handling multiple certificates (see
http://gagravarr.org/writing/openssl-certs/general.shtml and
http://www.openssl.org/docs/ssl/SSL_CTX_use_certificate.html, the
latter which says: "NOTES The internal certificate store of OpenSSL
can hold two private key/certificate pairs at a time: one
key/certificate of type RSA and one key/certificate of type DSA.")

The http://www.openssl.org/docs/ssl/SSL_CTX_set_client_cert_cb.html
document suggests that the callback function (which postgresql already
uses) can be extended to search a private certificate store to select
and return the proper certificate.  However, it is not clear from this
manual page how to get access to the information about the requested
certificate--I can only presume the information was sent to the
client.  Following each certificate chain from the client certificates
loaded back to see if any match would be pretty painful as well.

Basically doing this would probably become a project instead of a 5
minute hack to support 80% of the functionality.  I understand the
desire to limit the number of hacks in the source code, though.
                -Seth Robertson                 in-pgsql-hackers@baka.org



Seth Robertson <in-pgsql-hackers@baka.org> writes:
> In message <8766.1241799013@sss.pgh.pa.us>, Tom Lane writes:
>>     Hmm, shouldn't we fix *that* rather than inventing a hack like this?

> Basically doing this would probably become a project instead of a 5
> minute hack to support 80% of the functionality.  I understand the
> desire to limit the number of hacks in the source code, though.

It's certainly possible that what you have done represents the best
available engineering tradeoff.  But at this point it's too late for 8.4
and so we have quite a bit of time to think about it.  I'd like to at
least consider alternative solutions before we choose this one.

BTW, I was reminded today that Fedora/Red Hat are hoping to standardize
all crypto-related functionality in their entire distro on the NSS
libraries:
http://fedoraproject.org/wiki/FedoraCryptoConsolidation
This is a long way from fruition, but at some point we are going to be
faced with using a compatibility wrapper that sort of emulates openssl
(they are not even pretending it'll be 100% compatible).  So I'm feeling
a bit leery of wiring in any additional dependence on details of openssl
functionality.  I hesitate though to suggest that we think about porting
ourselves to NSS --- I'm not sure that there would be benefits to us
within the context of Postgres alone.  Is anyone sufficiently up on the
different crypto libraries to comment on that?
        regards, tom lane


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Seth Robertson
Date:
In message <12314.1241809436@sss.pgh.pa.us>, Tom Lane writes:
   Seth Robertson <in-pgsql-hackers@baka.org> writes:   > In message <8766.1241799013@sss.pgh.pa.us>, Tom Lane writes:
>>     Hmm, shouldn't we fix *that* rather than inventing a hack like this?      > Basically doing this would probably
becomea project instead of a 5   > minute hack to support 80% of the functionality.  I understand the   > desire to
limitthe number of hacks in the source code, though.      It's certainly possible that what you have done represents
thebest   available engineering tradeoff.  But at this point it's too late for 8.4   and so we have quite a bit of time
tothink about it.  I'd like to at   least consider alternative solutions before we choose this one.      BTW, I was
remindedtoday that Fedora/Red Hat are hoping to standardize   all crypto-related functionality in their entire distro
onthe NSS   libraries:
 
   I'm not sure that there would be benefits to us within the context   of Postgres alone.  Is anyone sufficiently up
onthe different   crypto libraries to comment on that?
 

I am not perfectly up to speed, but switching to NSS would solve this
(automatic client certificate selection) problem in the crypto
library, since NSS supports a client certificate database and
furthermore has a default callback function NSS_GetClientAuthData
which searches the certificate database for a suitable match.  It also
supports OCSP (online certificate status protocol) which is an online
certificate revocation check (better than the current TODO item of
"Allow SSL CRL files to be re-read during configuration file reload,
rather than requiring a server restart").

Well, I guess that openssl supports OCSP as well, but the support does
not seem as complete (no AIA support--revocation URL embedded in the
certificate--that I can see).

It is of course possible to support both at the same time (at
compile-time, if nowhere else).
                -Seth Robertson                 in-pgsql-hackers@baka.org


Seth Robertson <in-pgsql-hackers@baka.org> writes:
> In message <12314.1241809436@sss.pgh.pa.us>, Tom Lane writes:
>     BTW, I was reminded today that Fedora/Red Hat are hoping to standardize
>     all crypto-related functionality in their entire distro on the NSS
>     libraries:

> I am not perfectly up to speed, but switching to NSS would solve this
> (automatic client certificate selection) problem in the crypto
> library, since NSS supports a client certificate database and
> furthermore has a default callback function NSS_GetClientAuthData
> which searches the certificate database for a suitable match.

Interesting.

> It also
> supports OCSP (online certificate status protocol) which is an online
> certificate revocation check (better than the current TODO item of
> "Allow SSL CRL files to be re-read during configuration file reload,
> rather than requiring a server restart").

> Well, I guess that openssl supports OCSP as well, but the support does
> not seem as complete (no AIA support--revocation URL embedded in the
> certificate--that I can see).

Well, one of the arguments the Fedora crowd is making for NSS is that
it's more feature-complete than the other crypto libraries, so this
doesn't surprise me much.

> It is of course possible to support both at the same time (at
> compile-time, if nowhere else).

Yes, I suppose we'd not wish to just drop openssl completely.
I wonder how much code duplication would ensue from a compile-time
choice of which library to use ...
        regards, tom lane


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Seth Robertson
Date:
In message <14727.1241816192@sss.pgh.pa.us>, Tom Lane writes:
   > It is of course possible to support both at the same time (at   > compile-time, if nowhere else).      Yes, I
supposewe'd not wish to just drop openssl completely.   I wonder how much code duplication would ensue from a
compile-time  choice of which library to use ...
 

My only datapoint for you is curl, which is an application I happen to
have discovered that can use either NSS and OpenSSL.
Lines  Words  Chars Filename 2508   7890  74682 ssluse.c 1331   3708  36411 nss.c

I imagine that you would more or less have to provide a different
be-secure.c and fe-secure.c file for the two different
libraries--whether as a separate file or via #ifdefs.  It looks like
there is a small amount of common code present (why *is*
pg_block_sigpipe() in that file anyway?)
                -Seth Robertson                 in-pgsql-hackers@baka.org



Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Peter Eisentraut
Date:
On Friday 08 May 2009 22:03:56 Tom Lane wrote:
>  I hesitate though to suggest that we think about porting
> ourselves to NSS --- I'm not sure that there would be benefits to us
> within the context of Postgres alone.

That could be attractive if we ripped out the OpenSSL code at the same time, 
as the NSS API is purportedly more abstract and presumably would reduce the 
amount and the complexity of the code.


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Magnus Hagander
Date:
Peter Eisentraut wrote:
> On Friday 08 May 2009 22:03:56 Tom Lane wrote:
>>  I hesitate though to suggest that we think about porting
>> ourselves to NSS --- I'm not sure that there would be benefits to us
>> within the context of Postgres alone.
> 
> That could be attractive if we ripped out the OpenSSL code at the same time, 
> as the NSS API is purportedly more abstract and presumably would reduce the 
> amount and the complexity of the code.

Is NSS available on all the platforms that we are (and that has OpenSSL
today)?

Another thought: if we were to make ourselves support multiple SSL
libraries (that has been suggested before - at that point, people wanted
GnuTLS), we could also add support for Windows SChannel, which I'm sure
some win32 people would certainly prefer - much easier to do SSL
deployments within an existing MS infrastructure...

But no, that certainly wouldn't *reduce* the amount of code...

//Magnus




Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Magnus Hagander
Date:
Seth Robertson wrote:
> In message <14727.1241816192@sss.pgh.pa.us>, Tom Lane writes:
> 
>     > It is of course possible to support both at the same time (at
>     > compile-time, if nowhere else).
>     
>     Yes, I suppose we'd not wish to just drop openssl completely.
>     I wonder how much code duplication would ensue from a compile-time
>     choice of which library to use ...
> 
> My only datapoint for you is curl, which is an application I happen to
> have discovered that can use either NSS and OpenSSL.
> 
>  Lines  Words  Chars Filename
>   2508   7890  74682 ssluse.c
>   1331   3708  36411 nss.c

IIRC, they also support gnutls. So we can probably get hints there about
how to get this support if we want to :-)


> I imagine that you would more or less have to provide a different
> be-secure.c and fe-secure.c file for the two different
> libraries--whether as a separate file or via #ifdefs.  It looks like
> there is a small amount of common code present (why *is*
> pg_block_sigpipe() in that file anyway?)

Clearly this would be a good time to fix such abstraction errors if we
decide to go ahead :-)


-- Magnus HaganderSelf: http://www.hagander.net/Work: http://www.redpill-linpro.com/


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Alvaro Herrera
Date:
Magnus Hagander wrote:

> Another thought: if we were to make ourselves support multiple SSL
> libraries (that has been suggested before - at that point, people wanted
> GnuTLS), we could also add support for Windows SChannel, which I'm sure
> some win32 people would certainly prefer - much easier to do SSL
> deployments within an existing MS infrastructure...

If we were to support multiple libraries, would they be selected at run
time or compile time?  If only compile time, how would it work for the
Windows installer with the SChannel thingy --- would they have to
distribute two separate packages, for OpenSSL and SChannel?

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Seth Robertson
Date:
In message <4A07DB89.2080508@hagander.net>, Magnus Hagander writes:
   Is NSS available on all the platforms that we are (and that has OpenSSL   today)?

NSS stopped publishing their supported platform list for NSS for some
strange reasons (older version have it).  But I'd probably assume that
the list includes AIX, Tru64, HPUX, Linux, Windows, Solaris, Mac OSX.
I specifically don't see signs that they attempt to support the *BSD
platforms, but the *BSD people have working ports.

Generally from almost dozens of minutes of googling, I'd have to say
that in terms of portability and declared actual ports:

OpenSSL >> PostgreSQL >> Mozilla NSS >> GnuTLS

GnuTLS doesn't seem to be as mature as either OpenSSL and Mozilla NSS,
at least in my current hot-button issue of client certificate
validation.

Good luck with that Windows SChannel thing...I didn't find any
opensource program which uses it.
                -Seth Robertson                 in-pgsql-hackers@baka.org


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Seth Robertson
Date:
In message <20090511144317.GC8689@alvh.no-ip.org>, Alvaro Herrera writes:
   Magnus Hagander wrote:      > Another thought: if we were to make ourselves support multiple SSL   > libraries (that
hasbeen suggested before - at that point, people wanted   > GnuTLS), we could also add support for Windows SChannel,
whichI'm sure   > some win32 people would certainly prefer - much easier to do SSL   > deployments within an existing
MSinfrastructure...      If we were to support multiple libraries, would they be selected at run   time or compile
time? If only compile time, how would it work for the   Windows installer with the SChannel thingy --- would they have
to  distribute two separate packages, for OpenSSL and SChannel?
 

While I have successfully performed runtime conditional dynamic
loading inside programs (each shared library with its own list of
dependent libraries) on one platform with one selected dynamic loading
API, I cannot say I recommend it.  This would aid neither portability,
debug-ability, or performance (though compared to the overhead of SSL,
the jump table is kinda irrelevant).
                -Seth Robertson                 in-pgsql-hackers@baka.org


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Peter Eisentraut
Date:
On Monday 11 May 2009 11:02:17 Magnus Hagander wrote:
> Another thought: if we were to make ourselves support multiple SSL
> libraries (that has been suggested before - at that point, people wanted
> GnuTLS), we could also add support for Windows SChannel, which I'm sure
> some win32 people would certainly prefer - much easier to do SSL
> deployments within an existing MS infrastructure...
>
> But no, that certainly wouldn't *reduce* the amount of code...

We'll call that Plan C: Making PostgreSQL the first piece of software in the 
world to support four different crypto libraries. ;-)


Re: [PATCH] Automatic client certificate selection support for libpq v1

From
Magnus Hagander
Date:
Peter Eisentraut wrote:
> On Monday 11 May 2009 11:02:17 Magnus Hagander wrote:
>> Another thought: if we were to make ourselves support multiple SSL
>> libraries (that has been suggested before - at that point, people wanted
>> GnuTLS), we could also add support for Windows SChannel, which I'm sure
>> some win32 people would certainly prefer - much easier to do SSL
>> deployments within an existing MS infrastructure...
>>
>> But no, that certainly wouldn't *reduce* the amount of code...
> 
> We'll call that Plan C: Making PostgreSQL the first piece of software in the 
> world to support four different crypto libraries. ;-)

I could've sworn curl did :-) But it turns out they do SChannel
*through* OpenSSL. :-) So we can probably live with that ;)

//Magnus