package org.thoughtcrime.ssl.pinning; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertPath; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.PKIXCertPathValidatorResult; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import android.os.Build; import android.util.Log; public class SystemKeyStore { private static final String TAG = "SystemKeyStore"; private final PKIXParameters parameters; private final CertPathValidator validator; private final CertificateFactory certificateFactory; public SystemKeyStore() throws CertificateException { try { parameters = this.getPkixParameters(); certificateFactory = CertificateFactory.getInstance("X509"); validator = CertPathValidator.getInstance("PKIX"); } catch (final NoSuchAlgorithmException nsae) { throw new CertificateException(nsae); } } public X509Certificate getTrustRoot(final X509Certificate[] chain) throws CertificateException { try { final CertPath certPath = certificateFactory .generateCertPath(Arrays.asList(chain)); final PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) validator .validate(certPath, parameters); if (result == null) { return null; } else { return result.getTrustAnchor().getTrustedCert(); } } catch (final CertPathValidatorException e) { return null; } catch (final InvalidAlgorithmParameterException e) { throw new CertificateException(e); } } private PKIXParameters getPkixParameters() { try { final KeyStore trustStore = this.getTrustStore(); final Set<TrustAnchor> trusted = new HashSet<TrustAnchor>(); for (final Enumeration<String> aliases = trustStore.aliases(); aliases .hasMoreElements();) { final String alias = aliases.nextElement(); final X509Certificate cert = (X509Certificate) trustStore .getCertificate(alias); if (cert != null) { trusted.add(new TrustAnchor(cert, null)); } } final PKIXParameters parameters = new PKIXParameters(trusted); parameters.setRevocationEnabled(false); return parameters; } catch (final InvalidAlgorithmParameterException e) { throw new AssertionError(e); } catch (final KeyStoreException e) { throw new AssertionError(e); } } protected KeyStore getTrustStore() { try { KeyStore trustStore; Log.d(TAG, "Beginning keystore load"); if (Build.VERSION.SDK_INT >= 14) { trustStore = KeyStore.getInstance("AndroidCAStore"); trustStore.load(null, null); } else { trustStore = KeyStore.getInstance("BKS"); trustStore.load(new BufferedInputStream(new FileInputStream( getTrustStorePath())), getTrustStorePassword() .toCharArray()); } Log.d(TAG, "Loaded keystore"); return trustStore; } catch (final NoSuchAlgorithmException nsae) { throw new AssertionError(nsae); } catch (final KeyStoreException e) { throw new AssertionError(e); } catch (final CertificateException e) { throw new AssertionError(e); } catch (final FileNotFoundException e) { throw new AssertionError(e); } catch (final IOException e) { throw new AssertionError(e); } } protected String getTrustStorePath() { String path = System.getProperty("javax.net.ssl.trustStore"); if (path == null) { path = System.getProperty("java.home") + File.separator + "etc" + File.separator + "security" + File.separator + "cacerts.bks"; } return path; } protected String getTrustStorePassword() { String password = System .getProperty("javax.net.ssl.trustStorePassword"); if (password == null) { password = "changeit"; } return password; } }