Thread: Support for cert auth in JDBC

Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
[I posted this by mistake to the main dev mailing list... apologies if
you got this multiple times]

Hello developers,

My project had a requirement to use certificate authentication to the PG
server. Our application uses Hibernate.

We did just that and my boss has OKed a source release.

Now, the current version of the code has dependencies on our internal
libraries, so I'll need to spend a bit of time making this 'standard'
Java code.

Would you please tell me how you'd prefer for me to proceed to do that?
Do I need write access to your CVS repo, or should I just send the code
and test case by email?

Is there a specific version of the JDBC code you want me to work from,
should I just pick whatever is HEAD?

Any package you'd like me to choose?

Any specific crypto/ssl requirements to consider?

Any specific dependencies to use instead of others? (e.g. I like SLF4J,
but that's not everyone's choice...)

--
Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 18/05/2011 12:49 PM, Marc-André Laverdière wrote:
> [I posted this by mistake to the main dev mailing list... apologies if
> you got this multiple times]
>
> Hello developers,
>
> My project had a requirement to use certificate authentication to the PG
> server. Our application uses Hibernate.
>
> We did just that and my boss has OKed a source release.

Eh? Did what?

PgJDBC supports X.509 client certificates just fine.

What did you need to do? To which PgJDBC version did you do it? To
resolve what perceived issue(s) in the current codebase?

--
Craig Ringer

Tech-related writing at http://soapyfrogs.blogspot.com/

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
Hello,

This implementations allows to specify which keystore and which
truststore to load. This allows certificate authentication in the
application easily.

In the official documentation, it says:

<quote>
Custom SSLSocketFactory

PostgreSQL™ provides a way for developers to customize how a SSL
connection is established. This may be used to provide a custom
certificate source or other extensions by allowing the developer to
create their own SSLContext instance. The connection URL parameters
sslfactory and sslfactoryarg allow the user to specify which custom
class to use for creating the SSLSocketFactory. The class name specified
by sslfactory must extend javax.net.ssl.SSLSocketFactory and be
available to the driver's classloader. This class must have a zero
argument constructor or a single argument constructor taking a String
argument. This argument may optionally be supplied by sslfactoryarg.

Information on how to actually implement such a class is beyond the
scope of this documentation. Places to look for help are the JSSE
Reference Guide and the source to the NonValidatingFactory provided by
the JDBC driver.

The Java SSL API is not very well known to the JDBC driver developers
and we would be interested in any interesting and generally useful
extensions that you have implemented using this mechanism. Specifically
it would be nice to be able to provide client certificates to be
validated by the server.
</quote>

What I'm talking about is this factory referred to in the last paragraph.

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On Wednesday 18 May 2011 11:10 AM, Craig Ringer wrote:
> On 18/05/2011 12:49 PM, Marc-André Laverdière wrote:
>> [I posted this by mistake to the main dev mailing list... apologies if
>> you got this multiple times]
>>
>> Hello developers,
>>
>> My project had a requirement to use certificate authentication to the PG
>> server. Our application uses Hibernate.
>>
>> We did just that and my boss has OKed a source release.
>
> Eh? Did what?
>
> PgJDBC supports X.509 client certificates just fine.
>
> What did you need to do? To which PgJDBC version did you do it? To
> resolve what perceived issue(s) in the current codebase?
>

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 18/05/2011 2:06 PM, Marc-André Laverdière wrote:
> Hello,
>
> This implementations allows to specify which keystore and which
> truststore to load. This allows certificate authentication in the
> application easily.

It's already pretty easy. You can:

- Load your keys in the standard keystore;
- Populate a new JECKSf-format keystore with your cert and key and use
the javax.net.ssl.trustStore etc system properties on the cmdline or via
System.setProperty() to use that store instead of the default store;
- Provide your own javax.net.ssl.SSLSocketFactory that wraps the default
implementation with any additional behavior you need.

PgJDBC could use some documentation/examples for the latter option, but
it shouldn't need any changes to the PgJDBC code.

> The Java SSL API is not very well known to the JDBC driver developers
> and we would be interested in any interesting and generally useful
> extensions that you have implemented using this mechanism. Specifically
> it would be nice to be able to provide client certificates to be
> validated by the server.
> </quote>
>
> What I'm talking about is this factory referred to in the last paragraph.

OK, so you've just written an easy-to-use canned SSLSocketFactory that
loads client certificates from an application-configurable
keystore/truststore?

I did this in my app to allow it to use a PKCS#12 format X.509
certificate directly and it was a pretty low-pain procedure. It'd be
nice to have more general purpose examples in the PgJDBC sources,
though. Maybe I should dig out the examples I posted to this mailing
list a while ago and submit them, too?

I'm not one of the PgJDBC developers, but I'd be happy to have a look at
what you've done and see if I can be of any help, provide useful
feedback, etc.

It'd probably be best if you published your work as a patch ("diff")
against PgJDBC CVS HEAD, posting the patch to this mailing list so
people can look at it and try it. Make sure the email you send the patch
in clearly explains the reason for any change to the existing PgJDBC
code, and if you do change the core PgJDBC code make sure it passes any
tests and that it compiles under the oldest supported JDK.

--
Craig Ringer

Tech-related writing at http://soapyfrogs.blogspot.com/

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
It is true that anyone who knows the right Java APIs can put that
factory together with little pain. I just think that the average user
shouldn't have to bother about it.

Also, some use cases do not allow to use the default keystore and trust
store for everything.

Just for example, this is the setup in my application:
* 1 Cert for some server component that speaks TLS
* 1 Cert for the pgsql client component
* 1 Cert for the JNDI client component (connects to LDAP)

So we end up with 3 different keystores (and maybe trust stores too),
all of which may have different passwords. It is actually not that much
of a big deal to use, but the 'defaults' won't help us here too much I
think.

Using this kind of configurable setup allows much simpler deployments
than having to change stuff in a central keystore (which may have other
keys to NOT mess up with), and allows to test in different environments
and very easily.

Maybe our use case is overkill. Anyways, I'm attaching the code as I
have it now. I tested the code from which this one comes from, but this
incarnation isn't tested. I'll put more time on it once I hear back from
the maintainers. :)

I'd love to have some comments on this rough version also (CVS diff
didn't do anything with this file, so there is no point to include that).

P.S. Undocumented detail: we need to put the user's name in the
connection settings anyway, as it won't work without it.

Regards,

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On Wednesday 18 May 2011 12:32 PM, Craig Ringer wrote:
> On 18/05/2011 2:06 PM, Marc-André Laverdière wrote:
>> Hello,
>>
>> This implementations allows to specify which keystore and which
>> truststore to load. This allows certificate authentication in the
>> application easily.
>
> It's already pretty easy. You can:
>
> - Load your keys in the standard keystore;
> - Populate a new JECKSf-format keystore with your cert and key and use
> the javax.net.ssl.trustStore etc system properties on the cmdline or via
> System.setProperty() to use that store instead of the default store;
> - Provide your own javax.net.ssl.SSLSocketFactory that wraps the default
> implementation with any additional behavior you need.
>
> PgJDBC could use some documentation/examples for the latter option, but
> it shouldn't need any changes to the PgJDBC code.
>
>> The Java SSL API is not very well known to the JDBC driver developers
>> and we would be interested in any interesting and generally useful
>> extensions that you have implemented using this mechanism. Specifically
>> it would be nice to be able to provide client certificates to be
>> validated by the server.
>> </quote>
>>
>> What I'm talking about is this factory referred to in the last paragraph.
>
> OK, so you've just written an easy-to-use canned SSLSocketFactory that
> loads client certificates from an application-configurable
> keystore/truststore?
>
> I did this in my app to allow it to use a PKCS#12 format X.509
> certificate directly and it was a pretty low-pain procedure. It'd be
> nice to have more general purpose examples in the PgJDBC sources,
> though. Maybe I should dig out the examples I posted to this mailing
> list a while ago and submit them, too?
>
> I'm not one of the PgJDBC developers, but I'd be happy to have a look at
> what you've done and see if I can be of any help, provide useful
> feedback, etc.
>
> It'd probably be best if you published your work as a patch ("diff")
> against PgJDBC CVS HEAD, posting the patch to this mailing list so
> people can look at it and try it. Make sure the email you send the patch
> in clearly explains the reason for any change to the existing PgJDBC
> code, and if you do change the core PgJDBC code make sure it passes any
> tests and that it compiles under the oldest supported JDK.
>

Attachment

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 05/18/2011 03:48 PM, Marc-André Laverdière wrote:
> It is true that anyone who knows the right Java APIs can put that
> factory together with little pain. I just think that the average user
> shouldn't have to bother about it.

In that, I agree. Canned factories for simple cases like loading a
PKCS#12 format cert file, loading an app-specified keystore with a
callback for a password prompt, etc would make a lot of sense.

> So we end up with 3 different keystores (and maybe trust stores too),
> all of which may have different passwords. It is actually not that much
> of a big deal to use, but the 'defaults' won't help us here too much I
> think.

Quite right, if your different keystores must have different passwords
then you'd need to implement your own factory.

> P.S. Undocumented detail: we need to put the user's name in the
> connection settings anyway, as it won't work without it.

Interesting. I've only ever used setups where X.509 certs are
supplementary to traditional password authentication. I'm surprised that
the username isn't just deduced from the X.509 DN.


A few comments on your code: Overall, it looks pretty sensible at first
reading. There are a few things I noticed:

- The code doesn't accept arguments for keystore and truststore type, so
it won't be possible to load (eg) a PKCS#12 certificate file directly.
Only stores of the default types will work.

- It's not very subclassing-friendly, which could be an issue if it's to
be shipped in PgJDBC.


Specific subclassing use cases I see are allowing different
configuration mechanisms (Properties instances in thread-local storage,
JNDI, BeanManager contexts, blah blah) and accepting pre-configured
KeyStore & TrustStore instances. I needed to use the latter in my app,
and the former could become an issue whenever you need to create
CertAuthFactory instances with different configurations in the same app
- for example, for different users.

Personally, I dislike the use of system properties for configuration of
the class. It's totally thread-unsafe and is a real pain in any
situation where you don't necessarily want exactly the same
configuration for every instance. There's nothing wrong with having it
as a convenient default, but it'd be nice to be able to override it with
another configuration mechanism if this code is to ship with PgJDBC.

Alas the SSLSocketFactory interface doesn't offer any really nice
options like a way to pass a Properties instance to the ctor, and
accepting URL-encoded query-string like params as a String isn't
attractive given their length and the potential password security
issues. What I'd want to do is allow subclasses to override the
configuration behaviour by:

- Lazily initializing _internalFactory on first access rather than in
the ctor, so that:

- a subclass's ctor can do something useful and application-defined with
the String parameter passed to the one-arg form, like reading a config
file, looking up a Properties instance from a config service or JNDI,
etc. This would require that:

- Configuration values are acessed via protected methods rather than
direct System.getProperty() calls so those can be overridden by a
subclass to get the information from elsewhere.

Ideally (IMO) also:

- the KeyStore instantiation and loading for ks and trustKs is done in
protected methods too, so these can be completely overridden to obtain
instances another way.

--
Craig Ringer

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
Oh, also, your code has a simple thinko or copy-n-paste bug. On line 79:

fInTrustStore = new FileInputStream(keyPath);

should read:

fInTrustStore = new FileInputStream(trustPath);

Currently, trustPath never escapes the method and is effectively unused;
it's only tested for null/empty, then ignored.

--
Craig Ringer

Re: Support for cert auth in JDBC

From
Kris Jurka
Date:

On Wed, 18 May 2011, Craig Ringer wrote:

> Alas the SSLSocketFactory interface doesn't offer any really nice options
> like a way to pass a Properties instance to the ctor,

That'd be an easy thing to fix, just add another case to
org.postgresql.ssl.MakeSSL#convert to pass through the provided Properties
object.  I've thought about that in the past, but with no real use case, I
wasn't in a big rush to do so.

Kris Jurka

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 05/18/2011 11:32 PM, Kris Jurka wrote:
>
>
> On Wed, 18 May 2011, Craig Ringer wrote:
>
>> Alas the SSLSocketFactory interface doesn't offer any really nice
>> options like a way to pass a Properties instance to the ctor,
>
> That'd be an easy thing to fix, just add another case to
> org.postgresql.ssl.MakeSSL#convert to pass through the provided
> Properties object. I've thought about that in the past, but with no real
> use case, I wasn't in a big rush to do so.

OK, good to know.

It wasn't a big issue for me in the end, as I landed up fetching my
configuration using the String argument form as a key to an
application-specific configuration provider. It's much easier to pass a
String argument through various layers one often has over the JDBC
driver, like an ORM or the like.

--
Craig Ringer

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 05/18/2011 03:48 PM, Marc-André Laverdière wrote:
> It is true that anyone who knows the right Java APIs can put that
> factory together with little pain. I just think that the average user
> shouldn't have to bother about it.
>
> Also, some use cases do not allow to use the default keystore and trust
> store for everything.

I agree, and I think you're right that the PgJDBC  code should have a
re-usable class to provide support for these use cases without everyone
having to code their own.

I've taken your code and re-worked it a bit to:

- Use the PgJDBC WrappedFactory rather than re-implementing an
   effectively identical one;

- Separate the basic construction process of the SSLSocketFactory
   from its configuration, providing an abstract superclass that does
   the construction via a few simple method calls, so someone who needs
   different configuration sources/methods can re-use the code;

- Provided a concrete subclass of the above that gets its configuration
   from system properties and uses the superclass methods to construct
   the factory. This class has the same functionality as what you posted
   originally plus a few additional configuration options for additional
   use cases like non-default KeyStore types (pkcs12 etc); and

- Added more extensive JavaDoc

It's also possible to pass your own KeyStore and/or TrustStore instances
directly if your app has to do something funky like manage an in-memory
KeyStore.

What I haven't done yet is tested it! This is a preview so you can
comment on it and tell me if you think I've gone completely off the
rails or not.

The simplest uses of the code remain as simple as they were with your
original version. You just set some system properties and specify
SysPropCertAuthFactory as the sslsocketfactory class. More complex use
cases become possible without having to re-implement the whole lot - in
particular, if you can't fetch your configuration from system properties
you can provide alternative mechanisms to look it up without having to
re-write all the JSSE crap.

So: thanks VERY much for posting this code. My original demos weren't
flexible enough to be included in PgJDBC, and by posting this you really
helped motivate me to try to turn your code and my original demoes into
something that _was_.

What do you think? Note that you'll need PgJDBC on your classpath to
complile this now, because it uses org.postgresql.ssl.WrappedFactory  .

--
Craig Ringer

Attachment

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
Hi guys,

Here are some improvements based on the comments I saw so far.
I'm also adding a small cheapo tester. Definitely not JUnit-ready :)

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On Thursday 19 May 2011 11:16 AM, Craig Ringer wrote:
> On 05/18/2011 11:32 PM, Kris Jurka wrote:
>>
>>
>> On Wed, 18 May 2011, Craig Ringer wrote:
>>
>>> Alas the SSLSocketFactory interface doesn't offer any really nice
>>> options like a way to pass a Properties instance to the ctor,
>>
>> That'd be an easy thing to fix, just add another case to
>> org.postgresql.ssl.MakeSSL#convert to pass through the provided
>> Properties object. I've thought about that in the past, but with no real
>> use case, I wasn't in a big rush to do so.
>
> OK, good to know.
>
> It wasn't a big issue for me in the end, as I landed up fetching my
> configuration using the String argument form as a key to an
> application-specific configuration provider. It's much easier to pass a
> String argument through various layers one often has over the JDBC
> driver, like an ORM or the like.
>
> --
> Craig Ringer

Attachment

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
Hello,

Thanks for the changes. It is a good step forward in terms of
extensibility. That being said, I think we could just put a lot of the
loading code in AbstractCertAuthFactory, so that it is more reusable.

There was a tiny bug in SysPropCertAuthFactory whereas a path was sent
instead of a password. I'm attaching the fix.

I also added the code that allows to load both PKCS12 and JKS blindly. I
think that we can remove the property for specifying the type. I  doubt
we have to worry about other types of keystores than those two.

I'm also adding the slightly modified tester which uses the right class.

Regards,

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On Thursday 19 May 2011 11:28 AM, Craig Ringer wrote:
> On 05/18/2011 03:48 PM, Marc-André Laverdière wrote:
>> It is true that anyone who knows the right Java APIs can put that
>> factory together with little pain. I just think that the average user
>> shouldn't have to bother about it.
>>
>> Also, some use cases do not allow to use the default keystore and trust
>> store for everything.
>
> I agree, and I think you're right that the PgJDBC  code should have a
> re-usable class to provide support for these use cases without everyone
> having to code their own.
>
> I've taken your code and re-worked it a bit to:
>
> - Use the PgJDBC WrappedFactory rather than re-implementing an
>   effectively identical one;
>
> - Separate the basic construction process of the SSLSocketFactory
>   from its configuration, providing an abstract superclass that does
>   the construction via a few simple method calls, so someone who needs
>   different configuration sources/methods can re-use the code;
>
> - Provided a concrete subclass of the above that gets its configuration
>   from system properties and uses the superclass methods to construct
>   the factory. This class has the same functionality as what you posted
>   originally plus a few additional configuration options for additional
>   use cases like non-default KeyStore types (pkcs12 etc); and
>
> - Added more extensive JavaDoc
>
> It's also possible to pass your own KeyStore and/or TrustStore instances
> directly if your app has to do something funky like manage an in-memory
> KeyStore.
>
> What I haven't done yet is tested it! This is a preview so you can
> comment on it and tell me if you think I've gone completely off the
> rails or not.
>
> The simplest uses of the code remain as simple as they were with your
> original version. You just set some system properties and specify
> SysPropCertAuthFactory as the sslsocketfactory class. More complex use
> cases become possible without having to re-implement the whole lot - in
> particular, if you can't fetch your configuration from system properties
> you can provide alternative mechanisms to look it up without having to
> re-write all the JSSE crap.
>
> So: thanks VERY much for posting this code. My original demos weren't
> flexible enough to be included in PgJDBC, and by posting this you really
> helped motivate me to try to turn your code and my original demoes into
> something that _was_.
>
> What do you think? Note that you'll need PgJDBC on your classpath to
> complile this now, because it uses org.postgresql.ssl.WrappedFactory  .
>
> --
> Craig Ringer

Attachment

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
Thanks for those changes. Comments follow.

I'm attaching a further-tweaked version of the code you just sent. I
only had to change AbstractCertAuthFactory, so the other files remain
unaltered. Changes are:

- Only attempt to autodetect keystore type when null keystore type was
   passed, instead of always accepting but ignoring the keystore type
   argument.

- Make string constants private so nobody lands up relying on them
   so they can't be changed without breaking backward compat.

- Make "internal helper only" methods private. If they're protected,
   they're API not internal helpers.

Reasonable?

See further comments inline below:

On 05/19/2011 02:41 PM, Marc-André Laverdière wrote:

 > There was a tiny bug in SysPropCertAuthFactory whereas a path was sent
 > instead of a password. I'm attaching the fix.

Whoops. Thanks.

> Thanks for the changes. It is a good step forward in terms of
> extensibility. That being said, I think we could just put a lot of the
> loading code in AbstractCertAuthFactory, so that it is more reusable.

I thought it was, as much as already possible. What more would you move
into AbstractCertAuthFactory ? Or do you want to create a single helper
method that takes something like:

initFactory(
   String ksPath, char[] ksPass, char[] keyPass,
   String tsPath, char[] tsPass)

to reduce verbosity, one that uses the existing buildSSLSocketFactory(),
createKeyManagers() and createTrustManagers() behind the scenes?

To me, it seems a pretty small thing to have to call createKeyManagers
and createTrustManagers and pass the args to buildSSLSocketFactory(...).

I did intentionally move the checks for null/empty keystore path and
truststore path out of AbstractCertAuthFactory and into
SysPropCertAuthFactory. It's already possible to say "use system
default" by passing null to buildSSLSocketFactory(...), so I don't think
createKeyManagers(..) or createTrustManagers() should be making that
decision implicitly for the caller. In security, it might be quite
undesirable to have the app fail silently back to the system truststore
- you might have good reasons to have specified your own.

I can see that it's necessary to treat a missing key as "use default"
when using system properties as a configuration mechanism, but don't
think that should be an assumption that AbstractCertAuthFactory makes
for all users of that code.

> I also added the code that allows to load both PKCS12 and JKS blindly. I
> think that we can remove the property for specifying the type. I  doubt
> we have to worry about other types of keystores than those two.

JECKS is also common.

I don't love this part - it's making assumptions that may not prove true
in the long run, and IOException is a very broad exception to rely on to
detect a very specific thing like wrong keystore format. It could
potentially result in confusing error messages, too. For example, a
corrupt or damaged JKS keystore might fail to load with an error
reporting that a "pkcs12 keystore could not be read", causing the user
to wonder why the S@#$@ the code was trying to read it as PKCS#12 and
not identify the real problem, that it tried JKS first and failed
because the keystore was damaged.

It seems OK to me to attempt to auto-detect the keystore type when no
keystore type is given. The code you posted _ignores_ the keystore type
argument. If a non-null keystore type is passed it should be honoured,
but if a null keystore type is passed then I think it's fine to try to
detect it rather than blindly assuming KeyStore.getDefaultType() .

--
Craig Ringer


Attachment

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
That's good changes.
I'm not super keen on the idea of asking the user of providing the type.
But I'm not gonna fight over that :)

Now, would you please elaborate on those todos?

Also, methinks the @author tag at the top needs an extra line as follows:
@author Craig Ringer (craig@postnewspapers.com.au)

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On Thursday 19 May 2011 12:57 PM, Craig Ringer wrote:
> Thanks for those changes. Comments follow.
>
> I'm attaching a further-tweaked version of the code you just sent. I
> only had to change AbstractCertAuthFactory, so the other files remain
> unaltered. Changes are:
>
> - Only attempt to autodetect keystore type when null keystore type was
>   passed, instead of always accepting but ignoring the keystore type
>   argument.
>
> - Make string constants private so nobody lands up relying on them
>   so they can't be changed without breaking backward compat.
>
> - Make "internal helper only" methods private. If they're protected,
>   they're API not internal helpers.
>
> Reasonable?
>
> See further comments inline below:
>
> On 05/19/2011 02:41 PM, Marc-André Laverdière wrote:
>
>> There was a tiny bug in SysPropCertAuthFactory whereas a path was sent
>> instead of a password. I'm attaching the fix.
>
> Whoops. Thanks.
>
>> Thanks for the changes. It is a good step forward in terms of
>> extensibility. That being said, I think we could just put a lot of the
>> loading code in AbstractCertAuthFactory, so that it is more reusable.
>
> I thought it was, as much as already possible. What more would you move
> into AbstractCertAuthFactory ? Or do you want to create a single helper
> method that takes something like:
>
> initFactory(
>   String ksPath, char[] ksPass, char[] keyPass,
>   String tsPath, char[] tsPass)
>
> to reduce verbosity, one that uses the existing buildSSLSocketFactory(),
> createKeyManagers() and createTrustManagers() behind the scenes?
>
> To me, it seems a pretty small thing to have to call createKeyManagers
> and createTrustManagers and pass the args to buildSSLSocketFactory(...).
>
> I did intentionally move the checks for null/empty keystore path and
> truststore path out of AbstractCertAuthFactory and into
> SysPropCertAuthFactory. It's already possible to say "use system
> default" by passing null to buildSSLSocketFactory(...), so I don't think
> createKeyManagers(..) or createTrustManagers() should be making that
> decision implicitly for the caller. In security, it might be quite
> undesirable to have the app fail silently back to the system truststore
> - you might have good reasons to have specified your own.
>
> I can see that it's necessary to treat a missing key as "use default"
> when using system properties as a configuration mechanism, but don't
> think that should be an assumption that AbstractCertAuthFactory makes
> for all users of that code.
>
>> I also added the code that allows to load both PKCS12 and JKS blindly. I
>> think that we can remove the property for specifying the type. I  doubt
>> we have to worry about other types of keystores than those two.
>
> JECKS is also common.
>
> I don't love this part - it's making assumptions that may not prove true
> in the long run, and IOException is a very broad exception to rely on to
> detect a very specific thing like wrong keystore format. It could
> potentially result in confusing error messages, too. For example, a
> corrupt or damaged JKS keystore might fail to load with an error
> reporting that a "pkcs12 keystore could not be read", causing the user
> to wonder why the S@#$@ the code was trying to read it as PKCS#12 and
> not identify the real problem, that it tried JKS first and failed
> because the keystore was damaged.
>
> It seems OK to me to attempt to auto-detect the keystore type when no
> keystore type is given. The code you posted _ignores_ the keystore type
> argument. If a non-null keystore type is passed it should be honoured,
> but if a null keystore type is passed then I think it's fine to try to
> detect it rather than blindly assuming KeyStore.getDefaultType() .
>
> --
> Craig Ringer
>
>
>
>

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 05/19/2011 04:11 PM, Marc-André Laverdière wrote:
> That's good changes.
> I'm not super keen on the idea of asking the user of providing the type.
> But I'm not gonna fight over that :)

So long as the option exists, I'm happy. I think it's a reasonable idea
to try to auto-detect it by default.

> Now, would you please elaborate on those todos?

Whoops, I never meant to send the code to you with those in it.

The latter one no longer applies, it's resolved.

The first one isn't important for now. The main use case is if you want
to add additional trusted certs without "hiding" the system trust
database. It's a separate task and now that it's possible to pass your
own TrustManager can be done by apps that need it without modifying
AbstractCertAuthFactory at all.

So both may be removed. Thanks for pointing that out.

I'll see if I can put together an example X509TrustManager that tries to
verify trust against an app-supplied KeyStore first and failing that
against the system store. I have one around that I can adapt, but won't
be able to do that immediately as I have to get on with other work.

--
Craig Ringer

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
Hi folks,

It is not over... It is not in the CVS repository yet :D

What would be the next step?
My guess is that we need to update the testware for it. That sounds like
a tricky proposition that would mess up a bunch of things here and
there... Any ideas on how to do it best?

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On Thursday 19 May 2011 11:44 AM, Marc-André Laverdière wrote:
> Hi guys,
>
> Here are some improvements based on the comments I saw so far.
> I'm also adding a small cheapo tester. Definitely not JUnit-ready :)
>
> Marc-André Laverdière
> Software Security Scientist
> Innovation Labs, Tata Consultancy Services
> Hyderabad, India
>
> On Thursday 19 May 2011 11:16 AM, Craig Ringer wrote:
>> On 05/18/2011 11:32 PM, Kris Jurka wrote:
>>>
>>>
>>> On Wed, 18 May 2011, Craig Ringer wrote:
>>>
>>>> Alas the SSLSocketFactory interface doesn't offer any really nice
>>>> options like a way to pass a Properties instance to the ctor,
>>>
>>> That'd be an easy thing to fix, just add another case to
>>> org.postgresql.ssl.MakeSSL#convert to pass through the provided
>>> Properties object. I've thought about that in the past, but with no real
>>> use case, I wasn't in a big rush to do so.
>>
>> OK, good to know.
>>
>> It wasn't a big issue for me in the end, as I landed up fetching my
>> configuration using the String argument form as a key to an
>> application-specific configuration provider. It's much easier to pass a
>> String argument through various layers one often has over the JDBC
>> driver, like an ORM or the like.
>>
>> --
>> Craig Ringer
>>
>>
>>

Re: Support for cert auth in JDBC

From
Kris Jurka
Date:

On Tue, 24 May 2011, Marc-Andr? Laverdi?re wrote:

> It is not over... It is not in the CVS repository yet :D
>
> What would be the next step?

It was not clear to me that the discussion between you and Craig had
resulted in a final code version.  Apparently you think so.  Craig do you
concur?  If so I'll take a look at it and see about committing it.

> My guess is that we need to update the testware for it. That sounds like
> a tricky proposition that would mess up a bunch of things here and
> there... Any ideas on how to do it best?

I don't think there's any good way to setup automated tests for things
like client certificates which need significant server configuration.  So
I wouldn't bother with that.  Perhaps some documentation updates would be
in order, but I haven't looked at the code yet to know what might be
appropriate.

Kris Jurka

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 25/05/11 00:27, Kris Jurka wrote:
>
>
> On Tue, 24 May 2011, Marc-Andr? Laverdi?re wrote:
>
>> It is not over... It is not in the CVS repository yet :D
>>
>> What would be the next step?
>
> It was not clear to me that the discussion between you and Craig had
> resulted in a final code version.  Apparently you think so.  Craig do
> you concur?

I'm happy with the state of the code, but should really test it properly
before signing off on that. In particular, I need to test PKCS#12 cert
files and test a JECKS keystore containing multiple keys only one of
which is valid to access Pg.

On the other hand, I'm swamped at the moment and unsure if I'll get to
that in a reasonable amount of time. The tests Marc-André wrote
demonstrate the core functionality pretty well, and the code would be
good to get into the official codebase to save others from duplicating
the same work over and over as both Marc-André and I have each done already.

Argh. I'm going to have to come back to that, as I have a backup server
to fix. Maybe it's best if you have a look and see what you think of it,
while I try to find some time to do some more testing.

> Perhaps some documentation updates
> would be in order, but I haven't looked at the code yet to know what
> might be appropriate.

Some documentation updates are definitely in order, to sit alongside the
existing documentation for the non-validating ssl factory.


By the way, I _do_ think it'd be useful to add support for constructing
the socket factory with:

  FactoryClass(String arg, Properties jdbcProperties)

... where the properties argument contains all the Pg JDBC properties
like the user name and password. It'd make it easier for apps to pass
custom args into a socket factory, especially things like the password
to the user's private key that they don't want to have to put in the
sslocketfactoryarg string.

I could also then produce a second version of the cert factory for
people to use that got all its settings from the jdbc connection
properties instead of the sytem properties.

I wouldn't suggest adding that now, though, but maybe as a revision once
the working code is already committed.

--
Craig Ringer

Re: Support for cert auth in JDBC

From
Marc-André Laverdière
Date:
Hello everybody,

I haven't heard back about this testing... did anyone get time to do it?

Marc-André Laverdière
Software Security Scientist
Innovation Labs, Tata Consultancy Services
Hyderabad, India

On 05/25/2011 07:09 AM, Craig Ringer wrote:
> On 25/05/11 00:27, Kris Jurka wrote:
>>
>>
>> On Tue, 24 May 2011, Marc-Andr? Laverdi?re wrote:
>>
>>> It is not over... It is not in the CVS repository yet :D
>>>
>>> What would be the next step?
>>
>> It was not clear to me that the discussion between you and Craig had
>> resulted in a final code version.  Apparently you think so.  Craig do
>> you concur?
>
> I'm happy with the state of the code, but should really test it properly
> before signing off on that. In particular, I need to test PKCS#12 cert
> files and test a JECKS keystore containing multiple keys only one of
> which is valid to access Pg.
>
> On the other hand, I'm swamped at the moment and unsure if I'll get to
> that in a reasonable amount of time. The tests Marc-André wrote
> demonstrate the core functionality pretty well, and the code would be
> good to get into the official codebase to save others from duplicating
> the same work over and over as both Marc-André and I have each done already.
>
> Argh. I'm going to have to come back to that, as I have a backup server
> to fix. Maybe it's best if you have a look and see what you think of it,
> while I try to find some time to do some more testing.
>
>> Perhaps some documentation updates
>> would be in order, but I haven't looked at the code yet to know what
>> might be appropriate.
>
> Some documentation updates are definitely in order, to sit alongside the
> existing documentation for the non-validating ssl factory.
>
>
> By the way, I _do_ think it'd be useful to add support for constructing
> the socket factory with:
>
>    FactoryClass(String arg, Properties jdbcProperties)
>
> ... where the properties argument contains all the Pg JDBC properties
> like the user name and password. It'd make it easier for apps to pass
> custom args into a socket factory, especially things like the password
> to the user's private key that they don't want to have to put in the
> sslocketfactoryarg string.
>
> I could also then produce a second version of the cert factory for
> people to use that got all its settings from the jdbc connection
> properties instead of the sytem properties.
>
> I wouldn't suggest adding that now, though, but maybe as a revision once
> the working code is already committed.
>
> --
> Craig Ringer

Re: Support for cert auth in JDBC

From
Craig Ringer
Date:
On 27/06/11 14:18, Marc-André Laverdière wrote:
> Hello everybody,
>
> I haven't heard back about this testing... did anyone get time to do it?

Argh. I've been head-down in work and completely forgot about it.

--
Craig Ringer

Re: Support for cert auth in JDBC

From
Bruno Harbulot
Date:
Hi all,

Following the recent discussions about SSL support, here is a bit of
feedback on this version.

To fix the "TODO: Delegate trust checks to system trustmanager if
no match in our own trustmanager?" is fairly easy: just pass null to
SSLContext.init(...).

I would do this in createTrustManager:

         KeyStore trustKs = loadKeyStore(trustStorePath, trustStorePass,
trustStoreType);
         if (trustKs != null) {
             TrustManagerFactory trustFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
             trustFactory.init(trustKs);
             return trustFactory.getTrustManagers();
         } else {
             return null;
         }

and this in loadKeyStore (instead of throwing an exception):

         if (path == null || "".equals(path))
             return null;

The null default also works for the SecureRandom if anyone isn't
specifying it.

(I would also do it do avoid potential NPEs perhaps in createKeyManager,
although there is no actual default.)




Since using PKCS#11 was discussed a few days ago on the mailing list
[1], I would also suggest a couple of changes, similar to what I had
done for Apache Tomcat [2].

Essentially, not all keystores are file-based (e.g. PKCS#11, NSS, OSX
KeychainStore, Windows store). The "NONE" file-path should be used for
those:
http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization
In this case, use a null InputStream (not necessarily a FileInputStream).

For PKCS#11, it's also useful to specify the provider (if the PKCS#11
configuration is in the JRE security configuration. This could be done
as follows (with an extra provider name parameter, which would be null
by default):

     private static KeyStore loadKeyStoreOfType(String path, char[]
password, String type, String provider) throws IOException,
GeneralSecurityException{
         // Load the keystore with the specified keystore type.
         if (path == null || "".equals(path))
             return null;
         if (password == null)
             throw new IllegalArgumentException("Password is null");
         if (type == null)
             type = KeyStore.getDefaultType();
         InputStream fIn = null;
         try{
             KeyStore ks;
             if (provider != null) {
                 ks = KeyStore.getInstance(type, provider);
             } else {
                 ks = KeyStore.getInstance(type);
             }
             // Using "NONE" for keystore that are not file-based.
             //
http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#Customization
             if (!"NONE".equals(path)) {
                 fIn = new FileInputStream(path);
             }
             ks.load(fIn, password);
             return ks;
         } finally{
             if (fIn != null) {
                 fIn.close();
             }
         }
     }


On 19/05/2011 08:27, Craig Ringer wrote:
> Thanks for those changes. Comments follow.
>
> I'm attaching a further-tweaked version of the code you just sent. I
> only had to change AbstractCertAuthFactory, so the other files remain
> unaltered. Changes are:
>
> - Only attempt to autodetect keystore type when null keystore type was
> passed, instead of always accepting but ignoring the keystore type
> argument.
>
> - Make string constants private so nobody lands up relying on them
> so they can't be changed without breaking backward compat.
>
> - Make "internal helper only" methods private. If they're protected,
> they're API not internal helpers.
>
> Reasonable?
>
>> I also added the code that allows to load both PKCS12 and JKS blindly. I
>> think that we can remove the property for specifying the type. I doubt
>> we have to worry about other types of keystores than those two.
>
> JECKS is also common.
>
> I don't love this part - it's making assumptions that may not prove true
> in the long run, and IOException is a very broad exception to rely on to
> detect a very specific thing like wrong keystore format. It could
> potentially result in confusing error messages, too. For example, a
> corrupt or damaged JKS keystore might fail to load with an error
> reporting that a "pkcs12 keystore could not be read", causing the user
> to wonder why the S@#$@ the code was trying to read it as PKCS#12 and
> not identify the real problem, that it tried JKS first and failed
> because the keystore was damaged.
>
> It seems OK to me to attempt to auto-detect the keystore type when no
> keystore type is given. The code you posted _ignores_ the keystore type
> argument. If a non-null keystore type is passed it should be honoured,
> but if a null keystore type is passed then I think it's fine to try to
> detect it rather than blindly assuming KeyStore.getDefaultType() .


I would personally prefer not to try to have the driver guess the
keystore type blindly. SSL errors can be obscure enough for users will
little SSL experience as it is (like "Could not find matching cipher
suites" sometimes when it's a problem with the key/cert).

Having the user specify the type or fall back on
KeyStore.getDefaultType() seems more in line with the rest of the
documentation in the JSSR ref. guide.



If this is of interest, I have done a bit of work on trying to make it
easier to configure SSLContexts while keeping default values in
jSSLutils [3].
I found that creating an SSLContextFactory interface/abstract class
tends to make this sort of configuration easier, as you don't need to
extend the SSLSocketFactory as much.
A similar approach could be used in the JDBC driver, but it would
require the creation of such an interface and modifications to
"MakeSSL". It might be too much.




Best wishes,

Bruno.

[1] http://archives.postgresql.org/pgsql-jdbc/2011-11/msg00015.php
[2] https://issues.apache.org/bugzilla/show_bug.cgi?id=43094
[3] http://www.jsslutils.org/