我需要在一个套接字ssl连接中使用密钥对,而不会在客户端中进行任何更改。
为什么?
因为一个客户端在信任库中使用CN属性进行连接握手,而其他客户端使用同一属性中的另一个值以相同的方式处理相同的任务。
所以我需要使用两个密钥存储(私有)具有不同的CN属性以及别名和共享两个不同的信任存储(公共key)具有不同的CN属性和别名。
描述吼叫:
keyStore1
密钥库类型:JKS
密钥库提供商:SUN
别名: identity1
所有者: CN = app1 ...
发行人:CN = app1 ...
trustStore1
别名: identity1
所有者: CN = app1 ...
发行人:CN = app1 ...
keyStore2
别名: identity2
所有者:CN = app2 ...
发行人:CN = app2 ...
trustStore2
别名: identity2
所有者: CN = app2 ...
发行人:CN = app2 ...
我尝试以这种方式实现此功能:
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);
... 但是我收到了这条错误消息
...
java.security.KeyStoreException:未初始化的密钥库 在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) 在javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:192)
...
所以我真的想知道是否可以在一个套接字连接中使用密钥对,或者以我无法看到或处理的不同方式解决这个问题。
编辑1
布鲁诺,你能给我一个完整或完整的例子吗?因为我不清楚....
我尝试了两件事:
根据先前的建议,一个解决方案是将两个密钥放在私有密钥库中......但是没有工作,我收到了以下消息:
线程中的异常" main" java.lang.NoSuchMethodError:javax.net.ssl.SSLContext.setDefault(Ljavax / net / ssl / SSLContext;) at ... initialiseManager(499)
你是对的...我仍然需要选择一个上下文或
javax.net.ssl.SSLException: 没有可用的证书或密钥对应于已启用的SSL密码套件。 在尝试向服务器发送消息时......
其次我遵循了你的建议......但SSL套接字连接没有启动
我在很多其他人的帮助下实现了这一点 这个网站的代码...感谢所有
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激活SSL连接
2012.02.09 18:47:00 [... :: run]
2012.02.09 18:47:00 Trust File Loaded publicKey
2012.02.09 18:47:00信任文件已加载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注册的主要经理人数:1 *
但是当我尝试为服务器发送消息时没有发生任何事情......
很难找到一个在这种情况下真正起作用的例子。
编辑2
嗨布鲁诺
你真的有关于这个主题的高级知识,java和ssh,我很感激你的 救命。所有这些信息都有助于我更好地理解这个问题,同时向我展示方式......很多
你又是对的......我在Java 5 JRE上使用Java 6的代码
但是再次关注你的食谱我得到了这个代码:
// 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);
我是否需要实现我的目标?
编辑3
使用这种方法,使用第二种方法在客户端和服务器之间进行握手 在客户端
中使用公共信任存储2的alias2的密钥库...但是当我尝试在客户端
中使用trust store1时,我仍然遇到错误...收到[addr = / 11.111.111.11]的消息 还原为JVM服务器别名:alias2 恢复到JVM密钥:alias2 恢复错误: javax.net.ssl.SSLHandshakeException:收到致命警报:certificate_unknown
当客户端使用带有cert alias1的公共truststore1时,我的代码不会更改服务器以使用私有key1和alias1 ...
要解决这个问题还有什么必要...我相信它已接近最终解决方案......
再次来了!编辑4
Bruno,我按照你的建议改变了getCertificateChain方法
public X509Certificate[] getCertificateChain(String alias) {
X509Certificate[] chain = origKm.getCertificateChain(alias);
return chain;
}
和方法
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
String alias;
我也删除了重复的方法......
在成瘾中,使用旧信托商店的客户不会验证主机名
private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
但是对于需要使用第二个信任存储的客户端进行此验证并且这是一个原因,因为我需要处理密钥对证书...
EDIT5
我想知道如何实现服务器套接字以使其能够识别和使用 根据客户端使用的证书来更正证书 握手与服务器通信。
更好地解释,在服务器端是:
AppServerSideSocket.jar
在客户端......
AppClientSideSocket.jar - 公钥存储: publicKeyApp
AppServerSideSocket.jar 侦听客户端请求和一旦收到进程 客户发送的信息
AppClientSideSocket.jar 使用 publicKeyApp 使用SSL连接服务器 验证服务器主机名并在握手后发送AppServerSideSocket应用程序的信息。
现在我有另一个客户端应用程序, AppClientSideSocketNEW.jar ,以及要验证的验证服务器主机名 与服务器通信。在这种情况下,CN用在客户端的公共证书中 必须与 AppServerSideSocket.jar 所在的主机名匹配。
最初在服务器端以这种方式配置连接:
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);
}
所有客户端都收到了相同的publicKeyApp并且没有验证主机名与服务器连接,所以没关系 如果服务器套接字应用程序( AppServerSideSocket.jar )安装在具有hostname的服务器中的服务器是 badServer1.com和privateKeyApp和publicKeyApp中的密钥CN使用goodServer1.com设置,因为所有的 客户端不会验证密钥的主机名或CN属性。
贝娄展示了一种这种联系
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);
但新客户端( AppClientSideSocketNEW.jar )必须执行此验证,现在必须提供新证书 对于此客户端,CN属性的新值反映了服务器套接字所在的正确主机名CN。
我无法访问第二个客户端,我确信它会进行主机名验证。
所以我创建了两个新的密钥对证书( privateKeyAppNew和publicKeyAppNew ),显然发生了通信 使用这个新密钥对的服务器和使用这个新的公共publicKeyAppNew密钥的新客户端之间的成功,在配置服务器后使用这个新的密钥对。
但我需要继续为旧客户使用旧密钥对。我想知道如何解决这个问题。
使用密钥管理器让我能够在客户端尝试连接时验证服务器应用程序上的客户端证书 选择合适的并使用正确的证书进行握手?
或者我需要在不同的端口中为哪种客户端提供不同的ssl套接字连接?
答案 0 :(得分:5)
“显而易见”的问题是你实际上没有使用你创建的SSLContext
:
SSLServerSocketFactory sslSrvSockFact =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
这至少应该是:
SSLServerSocketFactory sslSrvSockFact =
(SSLServerSocketFactory) ctx.getServerSocketFactory();
问题在于您必须在一个上下文或另一个上下文之间进行选择......
问题的解决方案位于the answer I gave to your other similar question a couple of days ago:您需要实施自己的X509KeyManager
才能选择要使用的密钥。
是否要使用单个密钥库或从两个密钥库加载密钥/证书并不重要:如果您真的想要,您当然可以实现getPrivateKey
和getCertificateChain
以便它们根据别名从两个不同的密钥库加载密钥/证书。但是,这将是不必要的复杂。无论如何,您仍然需要根据别名选择执行某些操作,因此您也可以使用不同的别名从单个密钥存储区加载密钥/证书。
从服务器的角度来看,选择一个别名(以及密钥/证书对)的唯一方法是使用套接字(或引擎,如果您使用的是X509ExtendedKeyManager
)中可用的内容。由于Java 7不支持服务器名称指示(这将允许客户端在此选择过程之前告知它请求的主机名),您可能必须根据客户端IP地址或您的服务器IP地址执行此操作。正在使用(如果你有多个)。
使用两个私钥(密钥库)和两个公钥(信任库)
您似乎对密钥库和信任库的含义感到困惑。除非您计划使用客户端证书身份验证,否则可以忽略服务器上的信任存储设置。您可以使用默认值(null
)作为SSLContext.init(...)
的第二个参数。您的“密钥库(密钥库)”是本地方(本例中为您的服务器)使用的信息,“信任库(密钥库)”用于确定要信任的远程方。
您要向客户端呈现的公钥(或者,准备好的证书)也在您的密钥库中,与您的私钥相关联,而不是在信任库中。
修改强>
线程“main”中的异常java.lang.NoSuchMethodError: javax.net.ssl.SSLContext.setDefault(Ljavax / net / ssl / SSLContext;)at ... initialiseManager(499)
如果应用程序尝试调用类的指定方法,则抛出该异常 (静态或实例),该类不再具有定义 那种方法。
通常,编译器会捕获此错误;这个错误只能 如果类的定义不兼容,则在运行时发生 改变。
这与您的SSL设置无关。不确定你在这里做了什么,但看起来你可能在Java 5 JRE上使用Java 6的代码(Java 6在setDefault
上没有SSLContext
)。更重要的是,你似乎在这里使用Java的一般方式有些不对。
javax.net.ssl.SSLException:
没有可用的证书或密钥对应于SSL密码套件 已启用。
这很可能是因为您似乎没有使用您初始化的SSLContext
这个事实......
我的回答here仍然存在。我会尝试让它更明确一点。我在这里假设你的一个证书/私钥正在使用alias1
而另一个alias2
。如果您不确定,请使用keyool -list
查找。您可以自行选择和设置它们。
// 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();
执行相同操作,并在此基础上,在getCertificateChain(String alias)
中,根据别名选择要使用的两个密钥库中的哪一个,并使用它来获取证书链。 getPrivateKey(...)
也是如此。
答案 1 :(得分:1)
简单的方法是将所有内容放在一个密钥库中 - 所有密钥和所有信任证书。这将消除你的问题。