问题:
在项目中要向不同的外部应用通过https连接访问webservice,
但是Java中用System.setProperty("javax.net.ssl.keyStore",...), 多个证书无法同时设置,会有冲突,请问这个该怎么处理
解决:
使用 KeyStoreManager 和 TrustManager 就可以了
实际上就是通过 KeyStoreManager, TrustManager 创建 SSLContext 对象,再通过 SSLContext 对象创建 SSLSocketFactory 对象,并将 SSLSocketFactory 对象赋给 HttpsURLConnection 对象。
KeyStoreManager 管理着双向认证中的客户端证书库
TrustManager 管理着双向认证中服务端证书信任库,相当于浏览器中我知道该证书非 CA 签发,但我需要继续操作。
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
public class Test {
public static void main(String[] args) throws Exception {
// System.setProperty("javax.net.debug", "all");
URL url = new URL("https://www.xxxx.com");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(getSSLSocketFactory());
InputStream in = connection.getInputStream();
byte[] bys = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int p = 0; (p = in.read(bys)) != -1;) {
baos.write(bys, 0, p);
}
String str = new String(baos.toByteArray());
System.out.println(str);
}
private static SSLSocketFactory getSSLSocketFactory() {
MyKeyManager keyManager = new MyKeyManager(KeyStoreType.PKCS12, "d:/key.p12", "123456".toCharArray());
MyTrustManager trustManager = new MyTrustManager("d:/trust.keystore", "123456".toCharArray());
MySSLContext context = new MySSLContext("TLS", keyManager, trustManager);
return context.getSSLContext().getSocketFactory();
}
}
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
public class MySSLContext {
private String protocol;
private MyKeyManager keyManager;
private MyTrustManager trustManager;
public MySSLContext(String protocol, MyKeyManager keyManager, MyTrustManager trustManager) {
this.protocol = protocol;
this.keyManager = keyManager;
this.trustManager = trustManager;
}
public MySSLContext(String protocol, MyTrustManager trustManager) {
this(protocol, null, trustManager);
}
public MySSLContext(String protocol, MyKeyManager keyManager) {
this(protocol, keyManager, null);
}
public SSLContext getSSLContext() {
try {
SSLContext context = SSLContext.getInstance(protocol);
context.init(getKeyManagers(), getTrustManagers(), null);
return context;
} catch (Exception e) {
throw new IllegalStateException("error, protocol: " + protocol, e);
}
}
private KeyManager[] getKeyManagers() {
if (keyManager == null) {
return null;
}
return keyManager.getKeyManagers();
}
private TrustManager[] getTrustManagers() {
if (trustManager == null) {
return null;
}
return trustManager.getTrustManagers();
}
}
import java.security.KeyStore;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
public class MyKeyManager {
private KeyStore ks;
private char[] password;
public MyKeyManager(String keyStore, char[] password) {
this(KeyStoreType.JKS, keyStore, password);
}
public MyKeyManager(KeyStoreType type, String keyStore, char[] password) {
this.password = password;
this.ks = MyKeyStoreUtil.loadKeyStore(type, keyStore, password);
}
public KeyManager[] getKeyManagers() {
try {
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
return kmf.getKeyManagers();
} catch (Exception e) {
throw new KeyStoreRuntimeException("cannot get KeyManagers", e);
}
}
}
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class MyTrustManager {
private KeyStore ks;
public MyTrustManager(String keyStore, char[] password) {
this(KeyStoreType.JKS, keyStore, password);
}
public MyTrustManager(KeyStoreType type, String keyStore, char[] password) {
this.ks = MyKeyStoreUtil.loadKeyStore(type, keyStore, password);
}
public TrustManager[] getTrustManagers() {
return new TrustManager[]{ new ClientTrustManager() };
}
private class ClientTrustManager implements X509TrustManager {
private X509TrustManager sunJSSEX509TrustManager;
public ClientTrustManager() {
loadTrust();
}
private void loadTrust() {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager tms[] = tmf.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
sunJSSEX509TrustManager = (X509TrustManager) tms[i];
return;
}
}
} catch (Exception e) {
throw new KeyStoreRuntimeException(e);
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
sunJSSEX509TrustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return sunJSSEX509TrustManager.getAcceptedIssuers();
}
}
}
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
public class MyKeyStoreUtil {
private MyKeyStoreUtil() {
}
public static KeyStore loadKeyStore(KeyStoreType type, String keyStore, char[] password) {
if (type == null) {
type = KeyStoreType.JKS;
}
InputStream in = null;
try {
try {
KeyStore ks = type.getKeyStore();
in = new FileInputStream(keyStore);
ks.load(in, password);
return ks;
} finally {
if (in != null) {
in.close();
}
}
} catch (Exception e) {
throw new KeyStoreRuntimeException("type: " + type +
", keyStore: " + keyStore, e);
}
}
public static enum KeyStoreType {
JKS {
@Override
public KeyStore getKeyStore() throws KeyStoreException {
return getKeyStore("JKS");
}
},
PKCS12 {
@Override
public KeyStore getKeyStore() throws KeyStoreException {
return getKeyStore("PKCS12");
}
};
public abstract KeyStore getKeyStore() throws KeyStoreException ;
private static KeyStore getKeyStore(String type) throws KeyStoreException {
return KeyStore.getInstance(type);
}
}
public static class KeyStoreRuntimeException extends RuntimeException {
private static final long serialVersionUID = 1L;
public KeyStoreRuntimeException(String message, Throwable cause) {
super(message, cause);
}
public KeyStoreRuntimeException(Throwable cause) {
super(cause);
}
}
}