-
-
Save HughJeffner/6eac419b18c6001aeadb to your computer and use it in GitHub Desktop.
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Iterables; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.cert.CertificateException; | |
import java.security.cert.X509Certificate; | |
import java.util.Arrays; | |
import java.util.List; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.TrustManager; | |
import javax.net.ssl.TrustManagerFactory; | |
import javax.net.ssl.X509TrustManager; | |
/** | |
* Represents an ordered list of {@link X509TrustManager}s with additive trust. If any one of the composed managers | |
* trusts a certificate chain, then it is trusted by the composite manager. | |
* | |
* This is necessary because of the fine-print on {@link SSLContext#init}: Only the first instance of a particular key | |
* and/or trust manager implementation type in the array is used. (For example, only the first | |
* javax.net.ssl.X509KeyManager in the array will be used.) | |
* | |
* @author codyaray | |
* @since 4/22/2013 | |
* @see <a href="http://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm"> | |
* http://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm | |
* </a> | |
*/ | |
@SuppressWarnings("unused") | |
public class CompositeX509TrustManager implements X509TrustManager { | |
private final List<X509TrustManager> trustManagers; | |
public CompositeX509TrustManager(List<X509TrustManager> trustManagers) { | |
this.trustManagers = ImmutableList.copyOf(trustManagers); | |
} | |
public CompositeX509TrustManager(KeyStore keystore) { | |
this.trustManagers = ImmutableList.of(getDefaultTrustManager(), getTrustManager(keystore)); | |
} | |
@Override | |
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |
for (X509TrustManager trustManager : trustManagers) { | |
try { | |
trustManager.checkClientTrusted(chain, authType); | |
return; // someone trusts them. success! | |
} catch (CertificateException e) { | |
// maybe someone else will trust them | |
} | |
} | |
throw new CertificateException("None of the TrustManagers trust this certificate chain"); | |
} | |
@Override | |
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |
for (X509TrustManager trustManager : trustManagers) { | |
try { | |
trustManager.checkServerTrusted(chain, authType); | |
return; // someone trusts them. success! | |
} catch (CertificateException e) { | |
// maybe someone else will trust them | |
} | |
} | |
throw new CertificateException("None of the TrustManagers trust this certificate chain"); | |
} | |
@Override | |
public X509Certificate[] getAcceptedIssuers() { | |
ImmutableList.Builder<X509Certificate> certificates = ImmutableList.builder(); | |
for (X509TrustManager trustManager : trustManagers) { | |
for (X509Certificate cert : trustManager.getAcceptedIssuers()) { | |
certificates.add(cert); | |
} | |
} | |
return Iterables.toArray(certificates.build(), X509Certificate.class); | |
} | |
public static TrustManager[] getTrustManagers(KeyStore keyStore) { | |
return new TrustManager[] { new CompositeX509TrustManager(keyStore) }; | |
} | |
public static X509TrustManager getDefaultTrustManager() { | |
return getTrustManager(null); | |
} | |
public static X509TrustManager getTrustManager(KeyStore keystore) { | |
return getTrustManager(TrustManagerFactory.getDefaultAlgorithm(), keystore); | |
} | |
public static X509TrustManager getTrustManager(String algorithm, KeyStore keystore) { | |
TrustManagerFactory factory; | |
try { | |
factory = TrustManagerFactory.getInstance(algorithm); | |
factory.init(keystore); | |
return Iterables.getFirst(Iterables.filter( | |
Arrays.asList(factory.getTrustManagers()), X509TrustManager.class), null); | |
} catch (NoSuchAlgorithmException | KeyStoreException e) { | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
} |
try { | |
KeyStore keystore; // Get your own keystore here | |
SSLContext sslContext = SSLContext.getInstance("TLS"); | |
TrustManager[] tm = CompositeX509TrustManager.getTrustManagers(keystore); | |
sslContext.init(null, tm, null); | |
} catch (NoSuchAlgorithmException | KeyManagementException e) { | |
e.printStackTrace(); | |
} |
Thank you for sharing HughJeffner! After founding this gist I checked with the original author and discovered the snippet for CompositeX509KeyManager. I included these two classes within my library named GitHub - SSLContext-Kickstart. I thought it would be maybe handy to share it here
Hey, I tried executing this I found out an issue that we are adding an custom keystore1, but when we add another custom keystore2, the previous one gets deleted. Can you help?
What I think you should do is transform the custom keystore into a trustmanager and do that also to the other one. Add those multiple trustmanager into a list and supply it to the constructor of this CompositeTrustManager
I think the solution is pretty straight forward. The CompositeTrustManager is using an immutable list, but if you change that to an arraylist you will be able to adjust it during runtime.
So if you add the following snippet it should probably do the trick:
public void addTrustStore(KeyStore trustStore) {
X509TrustManager trustManager = getTrustManager(trustStore);
this.trustManagers.add(trustManager);
}
java.lang.IllegalStateException: Unable to extract the trust manager on AndroidPlatform, sslSocketFactory is class com.google.android.gms.org.conscrypt.OpenSSLSocketFactoryImpl
at okhttp3.OkHttpClient$Builder.sslSocketFactory(OkHttpClient.kt:751)
Thank you so much. This solved my problem!!!
Hey, thanks man. This helped a lot! :)