I need to use to key-pair in one socket ssl connection without change nothing in clients.
Why?
Because one client use a CN attribute in trust store for connection handshake and other clients using another value in the same attribute to process the same task in the same way.
So I need to use two key store (private) with distinct CN attributes and also aliases and share two different trust store (public key) with distinct CN attributes and also aliases too.
Describing bellow:
keyStore1
Keystore type: JKS
Keystore provider: SUN
Alias name: identity1
Owner: CN=app1 ...
Issuer: CN=app1 ...
trustStore1
Alias name: identity1
Owner: CN=app1 ...
Issuer: CN=app1 ...
keyStore2
Alias name: identity2
Owner: CN=app2 ...
Issuer: CN=app2 ...
trustStore2
Alias name: identity2
Owner: CN=app2 ...
Issuer: CN=app2 ...
I tried to implement this feature in this way:
KeyStore KeyStore1;
try {
String keyStoreFile1 = "privatekey1";
String keyStoreType1 = "jks";
char[] keyStorePwd1 = "password".toCharArray();
keyStore1 = KeyStore.getInstance(keyStoreType1);
keyStore1.load(new FileInputStream(keyStoreFile1), keyStorePwd1);
} catch (java.security.GeneralSecurityException thr) {
throw new IOException("Cannot load keystore (" + thr + ")");
}
KeyStore trustStore1;
try {
String trustStoreFile1 = "publickey1";
String trustStoreType1 = "jks";
char[] trustStorePwd1 = "password".toCharArray();
trustStore1 = KeyStore.getInstance(trustStoreType1);
trustStore.load(new FileInputStream(trustStoreFile1), trustStorePwd1);
} catch (java.security.GeneralSecurityException thr) {
throw new IOException("Cannot load truststore (" + thr + ")");
}
KeyStore keyStore2;
try {
String keyStoreFile2 = "privatekey2";
String keyStoreType2 = "jks";
char[] keyStorePwd2 = "anotherpass".toCharArray();
keyStore2 = KeyStore.getInstance(key2StoreType);
keyStore2.load(new FileInputStream(keyStoreFile2), keyStorePwd2);
} catch (java.security.GeneralSecurityException thr) {
throw new IOException("Cannot load keystore (" + thr + ")");
}
KeyStore trustStore2;
try {
String trustStoreFile2 = "publickey2";
String trustStoreType2 = "jks";
char[] trustStorePwd2 = "anotherpass".toCharArray();
trustStore2 = KeyStore.getInstance(trustStoreType2);
trustStore2.load(new FileInputStream(trustStoreFile2), trustStorePwd2);
} catch (java.security.GeneralSecurityException thr) {
throw new IOException("Cannot load truststore (" + thr + ")");
}
KeyManagerFactory kmfkey1 = KeyManagerFactory
.getInstance(KeyManagerFactory.getkey1Algorithm());
kmfkey1.init(keyStore1, "password".toCharArray());
TrustManagerFactory tmfkey1 =
TrustManagerFactory.getInstance(TrustManagerFactory.getkey1Algorithm());
tmfkey1.init(trustStore1);
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(kmfkey1.getKeyManagers(), tmfkey1.getTrustManagers(), null);
KeyManagerFactory kmfkey2 = KeyManagerFactory.
getInstance(KeyManagerFactory.getkey1Algorithm());
kmfkey2.init(keyStore2, "password".toCharArray());
TrustManagerFactory tmfkey2 = TrustManagerFactory
.getInstance(TrustManagerFactory.getkey1Algorithm());
tmfkey2.init(trustStore2);
SSLContext ctxkey2 = SSLContext.getInstance("SSL");
ctxkey2.init(kmfkey2.getKeyManagers(), tmfkey2.getTrustManagers(), null);
SSLServerSocketFactory sslSrvSockFact = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
serverSocket = sslSrvSockFact.createServerSocket(port);
...
But I received this error message
...
java.security.KeyStoreException: Uninitialized keystore
at java.security.KeyStore.aliases(KeyStore.java:941)
at com.sun.net.ssl.internal.ssl.SunX509KeyManagerImpl.(SunX509KeyManagerImpl.java:106)
at com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:41)
at javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:192)
...
So I really want to know if is possible to use to key-pairs in one socket connection or solve this in a different way that I can't see or deal with.
EDIT 1
Bruno, could you give me an entire or complete example please?
Because is not clear for me....
I tried two things:
One solutions is put the two keys inside a private keystore following a previous suggestion... but doesn't work and I received the message bellow:
Exception in thread "main" java.lang.NoSuchMethodError: javax.net.ssl.SSLContext.setDefault(Ljavax/net/ssl/SSLContext;)
at ...initialiseManager(499)
You was right ... I still need to choose one context or
javax.net.ssl.SSLException:
No available certificate or key corresponds to the SSL cipher suites which are enabled.
while trying send a message to the server...
Second I followed your suggestion...but SSL Socket connection doesn't start
I implemented this with help of many other guys that showed their
code here in this site...thanks for all
private KeyManager[] getKeyManagers() throws IOException, GeneralSecurityException {
// First, get the default KeyManagerFactory.
String alg = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmFact = KeyManagerFactory.getInstance(alg);
// Next, set up the KeyStore to use. We need to load the file into
// a KeyStore instance.
File keyFile = new File("privatekey1");
FileInputStream fis = new FileInputStream(keyFile);
LogManager.log("Loaded keystore privatekey1 " + keyFile.getAbsolutePath(),
LogManager.LOG_LOWEST_LEVEL);
KeyStore ks = KeyStore.getInstance("jks");
String keyStorePassword = "password";
ks.load(fis, keyStorePassword.toCharArray());
fis.close();
// Now we initialise the KeyManagerFactory with this KeyStore
kmFact.init(ks, keyStorePassword.toCharArray());
KeyManagerFactory dkmFact = KeyManagerFactory.getInstance(alg);
File keyFileTwo = new File("privatekey2");
FileInputStream fisTwo = new FileInputStream(keyFileTwo);
LogManager.log("Loaded keystore privatekey2 " + keyFileTwo.getAbsolutePath(), LogManager.LOG_LOWEST_LEVEL);
KeyStore ksTwo = KeyStore.getInstance("jks");
String keyStorePasswordTwo = "password";
ksTwo.load(fisTwo, keyStorePasswordTwo.toCharArray());
fisTwo.close();
// Now we initialise the KeyManagerFactory with this KeyStore
dkmFact.init(ksTwo, keyStorePasswordTwo.toCharArray());
// default
//KeyManagerFactory dkmFact = KeyManagerFactory.getInstance(alg);
//dkmFact.init(null, null);
// Get the first X509KeyManager in the list
X509KeyManager customX509KeyManager = getX509KeyManager(alg, kmFact);
X509KeyManager jvmX509KeyManager = getX509KeyManager(alg, dkmFact);
KeyManager[] km = {new MultiKeyStoreManager(jvmX509KeyManager, customX509KeyManager)};
LogManager.log("Number of key managers registered:" + km.length, LogManager.LOG_LOWEST_LEVEL);
return km;
}
/**
* Find a X509 Key Manager compatible with a particular algorithm
* @param algorithm
* @param kmFact
* @return
* @throws NoSuchAlgorithmException
*/
private X509KeyManager getX509KeyManager(String algorithm, KeyManagerFactory kmFact)
throws NoSuchAlgorithmException {
KeyManager[] keyManagers = kmFact.getKeyManagers();
if (keyManagers == null || keyManagers.length == 0) {
throw new NoSuchAlgorithmException("The default algorithm :" + algorithm + " produced no key managers");
}
X509KeyManager x509KeyManager = null;
for (int i = 0; i < keyManagers.length; i++) {
if (keyManagers[i] instanceof X509KeyManager) {
x509KeyManager = (X509KeyManager) keyManagers[i];
break;
}
}
if (x509KeyManager == null) {
throw new NoSuchAlgorithmException("The default algorithm :" + algorithm + " did not produce a X509 Key manager");
}
return x509KeyManager;
}
private void initialiseManager(int iPort) throws IOException, GeneralSecurityException {
// Next construct and initialise a SSLContext with the KeyStore and
// the TrustStore. We use the default SecureRandom.
// load your key store as a stream and initialize a KeyStore
File trustFile = new File("publicKey");
LogManager.log("Trust File Loaded " + trustFile.getAbsolutePath(), LogManager.LOG_LOWEST_LEVEL);
InputStream trustStream = new FileInputStream(trustFile);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// if your store is password protected then declare it (it can be null however)
char[] trustPassword = "password".toCharArray();
// load the stream to your store
trustStore.load(trustStream, trustPassword);
File trustFileTwo = new File("publicKeyTwo");
LogManager.log("Trust File Loaded " + trustFileTwo.getAbsolutePath(), LogManager.LOG_LOWEST_LEVEL);
InputStream trustStreamTwo = new FileInputStream(trustFileTwo);
KeyStore trustStoreTwo = KeyStore.getInstance(KeyStore.getDefaultType());
// if your store is password protected then declare it (it can be null however)
char[] trustPasswordTwo = "password".toCharArray();
// load the stream to your store
trustStoreTwo.load(trustStreamTwo, trustPasswordTwo);
// initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
trustFactory.init(trustStoreTwo);
// get the trust managers from the factory
TrustManager[] managers = trustFactory.getTrustManagers();
SSLContext context = SSLContext.getInstance("SSL");
context.init(getKeyManagers(), managers, new SecureRandom());
SSLContext.setDefault(context);
SSLServerSocketFactory sslSrvFact = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
serverSocket = sslSrvFact.createServerSocket(iPort);
// this method didn't create a Socket Connection correctly
}
class MultiKeyStoreManager implements X509KeyManager {
private final X509KeyManager jvmKeyManager;
private final X509KeyManager customKeyManager;
public MultiKeyStoreManager(X509KeyManager jvmKeyManager, X509KeyManager customKeyManager) {
this.jvmKeyManager = jvmKeyManager;
this.customKeyManager = customKeyManager;
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
// try the first key manager
String alias = customKeyManager.chooseClientAlias(keyType, issuers, socket);
if (alias == null) {
alias = jvmKeyManager.chooseClientAlias(keyType, issuers, socket);
LogManager.log("Reverting to JVM CLIENT alias : " + alias, LogManager.LOG_LOWEST_LEVEL);
}
return alias;
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
// try the first key manager
String alias = customKeyManager.chooseServerAlias(keyType, issuers, socket);
if (alias == null) {
alias = jvmKeyManager.chooseServerAlias(keyType, issuers, socket);
LogManager.log("Reverting to JVM Server alias : " + alias ,LogManager.LOG_LOWEST_LEVEL);
}
return alias;
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
String[] cAliases = customKeyManager.getClientAliases(keyType, issuers);
String[] jAliases = jvmKeyManager.getClientAliases(keyType, issuers);
LogManager.log("Supported Client Aliases Custom: " + cAliases.length + " JVM : " + jAliases.length,
LogManager.LOG_LOWEST_LEVEL);
return (String[]) ArrayUtils.addAll(cAliases, jAliases);
}
@Override
public PrivateKey getPrivateKey(String alias) {
PrivateKey key = customKeyManager.getPrivateKey(alias);
if (key == null) {
System.out.println("Reverting to JVM Key : " + alias);
return jvmKeyManager.getPrivateKey(alias);
} else {
return key;
}
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
String[] cAliases = customKeyManager.getServerAliases(keyType, issuers);
String[] jAliases = jvmKeyManager.getServerAliases(keyType, issuers);
LogManager.log("Supported Server Aliases Custom: " + cAliases.length + " JVM : " + jAliases.length,
LogManager.LOG_LOWEST_LEVEL);
return (String[]) ArrayUtils.addAll(cAliases, jAliases);
}
@Override
public java.security.cert.X509Certificate[] getCertificateChain(String string) {
java.security.cert.X509Certificate[] chain = customKeyManager.getCertificateChain("alias_key1");
if (chain == null || chain.length == 0) {
LogManager.log("Reverting to JVM Chain : " + string, LogManager.LOG_LOWEST_LEVEL);
return jvmKeyManager.getCertificateChain("alias_key2");
} else {
return chain;
}
}
}
and this gave me this status
*2012.02.09 18:47:00 Activating an SSL connection
2012.02.09 18:47:00 [... ::run]
2012.02.09 18:47:00 Trust File Loaded publicKey
2012.02.09 18:47:00 Trust File Loaded publicKeyTwo
2012.02.09 18:47:00 Loaded keystore privateKey privateKey
2012.02.09 18:47:00 Loaded keystore privateKey2 privateKeyTwo
2012.02.09 18:47:00 Number of key managers registered:1*
But nothing happened when I tried to send a message for the server...
Is being hard to find an example that really works in this case.
EDIT 2
Hi Bruno
Really you have advanced knowledge about this subject, java and ssh and I appreciate your
help. All this information is help me understand better this issue while is showing for me the way... Thx a lot
And again you are right...I'm using code for Java 6 on a Java 5 JRE
But following again your recipe I got this code :
// Load the key store: change store type if needed
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream fis = new FileInputStream("keyStore1");
char[] keyPass = "passw".toCharArray();
try {
ks.load(fis, keyPass);
} finally {
if (fis != null) {
fis.close();
}
}
// Get the default Key Manager
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keyPass);
final X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
X509KeyManager km = new X509KeyManager() {
public String chooseServerAlias(String[] keyType, Principal[] issuers, Socket socket) {
String alias;
InetAddress remoteAddress = socket.getInetAddress();
if (remoteAddress.getHostAddress().equalsIgnoreCase("11.111.111.11")) {
alias = "alias1";
LogManager.log("Reverting to JVM CLIENT alias : " + alias, LogManager.LOG_LOWEST_LEVEL);
} else {
alias = "alias2";
LogManager.log("Reverting to JVM CLIENT alias : " + alias, LogManager.LOG_LOWEST_LEVEL);
}
return alias;
}
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
// try this key manager
String alias = origKm.chooseClientAlias(keyType, issuers, socket);
LogManager.log("Reverting to JVM CLIENT alias : " + alias, LogManager.LOG_LOWEST_LEVEL);
return alias;
}
public String[] getClientAliases(String keyType, Principal[] issues) {
String[] cAliases = origKm.getClientAliases(keyType, issues);
LogManager.log("Supported Client Aliases : " + cAliases.length, LogManager.LOG_LOWEST_LEVEL);
return cAliases;
}
public String[] getServerAliases(String keyType, Principal[] issues) {
String[] sAliases = origKm.getServerAliases(keyType, issues);
LogManager.log("Supported Server Aliases: " + sAliases.length, LogManager.LOG_LOWEST_LEVEL);
return sAliases;
}
public String chooseServerAlias(String keyType, Principal[] issues, Socket socket) {
// try this key manager
String alias = origKm.chooseServerAlias(keyType, issues, socket);
LogManager.log("Reverting to JVM Server alias : " + alias, LogManager.LOG_LOWEST_LEVEL);
return alias;
}
public X509Certificate[] getCertificateChain(String keyType) {
// here I could specify my other keystore, keystore2 how I could do this?
// I'm thinking in the righ way when I implemented this code to get the correct private key?
X509Certificate[] chain = origKm.getCertificateChain("alias1");
if (chain == null || chain.length == 0) {
LogManager.log("Reverting to JVM Chain : " + keyType, LogManager.LOG_LOWEST_LEVEL);
return origKm.getCertificateChain("alias2");
} else {
return chain;
}
}
public PrivateKey getPrivateKey(String alias) {
PrivateKey key = origKm.getPrivateKey(alias);
// here I could get my other keystore according the alias, for example
// keystore2 how I could do this?
LogManager.log("Reverting to JVM Key : " + alias, LogManager.LOG_LOWEST_LEVEL);
return key;
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(new KeyManager[]{km}, null, null);
SSLServerSocketFactory sslSrvFact = sslContext.getServerSocketFactory();
objServerSocket = sslSrvFact.createServerSocket(iPort);
Is exactly this I need to achieve my objective?
EDIT 3
Using this approach a got a handshake between client and server using the second
keystore with alias2 using public trust store2 in client
...but I still got error when I tried to use trust store1 in client
...received a message from [addr=/11.111.111.11]
Reverting to JVM Server alias : alias2
Reverting to JVM Key : alias2
Error in retriving:
javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
My code not change the server to use the private key1 with alias1 ... when the client is using the public truststore1 with cert alias1...
What more is necessary to do for solve this...I believe is near the final solution...
thx again!
EDIT 4
Bruno , I changed the getCertificateChain method by following your suggestion showed bellow
public X509Certificate[] getCertificateChain(String alias) {
X509Certificate[] chain = origKm.getCertificateChain(alias);
return chain;
}
and the method
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
String alias;
also I removed the duplicated method...
And in the addiction the clients that use the old trust store don't verify the hostname
private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
But for the client that need to use the second trust store do this verification and it's a reason because I need to deal with to key-pair certificates...
EDIT5
I'd like to know how I can implement a server socket to let it able to identify and use
correct certificate according with the certificate being used by client to proceed
handshake communication with the server.
Explaining better, in the server side is:
AppServerSideSocket.jar
private keystore: privateKeyApp (type JKS, generated with keytool)
public keystore : publicKeyApp (type JKS, shared with all clients)
And in the client side ...
AppClientSideSocket.jar
- public keystore : publicKeyApp
The AppServerSideSocket.jar listening clients requests and once received process
information sent by clients
The AppClientSideSocket.jar connect with the server using SSL using publicKeyApp without
verify server hostname and after handshake send information for the AppServerSideSocket application.
Now I've another client application, AppClientSideSocketNEW.jar, and this verify server hostname to make
communication with the server. In this case, the CN used in the public certificate on the client side
must be match with the hostname where AppServerSideSocket.jar are.
Originally the connection was configured in this way on the server side:
if (usingSSLConn) {
System.setProperty("javax.net.ssl.keyStore", "privateKeyApp");
System.setProperty("javax.net.ssl.keyStorePassword", "privateKeyAppPassword");
SSLServerSocketFactory sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket serverSocketApp = sslServerSocketFactory.createServerSocket(Port);
} else
serverSocketApp = new ServerSocket(Port);
}
All the clients received the same publicKeyApp and connect with the server without verify hostname, so doesn't matter
if the server where server socket application (AppServerSideSocket.jar) is installed in the server with hostname is
badServer1.com and the CN of key in privateKeyApp and publicKeyApp is setted with goodServer1.com, because all the
clients don't verify hostname or the CN attribute of the key.
Bellow is showed a piece of this kind of connection
private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
System.setProperty("javax.net.ssl.trustStore", publicKey1);
System.getProperties().setProperty("java.protocol.handler.pkgs", "javax.net.ssl.internal.www.protocol");
HttpsURLConnection.setDefaultHostnameVerifier(DO_NOT_VERIFY);
...
SOAPConnectionFactory soapConn = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConn.createConnection();
...
URL endpoint = new URL(hostname + ":" + port);
But the new client (AppClientSideSocketNEW.jar) do this verification obligatorily, now is necessary provide a new certificate
for this client with new value for CN attribute reflecting the correct hostname CN where the server socket is.
I don't have access to second client and I'm sure that it do hostname verification.
So I created two new key-pair certificates (privateKeyAppNew and publicKeyAppNew) and apparently the communications happened
with success between the server using this new key-pair and new client using this new public publicKeyAppNew key, after configured the server to use this new key-pair of course.
But I need continue to use the old key-pair for old clients. I'd like to know how can I deal with this.
Using a keymanager let me able to verify the client certificate on the server app when client try to connect and
choose the appropriate and do the handshake using the correct certificate?
Or I need distinct ssl socket connection in different ports for which kind of clients?
解决方案
The "obvious" problem is that you're not actually making any use of the SSLContexts you create:
SSLServerSocketFactory sslSrvSockFact =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
This should at least be:
SSLServerSocketFactory sslSrvSockFact =
(SSLServerSocketFactory) ctx.getServerSocketFactory();
The problem is that you would have to choose between one context or the other...
The solution to your problem is in the answer I gave to your other similar question a couple of days ago: you need to implement your own X509KeyManager to be able to choose which key you're going to use.
Whether you want to use a single keystore or load your key/cert from two keystores doesn't matter that much: if you really want to, you can certainly implement getPrivateKey and getCertificateChain so that they load the keys/certs from two distinct keystores depending in the alias. It would be unnecessarily complicated, though. You will still have to do something based on the alias selection anyway, so you might as well load both keys/certificates from a single key store, using different aliases.
From the server point of view, the only way to choose one alias (and therefore key/cert pair) is to use what's available in the socket (or engine if you're using an X509ExtendedKeyManager). Since Java 7 doesn't support Server Name Indication (which would let the client tell which host name it's requesting ahead of this selection process), you may have to do this based on the client IP address, or on which of your server IP addresses is being used (if you have more than one).
Using two private keys (keystore) and two public keys (truststore)
You seem to be confused about what the keystore and the truststore are. Unless you're planning to use client-certificate authentication, you can ignore the trust store settings on the server. You can used the default (null) as the second parameter of your SSLContext.init(...). Your "keystore (keystore)" is the information used by the local party (your server in this case), the "truststore (keystore)" is used to determine which remote party to trust.
The public key (or, to be precised, the certificate) you're going to present to the client is also in your keystore, associated with your private key, not in the truststore.
EDIT:
Exception in thread "main" java.lang.NoSuchMethodError:
javax.net.ssl.SSLContext.setDefault(Ljavax/net/ssl/SSLContext;) at
...initialiseManager(499)
Thrown if an application tries to call a specified method of a class
(either static or instance), and that class no longer has a definition
of that method.
Normally, this error is caught by the compiler; this error can only
occur at run time if the definition of a class has incompatibly
changed.
This has nothing to do with your SSL settings. Not sure what you've done here, but it looks like you may be using code for Java 6 on a Java 5 JRE (Java 6 did not have a setDefault on SSLContext). More importantly, there's something wrong about the general way you seem to be using Java here.
javax.net.ssl.SSLException:
No available certificate or key corresponds to the SSL cipher suites
which are enabled.
That could very well be explained by the fact you didn't seem to be using the SSLContexts you had initialised at all...
If you have two pairs of private keys/certificates in your keystore.
My answer here still stands. I'll try to make it a bit more explicit. I'm assuming here that one of your cert/private key is using alias1 and the other alias2. Find out using keyool -list if you're not sure. It's up to you to choose and set them up.
// Load the key store: change store type if needed
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream fis = new FileInputStream("/path/to/keystore");
try {
ks.load(fis, keystorePassword);
} finally {
if (fis != null) { fis.close(); }
}
// Get the default Key Manager
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keyPassword);
final X509KeyManager origKm = (X509KeyManager)kmf.getKeyManagers()[0];
X509KeyManager km = new X509KeyManager() {
public String chooseServerAlias(String keyType,
Principal[] issuers, Socket socket) {
InetAddress remoteAddress = socket.getInetAddress();
if (/* remoteAddress has some conditions you need to define yourself */ {
return "alias1";
} else {
return "alias2";
}
}
public String chooseClientAlias(String[] keyType,
Principal[] issuers, Socket socket) {
// Delegate this other methods to origKm.
origKm.chooseClientAlias(keyType, issuers, socket);
}
// Delegate this other methods to origKm, in the same way as
// it was done for chooseClientAlias.
}
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] { km }, null, null);
SSLSocketFactory sslSocketFactory = sslContext.getSSLSocketFactory();
If you really want two distinct keystores.
Do the same and, on top of this, in getCertificateChain(String alias), choose which of the two keystores to use depending on the alias, and use it to get the certificate chain. Same thing for getPrivateKey(...).