2 * Copyright (C) 2012-2015 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * HSR Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 package org
.strongswan
.android
.logic
;
20 import android
.util
.Log
;
22 import java
.security
.KeyStore
;
23 import java
.security
.KeyStoreException
;
24 import java
.security
.cert
.Certificate
;
25 import java
.security
.cert
.X509Certificate
;
26 import java
.util
.ArrayList
;
27 import java
.util
.Enumeration
;
28 import java
.util
.Hashtable
;
29 import java
.util
.Observable
;
30 import java
.util
.concurrent
.locks
.ReentrantReadWriteLock
;
32 public class TrustedCertificateManager
extends Observable
34 private static final String TAG
= TrustedCertificateManager
.class.getSimpleName();
35 private final ReentrantReadWriteLock mLock
= new ReentrantReadWriteLock();
36 private Hashtable
<String
, X509Certificate
> mCACerts
= new Hashtable
<String
, X509Certificate
>();
37 private volatile boolean mReload
;
38 private boolean mLoaded
;
39 private final ArrayList
<KeyStore
> mKeyStores
= new ArrayList
<KeyStore
>();
41 public enum TrustedCertificateSource
47 private final String mPrefix
;
49 private TrustedCertificateSource(String prefix
)
54 private String
getPrefix()
61 * Private constructor to prevent instantiation from other classes.
63 private TrustedCertificateManager()
65 for (String name
: new String
[]{"LocalCertificateStore", "AndroidCAStore"})
70 store
= KeyStore
.getInstance(name
);
71 store
.load(null, null);
72 mKeyStores
.add(store
);
76 Log
.e(TAG
, "Unable to load KeyStore: " + name
);
83 * This is not instantiated until the first call to getInstance()
85 private static class Singleton
87 public static final TrustedCertificateManager mInstance
= new TrustedCertificateManager();
91 * Get the single instance of the CA certificate manager.
93 * @return CA certificate manager
95 public static TrustedCertificateManager
getInstance()
97 return Singleton
.mInstance
;
101 * Invalidates the current load state so that the next call to load()
102 * will force a reload of the cached CA certificates.
104 * Observers are notified when this method is called.
106 * @return reference to itself
108 public TrustedCertificateManager
reset()
110 Log
.d(TAG
, "Force reload of cached CA certificates on next load");
113 this.notifyObservers();
118 * Ensures that the certificates are loaded but does not force a reload.
119 * As this takes a while if the certificates are not loaded yet it should
120 * be called asynchronously.
122 * Observers are only notified when the certificates are initially loaded, not when reloaded.
124 * @return reference to itself
126 public TrustedCertificateManager
load()
128 Log
.d(TAG
, "Ensure cached CA certificates are loaded");
129 this.mLock
.writeLock().lock();
130 if (!this.mLoaded
|| this.mReload
)
132 this.mReload
= false;
135 this.mLock
.writeLock().unlock();
140 * Opens the CA certificate KeyStore and loads the cached certificates.
141 * The lock must be locked when calling this method.
143 private void loadCertificates()
145 Log
.d(TAG
, "Load cached CA certificates");
146 Hashtable
<String
, X509Certificate
> certs
= new Hashtable
<String
, X509Certificate
>();
147 for (KeyStore store
: this.mKeyStores
)
149 fetchCertificates(certs
, store
);
151 this.mCACerts
= certs
;
155 this.notifyObservers();
158 Log
.d(TAG
, "Cached CA certificates loaded");
162 * Load all X.509 certificates from the given KeyStore.
164 * @param certs Hashtable to store certificates in
165 * @param store KeyStore to load certificates from
167 private void fetchCertificates(Hashtable
<String
, X509Certificate
> certs
, KeyStore store
)
171 Enumeration
<String
> aliases
= store
.aliases();
172 while (aliases
.hasMoreElements())
174 String alias
= aliases
.nextElement();
176 cert
= store
.getCertificate(alias
);
177 if (cert
!= null && cert
instanceof X509Certificate
)
179 certs
.put(alias
, (X509Certificate
)cert
);
183 catch (KeyStoreException ex
)
185 ex
.printStackTrace();
190 * Retrieve the CA certificate with the given alias.
192 * @param alias alias of the certificate to get
193 * @return the certificate, null if not found
195 public X509Certificate
getCACertificateFromAlias(String alias
)
197 X509Certificate certificate
= null;
199 if (this.mLock
.readLock().tryLock())
201 certificate
= this.mCACerts
.get(alias
);
202 this.mLock
.readLock().unlock();
205 { /* if we cannot get the lock load it directly from the KeyStore,
206 * should be fast for a single certificate */
207 for (KeyStore store
: this.mKeyStores
)
211 Certificate cert
= store
.getCertificate(alias
);
212 if (cert
!= null && cert
instanceof X509Certificate
)
214 certificate
= (X509Certificate
)cert
;
218 catch (KeyStoreException e
)
228 * Get all CA certificates (from all keystores).
230 * @return Hashtable mapping aliases to certificates
232 @SuppressWarnings("unchecked")
233 public Hashtable
<String
, X509Certificate
> getAllCACertificates()
235 Hashtable
<String
, X509Certificate
> certs
;
236 this.mLock
.readLock().lock();
237 certs
= (Hashtable
<String
, X509Certificate
>)this.mCACerts
.clone();
238 this.mLock
.readLock().unlock();
243 * Get all certificates from the given source.
245 * @param source type to filter certificates
246 * @return Hashtable mapping aliases to certificates
248 public Hashtable
<String
, X509Certificate
> getCACertificates(TrustedCertificateSource source
)
250 Hashtable
<String
, X509Certificate
> certs
= new Hashtable
<String
, X509Certificate
>();
251 this.mLock
.readLock().lock();
252 for (String alias
: this.mCACerts
.keySet())
254 if (alias
.startsWith(source
.getPrefix()))
256 certs
.put(alias
, this.mCACerts
.get(alias
));
259 this.mLock
.readLock().unlock();