Lists: | pgsql-jdbc |
---|
From: | "Saleem EDAH-TALLY" <nmset(at)netcourrier(dot)com> |
---|---|
To: | pgsql-jdbc(at)postgresql(dot)org |
Subject: | SSL - Providing client certificates |
Date: | 2009-02-20 09:30:32 |
Message-ID: | 200902201030.33352.nmset@netcourrier.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-jdbc |
Hello,
http://jdbc.postgresql.org/documentation/83/ssl-factory.html states :
"Specifically it would be nice to be able to provide client certificates to be
validated by the server."
http://jdbc.postgresql.org/documentation/83/ssl-client.html refers to
validating the server's identity only, using javax.net.ssl.trustStore JVM-wide
setting.
However, if we set javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword,
the SSL connection is established and the client certificate is verified.
This seems contradictory with the documntation, or I am missing something.
I would be happy to read your comments.
Thank you.
From: | Kris Jurka <books(at)ejurka(dot)com> |
---|---|
To: | Saleem EDAH-TALLY <nmset(at)netcourrier(dot)com> |
Cc: | pgsql-jdbc(at)postgresql(dot)org |
Subject: | Re: SSL - Providing client certificates |
Date: | 2009-02-20 17:29:39 |
Message-ID: | Pine.BSO.4.64.0902201226580.23634@leary.csoft.net |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-jdbc |
On Fri, 20 Feb 2009, Saleem EDAH-TALLY wrote:
> However, if we set javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword,
> the SSL connection is established and the client certificate is verified.
>
When the code was first written, this wasn't tested and it was just
assumed that it wouldn't work. Recently we got a report that it did work,
but the documentation was not updated.
What I don't understand is how it selects the certificate to send. If you
have multiple keys in your keystore, how do you indicate which one to use?
Kris Jurka
From: | Guillaume Cottenceau <gc(at)mnc(dot)ch> |
---|---|
To: | Kris Jurka <books(at)ejurka(dot)com> |
Cc: | Saleem EDAH-TALLY <nmset(at)netcourrier(dot)com>, pgsql-jdbc(at)postgresql(dot)org |
Subject: | Re: SSL - Providing client certificates |
Date: | 2009-02-23 11:25:40 |
Message-ID: | 87iqn1v1hn.fsf@meuh.mnc.lan |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-jdbc |
Kris Jurka <books 'at' ejurka.com> writes:
> On Fri, 20 Feb 2009, Saleem EDAH-TALLY wrote:
>
>> However, if we set javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword,
>> the SSL connection is established and the client certificate is verified.
>>
>
> When the code was first written, this wasn't tested and it was just
> assumed that it wouldn't work. Recently we got a report that it did
> work, but the documentation was not updated.
>
> What I don't understand is how it selects the certificate to send. If
> you have multiple keys in your keystore, how do you indicate which one
> to use?
My quite limited understanding of the behaviour of SSL client
authentication may potentially help a little:
You initially send a certificate signing request to the
admin/owner of the server (signed with your private key); when
you receive the certificate reply (signed with their private
key), you can build a chain of trust between you and the server,
your keystore will look like:
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: <you>
Issuer: <server>
Certificate[2]:
Owner: <server>
Issuer: <server>
Then at the SSL handshake time, first the server presents his
certificate, second it asks for a client certificate, at that
time you are able to present the certificate belonging to the
chain of trust containing the server certificate on top.
--
Guillaume Cottenceau
From: | "Saleem EDAH-TALLY" <nmset(at)netcourrier(dot)com> |
---|---|
To: | pgsql-jdbc(at)postgresql(dot)org |
Subject: | Re: SSL - Providing client certificates |
Date: | 2009-02-23 14:53:02 |
Message-ID: | 200902231519.29993.nmset@netcourrier.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Lists: | pgsql-jdbc |
Regarding Kris Jurka's question :
> > What I don't understand is how it selects the certificate to send. If
> > you have multiple keys in your keystore, how do you indicate which one
> > to use?
http://java.sun.com/javase/6/docs/api/javax/net/ssl/SSLContext.html#init(javax.net.ssl.KeyManager[],
javax.net.ssl.TrustManager[], java.security.SecureRandom)
states
<>
Only the first instance of a particular key and/or trust manager implementation
type in the array is used...
</>
Hence it's not necessary to overload a keystore or a truststore.
And who knows how the entries in the keystore are sorted an presented to
SSLContext.init. My guess they are sorted in ascending order of the aliases,
but it's just a guess.
As an add-on to this thread, the following class allows to build a
SSLSocketFactory that is not JVM wide but specific to a connection. It can be
passed as sslfactory, and a label passed as sslfactoryarg.
It may be adapted and included in the jdbc-driver if found useful.
**********************************************************************
public class SSLBoth extends javax.net.ssl.SSLSocketFactory{
private String ksFile = null;
private String ksType = null;
private String ksPwd = null;
private String tsFile = null;
private String tsType = null;
private String tsPwd = null;
private javax.net.ssl.SSLSocketFactory ssf = null;
public SSLBoth(String label) {
setParams(label);
javax.net.ssl.KeyManagerFactory kmf = makeKMF();
javax.net.ssl.TrustManagerFactory tmf = makeTMF();
javax.net.ssl.SSLContext sslc = makeSSLContext(kmf.getKeyManagers(),
tmf.getTrustManagers());
ssf = sslc.getSocketFactory();
}
private void setParams(String label) {
ksFile = System.getProperty("KEYSTORE_FILE_" + label);
ksType = System.getProperty("KEYSTORE_TYPE_" + label);
ksPwd = System.getProperty("KEYSTORE_PWD_" + label);
tsFile = System.getProperty("TRUSTSTORE_FILE_" + label);
tsType = System.getProperty("TRUSTSTORE_TYPE_" + label);
tsPwd = System.getProperty("TRUSTSTORE_PWD_" + label);
}
private javax.net.ssl.KeyManagerFactory makeKMF() {
java.security.KeyStore ks = loadKeyStore(ksFile, ksType, ksPwd);
if (ks != null) {
try {
javax.net.ssl.KeyManagerFactory kmf =
javax.net.ssl.KeyManagerFactory.getInstance(javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, ksPwd.toCharArray());
return kmf;
} catch (java.security.KeyStoreException ex) {
ex.printStackTrace();
} catch (java.security.UnrecoverableKeyException ex) {
ex.printStackTrace();
} catch (java.security.NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
return null;
}
private javax.net.ssl.TrustManagerFactory makeTMF() {
java.security.KeyStore ts = loadKeyStore(tsFile, tsType, tsPwd);
if (ts != null) {
try {
javax.net.ssl.TrustManagerFactory tmf =
javax.net.ssl.TrustManagerFactory.getInstance(javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
return tmf;
} catch (java.security.KeyStoreException ex) {
ex.printStackTrace();
} catch (java.security.NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
return null;
}
private javax.net.ssl.SSLContext makeSSLContext(javax.net.ssl.KeyManager[]
km, javax.net.ssl.TrustManager[] tm) {
try {
javax.net.ssl.SSLContext sslc =
javax.net.ssl.SSLContext.getInstance("TLS");
sslc.init(km, tm, new java.security.SecureRandom());
return sslc;
} catch (java.security.KeyManagementException ex) {
ex.printStackTrace();
} catch (java.security.NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return null;
}
public static java.security.KeyStore loadKeyStore(String ksPath, String
type, String pwd) {
try {
java.security.KeyStore ks =
java.security.KeyStore.getInstance(type);
java.io.FileInputStream fis = new java.io.FileInputStream(ksPath);
ks.load(fis, pwd.toCharArray());
fis.close();
return ks;
}
catch (java.security.KeyStoreException ex) {
ex.printStackTrace();
}
catch (java.io.FileNotFoundException ex) {
ex.printStackTrace();
}
catch (java.io.IOException ex) {
ex.printStackTrace();
}
catch (java.security.NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
catch (java.security.cert.CertificateException ex) {
ex.printStackTrace();
}
return null;
}
@Override
public String[] getDefaultCipherSuites() {
return ssf.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return ssf.getSupportedCipherSuites();
}
@Override
public java.net.Socket createSocket(java.net.Socket arg0, String arg1, int
arg2, boolean arg3) throws java.io.IOException {
return ssf.createSocket(arg0, arg1, arg2, arg3);
}
@Override
public java.net.Socket createSocket(String arg0, int arg1) throws
java.io.IOException, java.net.UnknownHostException {
return ssf.createSocket(arg0, arg1);
}
@Override
public java.net.Socket createSocket(String arg0, int arg1,
java.net.InetAddress arg2, int arg3) throws java.io.IOException,
java.net.UnknownHostException {
return ssf.createSocket(arg0, arg1, arg2, arg3);
}
@Override
public java.net.Socket createSocket(java.net.InetAddress arg0, int arg1)
throws java.io.IOException {
return ssf.createSocket(arg0, arg1);
}
@Override
public java.net.Socket createSocket(java.net.InetAddress arg0, int arg1,
java.net.InetAddress arg2, int arg3) throws java.io.IOException {
return ssf.createSocket(arg0, arg1, arg2, arg3);
}
}
**********************************************************************