Skip to content Skip to sidebar Skip to footer

How To Programmatically Add Certificates To A Truststore And Use That Also For Verifying Server Authentication

I my app I want to use a https connection to a user-specified server which uses a self-signed certificate. What I gathered by now is, that self signed certificates are rejected (a

Solution 1:

Solution was found a while ago but no one has created the Answer yet to help guide others, so I'll be the Point Pimp(ette) this morning and post the URL added as the solution, plus copy in the code from the public source. Hope this helps guide others to the solution. :)


Here's the URL for the code below.

package com.fsck.k9.mail.store;

import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.DomainNameChecker;
import org.apache.commons.io.IOUtils;

import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
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.HashMap;
import java.util.Map;

publicfinalclassTrustManagerFactory {
    privatestaticfinalStringLOG_TAG="TrustManagerFactory";

    privatestatic X509TrustManager defaultTrustManager;
    privatestatic X509TrustManager unsecureTrustManager;
    privatestatic X509TrustManager localTrustManager;

    privatestatic X509Certificate[] lastCertChain = null;

    privatestatic File keyStoreFile;
    privatestatic KeyStore keyStore;


    privatestaticclassSimpleX509TrustManagerimplementsX509TrustManager {
        publicvoidcheckClientTrusted(X509Certificate[] chain, String authType)throws CertificateException {
        }

        publicvoidcheckServerTrusted(X509Certificate[] chain, String authType)throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            returnnull;
        }
    }

    privatestaticclassSecureX509TrustManagerimplementsX509TrustManager {
        privatestaticfinal Map<String, SecureX509TrustManager> mTrustManager =
            newHashMap<String, SecureX509TrustManager>();

        privatefinal String mHost;

        privateSecureX509TrustManager(String host) {
            mHost = host;
        }

        publicsynchronizedstatic X509TrustManager getInstance(String host) {
            SecureX509TrustManager trustManager;
            if (mTrustManager.containsKey(host)) {
                trustManager = mTrustManager.get(host);
            } else {
                trustManager = newSecureX509TrustManager(host);
                mTrustManager.put(host, trustManager);
            }

            return trustManager;
        }

        publicvoidcheckClientTrusted(X509Certificate[] chain, String authType)throws CertificateException {
            defaultTrustManager.checkClientTrusted(chain, authType);
        }

        publicvoidcheckServerTrusted(X509Certificate[] chain, String authType)throws CertificateException {
            // FIXME: Using a static field to store the certificate chain is a bad idea. Instead// create a CertificateException subclass and store the chain there.
            TrustManagerFactory.setLastCertChain(chain);
            try {
                defaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException e) {
                localTrustManager.checkServerTrusted(newX509Certificate[] {chain[0]}, authType);
            }
            if (!DomainNameChecker.match(chain[0], mHost)) {
                try {
                    Stringdn= chain[0].getSubjectDN().toString();
                    if ((dn != null) && (dn.equalsIgnoreCase(keyStore.getCertificateAlias(chain[0])))) {
                        return;
                    }
                } catch (KeyStoreException e) {
                    thrownewCertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
                }
                thrownewCertificateException("Certificate domain name does not match "
                                               + mHost);
            }
        }

        public X509Certificate[] getAcceptedIssuers() {
            return defaultTrustManager.getAcceptedIssuers();
        }

    }

    static {
        java.io.InputStreamfis=null;
        try {
            javax.net.ssl.TrustManagerFactorytmf= javax.net.ssl.TrustManagerFactory.getInstance("X509");
            Applicationapp= K9.app;
            keyStoreFile = newFile(app.getDir("KeyStore", Context.MODE_PRIVATE) + File.separator + "KeyStore.bks");
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            try {
                fis = newjava.io.FileInputStream(keyStoreFile);
            } catch (FileNotFoundException e1) {
                fis = null;
            }
            try {
                keyStore.load(fis, "".toCharArray());
            } catch (IOException e) {
                Log.e(LOG_TAG, "KeyStore IOException while initializing TrustManagerFactory ", e);
                keyStore = null;
            } catch (CertificateException e) {
                Log.e(LOG_TAG, "KeyStore CertificateException while initializing TrustManagerFactory ", e);
                keyStore = null;
            }
            tmf.init(keyStore);
            TrustManager[] tms = tmf.getTrustManagers();
            if (tms != null) {
                for (TrustManager tm : tms) {
                    if (tm instanceof X509TrustManager) {
                        localTrustManager = (X509TrustManager)tm;
                        break;
                    }
                }
            }
            tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
            tmf.init((KeyStore)null);
            tms = tmf.getTrustManagers();
            if (tms != null) {
                for (TrustManager tm : tms) {
                    if (tm instanceof X509TrustManager) {
                        defaultTrustManager = (X509TrustManager) tm;
                        break;
                    }
                }
            }

        } catch (NoSuchAlgorithmException e) {
            Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
        } catch (KeyStoreException e) {
            Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
        } finally {
            IOUtils.closeQuietly(fis);
        }
        unsecureTrustManager = newSimpleX509TrustManager();
    }

    privateTrustManagerFactory() {
    }

    publicstatic X509TrustManager get(String host, boolean secure) {
        return secure ? SecureX509TrustManager.getInstance(host) :
               unsecureTrustManager;
    }

    publicstatic KeyStore getKeyStore() {
        return keyStore;
    }

    publicstaticvoidsetLastCertChain(X509Certificate[] chain) {
        lastCertChain = chain;
    }
    publicstatic X509Certificate[] getLastCertChain() {
        return lastCertChain;
    }

    publicstaticvoidaddCertificateChain(String alias, X509Certificate[] chain)throws CertificateException {
        try {
            javax.net.ssl.TrustManagerFactorytmf= javax.net.ssl.TrustManagerFactory.getInstance("X509");
            for (X509Certificate element : chain) {
                keyStore.setCertificateEntry
                (element.getSubjectDN().toString(), element);
            }

            tmf.init(keyStore);
            TrustManager[] tms = tmf.getTrustManagers();
            if (tms != null) {
                for (TrustManager tm : tms) {
                    if (tm instanceof X509TrustManager) {
                        localTrustManager = (X509TrustManager) tm;
                        break;
                    }
                }
            }
            java.io.OutputStreamkeyStoreStream=null;
            try {
                keyStoreStream = newjava.io.FileOutputStream(keyStoreFile);
                keyStore.store(keyStoreStream, "".toCharArray());
            } catch (FileNotFoundException e) {
                thrownewCertificateException("Unable to write KeyStore: " + e.getMessage());
            } catch (CertificateException e) {
                thrownewCertificateException("Unable to write KeyStore: " + e.getMessage());
            } catch (IOException e) {
                thrownewCertificateException("Unable to write KeyStore: " + e.getMessage());
            } finally {
                IOUtils.closeQuietly(keyStoreStream);
            }

        } catch (NoSuchAlgorithmException e) {
            Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
        } catch (KeyStoreException e) {
            Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
        }
    }
}

Solution 2:

You can use self-signed certificates. To use a self-signed certificate, you can convert it into bouncy castle format keystore which is supported by Android and then store it as a raw resource in your Android app project. How to convert and use it, all details can be found on Bob's blog. Here is the link for the same - http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html. This worked quite well. Hope this helps

Post a Comment for "How To Programmatically Add Certificates To A Truststore And Use That Also For Verifying Server Authentication"