I have an in-house HTTP server written in Java; full source code at my disposal. The HTTP server can configure any number of web sites, each of which will have a separate listen socket created with:
skt=SSLServerSocketFactory.getDefault().createServerSocket(prt,bcklog,adr);
Using a standard key store created with the Java keytool, I cannot for the life of me work out how to get different certificates associated with different listen sockets so that each configured web site has it's own certificate.
I'm in a time pinch for this now, so some code samples that illustrate would be most appreciated. But as much I would appreciate any good overview on how JSSE hangs together in this regard (I have searched Sun's JSSE doco until my brain hurts (literally; though it might be as much caffeine withdrawal)).
Edit
Is there no simple way to use the alias to associate the server certificates in a key store with the listen sockets? So that:
- The customer has one key store to many for all certificates, and
- There is no need to fiddle around with multiple key stores, etc.
I was getting the impression (earlier this afternoon) that I could write a simple KeyManager, with only chooseServerAlias(...)
returning non-null, that being the name of the alias I wanted - anyone have any thoughts on that line of reasoning?
Solution
The solution I used, built from slyvarking's answer was to create a temporary key store and populate it with the desired key/cert extracted from the singular external key store. Code follows for any who are interested (svrctfals is my "server certificate alias" value):
SSLServerSocketFactory ssf; // server socket factory
SSLServerSocket skt; // server socket
// LOAD EXTERNAL KEY STORE
KeyStore mstkst;
try {
String kstfil=GlobalSettings.getString("javax.net.ssl.keyStore" ,System.getProperty("javax.net.ssl.keyStore" ,""));
String ksttyp=GlobalSettings.getString("javax.net.ssl.keyStoreType" ,System.getProperty("javax.net.ssl.keyStoreType" ,"jks"));
char[] kstpwd=GlobalSettings.getString("javax.net.ssl.keyStorePassword",System.getProperty("javax.net.ssl.keyStorePassword","")).toCharArray();
mstkst=KeyStore.getInstance(ksttyp);
mstkst.load(new FileInputStream(kstfil),kstpwd);
}
catch(java.security.GeneralSecurityException thr) {
throw new IOException("Cannot load keystore ("+thr+")");
}
// CREATE EPHEMERAL KEYSTORE FOR THIS SOCKET USING DESIRED CERTIFICATE
try {
SSLContext ctx=SSLContext.getInstance("TLS");
KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore sktkst;
char[] blkpwd=new char[0];
sktkst=KeyStore.getInstance("jks");
sktkst.load(null,blkpwd);
sktkst.setKeyEntry(svrctfals,mstkst.getKey(svrctfals,blkpwd),blkpwd,mstkst.getCertificateChain(svrctfals));
kmf.init(sktkst,blkpwd);
ctx.init(kmf.getKeyManagers(),null,null);
ssf=ctx.getServerSocketFactory();
}
catch(java.security.GeneralSecurityException thr) {
throw new IOException("Cannot create secure socket ("+thr+")");
}
// CREATE AND INITIALIZE SERVER SOCKET
skt=(SSLServerSocket)ssf.createServerSocket(prt,bcklog,adr);
...
return skt;