HTTPS全面解析

百度百科對https的介紹:
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。 它是一個URI scheme(抽象標識符體系),句法類同http:體系。用於安全的HTTP數據傳輸。https:URL表明它使用了HTTP,但HTTPS存在不同於HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。
HTTPS和HTTP的區別主要爲以下四點:
一、https協議需要到ca申請證書,一般免費證書很少,需要交費。
二、http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。
三、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,後者是443。
四、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
握手過程
爲了便於更好的認識和理解SSL 協議,這裏着重介紹SSL 協議的握手協議。SSL 協議既用到了公鑰加密技術又用到了對稱加密技術,對稱加密技術雖然比公鑰加密技術的速度快,可是公鑰加密技術提供了更好的身份認證技術。SSL 的握手協議非常有效的讓客戶和服務器之間完成相互之間的身份認證,其主要過程如下:
①客戶端的瀏覽器向服務器傳送客戶端SSL 協議的版本號,加密算法的種類,產生的隨機數,以及其他服務器和客戶端之間通訊所需要的各種信息。
②服務器向客戶端傳送SSL 協議的版本號,加密算法的種類,隨機數以及其他相關信息,同時服務器還將向客戶端傳送自己的證書。
③客戶利用服務器傳過來的信息驗證服務器的合法性,服務器的合法性包括:證書是否過期,發行服務器證書的CA 是否可靠,發行者證書的公鑰能否正確解開服務器證書的“發行者的數字簽名”,服務器證書上的域名是否和服務器的實際域名相匹配。如果合法性驗證沒有通過,通訊將斷開;如果合法性驗證通過,將繼續進行第四步。
④用戶端隨機產生一個用於後面通訊的“對稱密碼”,然後用服務器的公鑰(服務器的公鑰從步驟②中的服務器的證書中獲得)對其加密,然後將加密後的“預主密碼”傳給服務器。
⑤如果服務器要求客戶的身份認證(在握手過程中爲可選),用戶可以建立一個隨機數然後對其進行數據簽名,將這個含有簽名的隨機數和客戶自己的證書以及加密過的“預主密碼”一起傳給服務器。
⑥如果服務器要求客戶的身份認證,服務器必須檢驗客戶證書和簽名隨機數的合法性,具體的合法性驗證過程包括:客戶的證書使用日期是否有效,爲客戶提供證書的CA 是否可靠,發行CA 的公鑰能否正確解開客戶證書的發行CA 的數字簽名,檢查客戶的證書是否在證書廢止列表(CRL)中。檢驗如果沒有通過,通訊立刻中斷;如果驗證通過,服務器將用自己的私鑰解開加密的“預主密碼”,然後執行一系列步驟來產生主通訊密碼(客戶端也將通過同樣的方法產生相同的主通訊密碼)。
⑦服務器和客戶端用相同的主密碼即“通話密碼”,一個對稱密鑰用於SSL 協議的安全數據通訊的加解密通訊。同時在SSL 通訊過程中還要完成數據通訊的完整性,防止數據通訊中的任何變化。
⑧客戶端向服務器端發出信息,指明後面的數據通訊將使用的步驟⑦中的主密碼爲對稱密鑰,同時通知服務器客戶端的握手過程結束。
⑨服務器向客戶端發出信息,指明後面的數據通訊將使用的步驟⑦中的主密碼爲對稱密鑰,同時通知客戶端服務器端的握手過程結束。

⑩SSL 的握手部分結束,SSL 安全通道的數據通訊開始,客戶和服務器開始使用相同的對稱密鑰進行數據通訊,同時進行通訊完整性的檢驗。

下面我們就來寫一下Https請求

String path = "https://www.baidu.com";
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
String string = Utils.inputStream2String(is);
System.out.println(string);
這個可以正常訪問,它就會將百度的html返回回來,那下面我們就url改成其他的看看,將其改成我tomcat下的一個工程網址(已放開了https配置,設置了自簽名證書):https://localhost:8443/Test/myTest

String path = "https://localhost:8443/Test/myTest";
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
String string = Utils.inputStream2String(is);
System.out.println(string);
這時就訪問不了了,報了一個javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target錯誤
那麼這是爲什麼了呢,百度的https就可以訪問,而自己tomcat的https就不可以訪問呢?咱再來看一看百度百科
信任主機的問題
採用https的服務器必須從CA (Certificate Authority)申請一個用於證明服務器用途類型的證書。該證書只有用於對應的服務器的時候,客戶端纔信任此主機。所以所有的銀行系統網站,關鍵部分應用都是https 的。客戶通過信任該證書,從而信任了該主機。其實這樣做效率很低,但是銀行更側重安全。
原來只有從CA機構申請的證書默認情況是受信任的,客戶端可以直接訪問。而我自己tomcat下的證書是使用java下的keytool工具自動生成的,並不是CA機構頒發的,所以默認是不受信任的。那麼我們如何處理,使其受信任並且可以訪問呢?有兩種方式:1.無條件的設置信任所有的證書。2.設置只信任與服務器設置的jks對應的cer證書

1.無條件的設置信任所有的證書,但是這樣做是不安全的

public static void main(String[] args) {
	try {
	//初始化SSLContext
	SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
	//設置信任管理器
	TrustManager[] managers = new TrustManager[]{new EmptyTrustManager()};
	context.init(null, managers, null);
	//這個必須在HttpsURLConnection生成對象之前設置
	HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
			
	String path = "https://localhost:8443/Test/myTest";
	URL url = new URL(path);
	HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
	//這時設置SSLSocketFactory沒有用
	//conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
	InputStream is = conn.getInputStream();
	String string = Utils.inputStream2String(is);
	System.out.println(string);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

static class EmptyTrustManager implements X509TrustManager {

	@Override
	public void checkClientTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {

	}

	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {

	}

	@Override
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}

}
2.設置只信任與服務器設置的jks對應的cer證書。當你將自己的項目的網絡請求改爲https時,後臺哥們會給你一個xxx.cer證書,這個證書就會和後臺的xxx.jks進行驗證校驗。我們可以將xxx.cer放到工程中,去讀取文件,也可以將其打印成字符串,將字符串放到代碼中去讀取。以下我是以字符串的形式使用的

static String chen = "-----BEGIN CERTIFICATE-----\n"+
			"MIIDWTCCAkGgAwIBAgIENIaROTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE"+
			"CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG"+
			"A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzA5NDIzN1oXDTI2MTIyMzA5NDIzN1owXTELMAkGA1UE"+
			"BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV"+
			"BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC"+
			"ggEBAKolNf440rZx58iz5P58VrWWPMQDZPMYuDDeZMENHRIUOu+PmjKwpmJUqVnKMvyGFj9VtoPE"+
			"kZE7NQLzJ0FIfaTBLaHRTYLisk3qnVXgZyZq/rrLq935SURCRl76NP+pAyXBoWVUkvzRYwXfhFUi"+
			"zO5yjH+ZFfQzjGWCugd8oYCLKmP+pJnlP/faNu7YDjL9JkOm6KiEnmkklkSJXrBBxmpsy0lSShwY"+
			"rNoZ4wW8XwgbNdwjM+Z4+IeOD/gBZMSrI8n8TLKBFH6IydFJOkwhHO1BvdzNQHrcXF0CRqM5ctW4"+
			"K7LXXE8OJg59b28ghdiqVAWRnSEyIYNgEBLkXnaU95UCAwEAAaMhMB8wHQYDVR0OBBYEFDt5QPgy"+
			"T3yfkb9iXV92Wzo1YndfMA0GCSqGSIb3DQEBCwUAA4IBAQA9ZVQIGQERDvDlsjlSzmhcrX0Gpdxf"+
			"kFmgXEc+Tck04l2VaT70YXYztcWTm8iPlxAOTAjxRE0syIbbAQ4UPba0hFINCPpvCD31ax3ukFUj"+
			"NJH+rZUwo1HjV8qzKAA4nd3f31PRg3yyAzmgfAwqVNxiq26YVglvV6h3TnC6dgcnV4sejOvv5nTA"+
			"7qc0cbQvGIEz4bEwIc+0l2/gwIoeUIquM6OAQTVzX9LuJ1aUTpenut+9G+vkEO3pfy4gdnOOXntW"+
			"uzqhaUV9gxOd1et10n1pvDcYNG6hhAkvotgV8Pl+NnDZ22Hqin1XB1cOZv18zHxC9WThRma3VN0V"+
			"z08eItRz\n"+
			"-----END CERTIFICATE-----";

	public static void main(String[] args) {
		try {
			ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
			SSLContext sslContext = getSSLContext(baos);
			HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
			
			String path = "https://localhost:8443/Test/myTest";
			URL url = new URL(path);
			HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
			//conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
			InputStream is = conn.getInputStream();
			String string = Utils.inputStream2String(is);
			System.out.println(string);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	static SSLContext getSSLContext(InputStream is){
		try{
			//初始化SSLContext
			SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
			// 1.導入證書
			Certificate certificate = CertificateFactory.getInstance("X.509")
					.generateCertificate(is);
			// 2.證書導入密鑰庫
			KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
			keyStore.load(null);
			keyStore.setCertificateEntry("srca", certificate);
			// 3.把密鑰庫放入信任管理器
			TrustManagerFactory trustManagerFactory = TrustManagerFactory
					.getInstance(TrustManagerFactory.getDefaultAlgorithm());
			trustManagerFactory.init(keyStore);
			// 4.生成信任管理器
			TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
			// 將信任管理器設置到SSLContext
			context.init(null, trustManagers, null);
			
			return context;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
如果url中的Hostname用的是IP則情況就不一樣了,如果是String path = "https://127.0.0.1:8443/Test/myTest";再次訪問的時候,會報javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present錯誤。
所以在HttpsURLConnection中的默認主機名驗證的方法中應返回true以表示通過,

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
				
				@Override
				public boolean verify(String hostname, SSLSession session) {
					
					return true;
				}
			});
此設置應和SSLSocketFactory一樣,在生成HttpsURLConnection之前設置,不然無效,所以main方法中代碼應爲

public static void main(String[] args) {
		try {
			ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
			SSLContext sslContext = getSSLContext(baos);
			HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
			HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
				
				@Override
				public boolean verify(String hostname, SSLSession session) {
					
					return true;
				}
			});
			
			String path = "https://127.0.0.1:8443/Test/myTest";
			URL url = new URL(path);
			HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
			//conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
			InputStream is = conn.getInputStream();
			String string = Utils.inputStream2String(is);
			System.out.println(string);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

這時就可以正常訪問了。
服務器端配置https

下面我們就來講解如何生成自簽名證書,和tomcat如何部署,完成這兩步tomcat就可以使用https訪問了,首先我們使用java自帶的keytool工具生成證書,win+R打開運行,輸入cmd打開cmd命令窗體,按照如下方式輸入:

如何生成https證書:

1.生成jks,使用如下的命令就會生成一個chen.jks,密碼爲123456,jks是服務端tomcat配置https時使用的證書

C:\Program Files\Java\jdk1.7.0_67\bin>keytool -genkey -alias chen -keyalg
 RSA -keystore C:\CJ\chen.jks -validity 3600 -storepass 123456
您的名字與姓氏是什麼?
  [Unknown]:  localhost
您的組織單位名稱是什麼?
  [Unknown]:  chen
您的組織名稱是什麼?
  [Unknown]:  chen
您所在的城市或區域名稱是什麼?
  [Unknown]:  chen
您所在的省/市/自治區名稱是什麼?
  [Unknown]:  chen
該單位的雙字母國家/地區代碼是什麼?
  [Unknown]:  CN
CN=localhost, OU=chen, O=chen, L=chen, ST=chen, C=CN是否正確?
  [否]:  y

輸入 <chen_client> 的密鑰口令
        (如果和密鑰庫口令相同, 按回車):
再次輸入新口令:
2.生成cer,使用如下命令和chen.jks就會生成一個chen.cer,xxx.cer是客戶端https訪問時用於與服務端jks進行校驗的

C:\Program Files\Java\jdk1.7.0_67\bin>keytool -export -alias chen -file C
:\CJ\chen.cer -keystore C:\CJ\chen.jks -storepass 123456
存儲在文件 <C:\CJ\chen_client.cer> 中的證書
3.打印cer,使用如下命令就可以打印cer中的字符串,就是上述提到的將cer打印成字符串,放入代碼中,就不需要將xxx.cer放到工程中了。
C:\Program Files\Java\jdk1.7.0_67\bin>keytool -printcert -rfc -file C:\CJ\chen.cer
-----BEGIN CERTIFICATE-----
MIIDWTCCAkGgAwIBAgIENIaROTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE
CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG
A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzA5NDIzN1oXDTI2MTIyMzA5NDIzN1owXTELMAkGA1UE
BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV
BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKolNf440rZx58iz5P58VrWWPMQDZPMYuDDeZMENHRIUOu+PmjKwpmJUqVnKMvyGFj9VtoPE
kZE7NQLzJ0FIfaTBLaHRTYLisk3qnVXgZyZq/rrLq935SURCRl76NP+pAyXBoWVUkvzRYwXfhFUi
zO5yjH+ZFfQzjGWCugd8oYCLKmP+pJnlP/faNu7YDjL9JkOm6KiEnmkklkSJXrBBxmpsy0lSShwY
rNoZ4wW8XwgbNdwjM+Z4+IeOD/gBZMSrI8n8TLKBFH6IydFJOkwhHO1BvdzNQHrcXF0CRqM5ctW4
K7LXXE8OJg59b28ghdiqVAWRnSEyIYNgEBLkXnaU95UCAwEAAaMhMB8wHQYDVR0OBBYEFDt5QPgy
T3yfkb9iXV92Wzo1YndfMA0GCSqGSIb3DQEBCwUAA4IBAQA9ZVQIGQERDvDlsjlSzmhcrX0Gpdxf
kFmgXEc+Tck04l2VaT70YXYztcWTm8iPlxAOTAjxRE0syIbbAQ4UPba0hFINCPpvCD31ax3ukFUj
NJH+rZUwo1HjV8qzKAA4nd3f31PRg3yyAzmgfAwqVNxiq26YVglvV6h3TnC6dgcnV4sejOvv5nTA
7qc0cbQvGIEz4bEwIc+0l2/gwIoeUIquM6OAQTVzX9LuJ1aUTpenut+9G+vkEO3pfy4gdnOOXntW
uzqhaUV9gxOd1et10n1pvDcYNG6hhAkvotgV8Pl+NnDZ22Hqin1XB1cOZv18zHxC9WThRma3VN0V
z08eItRz
-----END CERTIFICATE-----
4.tomcat服務器配置 ,在tomcat下的conf文件夾下的server.xml中配置

<Connector SSLEnabled="true" acceptCount="100" clientAuth="false" 
		disableUploadTimeout="true" enableLookups="true" keystoreFile="C:\\CJ\\chen.jks" keystorePass="123456" maxSpareThreads="75" 
		maxThreads="200" minSpareThreads="5" port="8443" 
		protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" 
		secure="true" sslProtocol="TLS"
      /> 
在server.xml中的https默認配置的port爲8443,你也可以修改,當你的電腦的8443端口被其他應用佔用的時候,你就可以修改。這是重新啓動tomcat時,這時你的服務器就可以使用https訪問了。
這時該服務器用上面的網絡請求就可以訪問了。

雙向證書驗證
前面的https請求時,是服務器一個chen.jks,客戶端一個chen.cer。那麼雙向證書驗證,就還需要再次之前的配置上,再加上服務器一個chen_client.cer,客戶端一個chen_client.jks。

重新生成一個證書
1.生成jks

C:\Program Files\Java\jdk1.7.0_67\bin>keytool -genkey -alias chen -keyalg
 RSA -keystore C:\CJ\chen.jks -validity 3600 -storepass 123456
您的名字與姓氏是什麼?
  [Unknown]:  localhost
您的組織單位名稱是什麼?
  [Unknown]:  chen
您的組織名稱是什麼?
  [Unknown]:  chen
您所在的城市或區域名稱是什麼?
  [Unknown]:  chen
您所在的省/市/自治區名稱是什麼?
  [Unknown]:  chen
該單位的雙字母國家/地區代碼是什麼?
  [Unknown]:  CN
CN=localhost, OU=chen, O=chen, L=chen, ST=chen, C=CN是否正確?
  [否]:  y

輸入 <chen_client> 的密鑰口令
        (如果和密鑰庫口令相同, 按回車):
再次輸入新口令:
2.生成cer

C:\Program Files\Java\jdk1.7.0_67\bin>keytool -export -alias chen -file C
:\CJ\chen.cer -keystore C:\CJ\chen.jks -storepass 123456
存儲在文件 <C:\CJ\chen_client.cer> 中的證書
需要將cer證書添加到jks中,不然,如果服務端使用cer證書,會報一個Invalid keystore format錯誤

C:\Program Files\Java\jdk1.7.0_67\bin>keytool -import -alias chen_client -file C
:\CJ\chen_client.cer -keystore C:\CJ\chen_client_for_server.jks
3.修改tomcat的配置文件

需要將之前的clientAuth="false"改爲clientAuth="true",在增加一個字段truststoreFile="C:\\CJ\\chen_client_for_server.jks",指明jks的路徑。

<Connector SSLEnabled="true" acceptCount="100" clientAuth="true" 
		disableUploadTimeout="true" enableLookups="true" keystoreFile="C:\\CJ\\chen.jks" keystorePass="123456" maxSpareThreads="75" 
		maxThreads="200" minSpareThreads="5" port="8443" 
		protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" 
		secure="true" sslProtocol="TLS"
		truststoreFile="C:\\CJ\\chen_client_for_server.jks" 
      /> 
當是雙向證書驗證驗證時,如果在tomcat/conf/sever.xml文件中的配置屬性clientAuth="false",沒有將其改爲true,這是的雙向證書驗證驗依然是單向的,客戶端不做任何修改,https依然可以訪問,如果將其改爲true,就訪問不了了。
這時重啓服務器時,之前的https網絡請求就請求不了了,報java.net.SocketException: Software caused connection abort: recv failed。這時我們需要修改一下網絡請求代碼,context.init(null, trustManagers, null);第一個參數是KeyManager[],是客戶端的key,就是使用我們第二次生成的chen_client.jks,生成的KeyManager[]。添加如下代碼:
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream iStream = new FileInputStream("chen_client.jks");
clientKeyStore.load(iStream, "123456".toCharArray());
//將keystore放入密鑰管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
 //生成密鑰管理器
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// 將信任管理器設置到SSLContext
context.init(keyManagers, trustManagers, null);
這時就可以進行網絡請求了(java平臺),客戶端和服務器就是雙向證書驗證方式,網絡請求就會更加的安全可靠。(如果是雙向證書驗證的tomcat,如果客戶端不給kayManagers就會報 javax.net.ssl.SSLException: Connection closed by peer 錯誤)
這時我們將代碼移植到Android工程中,跑起來,訪問網絡失敗,報java.io.IOException: Wrong version of key store.異常。這是因爲Java平臺默認識別jks格式的證書文件,但是android平臺只識別bks格式的證書文件。所以這時我們就需要將jks格式轉成bks格式,我們可以使用Portecle工具進行轉換:下載。下載完之後解壓,裏面有一個Portecle.jar,在DOS界面,使用jave -jar Portecle.jar打開圖形界面,操作步驟:1.File->Open Keystore File->選擇chen_client.jks->輸入密碼 2.Tools->Change Keystore Type->BKS->輸入密碼 3.Save Keystore->選擇保存路徑(命名:chen_client.bks)。然後將Android工程中的chen_client.jks替換爲chen_client.bks。重新運行Android項目,就可以正常訪問了。Android中的完整代碼如下:

URLConnection雙向證書驗證的https請求:

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import com.tydz.taoyuan.R;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

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.TrustManager;
import javax.net.ssl.TrustManagerFactory;

public class HttpsActivity extends AppCompatActivity {

    static Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mTextView.setText(msg.obj.toString());
        }
    };

    static String chen = "-----BEGIN CERTIFICATE-----\n" +
            "MIIDWTCCAkGgAwIBAgIEcWnCMTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE\n" +
            "CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG\n" +
            "A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzE0MTIzNVoXDTI2MTIyMzE0MTIzNVowXTELMAkGA1UE\n" +
            "BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV\n" +
            "BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
            "ggEBAOCj9+qaE/DcDtJnEpeSc0+byTO3/yM673C4sgax7n4lCnjtmhgqiwASTCOnEMRJ6llmo/M8\n" +
            "+msz9i+1vE4lte7AkZ/3Wfu04BXq9wmDlVNWU3kU6TfZMUhqifTvRC6zQmfJaBdS6SSfmBslrUUC\n" +
            "ntD19vvGRLPkEt05s0itG54ex41fSgA4pBtj6qpBjLMS/03fCD6y3YdL+r0dN6bDxAuLo+2flJEy\n" +
            "9CrnXEzLcZ172zD+5mfvhFI7F1fF1kdjT4pNi22sap5AOFZazaK7snq03cLTchC7yBwcPCJ6IqzY\n" +
            "Yw6bVb79cj6nntbTb6lsrL7wv2kR8ubtiRTrrtCP2YMCAwEAAaMhMB8wHQYDVR0OBBYEFF5ZFY02\n" +
            "FejgLSsO9DOZppwUhGS4MA0GCSqGSIb3DQEBCwUAA4IBAQCNg76X3tRCtnDi7cT5M8ADMzSUlYvA\n" +
            "CaVYKQ+lB3WBLuqR3wVVJ/zeSGqiR4F59cj6Oij+fk5Fu05n+0nXX/sdirf2RTW1eaA+SzPYXdgA\n" +
            "0u8XJdaPu58q0GCPFpUv24ljzQEr/hZBS9HWlHmkgByecpgrrToOc3jJNIQr8g1NVO/b8RCBFyx8\n" +
            "Ax+Ytp8XNGKbmMnXifBxBnhMCT0DptmZuYsTacZ5qLqEhszChYSM3drYhoNId1HlLLeQbUumbB/8\n" +
            "N1BVVH2LYPTJgKdXTQAzTWiUAss/HD78fe30qI3MDrZ1h4eF+vCHqOwAOiLxQ0Rpb5oMsVCblmoR\n" +
            "+ool1ljG\n" +
            "-----END CERTIFICATE-----";
    private static TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_https);

        mTextView = (TextView) findViewById(R.id.textview);

        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    net();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    private void net() throws Exception{

        ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
        //InputStream iStream = new FileInputStream("chen_client.jks");
        InputStream iStream = getAssets().open("chen_client.bks");
        SSLContext sslContext = getSSLContext(baos,iStream);
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String hostname, SSLSession session) {

                return true;
            }
        });

        String path = "https://10.0.2.2:8444/OkHttp/text";
        URL url = new URL(path);
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        //********************************
        //POST請求
        /*
        conn.addRequestProperty("Content-Type", "application/json");
        conn.addRequestProperty("Connection", "Keep-Alive");// 維持長連接
        conn.addRequestProperty("Charset", "UTF-8");

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");

        OutputStream outputStream = conn.getOutputStream();
        outputStream.write("{\"name\":chen}".getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
        */
        //************************************

        //conn.setDefaultSSLSocketFactory(conn.getSSLSocketFactory());
        InputStream is = conn.getInputStream();
        String string = inputStream2String(is);
        System.out.println(string);

        sendMsg(string);

    }

    private void sendMsg(String msg){
        Message message = mHandler.obtainMessage();
        message.obj = msg;
        mHandler.sendMessage(message);
    }

    SSLContext getSSLContext(InputStream cer,InputStream bks){
        try{
            //初始化SSLContext
            SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
            // 1.導入證書
            Certificate certificate = CertificateFactory.getInstance("X.509")
                    .generateCertificate(cer);
            // 2.證書導入密鑰庫
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setCertificateEntry("srca", certificate);
            // 3.把密鑰庫放入信任管理器
            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            // 4.生成信任管理器
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            //初始化keystore
            KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            clientKeyStore.load(bks, "123456".toCharArray());
            //將keystore放入密鑰管理器
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
            //生成密鑰管理器
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
            // 將信任管理器設置到SSLContext
            context.init(keyManagers, trustManagers, null);

            return context;
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

    public static String inputStream2String(InputStream in) throws IOException {
        int len = -1;
        byte[] buffer = new byte[1024];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while ((len = in.read(buffer)) != -1) {
            baos.write(buffer, 0, len);
        }
        baos.close();

        return baos.toString("UTF-8");
    }
}
Volley雙向證書驗證的https請求:
Volley因爲API>=9底層的就是用HttpsURLConnection,HttpsURLConnection實現的,所以volley實現https的代碼可以參考java的HttpsURLConnection的,volley的http請求時的請求隊列:RequestQueue queue = Volley.newRequestQueue(getApplication());,newRequestQueue(Context)還有一個重載方法newRequestQueue(Context context, HttpStack stack),這個就是https的入口,HurlStack構造中就有一個參數傳的就是SSLSocketFactory,所以volley的https的請求代碼如下:

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

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.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class MainActivity extends AppCompatActivity {

    static Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mTextView.setText(msg.obj.toString());
        }
    };


    static String chen = "-----BEGIN CERTIFICATE-----\n" +
            "MIIDWTCCAkGgAwIBAgIEcWnCMTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE\n" +
            "CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG\n" +
            "A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzE0MTIzNVoXDTI2MTIyMzE0MTIzNVowXTELMAkGA1UE\n" +
            "BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV\n" +
            "BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
            "ggEBAOCj9+qaE/DcDtJnEpeSc0+byTO3/yM673C4sgax7n4lCnjtmhgqiwASTCOnEMRJ6llmo/M8\n" +
            "+msz9i+1vE4lte7AkZ/3Wfu04BXq9wmDlVNWU3kU6TfZMUhqifTvRC6zQmfJaBdS6SSfmBslrUUC\n" +
            "ntD19vvGRLPkEt05s0itG54ex41fSgA4pBtj6qpBjLMS/03fCD6y3YdL+r0dN6bDxAuLo+2flJEy\n" +
            "9CrnXEzLcZ172zD+5mfvhFI7F1fF1kdjT4pNi22sap5AOFZazaK7snq03cLTchC7yBwcPCJ6IqzY\n" +
            "Yw6bVb79cj6nntbTb6lsrL7wv2kR8ubtiRTrrtCP2YMCAwEAAaMhMB8wHQYDVR0OBBYEFF5ZFY02\n" +
            "FejgLSsO9DOZppwUhGS4MA0GCSqGSIb3DQEBCwUAA4IBAQCNg76X3tRCtnDi7cT5M8ADMzSUlYvA\n" +
            "CaVYKQ+lB3WBLuqR3wVVJ/zeSGqiR4F59cj6Oij+fk5Fu05n+0nXX/sdirf2RTW1eaA+SzPYXdgA\n" +
            "0u8XJdaPu58q0GCPFpUv24ljzQEr/hZBS9HWlHmkgByecpgrrToOc3jJNIQr8g1NVO/b8RCBFyx8\n" +
            "Ax+Ytp8XNGKbmMnXifBxBnhMCT0DptmZuYsTacZ5qLqEhszChYSM3drYhoNId1HlLLeQbUumbB/8\n" +
            "N1BVVH2LYPTJgKdXTQAzTWiUAss/HD78fe30qI3MDrZ1h4eF+vCHqOwAOiLxQ0Rpb5oMsVCblmoR\n" +
            "+ool1ljG\n" +
            "-----END CERTIFICATE-----";
    private static TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.textview);

    }

    public void click(View view){
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    volley();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }


    void volley() throws Exception{
        String path = "https://10.0.2.2:8444/OkHttp/text";
        ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
        //InputStream iStream = new FileInputStream("chen_client.jks");
        InputStream iStream = getAssets().open("chen_client.bks");
        SSLContext sslContext = getSSLContext(baos,iStream);
        //SSLSocketFactory在HurlStack內部已經實現
        //HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String hostname, SSLSession session) {

                return true;
            }
        });
        HurlStack hurlStack = new HurlStack(null,sslContext.getSocketFactory());
        RequestQueue queue = Volley.newRequestQueue(getApplication(),hurlStack);
        //get
        StringRequest request = new StringRequest(path, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                sendMsg(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
                sendMsg(error.toString());
            }
        });
        //post
	/*
	Map map = new HashMap<>();
        map.put("userName", "183********");
        map.put("password", "111111");
        JSONObject object = new JSONObject(map);

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, path, object, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                sendMsg(response.toString());
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
                sendMsg(error.toString());
            }
        });
	*/
        queue.add(request);
    }


    private void sendMsg(String msg){
        Message message = mHandler.obtainMessage();
        message.obj = msg;
        mHandler.sendMessage(message);
    }

    SSLContext getSSLContext(InputStream cer,InputStream bks){
        try{
            //初始化SSLContext
            SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
            // 1.導入證書
            Certificate certificate = CertificateFactory.getInstance("X.509")
                    .generateCertificate(cer);
            // 2.證書導入密鑰庫
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setCertificateEntry("srca", certificate);
            // 3.把密鑰庫放入信任管理器
            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            // 4.生成信任管理器
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            //初始化keystore
            KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            clientKeyStore.load(bks, "123456".toCharArray());
            //將keystore放入密鑰管理器
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
            //生成密鑰管理器
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
            // 將信任管理器設置到SSLContext
            context.init(keyManagers, trustManagers, new SecureRandom());

            return context;
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

}

OkHttp雙向證書驗證的https請求:

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

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.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class MainActivity extends AppCompatActivity {

    static Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mTextView.setText(msg.obj.toString());
        }
    };

    static String chen = "-----BEGIN CERTIFICATE-----\n" +
            "MIIDWTCCAkGgAwIBAgIEcWnCMTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJDTjENMAsGA1UE\n" +
            "CBMEY2hlbjENMAsGA1UEBxMEY2hlbjENMAsGA1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjESMBAG\n" +
            "A1UEAxMJbG9jYWxob3N0MB4XDTE3MDIxMzE0MTIzNVoXDTI2MTIyMzE0MTIzNVowXTELMAkGA1UE\n" +
            "BhMCQ04xDTALBgNVBAgTBGNoZW4xDTALBgNVBAcTBGNoZW4xDTALBgNVBAoTBGNoZW4xDTALBgNV\n" +
            "BAsTBGNoZW4xEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
            "ggEBAOCj9+qaE/DcDtJnEpeSc0+byTO3/yM673C4sgax7n4lCnjtmhgqiwASTCOnEMRJ6llmo/M8\n" +
            "+msz9i+1vE4lte7AkZ/3Wfu04BXq9wmDlVNWU3kU6TfZMUhqifTvRC6zQmfJaBdS6SSfmBslrUUC\n" +
            "ntD19vvGRLPkEt05s0itG54ex41fSgA4pBtj6qpBjLMS/03fCD6y3YdL+r0dN6bDxAuLo+2flJEy\n" +
            "9CrnXEzLcZ172zD+5mfvhFI7F1fF1kdjT4pNi22sap5AOFZazaK7snq03cLTchC7yBwcPCJ6IqzY\n" +
            "Yw6bVb79cj6nntbTb6lsrL7wv2kR8ubtiRTrrtCP2YMCAwEAAaMhMB8wHQYDVR0OBBYEFF5ZFY02\n" +
            "FejgLSsO9DOZppwUhGS4MA0GCSqGSIb3DQEBCwUAA4IBAQCNg76X3tRCtnDi7cT5M8ADMzSUlYvA\n" +
            "CaVYKQ+lB3WBLuqR3wVVJ/zeSGqiR4F59cj6Oij+fk5Fu05n+0nXX/sdirf2RTW1eaA+SzPYXdgA\n" +
            "0u8XJdaPu58q0GCPFpUv24ljzQEr/hZBS9HWlHmkgByecpgrrToOc3jJNIQr8g1NVO/b8RCBFyx8\n" +
            "Ax+Ytp8XNGKbmMnXifBxBnhMCT0DptmZuYsTacZ5qLqEhszChYSM3drYhoNId1HlLLeQbUumbB/8\n" +
            "N1BVVH2LYPTJgKdXTQAzTWiUAss/HD78fe30qI3MDrZ1h4eF+vCHqOwAOiLxQ0Rpb5oMsVCblmoR\n" +
            "+ool1ljG\n" +
            "-----END CERTIFICATE-----";
    private static TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.textview);

    }

    public void click(View view){
        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    okhttp();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    void okhttp() throws Exception{
        String path = "https://10.0.2.2:8444/OkHttp/text";
        ByteArrayInputStream baos = new ByteArrayInputStream(chen.getBytes());
        //InputStream iStream = new FileInputStream("chen_client.jks");
        InputStream iStream = getAssets().open("chen_client.bks");
        SSLManagerParams ssl = getSSLManagerParams(baos,iStream);
        OkHttpClient client = new OkHttpClient.Builder()
                .sslSocketFactory(ssl.mFactory,ssl.mTrustManager)
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                })
                .build();
	//get
        Request request = new Request.Builder().get().url(path).build();
	//post
	/*
	Map<String,String> map = new HashMap<>();
        map.put("userName", "183********");
        map.put("password", "111111");
        JSONObject jsonObject = new JSONObject(map);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"),jsonObject.toString());
        okhttp3.Request request = new okhttp3.Request.Builder().post(requestBody).url(path).build();
	*/
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                sendMsg(e.toString());
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                sendMsg(response.body().string());
            }
        });
    }


    private void sendMsg(String msg){
        Message message = mHandler.obtainMessage();
        message.obj = msg;
        mHandler.sendMessage(message);
    }


    static class SSLManagerParams{
        public SSLSocketFactory mFactory;
        public X509TrustManager mTrustManager;
    }

    SSLManagerParams getSSLManagerParams(InputStream cer,InputStream bks){
        SSLManagerParams ssl = new SSLManagerParams();
        try{
            //初始化SSLContext
            SSLContext context = SSLContext.getInstance("TLS");//TLS和SSL都可以
            // 1.導入證書
            Certificate certificate = CertificateFactory.getInstance("X.509")
                    .generateCertificate(cer);
            // 2.證書導入密鑰庫
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setCertificateEntry("srca", certificate);
            // 3.把密鑰庫放入信任管理器
            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            // 4.生成信任管理器
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            //初始化keystore
            KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            clientKeyStore.load(bks, "123456".toCharArray());
            //將keystore放入密鑰管理器
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
            //生成密鑰管理器
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
            // 將信任管理器設置到SSLContext
            context.init(keyManagers, trustManagers, new SecureRandom());

            ssl.mFactory = context.getSocketFactory();
            ssl.mTrustManager = chooseX509TrustManager(trustManagers);

            return ssl;
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

    private static X509TrustManager chooseX509TrustManager(TrustManager[] trustManagers)
    {
        for (TrustManager trustManager : trustManagers)
        {
            if (trustManager instanceof X509TrustManager)
            {
                return (X509TrustManager) trustManager;
            }
        }
        return null;
    }

}
好了,HPPTS全面解析到這裏就結束了。以上的三種網絡請求代碼爲了便於理解,並沒有做合法性檢測與封裝,下面我提供了一個將三種https請求的簡單封裝工程。

下載:CSDN

參考:http://blog.csdn.net/lmj623565791/article/details/48129405



發佈了43 篇原創文章 · 獲贊 17 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章