Re: 8.1 Build 405 JDBC and certificate trasnfer - Mailing list pgsql-jdbc
From | Neil Macneale |
---|---|
Subject | Re: 8.1 Build 405 JDBC and certificate trasnfer |
Date | |
Msg-id | 43F85003.8080001@theory.org Whole thread Raw |
In response to | 8.1 Build 405 JDBC and certificate trasnfer (Andrew Madu <andrewmadu@gmail.com>) |
Responses |
Re: 8.1 Build 405 JDBC and certificate trasnfer
|
List | pgsql-jdbc |
Andrew Madu wrote: > Hi, > can anyone confirm with me whether this driver supports certificate > transfer via the inclusion of root.crt in the data folder yet? > > regards > > Andrew I sure hope it doesn't, because I am putting together a patch to fix this:-) Attached is a patch to support client certificate authentication, to some degree. It has a limitation that your trust store must be the same as your key store. It is also completely uncommented, but it's not that complicated. The patch contains two things. First a change to MakeSSL which allows the user specified SSLSocketFactory to be constructed with the "info" Properties Object. I don't know if the postgresql JDBC veterans condone this, but there are simply to many configuration options to be contained in a simple string. (key word being simple). The second is a new class called ValidatingFactory, which is a SSLSocketFactory implementation which does the work required. Also included is a simple class file with a main method to show how to use the class. Like I said, I'm not done with the patch, but I figured since someone asked about it I may was well pipe up. It would be nice to get comments anyway! Cheers, Neil import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; import org.postgresql.Driver; import org.postgresql.ssl.NonValidatingFactory; import org.postgresql.ssl.ValidatingFactory; public class Client { public static void main(String[] a) throws Exception { // Load the drive class to register jdbc Class c = Driver.class; String url = "jdbc:postgresql://HOST/DB"; Properties props = new Properties(); props.setProperty("user","--ID--"); props.setProperty("password","--PASSWORD--"); props.setProperty("ssl", "true"); // validation args. the options are all options. for defaults, read the code. props.setProperty("sslfactory", ValidatingFactory.class.getName()); props.setProperty(ValidatingFactory.SSL_KEYSTORE_PASSWORD, "--PASSWORD--"); props.setProperty(ValidatingFactory.SSL_PROTOCOL, "TLS"); // or SSLv3, SSLv2,SSlv1 props.setProperty(ValidatingFactory.SSL_KEYSTORE_TYPE, "JKS"); // or PKCS12,JCEKS(?) props.setProperty(ValidatingFactory.SSL_FILE_KEYSTORE, "--FILE--"); Connection conn = DriverManager.getConnection(url, props); Statement st = conn.createStatement(); ResultSet rs = st.executeQuery("SELECT version();"); while (rs.next()) { System.out.println(rs.getString(1)); } rs.close(); st.close(); conn.close(); } } ### Eclipse Workspace Patch 1.0 #P pgjdbc Index: org/postgresql/ssl/MakeSSL.java =================================================================== RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/ssl/MakeSSL.java,v retrieving revision 1.5 diff -u -r1.5 MakeSSL.java --- org/postgresql/ssl/MakeSSL.java 24 Nov 2005 02:29:22 -0000 1.5 +++ org/postgresql/ssl/MakeSSL.java 19 Feb 2006 10:34:18 -0000 @@ -50,8 +50,14 @@ } catch (NoSuchMethodException nsme) { - ctor = factoryClass.getConstructor((Class[])null); - args = null; + try + { + ctor = factoryClass.getConstructor((Class[])null); + args = null; + } catch (NoSuchMethodException nsme2){ + ctor = factoryClass.getConstructor(new Class[]{Properties.class}); + args[0] = info; + } } factory = (SSLSocketFactory)ctor.newInstance(args); } @@ -60,7 +66,7 @@ throw new PSQLException(GT.tr("The SSLSocketFactory class provided {0} could not be instantiated.", classname),PSQLState.CONNECTION_FAILURE, e); } } - + Socket newConnection = factory.createSocket(stream.getSocket(), stream.getHost(), stream.getPort(), true); stream.changeSocket(newConnection); } Index: org/postgresql/ssl/ValidatingFactory.java =================================================================== RCS file: org/postgresql/ssl/ValidatingFactory.java diff -N org/postgresql/ssl/ValidatingFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/postgresql/ssl/ValidatingFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,97 @@ +package org.postgresql.ssl; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Properties; + +public class ValidatingFactory extends WrappedFactory { + + public static final String SSL_FILE_KEYSTORE = "ssl.keystore"; + + public static final String SSL_KEYSTORE_TYPE = "ssl.keystore.type"; + + public static final String SSL_KEYSTORE_PASSWORD = "ssl.keystore.password"; + + public static final String SSL_PROTOCOL = "ssl.protocol"; + + public ValidatingFactory(Properties props) throws Exception { + + File keystoreFile = getKeyStoreFile(props); + + String keyStoreType = getKeyStoreType(props, keystoreFile); + KeyStore trustStore = KeyStore.getInstance(keyStoreType); + KeyStore clientKeyStore = KeyStore.getInstance(keyStoreType); + + char[] password = getKeyStorePWD(props); + + trustStore.load(new FileInputStream(keystoreFile), password); + clientKeyStore.load(new FileInputStream(keystoreFile), password); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(trustStore); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init( clientKeyStore, password ); + + Arrays.fill(password, '\0'); + + SSLContext sslContext = SSLContext.getInstance(getProtocol(props)); + + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + _factory = sslContext.getSocketFactory(); + } + + private static File getKeyStoreFile(Properties props){ + String ks = props.getProperty(SSL_FILE_KEYSTORE); + if ( ks != null ){ + return new File(ks); + } + + File ans = new File(System.getProperty("user.home")); + ans = new File(ans, ".postgresql"); + ans = new File(ans, "postgresql.jks"); + return ans; + } + + private static String getKeyStoreType(Properties props, File keyStore){ + String kst = props.getProperty(SSL_KEYSTORE_TYPE); + if ( kst != null ){ + return kst; + } + + String fileName = keyStore.getName(); + if (fileName.lastIndexOf('.') > 0){ + return fileName.substring(fileName.lastIndexOf('.') + 1 ).toUpperCase(); + } + + return "JKS"; + } + + private static char[] getKeyStorePWD(Properties props){ + String pwd = props.getProperty(SSL_KEYSTORE_PASSWORD, ""); + return pwd.toCharArray(); + } + + private static String getProtocol(Properties props){ + if ( props.containsKey(SSL_PROTOCOL)){ + return props.getProperty(SSL_PROTOCOL); + } + return "SSLv3"; + } +}
pgsql-jdbc by date: