接受具有自签名证书的HTTPS连接我试图建立HTTPS连接,使用HttpClient但是问题是,由于证书不是由一个公认的证书颁发机构(CA)签署的,维瑞,环球信等等,在android可信证书集上,我一直得到javax.net.ssl.SSLException: Not trusted server certificate.我已经看到了简单地接受所有证书的解决方案,但是如果我想问用户呢?我想要一个类似浏览器的对话框,让用户决定是否继续。最好我想使用与浏览器相同的证书。有什么想法吗?
3 回答
红糖糍粑
TA贡献1815条经验 获得超6个赞
*.crt/res/rawR.raw.*
HTTPClientHttpsURLConnection
package com.example.customssl;import android.content.Context;import org.apache.http.client.HttpClient;import org.apache.http.conn.scheme.
PlainSocketFactory;import org.apache.http.conn.scheme.Scheme;import org.apache.http.conn.scheme.SchemeRegistry;import org.apache.http.conn
.ssl.AllowAllHostnameVerifier;import org.apache.http.conn.ssl.SSLSocketFactory;import org.apache.http.impl.client.DefaultHttpClient;import
org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;import org.apache.http.params.BasicHttpParams;import org.apache.http.params.Ht
tpParams;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManagerFactory;import java.io.IO
Exception;import java.io.InputStream;import java.net.URL;import java.security.KeyStore;import java.security.KeyStoreException;import java.s
ecurity.NoSuchAlgorithmException;import java.security.cert.Certificate;import java.security.cert.CertificateException;import java.security.
cert.CertificateFactory;public class CustomCAHttpsProvider {
/**
* Creates a {@link org.apache.http.client.HttpClient} which is configured to work with a custom authority
* certificate.
*
* @param context Application Context
* @param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* @param allowAllHosts If true then client will not check server against host names of certificate.
* @return Http Client.
* @throws Exception If there is an error initializing the client.
*/
public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// init ssl socket factory with key store
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);
// skip hostname security check if specified
if (allowAllHosts) {
sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
}
// basic http params for client
HttpParams params = new BasicHttpParams();
// normal scheme registry with our ssl socket factory for "https"
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
// create connection manager
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
// create http client
return new DefaultHttpClient(cm, params);
}
/**
* Creates a {@link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
* certificate.
*
* @param urlString remote url string.
* @param context Application Context
* @param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* @param allowAllHosts If true then client will not check server against host names of certificate.
* @return Http url connection.
* @throws Exception If there is an error initializing the connection.
*/
public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Create a connection from url
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
// skip hostname security check if specified
if (allowAllHosts) {
urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
}
return urlConnection;
}
private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException,
NoSuchAlgorithmException, IOException {
// init a default key store
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
// read and add certificate authority
Certificate cert = readCert(context, certRawResId);
keyStore.setCertificateEntry("ca", cert);
return keyStore;
}
private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {
// read certificate resource
InputStream caInput = context.getResources().openRawResource(certResourceId);
Certificate ca;
try {
// generate a certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
return ca;
}}Certificate对象是从 .crt档案。 违约 KeyStore是被创造出来的。 keyStore.setCertificateEntry("ca", cert)将证书添加到别名“ca”下的密钥存储区。您可以修改代码以添加更多证书(中间CA等)。 主要目标是生成一个 SSLSocketFactory然后可以由 HTTPClient或 HttpsURLConnection.SSLSocketFactory可以进一步配置,例如跳过主机名验证等。
- 3 回答
- 0 关注
- 453 浏览
添加回答
举报
0/150
提交
取消
