null
.
* @throws Exception
*/
- void initializeComponent(K9 application);
+ void initializeComponent(Application application);
}
public static Application app = null;
@@ -91,6 +92,15 @@ public class K9 extends Application {
*/
private static Listnull
.
*/
public static void registerApplicationAware(final ApplicationAware component) {
- if (!observers.contains(component)) {
- observers.add(component);
+ synchronized (observers) {
+ if (sInitialized) {
+ component.initializeComponent(K9.app);
+ } else if (!observers.contains(component)) {
+ observers.add(component);
+ }
}
}
diff --git a/src/com/fsck/k9/Preferences.java b/src/com/fsck/k9/Preferences.java
index 99d066d08..51b83d873 100644
--- a/src/com/fsck/k9/Preferences.java
+++ b/src/com/fsck/k9/Preferences.java
@@ -127,6 +127,7 @@ public class Preferences {
Store.removeAccount(account);
+ account.deleteCertificates();
account.delete(this);
if (newAccount == account) {
diff --git a/src/com/fsck/k9/activity/setup/AccountSetupBasics.java b/src/com/fsck/k9/activity/setup/AccountSetupBasics.java
index 435a35d24..94ba4cf5b 100644
--- a/src/com/fsck/k9/activity/setup/AccountSetupBasics.java
+++ b/src/com/fsck/k9/activity/setup/AccountSetupBasics.java
@@ -17,6 +17,7 @@ import android.widget.Button;
import android.widget.EditText;
import com.fsck.k9.*;
import com.fsck.k9.activity.K9Activity;
+import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
import com.fsck.k9.helper.Utility;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
@@ -36,7 +37,9 @@ public class AccountSetupBasics extends K9Activity
private final static String EXTRA_ACCOUNT = "com.fsck.k9.AccountSetupBasics.account";
private final static int DIALOG_NOTE = 1;
private final static String STATE_KEY_PROVIDER =
- "com.fsck.k9.AccountSetupBasics.provider";
+ "com.fsck.k9.AccountSetupBasics.provider";
+ private final static String STATE_KEY_CHECKED_INCOMING =
+ "com.fsck.k9.AccountSetupBasics.checkedIncoming";
private EditText mEmailView;
private EditText mPasswordView;
@@ -46,6 +49,7 @@ public class AccountSetupBasics extends K9Activity
private Provider mProvider;
private EmailAddressValidator mEmailValidator = new EmailAddressValidator();
+ private boolean mCheckedIncoming = false;
public static void actionNewAccount(Context context) {
Intent i = new Intent(context, AccountSetupBasics.class);
@@ -66,15 +70,6 @@ public class AccountSetupBasics extends K9Activity
mEmailView.addTextChangedListener(this);
mPasswordView.addTextChangedListener(this);
-
- if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
- String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT);
- mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
- }
-
- if (savedInstanceState != null && savedInstanceState.containsKey(STATE_KEY_PROVIDER)) {
- mProvider = (Provider)savedInstanceState.getSerializable(STATE_KEY_PROVIDER);
- }
}
@Override
@@ -92,6 +87,23 @@ public class AccountSetupBasics extends K9Activity
if (mProvider != null) {
outState.putSerializable(STATE_KEY_PROVIDER, mProvider);
}
+ outState.putBoolean(STATE_KEY_CHECKED_INCOMING, mCheckedIncoming);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+
+ if (savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
+ String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT);
+ mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
+ }
+
+ if (savedInstanceState.containsKey(STATE_KEY_PROVIDER)) {
+ mProvider = (Provider) savedInstanceState.getSerializable(STATE_KEY_PROVIDER);
+ }
+
+ mCheckedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING);
}
public void afterTextChanged(Editable s) {
@@ -229,7 +241,8 @@ public class AccountSetupBasics extends K9Activity
} else if (incomingUri.toString().startsWith("pop3")) {
mAccount.setDeletePolicy(Account.DELETE_POLICY_NEVER);
}
- AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, true);
+ // Check incoming here. Then check outgoing in onActivityResult()
+ AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING);
} catch (UnsupportedEncodingException enc) {
// This really shouldn't happen since the encoding is hardcoded to UTF-8
Log.e(K9.LOG_TAG, "Couldn't urlencode username or password.", enc);
@@ -266,11 +279,18 @@ public class AccountSetupBasics extends K9Activity
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
- mAccount.setDescription(mAccount.getEmail());
- mAccount.save(Preferences.getPreferences(this));
- K9.setServicesEnabled(this);
- AccountSetupNames.actionSetNames(this, mAccount);
- finish();
+ if (!mCheckedIncoming) {
+ //We've successfully checked incoming. Now check outgoing.
+ mCheckedIncoming = true;
+ AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING);
+ } else {
+ //We've successfully checked outgoing as well.
+ mAccount.setDescription(mAccount.getEmail());
+ mAccount.save(Preferences.getPreferences(this));
+ K9.setServicesEnabled(this);
+ AccountSetupNames.actionSetNames(this, mAccount);
+ finish();
+ }
}
}
diff --git a/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java b/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java
index 5941f7369..ea2d1c166 100644
--- a/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java
+++ b/src/com/fsck/k9/activity/setup/AccountSetupCheckSettings.java
@@ -22,7 +22,6 @@ import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.Transport;
-import com.fsck.k9.mail.store.TrustManagerFactory;
import com.fsck.k9.mail.store.WebDavStore;
import com.fsck.k9.mail.filter.Hex;
@@ -47,9 +46,12 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
private static final String EXTRA_ACCOUNT = "account";
- private static final String EXTRA_CHECK_INCOMING = "checkIncoming";
+ private static final String EXTRA_CHECK_DIRECTION ="checkDirection";
- private static final String EXTRA_CHECK_OUTGOING = "checkOutgoing";
+ public enum CheckDirection {
+ INCOMING,
+ OUTGOING
+ }
private Handler mHandler = new Handler();
@@ -59,20 +61,16 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
private Account mAccount;
- private boolean mCheckIncoming;
-
- private boolean mCheckOutgoing;
+ private CheckDirection mDirection;
private boolean mCanceled;
private boolean mDestroyed;
- public static void actionCheckSettings(Activity context, Account account,
- boolean checkIncoming, boolean checkOutgoing) {
+ public static void actionCheckSettings(Activity context, Account account, CheckDirection direction) {
Intent i = new Intent(context, AccountSetupCheckSettings.class);
i.putExtra(EXTRA_ACCOUNT, account.getUuid());
- i.putExtra(EXTRA_CHECK_INCOMING, checkIncoming);
- i.putExtra(EXTRA_CHECK_OUTGOING, checkOutgoing);
+ i.putExtra(EXTRA_CHECK_DIRECTION, direction);
context.startActivityForResult(i, ACTIVITY_REQUEST_CODE);
}
@@ -89,8 +87,7 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
String accountUuid = getIntent().getStringExtra(EXTRA_ACCOUNT);
mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
- mCheckIncoming = getIntent().getBooleanExtra(EXTRA_CHECK_INCOMING, false);
- mCheckOutgoing = getIntent().getBooleanExtra(EXTRA_CHECK_OUTGOING, false);
+ mDirection = (CheckDirection) getIntent().getSerializableExtra(EXTRA_CHECK_DIRECTION);
new Thread() {
@Override
@@ -108,9 +105,9 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
final MessagingController ctrl = MessagingController.getInstance(getApplication());
ctrl.clearCertificateErrorNotifications(AccountSetupCheckSettings.this,
- mAccount, mCheckIncoming, mCheckOutgoing);
+ mAccount, mDirection);
- if (mCheckIncoming) {
+ if (mDirection.equals(CheckDirection.INCOMING)) {
store = mAccount.getRemoteStore();
if (store instanceof WebDavStore) {
@@ -133,7 +130,7 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
finish();
return;
}
- if (mCheckOutgoing) {
+ if (mDirection.equals(CheckDirection.OUTGOING)) {
if (!(mAccount.getRemoteStore() instanceof WebDavStore)) {
setMessage(R.string.account_setup_check_settings_check_outgoing_msg);
}
@@ -366,21 +363,14 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
- String alias = mAccount.getUuid();
- if (mCheckIncoming) {
- alias = alias + ".incoming";
- }
- if (mCheckOutgoing) {
- alias = alias + ".outgoing";
- }
- TrustManagerFactory.addCertificateChain(alias, chain);
+ mAccount.addCertificate(mDirection, chain[0]);
} catch (CertificateException e) {
showErrorDialog(
R.string.account_setup_failed_dlg_certificate_message_fmt,
e.getMessage() == null ? "" : e.getMessage());
}
AccountSetupCheckSettings.actionCheckSettings(AccountSetupCheckSettings.this, mAccount,
- mCheckIncoming, mCheckOutgoing);
+ mDirection);
}
})
.setNegativeButton(
diff --git a/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java b/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java
index c76b6289f..e58fc8846 100644
--- a/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java
+++ b/src/com/fsck/k9/activity/setup/AccountSetupIncoming.java
@@ -16,6 +16,7 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import com.fsck.k9.*;
import com.fsck.k9.activity.K9Activity;
+import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.ServerSettings;
@@ -427,6 +428,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
mWebdavMailboxPathView.getText().toString());
}
+ mAccount.deleteCertificate(host, port, CheckDirection.INCOMING);
ServerSettings settings = new ServerSettings(mStoreType, host, port,
connectionSecurity, authType, username, password, extra);
@@ -437,7 +439,7 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
mAccount.setCompression(Account.TYPE_OTHER, mCompressionOther.isChecked());
mAccount.setSubscribedFoldersOnly(mSubscribedFoldersOnly.isChecked());
- AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false);
+ AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING);
} catch (Exception e) {
failure(e);
}
diff --git a/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java b/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
index 6f71545fe..6d1af8bc0 100644
--- a/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
+++ b/src/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
@@ -15,6 +15,7 @@ import android.widget.*;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.fsck.k9.*;
import com.fsck.k9.activity.K9Activity;
+import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.transport.SmtpTransport;
@@ -95,7 +96,7 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
try {
if (new URI(mAccount.getStoreUri()).getScheme().startsWith("webdav")) {
mAccount.setTransportUri(mAccount.getStoreUri());
- AccountSetupCheckSettings.actionCheckSettings(this, mAccount, false, true);
+ AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING);
}
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
@@ -308,10 +309,12 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
if (mRequireLoginView.isChecked()) {
userInfo = usernameEnc + ":" + passwordEnc + ":" + authType;
}
- uri = new URI(smtpSchemes[securityType], userInfo, mServerView.getText().toString(),
- Integer.parseInt(mPortView.getText().toString()), null, null, null);
+ String newHost = mServerView.getText().toString();
+ int newPort = Integer.parseInt(mPortView.getText().toString());
+ uri = new URI(smtpSchemes[securityType], userInfo, newHost, newPort, null, null, null);
+ mAccount.deleteCertificate(newHost, newPort, CheckDirection.OUTGOING);
mAccount.setTransportUri(uri.toString());
- AccountSetupCheckSettings.actionCheckSettings(this, mAccount, false, true);
+ AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING);
} catch (UnsupportedEncodingException enc) {
// This really shouldn't happen since the encoding is hardcoded to UTF-8
Log.e(K9.LOG_TAG, "Couldn't urlencode username or password.", enc);
diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java
index 33c457353..7de35d667 100644
--- a/src/com/fsck/k9/controller/MessagingController.java
+++ b/src/com/fsck/k9/controller/MessagingController.java
@@ -53,6 +53,7 @@ import com.fsck.k9.activity.FolderList;
import com.fsck.k9.activity.MessageList;
import com.fsck.k9.activity.MessageReference;
import com.fsck.k9.activity.NotificationDeleteConfirmation;
+import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
import com.fsck.k9.activity.setup.AccountSetupIncoming;
import com.fsck.k9.activity.setup.AccountSetupOutgoing;
import com.fsck.k9.cache.EmailProviderCache;
@@ -2671,14 +2672,13 @@ public class MessagingController implements Runnable {
}
public void clearCertificateErrorNotifications(Context context,
- final Account account, boolean incoming, boolean outgoing) {
+ final Account account, CheckDirection direction) {
final NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
- if (incoming) {
+ if (direction.equals(CheckDirection.INCOMING)) {
nm.cancel(null, K9.CERTIFICATE_EXCEPTION_NOTIFICATION_INCOMING + account.getAccountNumber());
- }
- if (outgoing) {
+ } else {
nm.cancel(null, K9.CERTIFICATE_EXCEPTION_NOTIFICATION_OUTGOING + account.getAccountNumber());
}
}
diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java
index a71a95aaf..eda66afb9 100644
--- a/src/com/fsck/k9/mail/store/ImapStore.java
+++ b/src/com/fsck/k9/mail/store/ImapStore.java
@@ -96,6 +96,8 @@ import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
import com.fsck.k9.mail.store.imap.ImapUtility;
import com.fsck.k9.mail.transport.imap.ImapSettings;
+import com.fsck.k9.net.ssl.TrustManagerFactory;
+import com.fsck.k9.net.ssl.TrustedSocketFactory;
import com.jcraft.jzlib.JZlib;
import com.jcraft.jzlib.ZOutputStream;
@@ -2446,9 +2448,12 @@ public class ImapStore extends Store {
connectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) {
SSLContext sslContext = SSLContext.getInstance("TLS");
boolean secure = connectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED;
- sslContext.init(null, new TrustManager[] {
- TrustManagerFactory.get(mSettings.getHost(), secure)
- }, new SecureRandom());
+ sslContext
+ .init(null,
+ new TrustManager[] { TrustManagerFactory.get(
+ mSettings.getHost(),
+ mSettings.getPort(), secure) },
+ new SecureRandom());
mSocket = TrustedSocketFactory.createSocket(sslContext);
} else {
mSocket = new Socket();
@@ -2501,9 +2506,11 @@ public class ImapStore extends Store {
SSLContext sslContext = SSLContext.getInstance("TLS");
boolean secure = mSettings.getConnectionSecurity() == CONNECTION_SECURITY_TLS_REQUIRED;
- sslContext.init(null, new TrustManager[] {
- TrustManagerFactory.get(mSettings.getHost(), secure)
- }, new SecureRandom());
+ sslContext.init(null,
+ new TrustManager[] { TrustManagerFactory.get(
+ mSettings.getHost(),
+ mSettings.getPort(), secure) },
+ new SecureRandom());
mSocket = TrustedSocketFactory.createSocket(sslContext, mSocket,
mSettings.getHost(), mSettings.getPort(), true);
mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT);
diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java
index 26e37d1dd..80711a48f 100644
--- a/src/com/fsck/k9/mail/store/Pop3Store.java
+++ b/src/com/fsck/k9/mail/store/Pop3Store.java
@@ -10,6 +10,8 @@ import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.*;
import com.fsck.k9.mail.internet.MimeMessage;
+import com.fsck.k9.net.ssl.TrustManagerFactory;
+import com.fsck.k9.net.ssl.TrustedSocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
@@ -327,9 +329,9 @@ public class Pop3Store extends Store {
mConnectionSecurity == CONNECTION_SECURITY_SSL_OPTIONAL) {
SSLContext sslContext = SSLContext.getInstance("TLS");
final boolean secure = mConnectionSecurity == CONNECTION_SECURITY_SSL_REQUIRED;
- sslContext.init(null, new TrustManager[] {
- TrustManagerFactory.get(mHost, secure)
- }, new SecureRandom());
+ sslContext.init(null,
+ new TrustManager[] { TrustManagerFactory.get(mHost,
+ mPort, secure) }, new SecureRandom());
mSocket = TrustedSocketFactory.createSocket(sslContext);
} else {
mSocket = new Socket();
@@ -356,9 +358,10 @@ public class Pop3Store extends Store {
SSLContext sslContext = SSLContext.getInstance("TLS");
boolean secure = mConnectionSecurity == CONNECTION_SECURITY_TLS_REQUIRED;
- sslContext.init(null, new TrustManager[] {
- TrustManagerFactory.get(mHost, secure)
- }, new SecureRandom());
+ sslContext.init(null,
+ new TrustManager[] { TrustManagerFactory.get(
+ mHost, mPort, secure) },
+ new SecureRandom());
mSocket = TrustedSocketFactory.createSocket(sslContext, mSocket, mHost,
mPort, true);
mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT);
diff --git a/src/com/fsck/k9/mail/store/TrustManagerFactory.java b/src/com/fsck/k9/mail/store/TrustManagerFactory.java
deleted file mode 100644
index 7b508c3bb..000000000
--- a/src/com/fsck/k9/mail/store/TrustManagerFactory.java
+++ /dev/null
@@ -1,214 +0,0 @@
-
-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 com.fsck.k9.mail.CertificateChainException;
-
-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;
-
-public final class TrustManagerFactory {
- private static final String LOG_TAG = "TrustManagerFactory";
-
- private static X509TrustManager defaultTrustManager;
- private static X509TrustManager unsecureTrustManager;
- private static X509TrustManager localTrustManager;
-
- private static File keyStoreFile;
- private static KeyStore keyStore;
-
-
- private static class SimpleX509TrustManager implements X509TrustManager {
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- }
-
- public void checkServerTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }
-
- private static class SecureX509TrustManager implements X509TrustManager {
- private static final Map+ * This test is to make sure entries in the keystore file aren't overwritten. + * See Issue 1326. + *
+ * + * @throws Exception + * if anything goes wrong + */ + public void testDifferentCertificatesOnSameServer() throws Exception { + mKeyStore.addCertificate(NOT_MATCHING_HOST, PORT1, mCert1); + mKeyStore.addCertificate(NOT_MATCHING_HOST, PORT2, mCert2); + + X509TrustManager trustManager1 = TrustManagerFactory.get(NOT_MATCHING_HOST, PORT1, true); + X509TrustManager trustManager2 = TrustManagerFactory.get(NOT_MATCHING_HOST, PORT2, true); + trustManager2.checkServerTrusted(new X509Certificate[] { mCert2 }, "authType"); + trustManager1.checkServerTrusted(new X509Certificate[] { mCert1 }, "authType"); + } + + public void testSelfSignedCertificateMatchingHost() throws Exception { + mKeyStore.addCertificate(MATCHING_HOST, PORT1, mCert1); + X509TrustManager trustManager = TrustManagerFactory.get(MATCHING_HOST, PORT1, true); + trustManager.checkServerTrusted(new X509Certificate[] { mCert1 }, "authType"); + } + + public void testSelfSignedCertificateNotMatchingHost() throws Exception { + mKeyStore.addCertificate(NOT_MATCHING_HOST, PORT1, mCert1); + X509TrustManager trustManager = TrustManagerFactory.get(NOT_MATCHING_HOST, PORT1, true); + trustManager.checkServerTrusted(new X509Certificate[] { mCert1 }, "authType"); + } + + public void testWrongCertificate() throws Exception { + mKeyStore.addCertificate(MATCHING_HOST, PORT1, mCert1); + X509TrustManager trustManager = TrustManagerFactory.get(MATCHING_HOST, PORT1, true); + assertCertificateRejection(trustManager, new X509Certificate[] { mCert2 }); + } + + public void testCertificateOfOtherHost() throws Exception { + mKeyStore.addCertificate(MATCHING_HOST, PORT1, mCert1); + mKeyStore.addCertificate(MATCHING_HOST, PORT2, mCert2); + + X509TrustManager trustManager = TrustManagerFactory.get(MATCHING_HOST, PORT1, true); + assertCertificateRejection(trustManager, new X509Certificate[] { mCert2 }); + } + + public void testUntrustedCertificateChain() throws Exception { + X509TrustManager trustManager = TrustManagerFactory.get(MATCHING_HOST, PORT1, true); + assertCertificateRejection(trustManager, new X509Certificate[] { mCert3, mCaCert }); + } + + public void testLocallyTrustedCertificateChain() throws Exception { + mKeyStore.addCertificate(MATCHING_HOST, PORT1, mCert3); + + X509TrustManager trustManager = TrustManagerFactory.get(MATCHING_HOST, PORT1, true); + trustManager.checkServerTrusted(new X509Certificate[] { mCert3, mCaCert }, "authType"); + } + + public void testLocallyTrustedCertificateChainNotMatchingHost() throws Exception { + mKeyStore.addCertificate(NOT_MATCHING_HOST, PORT1, mCert3); + + X509TrustManager trustManager = TrustManagerFactory.get(NOT_MATCHING_HOST, PORT1, true); + trustManager.checkServerTrusted(new X509Certificate[] { mCert3, mCaCert }, "authType"); + } + + public void testGloballyTrustedCertificateChain() throws Exception { + X509TrustManager trustManager = TrustManagerFactory.get("github.com", PORT1, true); + X509Certificate[] certificates = new X509Certificate[] { mGithubCert, mDigiCert }; + trustManager.checkServerTrusted(certificates, "authType"); + } + + public void testGloballyTrustedCertificateNotMatchingHost() throws Exception { + X509TrustManager trustManager = TrustManagerFactory.get(NOT_MATCHING_HOST, PORT1, true); + assertCertificateRejection(trustManager, new X509Certificate[] { mGithubCert, mDigiCert}); + } + + public void testGloballyTrustedCertificateNotMatchingHostOverride() throws Exception { + mKeyStore.addCertificate(MATCHING_HOST, PORT1, mGithubCert); + + X509TrustManager trustManager = TrustManagerFactory.get(MATCHING_HOST, PORT1, true); + X509Certificate[] certificates = new X509Certificate[] { mGithubCert, mDigiCert }; + trustManager.checkServerTrusted(certificates, "authType"); + } + + private void assertCertificateRejection(X509TrustManager trustManager, + X509Certificate[] certificates) { + boolean certificateValid; + try { + trustManager.checkServerTrusted(certificates, "authType"); + certificateValid = true; + } catch (CertificateException e) { + certificateValid = false; + } + assertFalse("The certificate should have been rejected but wasn't", certificateValid); + } + + public void testKeyStoreLoading() throws Exception { + mKeyStore.addCertificate(MATCHING_HOST, PORT1, mCert1); + mKeyStore.addCertificate(NOT_MATCHING_HOST, PORT2, mCert2); + assertTrue(mKeyStore.isValidCertificate(mCert1, MATCHING_HOST, PORT1)); + assertTrue(mKeyStore.isValidCertificate(mCert2, NOT_MATCHING_HOST, PORT2)); + + // reload store from same file + mKeyStore.setKeyStoreFile(mKeyStoreFile); + assertTrue(mKeyStore.isValidCertificate(mCert1, MATCHING_HOST, PORT1)); + assertTrue(mKeyStore.isValidCertificate(mCert2, NOT_MATCHING_HOST, PORT2)); + + // reload store from empty file + mKeyStoreFile.delete(); + mKeyStore.setKeyStoreFile(mKeyStoreFile); + assertFalse(mKeyStore.isValidCertificate(mCert1, MATCHING_HOST, PORT1)); + assertFalse(mKeyStore.isValidCertificate(mCert2, NOT_MATCHING_HOST, PORT2)); + } +}