接受具有自签名证书的HTTPS连接我试图建立HTTPS连接,使用HttpClient但是问题是,由于证书不是由一个公认的证书颁发机构(CA)签署的,维瑞,环球信等等,在android可信证书集上,我一直得到javax.net.ssl.SSLException: Not trusted server certificate.我已经看到了简单地接受所有证书的解决方案,但是如果我想问用户呢?我想要一个类似浏览器的对话框,让用户决定是否继续。最好我想使用与浏览器相同的证书。有什么想法吗?
3 回答
红糖糍粑
TA贡献1815条经验 获得超6个赞
*.crt
/res/raw
R.raw.*
HTTPClient
HttpsURLConnection
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 关注
- 397 浏览
添加回答
举报
0/150
提交
取消