2008-11-01 17:32:06 -04:00
|
|
|
|
2009-12-14 21:50:53 -05:00
|
|
|
package com.fsck.k9.mail.store;
|
2008-11-01 17:32:06 -04:00
|
|
|
|
2008-12-02 19:04:24 -05:00
|
|
|
import android.app.Application;
|
|
|
|
import android.content.Context;
|
2009-12-09 22:16:42 -05:00
|
|
|
import android.util.Log;
|
2009-12-14 21:50:53 -05:00
|
|
|
import com.fsck.k9.K9;
|
2010-05-19 15:16:36 -04:00
|
|
|
import com.fsck.k9.helper.DomainNameChecker;
|
2011-10-31 23:51:02 -04:00
|
|
|
import org.apache.commons.io.IOUtils;
|
2008-11-01 17:32:06 -04:00
|
|
|
|
2009-12-09 22:16:42 -05:00
|
|
|
import javax.net.ssl.TrustManager;
|
|
|
|
import javax.net.ssl.X509TrustManager;
|
2008-12-02 19:04:24 -05:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.IOException;
|
2008-11-01 17:32:06 -04:00
|
|
|
import java.security.KeyStore;
|
|
|
|
import java.security.KeyStoreException;
|
2009-12-09 22:16:42 -05:00
|
|
|
import java.security.NoSuchAlgorithmException;
|
2008-11-01 17:32:06 -04:00
|
|
|
import java.security.cert.CertificateException;
|
2009-12-09 22:16:42 -05:00
|
|
|
import java.security.cert.X509Certificate;
|
2010-07-27 14:59:41 -04:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
2008-12-02 19:04:24 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public final class TrustManagerFactory {
|
2008-11-01 17:32:06 -04:00
|
|
|
private static final String LOG_TAG = "TrustManagerFactory";
|
|
|
|
|
2008-12-02 19:04:24 -05:00
|
|
|
private static X509TrustManager defaultTrustManager;
|
|
|
|
private static X509TrustManager unsecureTrustManager;
|
2009-11-24 19:40:29 -05:00
|
|
|
private static X509TrustManager localTrustManager;
|
|
|
|
|
2008-12-02 19:04:24 -05:00
|
|
|
private static X509Certificate[] lastCertChain = null;
|
2009-11-24 19:40:29 -05:00
|
|
|
|
2008-12-02 19:04:24 -05:00
|
|
|
private static File keyStoreFile;
|
|
|
|
private static KeyStore keyStore;
|
|
|
|
|
2008-11-01 17:32:06 -04:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private static class SimpleX509TrustManager implements X509TrustManager {
|
2008-11-01 17:32:06 -04:00
|
|
|
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
2011-02-06 17:09:48 -05:00
|
|
|
throws CertificateException {
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
2011-02-06 17:09:48 -05:00
|
|
|
throws CertificateException {
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public X509Certificate[] getAcceptedIssuers() {
|
2008-11-01 17:32:06 -04:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private static class SecureX509TrustManager implements X509TrustManager {
|
2010-07-27 14:59:41 -04:00
|
|
|
private static final Map<String, SecureX509TrustManager> mTrustManager =
|
|
|
|
new HashMap<String, SecureX509TrustManager>();
|
2008-11-01 17:32:06 -04:00
|
|
|
|
2010-07-27 14:59:41 -04:00
|
|
|
private final String mHost;
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private SecureX509TrustManager(String host) {
|
2010-07-27 14:59:41 -04:00
|
|
|
mHost = host;
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public synchronized static X509TrustManager getInstance(String host) {
|
2010-07-27 14:59:41 -04:00
|
|
|
SecureX509TrustManager trustManager;
|
2011-02-06 17:09:48 -05:00
|
|
|
if (mTrustManager.containsKey(host)) {
|
2010-07-27 14:59:41 -04:00
|
|
|
trustManager = mTrustManager.get(host);
|
2011-02-06 17:09:48 -05:00
|
|
|
} else {
|
2010-07-27 14:59:41 -04:00
|
|
|
trustManager = new SecureX509TrustManager(host);
|
|
|
|
mTrustManager.put(host, trustManager);
|
2009-11-24 19:40:29 -05:00
|
|
|
}
|
2010-07-27 14:59:41 -04:00
|
|
|
|
|
|
|
return trustManager;
|
2009-11-24 19:40:29 -05:00
|
|
|
}
|
2008-12-02 19:04:24 -05:00
|
|
|
|
2008-11-01 17:32:06 -04:00
|
|
|
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
2011-02-06 17:09:48 -05:00
|
|
|
throws CertificateException {
|
2008-12-02 19:04:24 -05:00
|
|
|
defaultTrustManager.checkClientTrusted(chain, authType);
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
2011-02-06 17:09:48 -05:00
|
|
|
throws CertificateException {
|
2011-10-27 22:59:08 -04:00
|
|
|
// FIXME: Using a static field to store the certificate chain is a bad idea. Instead
|
|
|
|
// create a CertificateException subclass and store the chain there.
|
2009-11-24 19:40:29 -05:00
|
|
|
TrustManagerFactory.setLastCertChain(chain);
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
2009-11-24 19:40:29 -05:00
|
|
|
defaultTrustManager.checkServerTrusted(chain, authType);
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (CertificateException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
localTrustManager.checkServerTrusted(new X509Certificate[] {chain[0]}, authType);
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
if (!DomainNameChecker.match(chain[0], mHost)) {
|
|
|
|
try {
|
2009-11-24 19:40:29 -05:00
|
|
|
String dn = chain[0].getSubjectDN().toString();
|
2011-02-06 17:09:48 -05:00
|
|
|
if ((dn != null) && (dn.equalsIgnoreCase(keyStore.getCertificateAlias(chain[0])))) {
|
2009-11-24 19:40:29 -05:00
|
|
|
return;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (KeyStoreException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
throw new CertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
|
|
|
|
}
|
|
|
|
throw new CertificateException("Certificate domain name does not match "
|
|
|
|
+ mHost);
|
|
|
|
}
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public X509Certificate[] getAcceptedIssuers() {
|
2008-12-02 19:04:24 -05:00
|
|
|
return defaultTrustManager.getAcceptedIssuers();
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
2008-12-02 19:04:24 -05:00
|
|
|
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
static {
|
2011-10-31 23:51:02 -04:00
|
|
|
java.io.InputStream fis = null;
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
2008-11-01 17:32:06 -04:00
|
|
|
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
|
2009-12-14 21:50:53 -05:00
|
|
|
Application app = K9.app;
|
2008-12-02 19:04:24 -05:00
|
|
|
keyStoreFile = new File(app.getDir("KeyStore", Context.MODE_PRIVATE) + File.separator + "KeyStore.bks");
|
|
|
|
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
2009-11-24 19:40:29 -05:00
|
|
|
fis = new java.io.FileInputStream(keyStoreFile);
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (FileNotFoundException e1) {
|
2009-11-24 19:40:29 -05:00
|
|
|
fis = null;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
2009-11-24 19:40:29 -05:00
|
|
|
keyStore.load(fis, "".toCharArray());
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (IOException e) {
|
2008-12-02 19:04:24 -05:00
|
|
|
Log.e(LOG_TAG, "KeyStore IOException while initializing TrustManagerFactory ", e);
|
2009-11-24 19:40:29 -05:00
|
|
|
keyStore = null;
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (CertificateException e) {
|
2008-12-02 19:04:24 -05:00
|
|
|
Log.e(LOG_TAG, "KeyStore CertificateException while initializing TrustManagerFactory ", e);
|
2009-11-24 19:40:29 -05:00
|
|
|
keyStore = null;
|
|
|
|
}
|
2008-12-02 19:04:24 -05:00
|
|
|
tmf.init(keyStore);
|
2008-11-01 17:32:06 -04:00
|
|
|
TrustManager[] tms = tmf.getTrustManagers();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (tms != null) {
|
|
|
|
for (TrustManager tm : tms) {
|
|
|
|
if (tm instanceof X509TrustManager) {
|
2008-12-02 19:04:24 -05:00
|
|
|
localTrustManager = (X509TrustManager)tm;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
|
|
|
|
tmf.init((KeyStore)null);
|
|
|
|
tms = tmf.getTrustManagers();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (tms != null) {
|
|
|
|
for (TrustManager tm : tms) {
|
|
|
|
if (tm instanceof X509TrustManager) {
|
2008-12-02 19:04:24 -05:00
|
|
|
defaultTrustManager = (X509TrustManager) tm;
|
2008-11-01 17:32:06 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-02 19:04:24 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (NoSuchAlgorithmException e) {
|
2008-11-01 17:32:06 -04:00
|
|
|
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (KeyStoreException e) {
|
2008-11-01 17:32:06 -04:00
|
|
|
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
|
2011-10-31 23:51:02 -04:00
|
|
|
} finally {
|
|
|
|
IOUtils.closeQuietly(fis);
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
2008-12-02 19:04:24 -05:00
|
|
|
unsecureTrustManager = new SimpleX509TrustManager();
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
private TrustManagerFactory() {
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static X509TrustManager get(String host, boolean secure) {
|
2008-12-02 19:04:24 -05:00
|
|
|
return secure ? SecureX509TrustManager.getInstance(host) :
|
2009-11-24 19:40:29 -05:00
|
|
|
unsecureTrustManager;
|
2008-12-02 19:04:24 -05:00
|
|
|
}
|
2008-12-04 17:15:43 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static KeyStore getKeyStore() {
|
2009-11-24 19:40:29 -05:00
|
|
|
return keyStore;
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|
2008-12-04 17:15:43 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static void setLastCertChain(X509Certificate[] chain) {
|
2009-11-24 19:40:29 -05:00
|
|
|
lastCertChain = chain;
|
|
|
|
}
|
2011-02-06 17:09:48 -05:00
|
|
|
public static X509Certificate[] getLastCertChain() {
|
2009-11-24 19:40:29 -05:00
|
|
|
return lastCertChain;
|
|
|
|
}
|
2008-12-02 19:04:24 -05:00
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
public static void addCertificateChain(String alias, X509Certificate[] chain) throws CertificateException {
|
|
|
|
try {
|
2009-11-24 19:40:29 -05:00
|
|
|
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
|
2011-02-06 17:09:48 -05:00
|
|
|
for (X509Certificate element : chain) {
|
2008-12-02 19:04:24 -05:00
|
|
|
keyStore.setCertificateEntry
|
2010-07-18 21:52:18 -04:00
|
|
|
(element.getSubjectDN().toString(), element);
|
2009-11-24 19:40:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
tmf.init(keyStore);
|
|
|
|
TrustManager[] tms = tmf.getTrustManagers();
|
2011-02-06 17:09:48 -05:00
|
|
|
if (tms != null) {
|
|
|
|
for (TrustManager tm : tms) {
|
|
|
|
if (tm instanceof X509TrustManager) {
|
2009-11-24 19:40:29 -05:00
|
|
|
localTrustManager = (X509TrustManager) tm;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-31 23:51:02 -04:00
|
|
|
java.io.OutputStream keyStoreStream = null;
|
2011-02-06 17:09:48 -05:00
|
|
|
try {
|
2009-11-24 19:40:29 -05:00
|
|
|
keyStoreStream = new java.io.FileOutputStream(keyStoreFile);
|
|
|
|
keyStore.store(keyStoreStream, "".toCharArray());
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (FileNotFoundException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (CertificateException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (IOException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
|
2011-10-31 23:51:02 -04:00
|
|
|
} finally {
|
|
|
|
IOUtils.closeQuietly(keyStoreStream);
|
2009-11-24 19:40:29 -05:00
|
|
|
}
|
|
|
|
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (NoSuchAlgorithmException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
|
2011-02-06 17:09:48 -05:00
|
|
|
} catch (KeyStoreException e) {
|
2009-11-24 19:40:29 -05:00
|
|
|
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
|
|
|
|
}
|
|
|
|
}
|
2008-11-01 17:32:06 -04:00
|
|
|
}
|