diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/KeyStoreProvider.java b/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/KeyStoreProvider.java new file mode 100644 index 000000000..493e4afa8 --- /dev/null +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/KeyStoreProvider.java @@ -0,0 +1,61 @@ +package com.fsck.k9.mail.helpers; + + +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.X509Certificate; + + +public class KeyStoreProvider { + private static final String KEYSTORE_PASSWORD = "password"; + private static final String KEYSTORE_RESOURCE = "/keystore.jks"; + private static final String SERVER_CERTIFICATE_ALIAS = "mockimapserver"; + + + private final KeyStore keyStore; + + + public static KeyStoreProvider getInstance() { + KeyStore keyStore = loadKeyStore(); + return new KeyStoreProvider(keyStore); + } + + private static KeyStore loadKeyStore() { + try { + KeyStore keyStore = KeyStore.getInstance("JKS"); + + InputStream keyStoreInputStream = KeyStoreProvider.class.getResourceAsStream(KEYSTORE_RESOURCE); + try { + keyStore.load(keyStoreInputStream, KEYSTORE_PASSWORD.toCharArray()); + } finally { + keyStoreInputStream.close(); + } + + return keyStore; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private KeyStoreProvider(KeyStore keyStore) { + this.keyStore = keyStore; + } + + public KeyStore getKeyStore() { + return keyStore; + } + + public char[] getPassword() { + return KEYSTORE_PASSWORD.toCharArray(); + } + + public X509Certificate getServerCertificate() { + try { + KeyStore keyStore = loadKeyStore(); + return (X509Certificate) keyStore.getCertificate(SERVER_CERTIFICATE_ALIAS); + } catch (KeyStoreException e) { + throw new RuntimeException(e); + } + } +} diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/TestTrustedSocketFactory.java b/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/TestTrustedSocketFactory.java index 24e6b7b36..1d32b1a26 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/TestTrustedSocketFactory.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/TestTrustedSocketFactory.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.net.Socket; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.ssl.TrustedSocketFactory; @@ -14,11 +15,23 @@ import javax.net.ssl.TrustManager; public class TestTrustedSocketFactory implements TrustedSocketFactory { + private final X509Certificate serverCertificate; + + + public static TestTrustedSocketFactory newInstance() { + X509Certificate serverCertificate = KeyStoreProvider.getInstance().getServerCertificate(); + return new TestTrustedSocketFactory(serverCertificate); + } + + private TestTrustedSocketFactory(X509Certificate serverCertificate) { + this.serverCertificate = serverCertificate; + } + @Override public Socket createSocket(Socket socket, String host, int port, String clientCertificateAlias) throws NoSuchAlgorithmException, KeyManagementException, MessagingException, IOException { - TrustManager[] trustManagers = new TrustManager[] { new VeryTrustingTrustManager() }; + TrustManager[] trustManagers = new TrustManager[] { new VeryTrustingTrustManager(serverCertificate) }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagers, null); diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/VeryTrustingTrustManager.java b/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/VeryTrustingTrustManager.java index 985101ce0..a455d5532 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/VeryTrustingTrustManager.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/helpers/VeryTrustingTrustManager.java @@ -10,6 +10,13 @@ import javax.net.ssl.X509TrustManager; @SuppressLint("TrustAllX509TrustManager") class VeryTrustingTrustManager implements X509TrustManager { + private final X509Certificate serverCertificate; + + + public VeryTrustingTrustManager(X509Certificate serverCertificate) { + this.serverCertificate = serverCertificate; + } + @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // Accept all certificates @@ -22,7 +29,7 @@ class VeryTrustingTrustManager implements X509TrustManager { @Override public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; + return new X509Certificate[] { serverCertificate }; } } diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java index c50f96f04..300404ce1 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/ImapConnectionTest.java @@ -62,7 +62,7 @@ public class ImapConnectionTest { public void setUp() throws Exception { connectivityManager = mock(ConnectivityManager.class); oAuth2TokenProvider = createOAuth2TokenProvider(); - socketFactory = new TestTrustedSocketFactory(); + socketFactory = TestTrustedSocketFactory.newInstance(); settings = new SimpleImapSettings(); settings.setUsername(USERNAME); diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/mockserver/MockImapServer.java b/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/mockserver/MockImapServer.java index 41cb40cea..c9cf9e5bb 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/mockserver/MockImapServer.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/store/imap/mockserver/MockImapServer.java @@ -23,6 +23,7 @@ import java.util.zip.InflaterInputStream; import android.annotation.SuppressLint; +import com.fsck.k9.mail.helpers.KeyStoreProvider; import com.jcraft.jzlib.JZlib; import com.jcraft.jzlib.ZOutputStream; import javax.net.ssl.KeyManagerFactory; @@ -37,15 +38,13 @@ import org.apache.commons.io.IOUtils; @SuppressLint("NewApi") public class MockImapServer { - private static final String KEYSTORE_PASSWORD = "password"; - private static final String KEYSTORE_RESOURCE = "/keystore.jks"; - private static final byte[] CRLF = { '\r', '\n' }; private final Deque interactions = new ConcurrentLinkedDeque<>(); private final CountDownLatch waitForConnectionClosed = new CountDownLatch(1); private final CountDownLatch waitForAllExpectedCommands = new CountDownLatch(1); + private final KeyStoreProvider keyStoreProvider; private final Logger logger; private MockServerThread mockServerThread; @@ -54,10 +53,11 @@ public class MockImapServer { public MockImapServer() { - this(new DefaultLogger()); + this(KeyStoreProvider.getInstance(), new DefaultLogger()); } - public MockImapServer(Logger logger) { + public MockImapServer(KeyStoreProvider keyStoreProvider, Logger logger) { + this.keyStoreProvider = keyStoreProvider; this.logger = logger; } @@ -96,7 +96,7 @@ public class MockImapServer { port = serverSocket.getLocalPort(); mockServerThread = new MockServerThread(serverSocket, interactions, waitForConnectionClosed, - waitForAllExpectedCommands, logger); + waitForAllExpectedCommands, logger, keyStoreProvider); mockServerThread.start(); } @@ -236,6 +236,7 @@ public class MockImapServer { private final CountDownLatch waitForConnectionClosed; private final CountDownLatch waitForAllExpectedCommands; private final Logger logger; + private final KeyStoreProvider keyStoreProvider; private volatile boolean shouldStop = false; private volatile Socket clientSocket; @@ -246,13 +247,15 @@ public class MockImapServer { public MockServerThread(ServerSocket serverSocket, Deque interactions, - CountDownLatch waitForConnectionClosed, CountDownLatch waitForAllExpectedCommands, Logger logger) { + CountDownLatch waitForConnectionClosed, CountDownLatch waitForAllExpectedCommands, Logger logger, + KeyStoreProvider keyStoreProvider) { super("MockImapServer"); this.serverSocket = serverSocket; this.interactions = interactions; this.waitForConnectionClosed = waitForConnectionClosed; this.waitForAllExpectedCommands = waitForAllExpectedCommands; this.logger = logger; + this.keyStoreProvider = keyStoreProvider; } @Override @@ -356,11 +359,11 @@ public class MockImapServer { private void upgradeToTls(Socket socket) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { - KeyStore keyStore = loadKeyStore(); + KeyStore keyStore = keyStoreProvider.getKeyStore(); String defaultAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(defaultAlgorithm); - keyManagerFactory.init(keyStore, KEYSTORE_PASSWORD.toCharArray()); + keyManagerFactory.init(keyStore, keyStoreProvider.getPassword()); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagerFactory.getKeyManagers(), null, null); @@ -375,20 +378,6 @@ public class MockImapServer { output = Okio.buffer(Okio.sink(sslSocket.getOutputStream())); } - private KeyStore loadKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, - CertificateException { - KeyStore keyStore = KeyStore.getInstance("JKS"); - - InputStream keyStoreInputStream = getClass().getResourceAsStream(KEYSTORE_RESOURCE); - try { - keyStore.load(keyStoreInputStream, KEYSTORE_PASSWORD.toCharArray()); - } finally { - keyStoreInputStream.close(); - } - - return keyStore; - } - private void readAdditionalCommands() throws IOException { String command = input.readUtf8Line(); if (command == null) { diff --git a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java index ed26ae9d4..7cc67506d 100644 --- a/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java +++ b/k9mail-library/src/test/java/com/fsck/k9/mail/transport/smtp/SmtpTransportTest.java @@ -52,7 +52,7 @@ public class SmtpTransportTest { @Before public void before() throws AuthenticationFailedException { - socketFactory = new TestTrustedSocketFactory(); + socketFactory = TestTrustedSocketFactory.newInstance(); oAuth2TokenProvider = mock(OAuth2TokenProvider.class); when(oAuth2TokenProvider.getToken(eq(USERNAME), anyInt())) .thenReturn("oldToken").thenReturn("newToken");