Last active
April 18, 2023 08:55
-
-
Save Frank-Zhu/41e21a00df26d63cd38d to your computer and use it in GitHub Desktop.
Android HTTPS SSL双向验证
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.ecloud.ssldemo; | |
import android.content.Context; | |
import android.util.Log; | |
import com.squareup.okhttp.OkHttpClient; | |
import org.apache.http.client.ClientProtocolException; | |
import org.apache.http.client.HttpClient; | |
import org.apache.http.conn.scheme.Scheme; | |
import org.apache.http.conn.ssl.SSLSocketFactory; | |
import org.apache.http.impl.client.DefaultHttpClient; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.net.URL; | |
import java.security.KeyManagementException; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.UnrecoverableKeyException; | |
import javax.net.ssl.HttpsURLConnection; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.TrustManagerFactory; | |
/** | |
* Author: ZhuWenWu | |
* Version V1.0 | |
* Date: 2014/12/15 16:19. | |
* Description: | |
* Modification History: | |
* Date Author Version Description | |
* ----------------------------------------------------------------------------------- | |
* 2014/12/15 ZhuWenWu 1.0 1.0 | |
* Why & What is modified: | |
*/ | |
public class HttpClientSslHelper { | |
private static final String KEY_STORE_TYPE_BKS = "bks";//证书类型 固定值 | |
private static final String KEY_STORE_TYPE_P12 = "PKCS12";//证书类型 固定值 | |
private static final String KEY_STORE_CLIENT_PATH = "client.p12";//客户端要给服务器端认证的证书 | |
private static final String KEY_STORE_TRUST_PATH = "client.truststore";//客户端验证服务器端的证书库 | |
private static final String KEY_STORE_PASSWORD = "123456";// 客户端证书密码 | |
private static final String KEY_STORE_TRUST_PASSWORD = "123456";//客户端证书库密码 | |
/** | |
* 获取SslSocketFactory | |
* | |
* @param context 上下文 | |
* @param port | |
* @return SSLSocketFactory | |
*/ | |
public static SSLSocketFactory getSslSocketFactory(Context context, int port) { | |
try { | |
// 服务器端需要验证的客户端证书 | |
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12); | |
// 客户端信任的服务器端证书 | |
KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS); | |
InputStream ksIn = context.getResources().getAssets().open(KEY_STORE_CLIENT_PATH); | |
InputStream tsIn = context.getResources().getAssets().open(KEY_STORE_TRUST_PATH); | |
try { | |
keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray()); | |
trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray()); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} finally { | |
try { | |
ksIn.close(); | |
} catch (Exception ignore) { | |
} | |
try { | |
tsIn.close(); | |
} catch (Exception ignore) { | |
} | |
} | |
return new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore); | |
} catch (KeyManagementException | UnrecoverableKeyException | KeyStoreException | FileNotFoundException | NoSuchAlgorithmException | ClientProtocolException e) { | |
e.printStackTrace(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
/** | |
* 获取SSL认证需要的HttpClient | |
* | |
* @param context 上下文 | |
* @param port 端口号 | |
* @return HttpClient | |
*/ | |
public static HttpClient getSslSocketFactoryHttp(Context context, int port) { | |
HttpClient httpsClient = new DefaultHttpClient(); | |
SSLSocketFactory sslSocketFactory = getSslSocketFactory(context, port); | |
if (sslSocketFactory != null) { | |
Scheme sch = new Scheme("https", sslSocketFactory, port); | |
httpsClient.getConnectionManager().getSchemeRegistry().register(sch); | |
} | |
return httpsClient; | |
} | |
/** | |
* 获取SSLContext | |
* | |
* @param context 上下文 | |
* @return SSLContext | |
*/ | |
private static SSLContext getSSLContext(Context context) { | |
try { | |
// 服务器端需要验证的客户端证书 | |
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12); | |
// 客户端信任的服务器端证书 | |
KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS); | |
InputStream ksIn = context.getResources().getAssets().open(KEY_STORE_CLIENT_PATH); | |
InputStream tsIn = context.getResources().getAssets().open(KEY_STORE_TRUST_PATH); | |
try { | |
keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray()); | |
trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray()); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} finally { | |
try { | |
ksIn.close(); | |
} catch (Exception ignore) { | |
} | |
try { | |
tsIn.close(); | |
} catch (Exception ignore) { | |
} | |
} | |
SSLContext sslContext = SSLContext.getInstance("TLS"); | |
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | |
trustManagerFactory.init(trustStore); | |
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509"); | |
keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray()); | |
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); | |
return sslContext; | |
} catch (Exception e) { | |
Log.e("tag", e.getMessage(), e); | |
} | |
return null; | |
} | |
/** | |
* 获取SSL认证需要的HttpClient | |
* | |
* @param context 上下文 | |
* @return OkHttpClient | |
*/ | |
public static OkHttpClient getSSLContextHttp(Context context) { | |
OkHttpClient client = new OkHttpClient(); | |
SSLContext sslContext = getSSLContext(context); | |
if (sslContext != null) { | |
client.setSslSocketFactory(sslContext.getSocketFactory()); | |
} | |
return client; | |
} | |
/** | |
* 获取HttpsURLConnection | |
* | |
* @param context 上下文 | |
* @param url 连接url | |
* @param method 请求方式 | |
* @return HttpsURLConnection | |
*/ | |
public static HttpsURLConnection getHttpsURLConnection(Context context, String url, String method) { | |
URL u; | |
HttpsURLConnection connection = null; | |
try { | |
SSLContext sslContext = getSSLContext(context); | |
if (sslContext != null) { | |
u = new URL(url); | |
connection = (HttpsURLConnection) u.openConnection(); | |
connection.setRequestMethod(method);//"POST" "GET" | |
connection.setDoOutput(true); | |
connection.setDoInput(true); | |
connection.setUseCaches(false); | |
connection.setRequestProperty("Content-Type", "binary/octet-stream"); | |
connection.setSSLSocketFactory(sslContext.getSocketFactory()); | |
connection.setConnectTimeout(30000); | |
} | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return connection; | |
} | |
} |
implements interface X509TrustManager
抽象方法:
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
需要验证客户端证书的时候会回调第一个方法。
需要验证服务端帧数的时候会回调第二个方法。
请问下对于pem证书的接入方式是一样的吗
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
我的需求有些特殊,希望大神指点一下。
我遇到的问题是,客户端如何得知该服务器需要客户端证书认证呢?