我有一个连接到我们托管的SSL Web服务的Android应用程序。 Web服务器是apache,它有我们自己创建的CA和自签名SSL证书。
我已将我们的CA证书导入Android平板电脑的安全用户可信证书部分。
我已经测试了对Web服务器的访问权限,并且可以确认Web服务证书显示为有效(下面的屏幕截图)
以下是安全设置中的证书:
现在,当我尝试访问应用程序中的Web服务时,我会触发“无对等证书”异常。
这是简化的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证书?
答案 0 :(得分:4)
使用:HttpsURLConnection
解决URLConnection conn = null;
URL url = new URL(strURL);
conn = url.openConnection();
HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
这似乎适用于用户安装的CA证书。
答案 1 :(得分:2)
您也可以使用DefaultHttpClient
完成任务,即使here is suggested为:
首选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;
}