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

前言

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

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

主要实现如下功能:

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

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

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

一.实现配置类

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

package com.ssl.rx.http;

import java.security.KeyStore;

public class ConnectionConfiguration {

	/** 证书文件路径 */
private String truststorePath;
	/** 证书类型 */
private String truststoreType;
	/** 证书文件密码 */
private String truststorePassword;
	/** 是否验证证书链的签名有效性 */
private boolean verifyChainEnabled = true;
	/** 是否校验根证书,注意,自签名证书没有根证书 */
private boolean verifyRootCAEnabled = true;
	/** 是否允许通过自签名证书 */
private boolean selfSignedCertificateEnabled = false;
	/** 是否检查证书的有效期 */
private boolean expiredCertificatesCheckEnabled = true;
	/** 检查域名的匹配情况 */
private boolean notMatchingDomainCheckEnabled = true;

	private String server;
	private int port;

	public ConnectionConfiguration() {
		truststorePassword = "WlZSak5GcFVUbTlsVjJSNg==";
		truststorePath = "socket_tls_clientTrust.cert";
		truststoreType = "jks";
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getServer() {
		return server;
	}

	public void setServer(String server) {
		this.server = server;
	}

	public boolean isExpiredCertificatesCheckEnabled() {
		return expiredCertificatesCheckEnabled;
	}

	public void setSelfSignedCertificateEnabled(boolean selfSignedCertificateEnabled) {
		this.selfSignedCertificateEnabled = selfSignedCertificateEnabled;
	}

	public void setExpiredCertificatesCheckEnabled(boolean expiredCertificatesCheckEnabled) {
		this.expiredCertificatesCheckEnabled = expiredCertificatesCheckEnabled;
	}

	public boolean isSelfSignedCertificateEnabled() {
		return selfSignedCertificateEnabled;
	}

	public boolean isNotMatchingDomainCheckEnabled() {
		return notMatchingDomainCheckEnabled;
	}

	public boolean isVerifyRootCAEnabled() {
		return verifyRootCAEnabled;
	}

	public void setVerifyRootCAEnabled(boolean verifyRootCAEnabled) {
		this.verifyRootCAEnabled = verifyRootCAEnabled;
	}

	public void setVerifyChainEnabled(boolean verifyChainEnabled) {
		this.verifyChainEnabled = verifyChainEnabled;
	}

	public boolean isVerifyChainEnabled() {

		return verifyChainEnabled;
	}

	public String getTruststoreType() {
		return truststoreType;
	}

	public void setTruststoreType(String truststoreType) {
		this.truststoreType = truststoreType;
	}

	public String getTruststorePassword() {
		return truststorePassword;
	}

	public void setTruststorePassword(String truststorePassword) {
		this.truststorePassword = truststorePassword;
	}

	public String getTruststorePath() {
		return truststorePath;
	}

	public void setTruststorePath(String truststorePath) {
		this.truststorePath = truststorePath;
	}

	public void setNotMatchingDomainCheckEnabled(boolean notMatchingDomainCheckEnabled) {
		this.notMatchingDomainCheckEnabled = notMatchingDomainCheckEnabled;
	}

}

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

package com.ssl.rx.http;

public class KeyStoreOptions {
	private final String type;
	private final String path;
	private final String password;

	public KeyStoreOptions(String type, String path, String password) {
		super();
		this.type = type;
		this.path = path;
		this.password = password;
	}

	public String getType() {
		return type;
	}

	public String getPath() {
		return path;
	}

	public String getPassword() {
		return password;
	}

	@Override
public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((password == null) ? 0 : password.hashCode());
		result = prime * result + ((path == null) ? 0 : path.hashCode());
		result = prime * result + ((type == null) ? 0 : type.hashCode());
		return result;
	}

	@Override
public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		KeyStoreOptions other = (KeyStoreOptions) obj;
		if (password == null) {
			if (other.password != null)
				return false;
		} else if (!password.equals(other.password))
			return false;
		if (path == null) {
			if (other.path != null)
				return false;
		} else if (!path.equals(other.path))
			return false;
		if (type == null) {
			if (other.type != null)
				return false;
		} else if (!type.equals(other.type))
			return false;
		return true;
	}
}

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

二.实现核心代码

package com.ssl.rx.http;

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;

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;
  }
 }

以上就是Java 自动安装校验TLS/SSL证书的详细内容,更多关于Java TLS/SSL证书的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java如何跳过https的ssl证书验证详解

    打开我们首页,明显看到链接是https打头,https和http的通信协议差别,在于https安全性更高: http和https的差别 很明显,二者最大的区别在于https多了一个ssl证书验证,可以说https是身披SSL外壳的http.因为http存在如下缺陷: 1)通信使用明文,内容可能被窃听(重要密码泄露) 2)不验证通信方身份,有可能遭遇伪装(跨站点请求伪造) 3)无法证明报文的完整性,有可能已遭篡改(运营商劫持) 而https是利用SSL/TLS建立全信道,加密数据包.HTTPS使用

  • 纯Java实现数字证书生成签名的简单实例

    package com.ylsoft.cert; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator;

  • Java如何基于command调用openssl生成私钥证书

    在windows环境下进行的测试,前提条件,windows上需要先安装openssl. 配置环境变量,查看版本: import java.io.*; import java.util.Properties; public class OpensslCommand { private static void runCMD(String[] CMD) { java.lang.Process process = null; try { process = Runtime.getRuntime().ex

  • 使用httpclient无需证书调用https的示例(java调用https)

    使用httpclient无需证书调用https的url地址,传输字节流. 复制代码 代码如下: package com.paic.hmreport.metaQ; import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.FileOutputStream;import java.io.IOException;import ja

  • Java 自动安装校验TLS/SSL证书

    前言 最近实现Socks5 proxy与HTTP proxy中遇到了SSLSocket隧道的问题,当然,最终问题经过自动证书校验安装管理器实现了证书的管理,也解决了SSLSocket,但是目前的问题是浏览器对Socks5和HTTP proxy还有很多不足,目前实现的两个代理工具只能在程序中使用.当然,我们今天的主要话题如下: Java 实现TLS/SSL证书的自动安装校验,主要经过ssl/tls握手,密钥交换,证书校验机制实现.我们这里模拟浏览器,实现自动校验和证书的检测. 主要实现如下功能:

  • 解决docker的tls(ssl)证书过期问题

    问题现象: [root@localhost ~]# docker image pull xxx.com.cn/centos7 Using default tag: latest Error response from daemon: Get https://xxx.com.cn/v1/_ping: x509: certificate has expired or is not yet valid 可能的原因分析: linux使用查看date查看当前时间,与证书的有效时间作比对,得出具体的原因,可

  • 在Serv-U中使用SSL证书增强FTP服务器安全性图文设置方法

    为了保证特殊环境下的数据安全,有时是有必要启用SSL功能的.下面笔者以Serv-U服务器为例,介绍如何启用SSL加密功能. 创建SSL证书 要想使用Serv-U的SSL功能,当然需要SSL证书的支持才行.虽然Serv-U 在安装之时就已经自动生成了一个SSL证书,但这个默认生成的SSL证书在所有的Serv-U服务器中都是一样的,非常不安全,所以我们需要手工创建一个新的SSL证书. 以Serv-U6.0汉化版为例,在"Serv-U管理员"窗口中,展开"本地服务器→设置"

  • 在Nginx服务器上安装SSL证书完成HTTPS请求的步骤详解(springboot项目)

    目录 步骤1:下载证书到本地 步骤2:(可选)在Nginx独立服务器上安装证书 http本博客是在我完成了http重定向https配置之后来总结的,如有问题请大家见谅!如有问题请评论留言!!! 阿里云文档地址:https://help.aliyun.com/document_detail/98728.htm?spm=a2c4g.11186623.2.7.550a7845ysZdw5#section-liy-o8x-gug 步骤1:下载证书到本地 1.登录SSL证书控制台. 2.在概览页面,单击证

  • Linux Nginx下SSL证书安装方法及WordPress CDN配置

    一.Nginx安装SSL证书 需要两个配置文件 (温馨提示:安装证书前请先备份您需要修改的服务器配置文件) 1_root_bundle.crt: 2_domainname.com.key. 注:这三个证书文件都在文件夹for Nginx.zip中,例:1_root_bundle.crt是根证书链(公钥),2_ domainname.com.key为私钥. (其中:证书公钥.私钥文件一般以您的域名命名:证书后缀名crt和cer的性质是一样的). 二.Nginx证书代码修改 1.打开Nginx安装目

  • Android APP之WebView校验SSL证书的方法

    Android系统的碎片化很严重,并且手机日期不正确.手机根证书异常.com.google.android.webview BUG等各种原因,都会导致WebViewClient无法访问HTTPS站点.SSL错误的处理方式十分关键,如果处理不当,可能导致中间人攻击,黑客窃听数据,进而引发安全事故. 严谨地处理onReceivedSslError尤为重要.请参考以下代码,原理是:如果webview报告SSL错误,程序将会对服务器证书进行强校验,如果服务器传入证书的指纹(sha256)与记录值一致,说

  • 微信小程序 免费SSL证书https、TLS版本问题的解决办法

    微信小程序 免费SSL证书https.TLS版本问题的解决办法 微信小程序与第三方服务器通讯的域名5个必要条件 1.一个已备案的域名,不是localhost.也不是127.0.0.1,域名不能加端口 2.加ssl证书,也就是https://~~~ 4.HTTPS 服务器的 TLS 版本支持1.2及以下版本,一般就是1.0.1.1.1.2要同时支持这三个版本,一个也不能少,要不然就会出现下面这种情况 5.微信小程序后台加上合法域名设置(一个月内改的次数是有限的,且行且珍惜)如下图 以上5个条件,必

  • windows服务器ssl证书创建、安装及配置方法

    用IIS发布https网站,SSL的安全服务配置步骤: 生成申请证书请求获取及安装中级CA证书安装服务器证书及配置绑定一.生成证书请求 进入IIS控制台 在"开始"菜单上,依次单击"所有程序"."附件"和"运行". 在"打开"框中,键入 inetmgr,然后单击"确定".点击对应机器主页,然后选择"服务器证书". 创建证书请求 进入服务器证书配置页面,并选择"

  • 阿里云负载均衡SLB安装SSL证书的方法

    获取证书文件 1.登陆用户中心(如何登陆用户中心?)获取SSL证书(证书管理系统现在有2个版本并存[根据购买SSL证书品牌,类型等随机分配],证书管理系统版本不同,获取证书方式略有差异,最终得到的证书是没有区别的,请按照您现行使用的证书系统版本获取证书文件.) 1-1. 版本1-如何获取SSL证书文件:点击这里 ,找到如下图所示页面,请把SSL证书文件(包括"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----&quo

随机推荐