Reputation: 1203
My app needs to connect to my own server, so I added my server's self signed certificate to the KeyStore. It works very well with my server but the issue is that now my app won't accept all other certificates! For example if I try to connect to https://maps.googleapis.com/ I get a missing certificate exception. How could I fix this?
Here is how I trust my certificate:
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");
}
and here is the exception I get when trying to connect to google:
06-29 23:27:59.181: E/AdapterClass(16358): javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Upvotes: 2
Views: 1491
Reputation: 2769
You need to create your custom TrustManager
which have local (from your KeyStore
) TrustManager
, and default TrustManager
. When one of them cannot find certificate, the other one should work.
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);
}
}
//...
}
Source: http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
@edit
Or as @CommonsWare suggested, you can use his CWAC-Security library. It look awesome, but I haven't used it yet.
Upvotes: 1
Reputation: 8938
Instead of trying to do this programatically, just use keytool to add the certificate to your existing cacerts trust store file.
Upvotes: 0