售前咨询
技术支持
渠道合作

关于TLS/SSL证书的自动安装校验

SSL/TLS在客户端和服务器之间建立加密通信通道。JAVA通过JSSE(javax.net.ssl)提供了对SSL和TLS的支持。通过其所提供的一系列API,开发者可以像使用普通Socket一样使用基于SSL或TLS的安全套接字,而不用关心SSL和TLS协议的细节,例如握手的流程等等。这使利用JAVA开发安全的SSL/TLS服务器或客户端非常容易。

SSL提供的安全质量完全依赖于私钥,私钥是安全证书的基础,而安全证书则是验证服务器身份的重要因素。

下面主要说一说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;
   }

   
 
 }

 

上一篇:

下一篇:

相关新闻