使用自签名证书和CA的Android SSL HTTP请求

我有一个连接到我们托pipe的SSL Web服务的Android应用程序。 Web服务器是apache,拥有自己创build的CA和一个自签名的SSL证书。

我已将我们的CA证书导入安全性的“用户可信证书”部分中的Android平板电脑上。

我testing了对Web服务器的访问,并且可以确认Web服务证书显示为有效(下面的截图)

有效的证书

这是安全设置中的证书:

可信证书

现在,当我尝试访问我的应用程序中的Web服务时,就会触发“无对等证书”exception。

这是简化的SSL实现:

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // allows network on main thread (temp hack) StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); SchemeRegistry schemeRegistry = new SchemeRegistry(); //schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); schemeRegistry.register(new Scheme("https", newSSLSocketFactory(), 443)); HttpParams params = new BasicHttpParams(); SingleClientConnManager mgr = new SingleClientConnManager(params, schemeRegistry); HttpClient client = new DefaultHttpClient(mgr, params); HttpPost httpRequest = new HttpPost("https://our-web-service.com"); try { client.execute(httpRequest); } catch (Exception e) { e.printStackTrace(); // } } /* * Standard SSL CA Store Setup // */ private SSLSocketFactory newSSLSocketFactory() { KeyStore trusted; try { trusted = KeyStore.getInstance("AndroidCAStore"); trusted.load(null, null); Enumeration<String> aliases = trusted.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); X509Certificate cert = (X509Certificate) trusted.getCertificate(alias); Log.d("", "Alias="+alias); Log.d("", "Subject DN: " + cert.getSubjectDN().getName()); Log.d("", "Issuer DN: " + cert.getIssuerDN().getName()); } SSLSocketFactory sf = new SSLSocketFactory(trusted); sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); return sf; } catch (Exception e) { // TODO Auto-generated catch block throw new AssertionError(e); } } } 

while循环只是吐出证书,我可以在日志中看到我自己的CA. 但是我仍然得到“无同行证书”例外。

10-17 18:29:01.234:I / System.out(4006):没有对等证书

在这个实现中,我是否需要手动加载我的CA证书?

Solutions Collecting From Web of "使用自签名证书和CA的Android SSL HTTP请求"

通过使用:HttpsURLConnection解决

 URLConnection conn = null; URL url = new URL(strURL); conn = url.openConnection(); HttpsURLConnection httpsConn = (HttpsURLConnection) conn; 

这似乎与用户安装的CA证书正常工作。

您也可以使用DefaultHttpClient完成任务,即使这里build议 :

希望HttpURLConnection用于新的代码

在导入或添加证书到您的应用程序中也要注意,因为您可能在更新证书过期时遇到问题。

这里如何获得一个信任自签名证书的DefaultHttpClient

  * This method returns the appropriate HttpClient. * @param isTLS Whether Transport Layer Security is required. * @param trustStoreInputStream The InputStream generated from the BKS keystore. * @param trustStorePsw The password related to the keystore. * @return The DefaultHttpClient object used to invoke execute(request) method. private DefaultHttpClient getHttpClient(boolean isTLS, InputStream trustStoreInputStream, String trustStorePsw) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, UnrecoverableKeyException { DefaultHttpClient client = null; SchemeRegistry schemeRegistry = new SchemeRegistry(); Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 8080); schemeRegistry.register(http); if(isTLS) { KeyStore trustKeyStore = null; char[] trustStorePswCharArray = null; if(trustStorePsw!=null) { trustStorePswCharArray = trustStorePsw.toCharArray(); } trustKeyStore = KeyStore.getInstance("BKS"); trustKeyStore.load(trustStoreInputStream, trustStorePswCharArray); SSLSocketFactory sslSocketFactory = null; sslSocketFactory = new SSLSocketFactory(trustKeyStore); Scheme https = new Scheme("https", sslSocketFactory, 8443); schemeRegistry.register(https); } HttpParams httpParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParams, CONNECTION_TIMEOUT); HttpConnectionParams.setSoTimeout(httpParams, SOCKET_TIMEOUT); ClientConnectionManager clientConnectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry); client = new DefaultHttpClient(clientConnectionManager, httpParams); return client; } 

在这里如何获得一个HttpsURLConnection

  * This method set the certificate for the HttpsURLConnection * @param url The url to contact. * @param certificateInputStream The InputStream generated from the .crt certificate. * @param certAlias The alias for the certificate. * @return The returned HttpsURLConnection private HttpsURLConnection getHttpsURLConnection(URL url, InputStream certificateInputStream, String certAlias) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException { HttpsURLConnection connection = null; CertificateFactory certFactory = null; Certificate cert = null; KeyStore keyStore = null; TrustManagerFactory tmFactory = null; SSLContext sslContext = null; // Load certificates from an InputStream certFactory = CertificateFactory.getInstance("X.509"); cert = certFactory.generateCertificate(certificateInputStream); certificateInputStream.close(); // Create a KeyStore containing the trusted certificates keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry(certAlias, cert); // Create a TrustManager that trusts the certificates in our KeyStore tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmFactory.init(keyStore); // Create an SSLContext that uses our TrustManager sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmFactory.getTrustManagers(), null); connection = (HttpsURLConnection)url.openConnection(); connection.setSSLSocketFactory(sslContext.getSocketFactory()); return connection; }