9

我有一个连接到我们托管的 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 证书?

4

2 回答 2

4

通过使用解决:HttpsURLConnection

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

这似乎适用于用户安装的 CA 证书。

于 2013-10-21T10:26:57.837 回答
2

您也可以使用 来完成任务DefaultHttpClient,尽管这里建议

新代码首选 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;
}
于 2014-04-03T14:10:14.443 回答