Thread: SSL - Providing client certificates

SSL - Providing client certificates

From
"Saleem EDAH-TALLY"
Date:
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.

Re: SSL - Providing client certificates

From
Kris Jurka
Date:

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

Re: SSL - Providing client certificates

From
Guillaume Cottenceau
Date:
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

Re: SSL - Providing client certificates

From
"Saleem EDAH-TALLY"
Date:
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);
}



}



**********************************************************************