Change TrustManager to return list of "accepted issuers"
This commit is contained in:
parent
0f1bc05eef
commit
51839cc51f
6 changed files with 97 additions and 27 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<ImapInteraction> 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<ImapInteraction> 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) {
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue