package com.example.client.ssl; import android.util.Base64; import com.example.ExampleConfig; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; // useful articles about trusting SSL certificates: // http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html // http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https/6378872#6378872 // http://nelenkov.blogspot.cz/2011/12/using-custom-certificate-trust-store-on.html public class SelfSignedTrustManager implements X509TrustManager { private X509TrustManager mDefaultTrustManager = null; private X509TrustManager mLocalTrustManager = null; private X509Certificate[] mAcceptedIssuers; public SelfSignedTrustManager(KeyStore localKeyStore) throws NoSuchAlgorithmException, KeyStoreException { super(); // init factory TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore keyStore = null; trustManagerFactory.init(keyStore); // create default trust manager checking certificates signed with certificate authority TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); if(trustManagers.length == 0) { throw new NoSuchAlgorithmException("No trust manager found."); } mDefaultTrustManager = (X509TrustManager) trustManagers[0]; // create local trust manager checking self signed certificate mLocalTrustManager = new LocalStoreX509TrustManager(localKeyStore); // create accepted issuers List<X509Certificate> allIssuers = new ArrayList<>(); // for(X509Certificate cert:mDefaultTrustManager.getAcceptedIssuers()) // { // // warning, this cycle takes a lot of time, maybe more than 1 sec // allIssuers.add(cert); // } for(X509Certificate cert : mLocalTrustManager.getAcceptedIssuers()) { allIssuers.add(cert); } mAcceptedIssuers = allIssuers.toArray(new X509Certificate[allIssuers.size()]); } @Override public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException { // check client certificate, first self signed, then default try { //Logcat.d("localTrustManager"); mLocalTrustManager.checkClientTrusted(certificates, authType); } catch(CertificateException e) { //Logcat.d("defaultTrustManager"); mDefaultTrustManager.checkClientTrusted(certificates, authType); } } @Override public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException { boolean expectedCertificateFound = false; // manually verify certificate comparing encoded representation of the certificate for(X509Certificate certificate : certificates) { try { String certHash = SHA1Base64Encoded(certificate.getEncoded()); //Logcat.d("certificate public key = " + certificate.getPublicKey().toString().substring(0, 100) + " ..."); //Logcat.d("certificate hash = " + certHash); //Logcat.d("---------------------------------------"); if(certHash.trim().equals(ExampleConfig.SSL_CERTIFICATE_SHA1)) { // manual verification successfull expectedCertificateFound = true; } } catch(Exception e) { // manual verification failed throw new CertificateException("Failed to compare hashes of certificates."); } } if(!expectedCertificateFound) { // if manual verification failed, throw exception throw new CertificateException("Expected certificate not found."); } // if manual verification successfull, check server certificate, first self signed, then default try { //Logcat.d("localTrustManager"); mLocalTrustManager.checkServerTrusted(certificates, authType); } catch(CertificateException e) { //Logcat.d("defaultTrustManager"); mDefaultTrustManager.checkServerTrusted(certificates, authType); } } @Override public X509Certificate[] getAcceptedIssuers() { return mAcceptedIssuers; } private String SHA1Base64Encoded(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md = MessageDigest.getInstance("SHA-1"); md.reset(); md.update(data); byte messageDigest[] = md.digest(); return Base64.encodeToString(messageDigest, Base64.NO_WRAP); } private static class LocalStoreX509TrustManager implements X509TrustManager { private X509TrustManager mTrustManager; public LocalStoreX509TrustManager(KeyStore localTrustStore) { try { TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(localTrustStore); mTrustManager = findX509TrustManager(tmf); if(mTrustManager == null) { throw new IllegalStateException("Couldn't find X509TrustManager."); } } catch(GeneralSecurityException e) { throw new RuntimeException(e); } } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { mTrustManager.checkClientTrusted(chain, authType); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { mTrustManager.checkServerTrusted(chain, authType); } @Override public X509Certificate[] getAcceptedIssuers() { return mTrustManager.getAcceptedIssuers(); } private X509TrustManager findX509TrustManager(TrustManagerFactory tmf) { TrustManager tms[] = tmf.getTrustManagers(); for(int i = 0; i < tms.length; i++) { if(tms[i] instanceof X509TrustManager) { return (X509TrustManager) tms[i]; } } return null; } } }