2014-06-29 32 views
2

我的应用程序需要连接到我自己的服务器,所以我将我的服务器的自签名证书添加到KeyStore。它适用于我的服务器,但问题是,现在我的应用程序不会接受所有其他证书!例如,如果我尝试连接到https://maps.googleapis.com/,我会得到一个丢失的证书异常。我怎么能解决这个问题?信任自签名证书时的Android应用程序SSL问题

这里是我信任我的证书:

public static void setSelfSignedCertSSLContext(AssetManager assets) 
     throws Exception { 
    // Load self-signed cert from an InputStream 
    CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
    InputStream caInput = assets.open("selfSigned.cer"); 
    Certificate ca; 
    try { 
     ca = cf.generateCertificate(caInput); 
     Log.d(LOG_TAG, "ca=" + ((X509Certificate) ca).getSubjectDN()); 
    } finally { 
     caInput.close(); 
    } 

    // Create a KeyStore containing our trusted CAs 
    String keyStoreType = KeyStore.getDefaultType(); 
    KeyStore keyStore = KeyStore.getInstance(keyStoreType); 
    keyStore.load(null, null); 
    keyStore.setCertificateEntry("ca", ca); 

    // Create a TrustManager that trusts the CAs in our KeyStore 
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); 
    tmf.init(keyStore); 

    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory 
      .getDefaultAlgorithm()); 
    kmf.init(keyStore, "changeit".toCharArray()); 

    // Create an SSLContext that uses our TrustManager 
    SSLContext context = SSLContext.getInstance("TLS"); 
    SSLContext.setDefault(context); 

    context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 
    HttpsURLConnection.setDefaultSSLSocketFactory(context 
      .getSocketFactory()); 

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 
     public boolean verify(String string, SSLSession ssls) { 
      return true; 
     } 
    }); 

    Log.d(LOG_TAG, "SSLContext set successfully"); 
} 

,这里是异常试图连接到谷歌时,我得到:

06-29 23:27:59.181: E/AdapterClass(16358): javax.net.ssl.SSLHandshakeException: 
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. 
+0

重复的https://stackoverflow.com/questions/24429485/loading-self-signed-cert-to-httpsurlconnection-breaks-default-ca-cert-validation/24430187 – CommonsWare

回答

1

您需要创建自定义TrustManager,其中包含本地(从您的KeyStoreTrustManager和默认TrustManager。当其中一人找不到证书时,另一人应该工作。

ex。

public class MyTrustManager implements X509TrustManager { 

    private X509TrustManager defaultTrustManager; 
    private X509TrustManager localTrustManager; 

    private X509Certificate[] acceptedIssuers; 

    public MyTrustManager(KeyStore localKeyStore) { 
     // init defaultTrustManager using the system defaults 
     // init localTrustManager using localKeyStore 
    } 

    public void checkServerTrusted(X509Certificate[] chain, String authType) 
      throws CertificateException { 
     try { 
      defaultTrustManager.checkServerTrusted(chain, authType); 
     } catch (CertificateException ce) { 
      localTrustManager.checkServerTrusted(chain, authType); 
     } 
    } 

    //... 
} 

来源:http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html

@edit

或者作为@CommonsWare建议,你可以用他的CWAC-安全库。它看起来很棒,但我还没有使用它。

+0

感谢这工作完美! – splinter123

0

而不是试图以编程方式做到这一点,只需使用keytool将证书添加到您现有的cacerts信任存储文件。

+0

'KeyChain' API仅适用于设备与Android 4.0及以上。 – Than

+0

您不需要钥匙串API即可使用标准Java cacerts文件。 –

+0

哦,不知道为什么我认为你写了keychain而不是keytool。 – Than