前言
最近实现Socks5 proxy与HTTP proxy中遇到了SSLSocket隧道的问题,当然,最终问题经过自动证书校验安装管理器实现了证书的管理,也解决了SSLSocket,但是目前的问题是浏览器对Socks5和HTTP proxy还有很多不足,目前实现的两个代理工具只能在程序中使用。当然,我们今天的主要话题如下:
Java 实现TLS/SSL证书的自动安装校验,主要经过ssl/tls握手,密钥交换,证书校验机制实现。我们这里模拟浏览器,实现自动校验和证书的检测。
主要实现如下功能:
1.自动检测,校验根证书,校验过期时间,校验签名的证书是否有效,校验证书和域名是否匹配
2.实现证书的自动存储,自动安装,加载
3.实现普通Socket自动升级为SSLSocket
一.实现配置类
首先,我们先添加2个配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
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; } } |
最后,我们来实现核心部分,证书管理器
二.实现核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
package com.ssl.rx.http; 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; } } |
三.测试代码
1 2 3 4 5 6 7 8 9 10 11 12 |
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 连接,也可以用于测试我们的上述代码,只不过需要稍加改造。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
package com.tianwt.rx.http; 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; } } |