Trusted CA certificates are loaded and cached by a static singleton
authorTobias Brunner <tobias@strongswan.org>
Wed, 18 Jul 2012 11:40:29 +0000 (13:40 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 13 Aug 2012 09:00:24 +0000 (11:00 +0200)
src/frontends/android/src/org/strongswan/android/logic/TrustedCertificateManager.java [new file with mode: 0644]

diff --git a/src/frontends/android/src/org/strongswan/android/logic/TrustedCertificateManager.java b/src/frontends/android/src/org/strongswan/android/logic/TrustedCertificateManager.java
new file mode 100644 (file)
index 0000000..04a292a
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+package org.strongswan.android.logic;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import android.util.Log;
+
+public class TrustedCertificateManager
+{
+       private static final String TAG = TrustedCertificateManager.class.getSimpleName();
+       private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
+       private Hashtable<String, X509Certificate> mCACerts = new Hashtable<String, X509Certificate>();
+       private boolean mLoaded;
+
+       /**
+        * Private constructor to prevent instantiation from other classes.
+        */
+       private TrustedCertificateManager()
+       {
+       }
+
+       /**
+        * This is not instantiated until the first call to getInstance()
+        */
+       private static class Singleton {
+               public static final TrustedCertificateManager mInstance = new TrustedCertificateManager();
+       }
+
+       /**
+        * Get the single instance of the CA certificate manager.
+        * @return CA certificate manager
+        */
+       public static TrustedCertificateManager getInstance()
+       {
+               return Singleton.mInstance;
+       }
+
+       /**
+        * Forces a load/reload of the cached CA certificates.
+        * As this takes a while it should be called asynchronously.
+        * @return reference to itself
+        */
+       public TrustedCertificateManager reload()
+       {
+               Log.d(TAG, "Force reload of cached CA certificates");
+               this.mLock.writeLock().lock();
+               loadCertificates();
+               this.mLock.writeLock().unlock();
+               return this;
+       }
+
+       /**
+        * Ensures that the certificates are loaded but does not force a reload.
+        * As this takes a while if the certificates are not loaded yet it should
+        * be called asynchronously.
+        * @return reference to itself
+        */
+       public TrustedCertificateManager load()
+       {
+               Log.d(TAG, "Ensure cached CA certificates are loaded");
+               this.mLock.writeLock().lock();
+               if (!this.mLoaded)
+               {
+                       loadCertificates();
+               }
+               this.mLock.writeLock().unlock();
+               return this;
+       }
+
+       /**
+        * Opens the CA certificate KeyStore and loads the cached certificates.
+        * The lock must be locked when calling this method.
+        */
+       private void loadCertificates()
+       {
+               Log.d(TAG, "Load cached CA certificates");
+               try
+               {
+                       KeyStore store = KeyStore.getInstance("AndroidCAStore");
+                       store.load(null, null);
+                       this.mCACerts = fetchCertificates(store);
+                       this.mLoaded = true;
+                       Log.d(TAG, "Cached CA certificates loaded");
+               }
+               catch (Exception ex)
+               {
+                       ex.printStackTrace();
+                       this.mCACerts = new Hashtable<String, X509Certificate>();
+               }
+       }
+
+       /**
+        * Load all X.509 certificates from the given KeyStore.
+        * @param store KeyStore to load certificates from
+        * @return Hashtable mapping aliases to certificates
+        */
+       private Hashtable<String, X509Certificate> fetchCertificates(KeyStore store)
+       {
+               Hashtable<String, X509Certificate> certs = new Hashtable<String, X509Certificate>();
+               try
+               {
+                       Enumeration<String> aliases = store.aliases();
+                       while (aliases.hasMoreElements())
+                       {
+                               String alias = aliases.nextElement();
+                               Certificate cert;
+                               cert = store.getCertificate(alias);
+                               if (cert != null && cert instanceof X509Certificate)
+                               {
+                                       certs.put(alias, (X509Certificate)cert);
+                               }
+                       }
+               }
+               catch (KeyStoreException ex)
+               {
+                       ex.printStackTrace();
+               }
+               return certs;
+       }
+
+       /**
+        * Retrieve the CA certificate with the given alias.
+        * @param alias alias of the certificate to get
+        * @return the certificate, null if not found
+        */
+       public X509Certificate getCACertificateFromAlias(String alias)
+       {
+               this.mLock.readLock().lock();
+               X509Certificate certificate = this.mCACerts.get(alias);
+               this.mLock.readLock().unlock();
+               return certificate;
+       }
+
+       /**
+        * Get all CA certificates (from the system and user keystore).
+        * @return Hashtable mapping aliases to certificates
+        */
+       @SuppressWarnings("unchecked")
+       public Hashtable<String, X509Certificate> getAllCACertificates()
+       {
+               Hashtable<String, X509Certificate> certs;
+               this.mLock.readLock().lock();
+               certs = (Hashtable<String, X509Certificate>)this.mCACerts.clone();
+               this.mLock.readLock().unlock();
+               return certs;
+       }
+
+       /**
+        * Get only the CA certificates installed by the user.
+        * @return Hashtable mapping aliases to certificates
+        */
+       public Hashtable<String, X509Certificate> getUserCACertificates()
+       {
+               Hashtable<String, X509Certificate> certs = new Hashtable<String, X509Certificate>();
+               this.mLock.readLock().lock();
+               for (String alias : this.mCACerts.keySet())
+               {
+                       if (alias.startsWith("user:"))
+                       {
+                               certs.put(alias, this.mCACerts.get(alias));
+                       }
+               }
+               this.mLock.readLock().unlock();
+               return certs;
+       }
+}