Skip to content

Instantly share code, notes, and snippets.

@Frank-Zhu
Last active April 18, 2023 08:55
Show Gist options
  • Save Frank-Zhu/41e21a00df26d63cd38d to your computer and use it in GitHub Desktop.
Save Frank-Zhu/41e21a00df26d63cd38d to your computer and use it in GitHub Desktop.
Android HTTPS SSL双向验证
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;
}
}
@Logan676
Copy link

Logan676 commented Aug 6, 2016

我的需求有些特殊,希望大神指点一下。

  1. 客户端可能会连上不同配置的服务器,有的服务器需要客户端证书认证,有的不需要。
  2. 客户端默认不支持客户端证书认证
  3. 当服务器配置了客户端证书认证之后,客户端才创建相应的SSLSocketFactory发起请求

我遇到的问题是,客户端如何得知该服务器需要客户端证书认证呢?

@al-liu
Copy link

al-liu commented Dec 8, 2016

implements interface X509TrustManager
抽象方法:
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
需要验证客户端证书的时候会回调第一个方法。
需要验证服务端帧数的时候会回调第二个方法。

@yinweichao
Copy link

请问下对于pem证书的接入方式是一样的吗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment