Java 自動安裝校驗TLS/SSL證書
前言
最近實現(xiàn)Socks5 proxy與HTTP proxy中遇到了SSLSocket隧道的問題,當(dāng)然,最終問題經(jīng)過自動證書校驗安裝管理器實現(xiàn)了證書的管理,也解決了SSLSocket,但是目前的問題是瀏覽器對Socks5和HTTP proxy還有很多不足,目前實現(xiàn)的兩個代理工具只能在程序中使用。當(dāng)然,我們今天的主要話題如下:
Java 實現(xiàn)TLS/SSL證書的自動安裝校驗,主要經(jīng)過ssl/tls握手,密鑰交換,證書校驗機制實現(xiàn)。我們這里模擬瀏覽器,實現(xiàn)自動校驗和證書的檢測。
主要實現(xiàn)如下功能:
1.自動檢測,校驗根證書,校驗過期時間,校驗簽名的證書是否有效,校驗證書和域名是否匹配
2.實現(xiàn)證書的自動存儲,自動安裝,加載
3.實現(xiàn)普通Socket自動升級為SSLSocket
一.實現(xiàn)配置類
首先,我們先添加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;
}
}
最后,我們來實現(xiàn)核心部分,證書管理器
二.實現(xiàn)核心代碼
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();
}
/**
* 開始握手等一系列密鑰協(xié)商
*
* @param socket
* @return
*/
public static boolean startHandshake(SSLSocket socket) {
try {
logger.log(Level.INFO, "-開始握手,認(rèn)證服務(wù)器證書-");
socket.startHandshake();
System.out.println();
logger.log(Level.INFO, "-握手結(jié)束,結(jié)束認(rèn)證服務(wù)器證書-");
} 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, "-證書鏈為空,認(rèn)證失敗-");
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, "證書文件不存在,選擇自動創(chuàng)建");
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, "-證書鏈為空,認(rèn)證失敗-");
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(); // 生成證書數(shù)組,用于存儲新證書
}
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, "設(shè)定指定證書別名:" + 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, "-強制認(rèn)可自簽名證書-");
trusted = true;
}
} catch (KeyStoreException e) {
e.printStackTrace();
}
if (!trusted) {
logger.log(Level.SEVERE, "-根證書簽名的網(wǎng)站:" + 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, "-證書已經(jīng)過期-");
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();
}
}
}
四.附加測試代碼
我們這里附加一個工具類,專門來實現(xiàn)Server-Side與Client-Side的SSLSocket 連接,也可以用于測試我們的上述代碼,只不過需要稍加改造。
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 需要經(jīng)過的代理
* @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;
}
/**
* 用于雙向認(rèn)證,客戶端使用
*
* @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;
}
/**
* 用于單向認(rèn)證,客戶端使用
*
* server側(cè)只需要自己的keystore文件,不需要truststore文件
* client側(cè)不需要自己的keystore文件,只需要truststore文件(其中包含server的公鑰)。
* 此外server側(cè)需要在創(chuàng)建SSLServerSocket之后設(shè)定不需要客戶端證書: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;
}
/**
* 用于雙向認(rèn)證
* @param socketClient 是否產(chǎn)生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()); //第一項是用來做服務(wù)器驗證的
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket clientSSLSocket = (SSLSocket) sslSocketFactory.createSocket(socketClient,socketClient.getInetAddress().getHostAddress(),socketClient.getPort(), true);
clientSSLSocket.setNeedClientAuth(false);
clientSSLSocket.setUseClientMode(false);
return clientSSLSocket;
}
/**
* 用于單向認(rèn)證
* server側(cè)只需要自己的keystore文件,不需要truststore文件
* client側(cè)不需要自己的keystore文件,只需要truststore文件(其中包含server的公鑰)。
* 此外server側(cè)需要在創(chuàng)建SSLServerSocket之后設(shè)定不需要客戶端證書: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()); //第一項是用來做服務(wù)器驗證的
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轉(zhuǎn)為sslsocket,客戶端和服務(wù)端均可使用
*
* 服務(wù)端使用的時候是把普通的socket轉(zhuǎn)為sslsocket,并且作為服務(wù)器套接字(注意:指的不是ServerSocket,當(dāng)然ServerSocket的本質(zhì)也是普通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); //這里設(shè)置為true時會強制握手
remoteSSLSocket.setUseClientMode(isClient); //注意服務(wù)器和客戶的角色選擇
} catch (IOException e) {
e.printStackTrace();
}
return remoteSSLSocket;
}
/**
* 用于客戶端,通過所有證書驗證
* @param isClient 是否生成客戶端SSLContext,否則生成服務(wù)端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;
}
}
以上就是Java 自動安裝校驗TLS/SSL證書的詳細(xì)內(nèi)容,更多關(guān)于Java TLS/SSL證書的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實現(xiàn)優(yōu)雅停止線程的有效方法詳解
這篇文章主要為大家詳細(xì)如何安全有效停止 Java 線程的,確保多線程應(yīng)用程序平穩(wěn)運行并實現(xiàn)最佳資源管理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
Java實現(xiàn)Excel批量導(dǎo)入數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)Excel批量導(dǎo)入數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-08-08
Mybatis反射核心類Reflector的實現(xiàn)
本文主要介紹了Mybatis反射核心類Reflector的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11
MyBatis中如何查詢某個時間段內(nèi)的數(shù)據(jù)
這篇文章主要介紹了MyBatis中如何查詢某個時間段內(nèi)的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
把spring boot項目發(fā)布tomcat容器(包含發(fā)布到tomcat6的方法)
這篇文章主要介紹了把spring boot項目發(fā)布tomcat容器(包含發(fā)布到tomcat6的方法),然后在文章給大家提到了如何將Spring Boot項目打包部署到外部Tomcat,需要的朋友參考下吧2017-11-11

