Java 实现TLS/SSL证书的自动安装校验

摘要:摘要: Java 实现TLS/SSL证书的自动安装校验,主要经过ssl/tls握手,密钥交换,证书校验机制实现。我们这里模拟浏览器,实现自动校验和证书的检测。

前言

最近实现Socks5 proxy与HTTP proxy中遇到了SSLSocket隧道的问题,当然,最终问题经过自动证书校验安装管理器实现了证书的管理,也解决了SSLSocket,但是目前的问题是浏览器对Socks5和HTTP proxy还有很多不足,目前实现的两个代理工具只能在程序中使用。当然,我们今天的主要话题如下:

Java 实现TLS/SSL证书的自动安装校验,主要经过ssl/tls握手,密钥交换,证书校验机制实现。我们这里模拟浏览器,实现自动校验和证书的检测。

主要实现如下功能:

1.自动检测,校验根证书,校验过期时间,校验签名的证书是否有效,校验证书和域名是否匹配

2.实现证书的自动存储,自动安装,加载

3.实现普通Socket自动升级为SSLSocket

一.实现配置类

首先,我们先添加2个配置类

package com.ssl.rx.http; import java.security.KeyStore; public class ConnectionConfiguration { /** 证书文件路径 */ private String truststorePath; /** 证书类型 */ private String truststoreType; /** 证书文件密码 */ private String truststorePassword; /** 是否验证证书链的签名有效性 */ private boolean verifyChainEnabled = true; /** 是否校验根证书,注意,自签名证书没有根证书 */ private boolean verifyRootCAEnabled = true; /** 是否允许通过自签名证书 */ private boolean selfSignedCertificateEnabled = false; /** 是否检查证书的有效期 */ private boolean expiredCertificatesCheckEnabled = true; /** 检查域名的匹配情况 */ private boolean notMatchingDomainCheckEnabled = true; private String server; private int port; public ConnectionConfiguration() { truststorePassword = "WlZSak5GcFVUbTlsVjJSNg=="; truststorePath = "socket_tls_clientTrust.cert"; truststoreType = "jks"; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getServer() { return server; } public void setServer(String server) { this.server = server; } public boolean isExpiredCertificatesCheckEnabled() { return expiredCertificatesCheckEnabled; } public void setSelfSignedCertificateEnabled(boolean selfSignedCertificateEnabled) { this.selfSignedCertificateEnabled = selfSignedCertificateEnabled; } public void setExpiredCertificatesCheckEnabled(boolean expiredCertificatesCheckEnabled) { this.expiredCertificatesCheckEnabled = expiredCertificatesCheckEnabled; } public boolean isSelfSignedCertificateEnabled() { return selfSignedCertificateEnabled; } public boolean isNotMatchingDomainCheckEnabled() { return notMatchingDomainCheckEnabled; } public boolean isVerifyRootCAEnabled() { return verifyRootCAEnabled; } public void setVerifyRootCAEnabled(boolean verifyRootCAEnabled) { this.verifyRootCAEnabled = verifyRootCAEnabled; } public void setVerifyChainEnabled(boolean verifyChainEnabled) { this.verifyChainEnabled = verifyChainEnabled; } public boolean isVerifyChainEnabled() { return verifyChainEnabled; } public String getTruststoreType() { return truststoreType; } public void setTruststoreType(String truststoreType) { this.truststoreType = truststoreType; } public String getTruststorePassword() { return truststorePassword; } public void setTruststorePassword(String truststorePassword) { this.truststorePassword = truststorePassword; } public String getTruststorePath() { return truststorePath; } public void setTruststorePath(String truststorePath) { this.truststorePath = truststorePath; } public void setNotMatchingDomainCheckEnabled(boolean notMatchingDomainCheckEnabled) { this.notMatchingDomainCheckEnabled = notMatchingDomainCheckEnabled; } }

然后增加一个用于存储keystore的javaBean

package com.ssl.rx.http; public class KeyStoreOptions { private final String type; private final String path; private final String password; public KeyStoreOptions(String type, String path, String password) { super(); this.type = type; this.path = path; this.password = password; } public String getType() { return type; } public String getPath() { return path; } public String getPassword() { return password; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + ((path == null) ? 0 : path.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; KeyStoreOptions other = (KeyStoreOptions) obj; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (path == null) { if (other.path != null) return false; } else if (!path.equals(other.path)) return false; if (type == null) { if (other.type != null) return false; } else if (!type.equals(other.type)) return false; return true; } }

最后,我们来实现核心部分,证书管理器

二.实现核心代码

package com.ssl.rx.http; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.PublicKey; import java.security.SecureRandom; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; public class SSLX509CertificateManager { private static final Logger logger = Logger.getLogger("SSLX509CertificateManager"); private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray(); private static Pattern cnPattern = Pattern.compile("(?i)(cn=)([^,]*)"); private static Map<KeyStoreOptions, KeyStore> stores = new HashMap<KeyStoreOptions, KeyStore>(); private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } /** * 开始握手等一系列密钥协商 * * @param socket * @return */ public static boolean startHandshake(SSLSocket socket) { try { logger.log(Level.INFO, "-开始握手,认证服务器证书-"); socket.startHandshake(); System.out.println(); logger.log(Level.INFO, "-握手结束,结束认证服务器证书-"); } catch (SSLException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } return true; } public static SSLSocket createTrustCASocket(String host, int port, ConnectionConfiguration config) throws Exception { if (config == null) { config = new ConnectionConfiguration(); } KeyStore ks = getKeyStore(config); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0]; CAX509TrustManager tm = new CAX509TrustManager(defaultTrustManager, ks, config); context.init(null, new TrustManager[] { tm }, new SecureRandom()); SSLSocketFactory factory = context.getSocketFactory(); logger.log(Level.INFO, "开始连接: " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket) factory.createSocket(host, port); socket.setSoTimeout(10000); config.setServer(host); config.setPort(port); // config.setTrustKeyStore(ks); X509Certificate certificate = (X509Certificate) ks.getCertificate(host + ":" + port); if (certificate != null && isValid(certificate)) { logger.log(Level.INFO, "-证书文件存在并且有效,无需进行握手-"); return socket; } if (!startHandshake(socket)) { logger.log(Level.SEVERE, "-握手失败-"); return null; } X509Certificate[] chain = tm.chain; if (chain == null || chain.length == 0) { logger.log(Level.SEVERE, "-证书链为空,认证失败-"); return null; } if (config.isVerifyRootCAEnabled()) { boolean isValidRootCA = checkX509CertificateRootCA(ks, chain, config.isSelfSignedCertificateEnabled()); if (!isValidRootCA) { return null; } } return socket; } /** * 获取keystore,防治多次加载 * * @param config * @return * @throws KeyStoreException * @throws IOException * @throws NoSuchAlgorithmException * @throws CertificateException * @throws FileNotFoundException */ private static KeyStore getKeyStore(ConnectionConfiguration config) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException { KeyStore ks; synchronized (stores) { KeyStoreOptions options = new KeyStoreOptions(config.getTruststoreType(), config.getTruststorePath(), config.getTruststorePassword()); if (stores.containsKey(options)) { logger.log(Level.INFO, "从缓存中获取trustKeystore"); ks = stores.get(options); } else { File file = new File(config.getTruststorePath()); char[] password = config.getTruststorePassword().toCharArray(); logger.log(Level.INFO, "加载" + file + "证书文件"); ks = KeyStore.getInstance(KeyStore.getDefaultType()); if (!file.exists()) { logger.log(Level.INFO, "证书文件不存在,选择自动创建"); ks.load(null, password); } else { logger.log(Level.INFO, "证书文件存在,开始加载"); InputStream in = new FileInputStream(file); ks.load(in, password); in.close(); } stores.put(options, ks); } } return ks; } public static SSLSocket createTrustCASocket(String host, int port) throws Exception { return createTrustCASocket(host, port, null); } public static SSLSocket createTrustCASocket(Socket s, ConnectionConfiguration config) throws Exception { if (config == null) { config = new ConnectionConfiguration(); } KeyStore ks = getKeyStore(config); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0]; CAX509TrustManager tm = new CAX509TrustManager(defaultTrustManager, ks, config); context.init(null, new TrustManager[] { tm }, new SecureRandom()); SSLSocketFactory factory = context.getSocketFactory(); String host = s.getInetAddress().getHostName(); int port = s.getPort(); logger.log(Level.INFO, "开始连接: " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket) factory.createSocket(s, host, port, true); socket.setSoTimeout(10000); config.setServer(s.getInetAddress().getHostName()); config.setPort(s.getPort()); X509Certificate certificate = (X509Certificate) ks.getCertificate(host + ":" + s.getPort()); if (certificate != null && isValid(certificate)) { logger.log(Level.INFO, "-证书文件存在并且有效,无需进行握手-"); return socket; } if (!startHandshake(socket)) { return null; } X509Certificate[] chain = tm.chain; if (chain == null || chain.length == 0) { logger.log(Level.SEVERE, "-证书链为空,认证失败-"); return null; } if (config.isVerifyRootCAEnabled()) { boolean isValidRootCA = checkX509CertificateRootCA(ks, chain, config.isSelfSignedCertificateEnabled()); if (!isValidRootCA) { logger.log(Level.SEVERE, "根证书校验无效"); return null; } } return socket; } public static SSLSocket createTrustCASocket(Socket s) throws Exception { return createTrustCASocket(s, null); } public static class CAX509TrustManager implements X509TrustManager { private final X509TrustManager tm; private X509Certificate[] chain; private KeyStore keyStore; private ConnectionConfiguration config; public MessageDigest sha1 = null; public MessageDigest md5 = null; public CAX509TrustManager(X509TrustManager tm, KeyStore ks, ConnectionConfiguration config) throws NoSuchAlgorithmException { this.tm = tm; this.keyStore = ks; sha1 = MessageDigest.getInstance("SHA1"); md5 = MessageDigest.getInstance("MD5"); this.config = config; } public X509Certificate[] getAcceptedIssuers() { return tm.getAcceptedIssuers(); // 生成证书数组,用于存储新证书 } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { tm.checkClientTrusted(chain, authType); // 检查客户端 } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (this.chain == null) { this.chain = getAcceptedIssuers(); } if (chain != null && chain.length > 0) { if (!checkX509CertificateValid(chain, config)) { logger.log(Level.SEVERE, "证书校验未通过"); return; } for (int i = 0; i < chain.length; i++) { X509Certificate certificate = chain[i]; if (i == 0) { saveCAToKeyStore(certificate, config.getServer() + ":" + config.getPort()); } else { saveCAToKeyStore(certificate, null); } } } } public void saveCAToKeyStore(X509Certificate certificate, String aliasKey) throws CertificateEncodingException { try { X509Certificate cert = certificate; System.out.println(" Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); String alias = keyStore.getCertificateAlias(cert); if (alias == null || alias != null && !isValid(certificate)) { if (aliasKey == null || aliasKey.length() == 0) { alias = cert.getSubjectDN().getName(); } else { alias = aliasKey; logger.log(Level.INFO, "设定指定证书别名:" + alias); } keyStore.setCertificateEntry(alias, certificate); OutputStream out = new FileOutputStream(config.getTruststorePath()); keyStore.store(out, config.getTruststorePassword().toCharArray()); out.close(); chain = Arrays.copyOf(chain, chain.length + 1); chain[chain.length - 1] = certificate; logger.fine(certificate.toString()); } } catch (KeyStoreException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } public static boolean isValid(X509Certificate cert) { if (cert == null) { return false; } try { cert.checkValidity(); } catch (CertificateExpiredException e) { e.printStackTrace(); return false; } catch (CertificateNotYetValidException e) { e.printStackTrace(); return false; } return true; } /** * 校验证书的有效性 * * @param chain * @param config * @return */ private static boolean checkX509CertificateValid(X509Certificate[] chain, ConnectionConfiguration config) { boolean result = true; if (config.isExpiredCertificatesCheckEnabled()) { result = result && checkX509CertificateExpired(chain); } if (config.isVerifyChainEnabled()) { result = result && checkX509CertificateChain(chain); } if (config.isNotMatchingDomainCheckEnabled()) { result = result && checkIsMatchDomain(chain, config.getServer()); } return result; } /** * 检查是否匹配域名 * * @param x509Certificates * @param server * @return */ public static boolean checkIsMatchDomain(X509Certificate[] x509Certificates, String server) { server = server.toLowerCase(); List<String> peerIdentities = getPeerIdentity(x509Certificates[0]); if (peerIdentities.size() == 1 && peerIdentities.get(0).startsWith("*.")) { String peerIdentity = peerIdentities.get(0).replace("*.", ""); if (!server.endsWith(peerIdentity)) { return false; } } else { for (int i = 0; i < peerIdentities.size(); i++) { String peerIdentity = peerIdentities.get(i).replace("*.", ""); if (server.endsWith(peerIdentity)) { return true; } } } return false; } /** * 校验根证书 * * @param trustStore * @param x509Certificates * @param isSelfSignedCertificate * 是否自签名证书 * @return */ public static boolean checkX509CertificateRootCA(KeyStore trustStore, X509Certificate[] x509Certificates, boolean isSelfSignedCertificate) { List<String> peerIdentities = getPeerIdentity(x509Certificates[0]); boolean trusted = false; try { int size = x509Certificates.length; trusted = trustStore.getCertificateAlias(x509Certificates[size - 1]) != null; if (!trusted && size == 1 && isSelfSignedCertificate) { logger.log(Level.WARNING, "-强制认可自签名证书-"); trusted = true; } } catch (KeyStoreException e) { e.printStackTrace(); } if (!trusted) { logger.log(Level.SEVERE, "-根证书签名的网站:" + peerIdentities + "不能被信任"); } return trusted; } /** * 检查证书是否过期 * * @param x509Certificates * @return */ public static boolean checkX509CertificateExpired(X509Certificate[] x509Certificates) { Date date = new Date(); for (int i = 0; i < x509Certificates.length; i++) { try { x509Certificates[i].checkValidity(date); } catch (GeneralSecurityException generalsecurityexception) { logger.log(Level.SEVERE, "-证书已经过期-"); return false; } } return true; } /** * 校验证书链的完整性 * * @param x509Certificates * @return */ public static boolean checkX509CertificateChain(X509Certificate[] x509Certificates) { Principal principalLast = null; List<String> peerIdentities = getPeerIdentity(x509Certificates[0]); for (int i = x509Certificates.length - 1; i >= 0; i--) { X509Certificate x509certificate = x509Certificates[i]; Principal principalIssuer = x509certificate.getIssuerDN(); Principal principalSubject = x509certificate.getSubjectDN(); if (principalLast != null) { if (principalIssuer.equals(principalLast)) { try { PublicKey publickey = x509Certificates[i + 1].getPublicKey(); x509Certificates[i].verify(publickey); } catch (GeneralSecurityException generalsecurityexception) { logger.log(Level.SEVERE, "-无效的证书签名-" + peerIdentities); return false; } } else { logger.log(Level.SEVERE, "-无效的证书签名-" + peerIdentities); return false; } } principalLast = principalSubject; } return true; } /** * 返回所有可用的签名方式 键值对 如CN=VeriSignMPKI-2-6 * * @param certificate * @return */ private static List<String> getSubjectAlternativeNames(X509Certificate certificate) { List<String> identities = new ArrayList<String>(); try { Collection<List<?>> altNames = certificate.getSubjectAlternativeNames(); if (altNames == null) { return Collections.emptyList(); } Iterator<List<?>> iterator = altNames.iterator(); do { if (!iterator.hasNext()) break; List<?> altName = iterator.next(); int size = altName.size(); if (size >= 2) { identities.add((String) altName.get(1)); } } while (true); } catch (CertificateParsingException e) { e.printStackTrace(); } return identities; } /** * 返回所有可用的签名方式的值 * * @param certificate * @return */ public static List<String> getPeerIdentity(X509Certificate x509Certificate) { List<String> names = getSubjectAlternativeNames(x509Certificate); if (names.isEmpty()) { String name = x509Certificate.getSubjectDN().getName(); Matcher matcher = cnPattern.matcher(name); if (matcher.find()) { name = matcher.group(2); } names = new ArrayList<String>(); names.add(name); } return names; } } 三.测试代码

public class TestX509CertManager{ public static void main(String[] args) { try { SSLSocket baiduSocket = SSLX509CertificateManager.createTrustCASocket("www.baidu.com", 443); SSLSocket taobaoSocket = SSLX509CertificateManager.createTrustCASocket("www.taobao.com", 443); SSLSocket imququSocket = SSLX509CertificateManager.createTrustCASocket("imququ.com", 443); } catch (Exception e) { e.printStackTrace(); } } } 四.附加测试代码

我们这里附加一个工具类,专门来实现Server-Side与Client-Side的SSLSocket 连接,也可以用于测试我们的上述代码,只不过需要稍加改造。

package com.tianwt.rx.http; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.HttpURLConnection; import java.net.Proxy; import java.net.Socket; import java.net.URL; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.PrivateKey; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509ExtendedKeyManager; public class SSLTrustManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager ,HostnameVerifier{ public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } public boolean isServerTrusted( java.security.cert.X509Certificate[] certs) { return true; } public boolean isClientTrusted( java.security.cert.X509Certificate[] certs) { return true; } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; } @Override public boolean verify(String urlHostName, SSLSession session) { //允许所有主机 return true; } /** * 客户端使用 */ public static HttpURLConnection connectTrustAllServer(String strUrl) throws Exception { return connectTrustAllServer(strUrl,null); } /** * 客户端使用 * * @param strUrl 要访问的地址 * @param proxy 需要经过的代理 * @return * @throws Exception */ public static HttpURLConnection connectTrustAllServer(String strUrl,Proxy proxy) throws Exception { javax.net.ssl.TrustManager[] trustCertsmanager = new javax.net.ssl.TrustManager[1]; javax.net.ssl.TrustManager tm = new SSLTrustManager(); trustCertsmanager[0] = tm; javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext .getInstance("TLS"); sc.init(null, trustCertsmanager, null); javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc .getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier((HostnameVerifier) tm); URL url = new URL(strUrl); HttpURLConnection urlConn = null; if(proxy==null) { urlConn = (HttpURLConnection) url.openConnection(); }else{ urlConn = (HttpURLConnection) url.openConnection(proxy); } urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"); return urlConn; } /** * 用于双向认证,客户端使用 * * @param strUrl * @param proxy * @return * @throws KeyStoreException * @throws NoSuchAlgorithmException * @throws CertificateException * @throws FileNotFoundException * @throws IOException * @throws UnrecoverableKeyException * @throws KeyManagementException */ public static HttpURLConnection connectProxyTrustCA(String strUrl,Proxy proxy) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslsession) { return true; } }); String clientKeyStoreFile = "D:/JDK8Home/tianwt/sslClientKeys"; String clientKeyStorePwd = "123456"; String catServerKeyPwd = "123456"; String serverTrustKeyStoreFile = "D:/JDK8Home/tianwt/sslClientTrust"; String serverTrustKeyStorePwd = "123456"; KeyStore serverKeyStore = KeyStore.getInstance("JKS"); serverKeyStore.load(new FileInputStream(clientKeyStoreFile), clientKeyStorePwd.toCharArray()); KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS"); serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(serverKeyStore, catServerKeyPwd.toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(serverTrustKeyStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); URL url = new URL(strUrl); HttpURLConnection httpURLConnection = null; if(proxy==null) { httpURLConnection = (HttpURLConnection) url.openConnection(); }else{ httpURLConnection = (HttpURLConnection) url.openConnection(proxy); } httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"); return httpURLConnection; } /** * 用于单向认证,客户端使用 * * server侧只需要自己的keystore文件,不需要truststore文件 * client侧不需要自己的keystore文件,只需要truststore文件(其中包含server的公钥)。 * 此外server侧需要在创建SSLServerSocket之后设定不需要客户端证书:setNeedClientAuth(false) * @param strUrl * @param proxy * @return * @throws KeyStoreException * @throws NoSuchAlgorithmException * @throws CertificateException * @throws FileNotFoundException * @throws IOException * @throws UnrecoverableKeyException * @throws KeyManagementException */ public static HttpURLConnection connectProxyTrustCA2(String strUrl,Proxy proxy) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslsession) { return true; } }); String serverTrustKeyStoreFile = "D:/JDK8Home/tianwt/sslClientTrust"; String serverTrustKeyStorePwd = "123456"; KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS"); serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(serverTrustKeyStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); URL url = new URL(strUrl); HttpURLConnection httpURLConnection = null; if(proxy==null) { httpURLConnection = (HttpURLConnection) url.openConnection(); }else{ httpURLConnection = (HttpURLConnection) url.openConnection(proxy); } httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"); return httpURLConnection; } /** * 用于双向认证 * @param socketClient 是否产生socket * @return * @throws KeyStoreException * @throws NoSuchAlgorithmException * @throws CertificateException * @throws FileNotFoundException * @throws IOException * @throws UnrecoverableKeyException * @throws KeyManagementException */ public SSLSocket createTlsConnect(Socket socketClient) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException { String protocol = "TLS"; String serverKey = "D:/JDK8Home/tianwt/sslServerKeys"; String serverTrust = "D:/JDK8Home/tianwt/sslServerTrust"; String serverKeyPwd = "123456"; //私钥密码 String serverTrustPwd = "123456"; //信任证书密码 String serverKeyStorePwd = "123456"; // keystore存储密码 KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(serverKey),serverKeyPwd.toCharArray()); KeyStore tks = KeyStore.getInstance("JKS"); tks.load(new FileInputStream(serverTrust), serverTrustPwd.toCharArray()); KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); km.init(keyStore, serverKeyStorePwd.toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(tks); SSLContext sslContext = SSLContext.getInstance(protocol); sslContext.init(km.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); //第一项是用来做服务器验证的 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); SSLSocket clientSSLSocket = (SSLSocket) sslSocketFactory.createSocket(socketClient,socketClient.getInetAddress().getHostAddress(),socketClient.getPort(), true); clientSSLSocket.setNeedClientAuth(false); clientSSLSocket.setUseClientMode(false); return clientSSLSocket; } /** * 用于单向认证 * server侧只需要自己的keystore文件,不需要truststore文件 * client侧不需要自己的keystore文件,只需要truststore文件(其中包含server的公钥)。 * 此外server侧需要在创建SSLServerSocket之后设定不需要客户端证书:setNeedClientAuth(false) * @param socketClient * @return * @throws KeyStoreException * @throws NoSuchAlgorithmException * @throws CertificateException * @throws FileNotFoundException * @throws IOException * @throws UnrecoverableKeyException * @throws KeyManagementException */ public static SSLSocket createTlsConnect2(Socket socketClient) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException { String protocol = "TLS"; String serverKey = "D:/JDK8Home/tianwt/sslServerKeys"; String serverKeyPwd = "123456"; //私钥密码 String serverKeyStorePwd = "123456"; // keystore存储密码 KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(serverKey),serverKeyPwd.toCharArray()); KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); km.init(keyStore, serverKeyStorePwd.toCharArray()); SSLContext sslContext = SSLContext.getInstance(protocol); sslContext.init(km.getKeyManagers(), null, new SecureRandom()); //第一项是用来做服务器验证的 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); SSLSocket clientSSLSocket = (SSLSocket) sslSocketFactory.createSocket(socketClient,socketClient.getInetAddress().getHostAddress(),socketClient.getPort(), true); clientSSLSocket.setNeedClientAuth(false); clientSSLSocket.setUseClientMode(false); return clientSSLSocket; } /** * 将普通的socket转为sslsocket,客户端和服务端均可使用 * * 服务端使用的时候是把普通的socket转为sslsocket,并且作为服务器套接字(注意:指的不是ServerSocket,当然ServerSocket的本质也是普通socket) * * @param remoteHost * @param isClient * @return */ public static SSLSocket getTlsTrustAllSocket(Socket remoteHost,boolean isClient) { SSLSocket remoteSSLSocket = null; SSLContext context = SSLTrustManager.getTrustAllSSLContext(isClient); try { remoteSSLSocket = (SSLSocket) context.getSocketFactory().createSocket(remoteHost, remoteHost.getInetAddress().getHostName(),remoteHost.getPort(), true); remoteSSLSocket.setTcpNoDelay(true); remoteSSLSocket.setSoTimeout(5000); remoteSSLSocket.setNeedClientAuth(false); //这里设置为true时会强制握手 remoteSSLSocket.setUseClientMode(isClient); //注意服务器和客户的角色选择 } catch (IOException e) { e.printStackTrace(); } return remoteSSLSocket; } /** * 用于客户端,通过所有证书验证 * @param isClient 是否生成客户端SSLContext,否则生成服务端SSLContext * @return */ public static SSLContext getTrustAllSSLContext(boolean isClient) { String protocol = "TLS"; javax.net.ssl.SSLContext sc = null; try { javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; javax.net.ssl.TrustManager tm = new SSLTrustManager(); trustAllCerts[0] = tm; sc = javax.net.ssl.SSLContext .getInstance(protocol); if(isClient) { sc.init(null, trustAllCerts, null); //作为客户端使用 } else { String serverKeyPath = "D:/JDK8Home/tianwt/sslServerKeys"; String serverKeyPwd = "123456"; //私钥密码 String serverKeyStorePwd = "123456"; // keystore存储密码 KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(serverKeyPath),serverKeyPwd.toCharArray()); KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); km.init(keyStore, serverKeyStorePwd.toCharArray()); KeyManager[] keyManagers = km.getKeyManagers(); keyManagers = Arrays.copyOf(keyManagers, keyManagers.length+1); sc.init(keyManagers, null, new SecureRandom()); } } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnrecoverableKeyException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return sc; } }