k-9/src/com/fsck/k9/mail/store/WebDavSocketFactory.java

72 lines
2.6 KiB
Java
Raw Normal View History

2013-10-28 22:42:37 -04:00
package com.fsck.k9.mail.store;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.params.HttpParams;
import com.fsck.k9.net.ssl.TrustManagerFactory;
2013-10-28 22:42:37 -04:00
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
/*
* TODO: find out what's going on here and document it.
* Using two socket factories looks suspicious.
*/
public class WebDavSocketFactory implements LayeredSocketFactory {
private SSLSocketFactory mSocketFactory;
private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory;
Fix inadequate certificate validation Proper host name validation was not being performed for certificates kept in the local keystore. If an attacker could convince a user to accept and store an attacker's certificate, then that certificate could be used for MITM attacks, giving the attacker access to all connections to all servers in all accounts in K-9. This commit changes how the certificates are stored. Previously, an entire certificate chain was stored for a server (and any of those certificates in the chain were available for validating signatures on certificates received when connecting). Now just the single certificate for the server is stored. This commit changes how locally stored certificates are retrieved. They can only be retrieved using the host:port that the user configured for the server. This also fixes issue 1326. Users can now use different certificates for different servers on the same host (listening to different ports). The above changes mean that users might have to re-accept certificates that they had previously accepted and are still using (but only if the certificate's Subject doesn't match the host that they are connecting to). This commit modifies AccountSetupBasics so that it now calls AccountSetupCheckSettings twice -- once for checking the incoming settings and once for the outgoing settings. Otherwise, an exception could occur while checking incoming settings, the user could say continue (or the user could accept a certificate key), and the outgoing settings would not be checked. This also helps with determining if a certificate exception was for the incoming or outgoing server, which is needed if the user decides to add the certificate to the keystore.
2013-11-23 13:26:57 -05:00
public WebDavSocketFactory(String host, int port, boolean secure) throws NoSuchAlgorithmException, KeyManagementException {
2013-10-28 22:42:37 -04:00
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(host, port)
2013-10-28 22:42:37 -04:00
}, new SecureRandom());
mSocketFactory = sslContext.getSocketFactory();
mSchemeSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory();
mSchemeSocketFactory.setHostnameVerifier(
org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException {
return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params);
}
public Socket createSocket() throws IOException {
return mSocketFactory.createSocket();
}
public boolean isSecure(Socket sock) throws IllegalArgumentException {
return mSchemeSocketFactory.isSecure(sock);
}
public Socket createSocket(
final Socket socket,
final String host,
final int port,
final boolean autoClose
) throws IOException, UnknownHostException {
SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket(
socket,
host,
port,
autoClose
);
//hostnameVerifier.verify(host, sslSocket);
// verifyHostName() didn't blowup - good!
return sslSocket;
}
}