Thread: A solution to the SSL customizing problem

A solution to the SSL customizing problem

From
Ulrich Meis
Date:
I have read previous posts and the proposal that the user should supply a
SSLSocketFactory. Besides the obvious question - how - I see an additional
problem in that approach:

It's anything but user friendly.
All you want is a secure connection to postgres and you end up digging deeply
into the JSSE spec.
Even if all you want is turn validation off, you will have to have some
knowledge of the spec.
The really hard bit comes when you want to retrieve the certificate from the
server. You are using SSL because you are concerned about security, so you
probably want checking. Now you will have to give your own TrustManager
implementation that saves the certificate received for checking. Furthermore,
you will have to save that certificate somehow and you'll end up handling
keystores and stuff. What an effort just for this feature!

**********
I propose a different solution.
There are three modes I can think of when opening a connection:

1. Disabling validation.

Not interesting for a user with security concerns - you loose half of SSL's
functionality.

2. Enabling validation (standard)
The problem is that you need to get your hands on the server's certificate.
If you distribute an applet for a single server, like I do, you can ship the
server's certificate with your applet. One thing you certainly don't want is
to tell people how to insert it with a command line tool (keytool) and so a
nice solution is to provide it in a keystore and point jdbc to it.
Furthermore you are likely not to have write permissions on the standard
keystore (if you want to update it in your applet) because it is in a subdir
of java_home.

3. Trust and save (disable validation and save received key)
Same as with openssl and known_hosts, you accept the host the first time you
connect, save its certificate and use the standard mode from then on.
Implementation of this feature is easier within the driver because you have
access to the SSL connection and can retrieve the certificate(s). As a user
you can't just pull it off the postgres port because postgres doesn't start
off in SSL mode. You will have to implement a TrustManager.

**************
What I did for the driver is the following: Anologously to

javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword

I introduced

org.postgresql.trustStore and org.postgresql.trustStorePassword

Now you can specify your own trustStore for pgjdbc connections.
If it doesn't exist, it will be created for you.

Additionally I introduced the trust-and-save mode.

Currently I look for a property org.postgresql.ssl_trustandsave but this would
better be handled in a URL parameter like "ssl_trustandsave".

When the driver is in trust-and-save mode, it will trust any server you
connect to and save its certificate in the trustStore.

In an application, you would first run in normal mode. If the connection
fails, you ask the user if he wants to trust the unknown key and if he
agrees, you connect again with ssl_trustandsave mode activated and the key is
saved. In subsequent connections, you turn ssl_trustandsave off.

**********
Implementation:

I introduced a class org.postgresql.util.PGSSLSocketFactory and changed one
line in org.postgresql.Driver and method makeSSL from

javax.net.ssl.SSLSocketFactory factory = (javax.net.ssl.SSLSocketFactory)
javax.net.ssl.SSLSocketFactory.getDefault();

to

org.postgresql.util.PGSSLSocketFactory factory =
org.postgresql.util.PGSSLSocketFactory.getInstance();
.

What do you think?

Kind Regards,

Uli

Attachment

Re: A solution to the SSL customizing problem

From
Tom Lane
Date:
Ulrich Meis <kenobi@halifax.rwth-aachen.de> writes:
> I propose a different solution.

One small question --- have you checked that this behaves reasonably
with both a CVS-tip postmaster and prior releases?  CVS tip does do
certificate presentation and checking, whereas that stuff was
mistakenly disabled in 7.4.  (I think all the relevant changes are
present in 8.0beta3, but not earlier.)

            regards, tom lane

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:

> I propose a different solution. [...]

This seems like a subset of the other solutions suggested. If you can
configure the SSLSocketFactory used, you can use a class just like the
one you provided without requiring that everyone uses it.

I'd rather see a flexible solution that can be customized to the needs
of a particular application. For example, the code that you provided
assumes that there is one global truststore and that it is a Java-format
keystore that is accessible locally. Neither of those are necessarily true.

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Monday 11 October 2004 18:40, Tom Lane wrote:
> Ulrich Meis <kenobi@halifax.rwth-aachen.de> writes:
> > I propose a different solution.
>
> One small question --- have you checked that this behaves reasonably
> with both a CVS-tip postmaster and prior releases?  CVS tip does do
> certificate presentation and checking, whereas that stuff was
> mistakenly disabled in 7.4.  (I think all the relevant changes are
> present in 8.0beta3, but not earlier.)

No, I only tested on 7.4.5 (plz see notes below).
But it does present its certificate, I saved it a hundred times ;-)
I don't think Java would accept a SSL connection  without presentation of a
certificate.

Using a different trustStore and trust policy by itself doesn't change the
behavior towards postmaster.The custom SSLContext and the resulting
SSLContextFactory use the defaults in all other cases, so in effect there
shouldn't be any difference in behavior.
In other words if the postmaster works with the current driver, it will work
with the customization, too.

If you are concerned about getting errors in connections that don't use one of
the introduced features, please take a look at the first three lines of
createSocket

*********
public Socket createSocket(Socket socket, String host, int port, boolean
autoClose) throws IOException {
        if ((System.getProperty("org.postgresql.Driver.trustStore") == null)
&&
                (System.getProperty("org.postgresql.ssl_trustandsave") ==
null))
            return ((SSLSocketFactory)
SSLSocketFactory.getDefault()).createSocket(socket, host, port, autoClose);
*********

If no custom behavior is specified, the class uses the same line of code as
you can find in the current Driver.java.
That way bugs in the new class are only exposed if you use a feature.

Uli


Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Monday 11 October 2004 22:59, you wrote:
> Ulrich Meis wrote:
> > I propose a different solution. [...]
>
> This seems like a subset of the other solutions suggested. If you can
> configure the SSLSocketFactory used, you can use a class just like the
> one you provided without requiring that everyone uses it.

Viewpoint one: configurability.

I agree, someone could write that same class.
There is just one thing that will take a few more lines of code: retrieving
the certificate from the server.
In an application you don't get your hands on the actual socket that the
driver uses. The only way I see to get the server's certificate is to
implement your own TrustManager.

Surely, providing your own SSLSocketFactory is more configurable.
Why not offer providing a SSLSocketFactory, too?

Viewpoint two: usability.

I think all most people want is to have an SSL connection running and don't
care too much about the details.
The proposed features allow them to handle the problem that everyone runs into
when using SSL: how to get the server's certificate into your trustStore?

This is a big problem for applet programmers because applets should just
load&work, you can't tell people about keytool.
With this implementation you can either ship the certificate with the applet
or you can use trustandsave on new servers.

> I'd rather see a flexible solution that can be customized to the needs
> of a particular application. For example, the code that you provided
> assumes that there is one global truststore and that it is a Java-format
> keystore that is accessible locally. Neither of those are necessarily true.

For these cases it would be nice if you could provide your own KeyStore
object...the question is just how.

************
Ok...here comes another solution.
You let the user provide a handler and introduce an id in the URL in case the
user needs per connection handling.

In the Driver class you offer a method(make it empty if compiled without SSL):

setPGSSLHandler(PGSSLHandler handler) {
 pgsslhandler=handler;}

and a URL parameter conid=123

and

abstract class PGSSLHandler {

public static final int STANDARD=0;
public static final int CUSTOMFACTORY=1;
public static final int CUSTOMSTORE=2;

abstract public int getHandleType(int conid);
abstract public boolean getTrustAndSave(int conid);

abstract public KeyStore getKeyStore(int conid);
abstract public SSLSocketFactory getSSLSocketFactory(int conid);

}

This is really flexible, you don't need to do any classloading and you don't
need to manage multiple user objects in the driver.

How's that?

Uli


Re: A solution to the SSL customizing problem

From
Kris Jurka
Date:

On Mon, 11 Oct 2004, Tom Lane wrote:

> Ulrich Meis <kenobi@halifax.rwth-aachen.de> writes:
> > I propose a different solution.
>
> One small question --- have you checked that this behaves reasonably
> with both a CVS-tip postmaster and prior releases?  CVS tip does do
> certificate presentation and checking, whereas that stuff was
> mistakenly disabled in 7.4.  (I think all the relevant changes are
> present in 8.0beta3, but not earlier.)
>

The problem he's talking about is Java's default verification of the
server certificate by the client, not presentation of a client certificate
to be checked by the server.  Currently the JDBC driver does not handle
client certificates at all.

Kris Jurka

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:
> On Monday 11 October 2004 22:59, you wrote:
>
>>Ulrich Meis wrote:
>>
>>>I propose a different solution. [...]
>>
>>This seems like a subset of the other solutions suggested. If you can
>>configure the SSLSocketFactory used, you can use a class just like the
>>one you provided without requiring that everyone uses it.
>
>
> Viewpoint one: configurability.
>
> I agree, someone could write that same class. [...]

We could provide such a helper class that implements some policy along
the lines of what your patch implements as a convenience to users, but I
don't think that behaviour should be hardwired into the driver. It's not
the place of the driver to make that sort of policy decision. It needs
to be configurable, and the obvious place to do the configuration is to
allow the user to provide their own SSLSocketFactory level, since that
gives you complete freedom to customize whichever bits of the SSL
handshake you want to.

So I suggest you look at solving the "how do I give the driver an
appropriate SSLSocketFactory" problem first. Once that is solved, the
particular configurable behaviour you want can be easily implemented.

-O

Re: A solution to the SSL customizing problem

From
Kris Jurka
Date:

On Mon, 11 Oct 2004, Ulrich Meis wrote:

> 1. Disabling validation.
>
> Not interesting for a user with security concerns - you loose half of SSL's
> functionality.

There is certainly a demand for this.  While you do lose security it
is the default behavior for other pg clients (notably libpq).

> 2. Enabling validation (standard)
> The problem is that you need to get your hands on the server's certificate.
> If you distribute an applet for a single server, like I do, you can ship the
> server's certificate with your applet. One thing you certainly don't want is
> to tell people how to insert it with a command line tool (keytool) and so a
> nice solution is to provide it in a keystore and point jdbc to it.
> Furthermore you are likely not to have write permissions on the standard
> keystore (if you want to update it in your applet) because it is in a subdir
> of java_home.

I guess the question is what about keystores that are not plain files.
Providing a general means of allowing the client to provide the certs from
any source they desire.

Could you elaborate more on how you package the keystore with your applet?
I wasn't aware you could do that.

> 3. Trust and save (disable validation and save received key)
> Same as with openssl and known_hosts, you accept the host the first time you
> connect, save its certificate and use the standard mode from then on.
> Implementation of this feature is easier within the driver because you have
> access to the SSL connection and can retrieve the certificate(s). As a user
> you can't just pull it off the postgres port because postgres doesn't start
> off in SSL mode. You will have to implement a TrustManager.

I don't understand what the purpose of this is.  Why save the cert if you
aren't going to validate?  Don't you need some kind of confirm callback to
allow the user to do some kind of verification of the cert?


Kris Jurka

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Tuesday 12 October 2004 04:57, Oliver Jowett wrote:

> So I suggest you look at solving the "how do I give the driver an
> appropriate SSLSocketFactory" problem first. Once that is solved, the
> particular configurable behaviour you want can be easily implemented.

How about my suggestions with the abstract handler class?
I know it was a long post ;-)

Uli


Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:
> On Tuesday 12 October 2004 04:57, Oliver Jowett wrote:
>
>
>>So I suggest you look at solving the "how do I give the driver an
>>appropriate SSLSocketFactory" problem first. Once that is solved, the
>>particular configurable behaviour you want can be easily implemented.
>
>
> How about my suggestions with the abstract handler class?
> I know it was a long post ;-)

Namely:

> In the Driver class you offer a method(make it empty if compiled without SSL):
>
> setPGSSLHandler(PGSSLHandler handler) {
>  pgsslhandler=handler;}
>

> abstract class PGSSLHandler {
>
> public static final int STANDARD=0;
> public static final int CUSTOMFACTORY=1;
> public static final int CUSTOMSTORE=2;
>
> abstract public int getHandleType(int conid);
> abstract public boolean getTrustAndSave(int conid);
>
> abstract public KeyStore getKeyStore(int conid);
> abstract public SSLSocketFactory getSSLSocketFactory(int conid);
>
> }

How do you arrange for setPGSSLHandler to be called if you are in a
managed environment that does not know anything about the postgresql
driver beyond the standard JDBC interfaces?

The "conid" stuff looks really grotty. How do you coordinate the
URL-level configuration with the PGSSLHandler implementation?

Why is anything but getSSLSocketFactory() needed? You can implement
whatever keystore/truststore policy you want via a SSLSocketFactory.

The only new thing there is really the conid stuff, and I'd rather deal
with classloader issues (specify the class by name, loaded by the
driver) than have to deal with managing magic opaque unique
configuration keys and a postgresql-specific interface.

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Monday 11 October 2004 22:07, Kris Jurka wrote:
> On Mon, 11 Oct 2004, Ulrich Meis wrote:
> > 1. Disabling validation.
> >
> > Not interesting for a user with security concerns - you loose half of
> > SSL's functionality.
>
> There is certainly a demand for this.  While you do lose security it
> is the default behavior for other pg clients (notably libpq).
>

I would guess that if you care enough about security to begin with, you would
probably want to take the whole package - assuming it's not too much work.


> > 2. Enabling validation (standard)
> > The problem is that you need to get your hands on the server's
> > certificate. If you distribute an applet for a single server, like I do,
> > you can ship the server's certificate with your applet. One thing you
> > certainly don't want is to tell people how to insert it with a command
> > line tool (keytool) and so a nice solution is to provide it in a keystore
> > and point jdbc to it. Furthermore you are likely not to have write
> > permissions on the standard keystore (if you want to update it in your
> > applet) because it is in a subdir of java_home.
>
> I guess the question is what about keystores that are not plain files.
> Providing a general means of allowing the client to provide the certs from
> any source they desire.
>

I suggested this version because it seemed to be a problem to offer an
interface to the user.
If you can offer one it's a nice feature to be able to supply a keystore.
I made a suggestion in another post of this thread where the user can supply
either a SSLContextFactory or a KeyStore. I am curious what you'll think
about that.

> Could you elaborate more on how you package the keystore with your applet?
> I wasn't aware you could do that.

Well, without my proposal you can't ;-)
With it, you can put a keystore file with the certificate in the same dir
where the applet is and read that file via http(s). If you could provide
pgjdbc with a keystore object, you would only have to load it with the file.
Here, you have to save the keystore to some temp directory, set
org.postgresql.trustStore to the temp file, make the connection and finally
delete the temp file. Needs a signed applet.

>
> > 3. Trust and save (disable validation and save received key)
> > Same as with openssl and known_hosts, you accept the host the first time
> > you connect, save its certificate and use the standard mode from then on.
> > Implementation of this feature is easier within the driver because you
> > have access to the SSL connection and can retrieve the certificate(s). As
> > a user you can't just pull it off the postgres port because postgres
> > doesn't start off in SSL mode. You will have to implement a TrustManager.
>
> I don't understand what the purpose of this is.  Why save the cert if you
> aren't going to validate?  Don't you need some kind of confirm callback to
> allow the user to do some kind of verification of the cert?

After saving the cert and in subsequent connections you would switch back to
normal mode with validation. Now that the certificate is in your store,
everything goes fine.

Looks like this:

1. Applet tries  "jdbc://foo/bar" and fails with no certificate exception.
2. Applet connects to "jdbc://foo/bar?ssl_trustandsave" and immediately
afterwards closes the connection
3. Applet loads keystore, identifies the new certificate and tells user
"Warning, can't verify identity of DB server, continue?". If the answer is
no, it will delete the entry from the store.

(if confirmed)5. Applet connects to "jdbc://foo/bar" and will succeed.

The shorter version (if you don't care about cert details)

2. Applet asks user "Can't verify identity of DB server, continue?"
3. Applet connects this once with trustandsave



Uli


Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Tuesday 12 October 2004 06:34, Oliver Jowett wrote:
> Ulrich Meis wrote:
> > On Tuesday 12 October 2004 04:57, Oliver Jowett wrote:
> >>So I suggest you look at solving the "how do I give the driver an
> >>appropriate SSLSocketFactory" problem first. Once that is solved, the
> >>particular configurable behaviour you want can be easily implemented.
> >
> > How about my suggestions with the abstract handler class?
> > I know it was a long post ;-)
>
> Namely:
> > In the Driver class you offer a method(make it empty if compiled without
> > SSL):
> >
> > setPGSSLHandler(PGSSLHandler handler) {
> >  pgsslhandler=handler;}
> >
> >
> > abstract class PGSSLHandler {
> >
> > public static final int STANDARD=0;
> > public static final int CUSTOMFACTORY=1;
> > public static final int CUSTOMSTORE=2;
> >
> > abstract public int getHandleType(int conid);
> > abstract public boolean getTrustAndSave(int conid);
> >
> > abstract public KeyStore getKeyStore(int conid);
> > abstract public SSLSocketFactory getSSLSocketFactory(int conid);
> >
> > }
>
> How do you arrange for setPGSSLHandler to be called if you are in a
> managed environment that does not know anything about the postgresql
> driver beyond the standard JDBC interfaces?

How about making it a static method?
You could only provide one handler per JVM but that will probably do in most
cases.

>
> The "conid" stuff looks really grotty. How do you coordinate the
> URL-level configuration with the PGSSLHandler implementation?

That coordination is up to the user.
He provides the conid in the URL and the driver just forwards it to the
handler method. I don't see a problem here.

> Why is anything but getSSLSocketFactory() needed? You can implement
> whatever keystore/truststore policy you want via a SSLSocketFactory.

I just thought it would be a nice feature because it spares people a lot of
work, nothing else ;-)

> The only new thing there is really the conid stuff, and I'd rather deal
> with classloader issues (specify the class by name, loaded by the
> driver) than have to deal with managing magic opaque unique
> configuration keys and a postgresql-specific interface.

The way I thought about it was that the connection just forwards the conid to
makeSSL. Then there is no need for the driver to manage it.

I thought - after reading previous posts about this - loading a user class
would not be an option because some environments might not allow the driver
to do so?

Uli



Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:
> On Tuesday 12 October 2004 06:34, Oliver Jowett wrote:
>
>>How do you arrange for setPGSSLHandler to be called if you are in a
>>managed environment that does not know anything about the postgresql
>>driver beyond the standard JDBC interfaces?
>
>
> How about making it a static method?
> You could only provide one handler per JVM but that will probably do in most
> cases.

That doesn't help..

The situation I am thinking of is when you are configuring a DataSource
for use in a managed environment, e.g. appserver. The appserver knows
nothing about the driver it is using beyond the standard JDBC interfaces
(and perhaps not even that, if it's using a JCA wrapper). This breaks as
soon as you have a magic method that needs to be called on the driver to
configure SSL properties. There is no way to teach the appserver how to
do this without hardwiring dependencies on the PG way of doing things..
which does not make for a very portable appserver!

>>The "conid" stuff looks really grotty. How do you coordinate the
>>URL-level configuration with the PGSSLHandler implementation?
>
> That coordination is up to the user.
> He provides the conid in the URL and the driver just forwards it to the
> handler method. I don't see a problem here.

It's a maintenance nightmare. The configuration used by the handler
method has to somehow be kept in sync with the user configuration (the
URL). However, the handler method's configuration is not managed by the
same mechanisms that the user configuration is (namely "edit the JDBC URL").

>>Why is anything but getSSLSocketFactory() needed? You can implement
>>whatever keystore/truststore policy you want via a SSLSocketFactory.
>
> I just thought it would be a nice feature because it spares people a lot of
> work, nothing else ;-)

If you want to provide a default policy, you can do it as a separate
class. I don't see any reason for the extra methods in the driver-level
interface.

>>The only new thing there is really the conid stuff, and I'd rather deal
>>with classloader issues (specify the class by name, loaded by the
>>driver) than have to deal with managing magic opaque unique
>>configuration keys and a postgresql-specific interface.
>
>
> The way I thought about it was that the connection just forwards the conid to
> makeSSL. Then there is no need for the driver to manage it.
>
> I thought - after reading previous posts about this - loading a user class
> would not be an option because some environments might not allow the driver
> to do so?

The problem arises when the user code is in a disjoint classloader to
the driver's classloader. The driver cannot necessary load classes that
the user code can see. This is an issue if the handler is doing
something application-specific & is therefore part of the user code.

There is a related problem to do with passing around classnames in that
you cannot do multiple configurations just by instantiating new handlers
with different details, you either have to have lots of wrapper
implementations or something like the 'conid' scheme above along with
all the associated baggage.

...

Thinking about this a bit more, it seems to me that the use case that
hits the classloader issue (user code wanting feedback from the driver
via a nonstandard callback in a managed environment) is actually a hard
problem to solve anyway. It seems like if you need to do that you're
placing too high a burden on the appserver to magically know about the
behaviour of the nonstandard callback. The SSL configuration is really a
configuration property of the connection/connection pool, not something
that should be managed by user code in a managed environment. So maybe
we should forget about that case for the moment. Anyway..

I'd be OK with something like:

- a URL parameter that specifies name of a subclass of SSLSocketFactory
to use, and
- a method on the PG DataSource implementations that allows setting a
SSLSocketFactory *instance*. This instance is passed via a PG-private
API to the driver when creating connections from the DataSource. This
overrides use of the URL parameter.

i.e. you have:

   if (SSLSocketFactory instance provided via DataSource)
     use provided instance
   else if (SSLSocketFactory classname provided via URL)
     create new instance by name and use it
   else
     use default SSLSocketFactory

DataSource users configure the environment to instantiate a
SSLSocketFactory, configure it via reflection + javabean accessors, set
it via reflection on the DataSource. I think this is within the reach of
generic configuration mechanisms, they only need to know how to
manipulate the configuration objects via javabean accessors and don't
need to know anything specific to PG.

-O

Re: A solution to the SSL customizing problem

From
Markus Schaber
Date:
Hi, Oliver,

On Tue, 12 Oct 2004 21:23:58 +1300
Oliver Jowett <oliver@opencloud.com> wrote:

> The situation I am thinking of is when you are configuring a DataSource
> for use in a managed environment, e.g. appserver. The appserver knows
> nothing about the driver it is using beyond the standard JDBC interfaces
> (and perhaps not even that, if it's using a JCA wrapper). This breaks as
> soon as you have a magic method that needs to be called on the driver to
> configure SSL properties. There is no way to teach the appserver how to
> do this without hardwiring dependencies on the PG way of doing things..
> which does not make for a very portable appserver!

That's true.

We were very happy to learn that the JBoss connection pooling uses
wrappers that have a method to get the underlying original connection,
so we could call addDataType() to add the postGIS classes.

This left us with ugly code like:

    public static PGConnection unWrapPGConn(Connection conn) {
        PGConnection result = null;
        if (conn == null) {
            log.error("trying to unWrapPGConn(null)!");
            return null;
        }

        if (conn instanceof PGConnection) {
            result = (PGConnection) conn;
        } else if (conn instanceof WrappedConnection) {
            WrappedConnection w = (WrappedConnection) conn;
            try {
                result = unWrapPGConn(w.getUnderlyingConnection());
            } catch (SQLException e) {
                log.error("unWrapPGConn: Could not get underyling SQL connection!");
                log.error(e.toString());
            }
        }
        if (result == null) {
            log.warn("unWrapPGConn called with unknown connection type.");
            log.warn("given Connection Class is: " + conn.getClass().getPackage() + "." + conn.getClass().getName());
        }
        return result;
    }

So, you can see that this is a real world problem. Imagine we would need
to have our App portable to other app servers - this would not only
complicate the source above. We also would need to provide the appropriate
classes in the other environments, so the classloader can find them for
the instanceof call - this could imply strange licence issues.

Additionally, we currently have different apps with different needs
running in the same app server - so fine grained configurability is a
must. We cannot provide a single static method because the apps are
developed and deployed independently.

FIN,
Markus
--
markus schaber | dipl. informatiker
logi-track ag | rennweg 14-16 | ch 8001 zürich
phone +41-43-888 62 52 | fax +41-43-888 62 53
mailto:schabios@logi-track.com | www.logi-track.com

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Tuesday 12 October 2004 10:23, Oliver Jowett wrote:

> >>The "conid" stuff looks really grotty. How do you coordinate the
> >>URL-level configuration with the PGSSLHandler implementation?
> >
> > That coordination is up to the user.
> > He provides the conid in the URL and the driver just forwards it to the
> > handler method. I don't see a problem here.
>
> It's a maintenance nightmare. The configuration used by the handler
> method has to somehow be kept in sync with the user configuration (the
> URL). However, the handler method's configuration is not managed by the
> same mechanisms that the user configuration is (namely "edit the JDBC
> URL").

In an app server environment I would think that either the user obtains a
datasource object and provides handler and connection id as in

datasource.setjdbcurl("jdbc://server1/db1?handlerclass=mysslhandler&conid=1");con1=...
datasource.setjdbcurl("jdbc://server1/db1?handlerclass=mysslhandlerconid=2");con2=...

or uses a configuration file like

<datasource1>
<jdbcurl>.......conid=1</jdbcurl>

<datasource2>
<jdbcurl>......conid=2</jdbcurl>

where in this case the connection id identifies a database and not a
particular connection. Maybe it would better be called dbid.

> There is a related problem to do with passing around classnames in that
> you cannot do multiple configurations just by instantiating new handlers
> with different details, you either have to have lots of wrapper
> implementations or something like the 'conid' scheme above along with
> all the associated baggage.

If you can forward a class name from the URL to makeSSL, you can forward an id
as well and avoid the wrapper classes. Associated baggage stays the same.

>
> ...
>
> Thinking about this a bit more, it seems to me that the use case that
> hits the classloader issue (user code wanting feedback from the driver
> via a nonstandard callback in a managed environment) is actually a hard
> problem to solve anyway. It seems like if you need to do that you're
> placing too high a burden on the appserver to magically know about the
> behaviour of the nonstandard callback. The SSL configuration is really a
> configuration property of the connection/connection pool, not something
> that should be managed by user code in a managed environment. So maybe
> we should forget about that case for the moment. Anyway..

I agree that if you want to customize SSL settings and use multiple
configurations, you probably don't want to use the app server's connection
pool anyway.

>
> I'd be OK with something like:
>
> - a URL parameter that specifies name of a subclass of SSLSocketFactory
> to use, and
> - a method on the PG DataSource implementations that allows setting a
> SSLSocketFactory *instance*. This instance is passed via a PG-private
> API to the driver when creating connections from the DataSource. This
> overrides use of the URL parameter.

Sounds good to me.
I would suggest an additional URL parameter and method on PG DataSource for
the connection/database id.


Another completely different idea that I haven't tested and/or thought through
yet:

How about passing a JNDI name in the URL that users and/or app servers bind
their custom SSLSocketFactory to?
something like

context.bind("org/somewhere/sslfactory_companyA",new
mysslfactory("companyA"));
jdbcurl =
"jdbc:postgresql://companyA/workdb?sslsocketfactory=org/somewhere/sslfactory_companyA";
con=...

context.bind("org/somewhere/sslfactory_companyB",new mysslfactory("companyB");
jdbcurl =
"jdbc:postgresql://companyB/workdb?sslsocketfactory=org/somewhere/sslfactory_companyB";
con=...

Then you could forget about ids and the second class loading option.
JNDI is included since jdk1.3 and there's a jndi.jar for jdk1.2.


Uli


Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:
> On Tuesday 12 October 2004 10:23, Oliver Jowett wrote:
>
>
>>>>The "conid" stuff looks really grotty. How do you coordinate the
>>>>URL-level configuration with the PGSSLHandler implementation?
>>>
>>>That coordination is up to the user.
>>>He provides the conid in the URL and the driver just forwards it to the
>>>handler method. I don't see a problem here.
>>
>>It's a maintenance nightmare. The configuration used by the handler
>>method has to somehow be kept in sync with the user configuration (the
>>URL). However, the handler method's configuration is not managed by the
>>same mechanisms that the user configuration is (namely "edit the JDBC
>>URL").
>
>
> In an app server environment I would think that either the user obtains a
> datasource object and provides handler and connection id as in
>
> datasource.setjdbcurl("jdbc://server1/db1?handlerclass=mysslhandler&conid=1");con1=...
> datasource.setjdbcurl("jdbc://server1/db1?handlerclass=mysslhandlerconid=2");con2=...

This is unlikely, the datasources are usually created and configured by
the appserver. That's one of the reasons for having a managed
environment in the first place..

> or uses a configuration file like
>
> <datasource1>
> <jdbcurl>.......conid=1</jdbcurl>
>
> <datasource2>
> <jdbcurl>......conid=2</jdbcurl>

A configuration file like this is the usual approach.

> where in this case the connection id identifies a database and not a
> particular connection. Maybe it would better be called dbid.

OK: so an administrator wants to add a new database that needs to use
SSL. They reconfigure the appserver with details of the driver & URL to
use, perhaps by editing a config file and restarting, perhaps by talking
to the running server via JMX, web interface, etc.  The URL includes a
new 'conid' value. To pick this value the administrator has to check all
the other connections by hand and find a new unique value. Fun!

Now, how does the administrator configure 'mysslhandler' to handle the
new 'conid' or 'dbid' they have just configured? Keep in mind that the
only mechanism they have access to for configuring things on the machine
may be whatever is provided by the appserver (JMX etc).. so "edit this
local file" or "change these system properties" are not useful answers.

>>I'd be OK with something like:
>>
>>- a URL parameter that specifies name of a subclass of SSLSocketFactory
>>to use, and
>>- a method on the PG DataSource implementations that allows setting a
>>SSLSocketFactory *instance*. This instance is passed via a PG-private
>>API to the driver when creating connections from the DataSource. This
>>overrides use of the URL parameter.
>
>
> Sounds good to me.
> I would suggest an additional URL parameter and method on PG DataSource for
> the connection/database id.

See above :)

If you want to pass configuration information to the instantiated class
(and that is really what you're trying to do here, right?), a better way
seems to be to include all of that information directly in the URL
rather than adding more indirection. i.e. something like:

jdbc:postgresql://server:port/dbname?sslfactory=my.factory&sslfactoryargs=truststore=foo,behaviour=bar

Or even just provide the whole URL-derived Properties object to the
instantiated class and let it pick out whichever properties it wants.
Though I don't like passing all Properties as it makes the set of valid
properties for a connection unpredictable. Among other things this means
you can't correctly implement Driver.getPropertyInfo().

> Another completely different idea that I haven't tested and/or thought through
> yet:
>
> How about passing a JNDI name in the URL that users and/or app servers bind
> their custom SSLSocketFactory to?

You have no guarantees that there is a JNDI provider available or that
it works as you expect from the driver's context or that you even have
permission to bind into it. So this seems like a really bad idea.

As a concrete example, if you try to do this in our appserver things are
going to blow up horribly -- there is a separate JNDI tree per
application, applications have a readonly view of their tree, and
non-application code such as JDBC drivers has no guarantees about which
tree (if any) is visible when they are executing.

> JNDI is included since jdk1.3 and there's a jndi.jar for jdk1.2.

The infrastructure is there, but the default providers leave a lot to be
desired. There's no purely in-memory provider, for example.

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Tuesday 12 October 2004 23:12, Oliver Jowett wrote:
> Ulrich Meis wrote:
> > On Tuesday 12 October 2004 10:23, Oliver Jowett wrote:
> [...]

> > Sounds good to me.
> > I would suggest an additional URL parameter and method on PG DataSource
> > for the connection/database id.
>
> See above :)

Alright, finally I got your point ;-)

> If you want to pass configuration information to the instantiated class
> (and that is really what you're trying to do here, right?), a better way
> seems to be to include all of that information directly in the URL
> rather than adding more indirection. i.e. something like:
>
> jdbc:postgresql://server:port/dbname?sslfactory=my.factory&sslfactoryargs=t
>ruststore=foo,behaviour=bar

I totally agree.

> Or even just provide the whole URL-derived Properties object to the
> instantiated class and let it pick out whichever properties it wants.
> Though I don't like passing all Properties as it makes the set of valid
> properties for a connection unpredictable. Among other things this means
> you can't correctly implement Driver.getPropertyInfo().

How about passing

1. the URL without parameters so the factory knows which server&database it's
dealing with
2. a sslfactoryargs parameter as you described?

That way the factory can easily identify which certificate belongs to which
server.


> > Another completely different idea that I haven't tested and/or thought
> > through yet:
> >
> > How about passing a JNDI name in the URL that users and/or app servers
> > bind their custom SSLSocketFactory to?
>
> You have no guarantees that there is a JNDI provider available or that
> it works as you expect from the driver's context or that you even have
> permission to bind into it. So this seems like a really bad idea.

Again, agreed.
I wanted to come around the problem that the user cannot provide his own
factory in a managed environment, but seeing that this functionality isn't
desired anyway, the problem vanishes.

> As a concrete example, if you try to do this in our appserver things are
> going to blow up horribly -- there is a separate JNDI tree per
> application, applications have a readonly view of their tree, and
> non-application code such as JDBC drivers has no guarantees about which
> tree (if any) is visible when they are executing.
>
> > JNDI is included since jdk1.3 and there's a jndi.jar for jdk1.2.
>
> The infrastructure is there, but the default providers leave a lot to be
> desired. There's no purely in-memory provider, for example.

My thoughts were upon simple-jndi from osjava for a stand alone application.

Uli


Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
Now what I got from the discussion:

1. New URL parameters:

sslfactory=a.class.name
sslfactoryargs=driver=does,not=care

These are forwarded to

2. makeSSL which does something like

if (sslfactory!=null) { //sslfactory url parameter
 factory = instantiated class, handle exceptions
 }
else if (DSfactory!=null) { // factory set via DataSource
 factory = dsfactory;
 }
else factory = SSLSocketFactory.getDefault();
if (factory instanceof PGSSLHandler) {
 ((PGSSLHandler)factory).setPGURL(...);
 ((PGSSLHandler)factory).setPGargs(...);
 }
java.net.Socket newConnection = factory.createsocket(....);
....

3. a new abstract class

abstract PGSSLHandler extends SSLSocketFactory {

public void setPGURL(String url_no_parameters);
public void setPGargs(String args);

}

4. in Driver

protected setSSLSocketFactory(SSLSocketfactory factory) {
 DSfactory=factory;
 }

5. in BaseDataSource

public void setPG_SSLSocketFactory(SSLSocketFactory factory) {
((org.postgresql.Driver)DriverManager.getDriver("jdbc:postgresql://server/db")).setSSLSocketFactory(factory);
 }


How does that sound?
I would offer a concrete implementation unless someone else wants to do it and
if I knew you're interested.

Uli


Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:

> 3. a new abstract class
>
> abstract PGSSLHandler extends SSLSocketFactory {
>
> public void setPGURL(String url_no_parameters);
> public void setPGargs(String args);
>
> }

You don't need this class. Just require that the named factory class
implements SSLSocketFactory and has a ctor that takes two Strings.

Otherwise it looks fine. I wouldn't worry about the DataSource piece for
the moment.. if you have the ability to pass args to the constructed
class via a URL or properties file it is less of an issue.

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Thursday 14 October 2004 02:43, Oliver Jowett wrote:
>...
> Otherwise it looks fine. I wouldn't worry about the DataSource piece for
> the moment.. if you have the ability to pass args to the constructed
> class via a URL or properties file it is less of an issue.

How does that look like?
Since I found the same code in v2 and v3, I copied the new method as well.

Uli

Attachment

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:
> On Thursday 14 October 2004 02:43, Oliver Jowett wrote:
>
>>...
>>Otherwise it looks fine. I wouldn't worry about the DataSource piece for
>>the moment.. if you have the ability to pass args to the constructed
>>class via a URL or properties file it is less of an issue.
>
>
> How does that look like?
> Since I found the same code in v2 and v3, I copied the new method as well.

getSSLSocketFactory() doesn't need to be duplicated. Just pass the
connection properties to makeSSL and construct the factory from there.

Use of SSL-specific code needs to be conditionally compiled or the
driver will not build if JSSE is not present. This is easy to do if you
move getSSLSocketFactory() into Driver.java.in.

This doesn't look right, what is '&urlServer&'?

> +         Object[] args = { info.getProperty("&urlServer&"), info.getProperty("sslfactoryargs") };

Otherwise, seems ok.

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Friday 15 October 2004 05:35, Oliver Jowett wrote:
>...
> getSSLSocketFactory() doesn't need to be duplicated. Just pass the
> connection properties to makeSSL and construct the factory from there.

done

> Use of SSL-specific code needs to be conditionally compiled or the
> driver will not build if JSSE is not present. This is easy to do if you
> move getSSLSocketFactory() into Driver.java.in.

I see...it's all in makeSSL now and prefixed by @SSL@

> This doesn't look right, what is '&urlServer&'?
>
> > +         Object[] args = { info.getProperty("&urlServer&"),
> > info.getProperty("sslfactoryargs") };

In parseURL I added a line to set that property to the connection url string
without parameters. It's the easiest way I am aware of to get the exact url
down to makeSSL. Since parseURL simply splits parameters upon & and doesn't
convert escaped &s, I used the &s to make absolutely sure that this property
never clashes with a real url parameter - also that wouldn't actually matter.
If nothing else, it makes it obvious that this is internal.

An alternative would be to reconstruct the url via the parameters. I didn't
choose that approach for two reasons:
1. A lot more lines of code
2. For implementors of a SSLSocketFactory, it would break the approach of
simply comparing the received string with the original connection url
provided because it might slightly differ(in case for instance).

Uli

Attachment

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:
> On Friday 15 October 2004 05:35, Oliver Jowett wrote:
>>This doesn't look right, what is '&urlServer&'?
>>
>>>+         Object[] args = { info.getProperty("&urlServer&"),
>>>info.getProperty("sslfactoryargs") };
>
> In parseURL I added a line to set that property to the connection url string
> without parameters. It's the easiest way I am aware of to get the exact url
> down to makeSSL. Since parseURL simply splits parameters upon & and doesn't
> convert escaped &s, I used the &s to make absolutely sure that this property
> never clashes with a real url parameter - also that wouldn't actually matter.
> If nothing else, it makes it obvious that this is internal.

Ouch, that's a bit nasty.

Why exactly would a SSLSocketFactory implementation need to know the
original URL?

-O

Re: A solution to the SSL customizing problem

From
Markus Schaber
Date:
Hi, Oliver,

On Fri, 15 Oct 2004 18:28:02 +1300
Oliver Jowett <oliver@opencloud.com> wrote:

> Why exactly would a SSLSocketFactory implementation need to know the
> original URL?

At least, it should know the original hostname for comparison to the one in the
certificate, to avoid host spoofing.

Markus

--
markus schaber | dipl. informatiker
logi-track ag | rennweg 14-16 | ch 8001 zürich
phone +41-43-888 62 52 | fax +41-43-888 62 53
mailto:schabios@logi-track.com | www.logi-track.com

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Friday 15 October 2004 07:28, Oliver Jowett wrote:
> Ulrich Meis wrote:
> > On Friday 15 October 2004 05:35, Oliver Jowett wrote:
> >>This doesn't look right, what is '&urlServer&'?
> >>
> >>>+         Object[] args = { info.getProperty("&urlServer&"),
> >>>info.getProperty("sslfactoryargs") };
> >
> > In parseURL I added a line to set that property to the connection url
> > string without parameters. It's the easiest way I am aware of to get the
> > exact url down to makeSSL. Since parseURL simply splits parameters upon &
> > and doesn't convert escaped &s, I used the &s to make absolutely sure
> > that this property never clashes with a real url parameter - also that
> > wouldn't actually matter. If nothing else, it makes it obvious that this
> > is internal.
>
> Ouch, that's a bit nasty.
>
> Why exactly would a SSLSocketFactory implementation need to know the
> original URL?

That makes it easy to associate a particular getConnection call with a
presented certificate.

But to make the code less nasty, hostname and port might actually do the trick
because that suffices to identify the server that presented the certificate
(since a server only has one cert).

The attached changes provide as first parameter "hostname:port" to the factory
as given in the Properties object, so I removed the &urlServer& thing.


Uli

Attachment

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Ulrich Meis wrote:

> The attached changes provide as first parameter "hostname:port" to the factory
> as given in the Properties object, so I removed the &urlServer& thing.

The host and port are already given to the SSLSocketFactory when the
socket is created:

>   @SSL@       java.net.Socket newConnection = factory.createSocket(p_stream.getSocket(), p_stream.getHost(),
p_stream.getPort(),true); 

Why do we need to also pass them separately to the factory's ctor?

-O

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Markus Schaber wrote:
> Hi, Oliver,
>
> On Fri, 15 Oct 2004 18:28:02 +1300
> Oliver Jowett <oliver@opencloud.com> wrote:
>
>
>>Why exactly would a SSLSocketFactory implementation need to know the
>>original URL?
>
>
> At least, it should know the original hostname for comparison to the one in the
> certificate, to avoid host spoofing.

We already preserve the hostname & port and give them to
SSLSocketFactory.createSocket().

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Friday 15 October 2004 21:44, Oliver Jowett wrote:
> Ulrich Meis wrote:
> > The attached changes provide as first parameter "hostname:port" to the
> > factory as given in the Properties object, so I removed the &urlServer&
> > thing.
>
> The host and port are already given to the SSLSocketFactory when the
>
> socket is created:
> >   @SSL@       java.net.Socket newConnection =
> > factory.createSocket(p_stream.getSocket(), p_stream.getHost(),
> > p_stream.getPort(), true);

Right! I forgot.

>
> Why do we need to also pass them separately to the factory's ctor?

We don't ;-)

I removed that.

See next try attached ;-)

Uli

Attachment

Re: A solution to the SSL customizing problem

From
Kris Jurka
Date:

On Sat, 16 Oct 2004, Ulrich Meis wrote:

> [here's a patch to customize ssl.]
>

I've applied a modified version of this patch.  I moved the Driver.makeSSL
implementation into it's own class to not use @SSL@ everywhere.  I renamed
the sslfactoryargs to sslfactorarg because it really is one argument.  If
the user chooses to encode multiple arguments into it, that's really his
own business.  I put a NonValidatingFactory class in to demonstrate
how this can work and provide the most requested functionality.

Questions:

In the non-validating factory I have a SSLContext.getInstance("TLS"), but
I've also seen it use "SSL".  Is either preferred or does it matter for
pg?

I've been building the jdbc2ee jar files against the actual j2sdkee1.2.1,
not just the jdbc optional package.  This includes support for
javax.net.ssl.SSLSocketFactory, but not javax.net.ssl.SSLContext and
associated classes which are in com.sun.net.ssl instead.  So at the moment
I've modified the ssl requirements to not build ssl into this
particular jar.  What do we want to do about this:

 - nothing, the ee really meant datasource and was never meant to
   include ssl
 - make the existing ssl support work by not building the
   NonValidingFactory class
 - make everything work by building the NonValidatingFactory by importing
   from com.sun.net.ssl instead.

Kris Jurka

Re: A solution to the SSL customizing problem

From
Oliver Jowett
Date:
Kris Jurka wrote:

> In the non-validating factory I have a SSLContext.getInstance("TLS"), but
> I've also seen it use "SSL".  Is either preferred or does it matter for
> pg?

http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#AppA
has a list of 'standard' protocol names. "TLS" supports the largest set
of protocols, I believe.

> I've been building the jdbc2ee jar files against the actual j2sdkee1.2.1,
> not just the jdbc optional package.  This includes support for
> javax.net.ssl.SSLSocketFactory, but not javax.net.ssl.SSLContext and
> associated classes which are in com.sun.net.ssl instead.  So at the moment
> I've modified the ssl requirements to not build ssl into this
> particular jar.  What do we want to do about this:
>
>  - nothing, the ee really meant datasource and was never meant to
>    include ssl
>  - make the existing ssl support work by not building the
>    NonValidingFactory class

Either of these look OK to me.

>  - make everything work by building the NonValidatingFactory by importing
>    from com.sun.net.ssl instead.

I think this is a bad idea, it'd break the build on non-Sun JDKs.

-O

Re: A solution to the SSL customizing problem

From
Ulrich Meis
Date:
On Sunday 17 October 2004 14:07, Kris Jurka wrote:
> On Sat, 16 Oct 2004, Ulrich Meis wrote:
> > [here's a patch to customize ssl.]
>
> I've applied a modified version of this patch.  I moved the Driver.makeSSL
> implementation into it's own class to not use @SSL@ everywhere.  I renamed
> the sslfactoryargs to sslfactorarg because it really is one argument.  If
> the user chooses to encode multiple arguments into it, that's really his
> own business.  I put a NonValidatingFactory class in to demonstrate
> how this can work and provide the most requested functionality.

Thanks a lot!

> Questions:
>
> In the non-validating factory I have a SSLContext.getInstance("TLS"), but
> I've also seen it use "SSL".  Is either preferred or does it matter for
> pg?

The JSSE docs say :

---
Like other JCA provider-based "engine" classes, SSLContext objects are created
using the getInstance factory methods of the SSLContext class. These static
methods each return an instance that implements at least the requested secure
socket protocol.
---

My guess is that the minimum requirement for pg is ssl (tls being its
successor). Hence, I would use getInstance("SSL") but I suppose most java
versions will support both anyway.

Uli