我实现了自定义密钥管理器,以便在需要ssl握手时选择使用哪个别名。 问题是尽管已正确实例化了自定义密钥管理器的所有方法,但都没有调用。
使用仅包含一个别名的密钥库,可以很好地进行通信并且代码可以正常工作,但是此处的目的是可以在运行时更改别名。
这是我实现的完整代码。感谢您的帮助。
package ssl;
import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
public class AliasSelectorKeyManager extends X509ExtendedKeyManager {
private X509KeyManager sourceKeyManager = null;
private String alias;
public AliasSelectorKeyManager(X509KeyManager keyManager, String alias) {
this.sourceKeyManager = keyManager;
this.alias = alias;
}
@Override
public String chooseEngineClientAlias(String[] paramArrayOfString, Principal[] paramArrayOfPrincipal, SSLEngine paramSSLEngine) {
return chooseClientAlias(paramArrayOfString, paramArrayOfPrincipal, null);
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
boolean aliasFound = false;
//Get all aliases from the key manager. If any matches with the managed alias,
//then return it.
//If the alias has not been found, return null (and let the API to handle it,
//causing the handshake to fail).
for (int i = 0; i < keyType.length && !aliasFound; i++) {
String[] validAliases = sourceKeyManager.getClientAliases(keyType[i], issuers);
if (validAliases != null) {
for (int j = 0; j < validAliases.length && !aliasFound; j++) {
if (validAliases[j].equals(alias)) {
aliasFound = true;
}
}
}
}
if (aliasFound) {
return alias;
} else {
return null;
}
}
}
所有这些操作只是覆盖了调用特定sourceKeyManager
实现的每个方法。自定义包含两种方法:
这是我的SSL客户端主体:
package ssl;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
public class SSLClientV2 {
public static void main(String[] args) {
String keyStoreType = "PKCS12";
String keyManagementAlgorithm = "SunX509";
String keyStorePassword = "password";
String keyStoreFileName = "C:/keystore.p12";
String protocolVersion = "TLSv1.2";
System.out.println("Key store File name.......: " + keyStoreFileName);
System.out.println("Key store type............: " + keyStoreType);
System.out.println("Key store Password........: " + keyStorePassword);
System.out.println("SSL Protocol..............: " + protocolVersion);
System.out.println("Key Management Algorithm..: " + keyManagementAlgorithm);
System.out.println(System.lineSeparator());
KeyStore keyStore = null;
KeyManagerFactory keyManagerFactory = null;
SSLContext sslContext = null;
try (FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName)) {
System.out.println("Loading keystore...");
keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
System.out.println("Keystore loaded successfully.");
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
System.out.println("ERROR: Could not load keystore.");
e.printStackTrace();
}
System.out.print(System.lineSeparator());
if (keyStore != null) {
try {
System.out.println("Initializing Key Manager Factory...");
keyManagerFactory = KeyManagerFactory.getInstance(keyManagementAlgorithm);
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
System.out.println("Key Manager Factory initialized successfully.");
} catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) {
System.out.println("ERROR: Could not initialize Key Manager Factory.");
e.printStackTrace();
}
}
System.out.print(System.lineSeparator());
if (keyManagerFactory != null) {
try {
System.out.println("Initializing SSL Context...");
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManager[] trustManagers = new TrustManager[] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
}
}
};
for (int i = 0; i < keyManagers.length; i++) {
if (keyManagers[i] instanceof X509KeyManager) {
keyManagers[i] = new AliasSelectorKeyManager((X509KeyManager) keyManagers[i], "my.custom.alias");
System.out.println("Custom Key Manager loaded (#" + (i + 1) + ", class: " + keyManagers[i].getClass().getName() + ")");
}
}
sslContext = SSLContext.getInstance(protocolVersion);
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
sslContext.init(keyManagers, trustManagers, secureRandom);
System.out.println("SSL Context initialized successfully.");
} catch (KeyManagementException | NoSuchAlgorithmException e) {
System.out.println("ERROR: Could not initialize SSL Context.");
e.printStackTrace();
}
}
System.out.print(System.lineSeparator());
if (sslContext != null) {
try (SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket("192.168.10.10", 1443)) {
System.out.println("Communication initialized, starting handshake...");
socket.startHandshake();
System.out.println("Handshake completed successfully.");
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader r = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String m = null;
System.out.print(System.lineSeparator());
String content = "Hello World";
System.out.println("Sending: " + content);
w.write(content);
w.flush();
System.out.println("Message received: ");
while ((m = r.readLine()) != null) {
System.out.println(m);
}
w.close();
r.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
答案 0 :(得分:0)
也请重写此方法: X509KeyManager :: getClientAliases(String keyType,Principal []发行者)
答案 1 :(得分:0)
服务器端是否开启了 needClientAuth
标志?
https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html#setNeedClientAuth(boolean)
只有在标志打开时,服务器才会在握手期间询问客户端的身份验证。