diff --git a/app/src/main/java/eu/faircode/email/ConnectionHelper.java b/app/src/main/java/eu/faircode/email/ConnectionHelper.java index 9c21757f2b..3df61f01c8 100644 --- a/app/src/main/java/eu/faircode/email/ConnectionHelper.java +++ b/app/src/main/java/eu/faircode/email/ConnectionHelper.java @@ -938,7 +938,7 @@ public class ConnectionHelper { } } - static SSLSocket starttls(Socket socket, String host, int port, Context context) throws IOException { + static SSLSocket starttls(SSLSocketFactory sslFactory, Socket socket, String host, int port, Context context) throws IOException { String response; String command; boolean has = false; @@ -1006,7 +1006,6 @@ public class ConnectionHelper { } while (response != null && !(response.startsWith("A001 OK") || response.startsWith("220 "))); - SSLSocketFactory sslFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); return (SSLSocket) sslFactory.createSocket(socket, host, port, false); } else throw new SocketException("No STARTTLS"); diff --git a/app/src/main/java/eu/faircode/email/EmailProvider.java b/app/src/main/java/eu/faircode/email/EmailProvider.java index 430943d73b..5f9ca0e49d 100644 --- a/app/src/main/java/eu/faircode/email/EmailProvider.java +++ b/app/src/main/java/eu/faircode/email/EmailProvider.java @@ -1430,9 +1430,8 @@ public class EmailProvider implements Parcelable { for (InetAddress iaddr : DnsHelper.getAllByName(context, host)) { InetSocketAddress address = new InetSocketAddress(iaddr, Server.this.port); - SocketFactory factory = (starttls - ? SocketFactory.getDefault() - : SSLSocketFactory.getDefault()); + SSLSocketFactory sslFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + SocketFactory factory = (starttls ? SocketFactory.getDefault() : sslFactory); try (Socket socket = factory.createSocket()) { EntityLog.log(context, "Connecting to " + address); socket.connect(address, SCAN_TIMEOUT); @@ -1443,7 +1442,7 @@ public class EmailProvider implements Parcelable { SSLSocket sslSocket = null; try { if (starttls) - sslSocket = ConnectionHelper.starttls(socket, host, port, context); + sslSocket = ConnectionHelper.starttls(sslFactory, socket, host, port, context); else sslSocket = (SSLSocket) socket; diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index 68a00e2521..6c9c2744d7 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -170,8 +170,11 @@ public class EmailService implements AutoCloseable { // TLS_EMPTY_RENEGOTIATION_INFO_SCSV https://tools.ietf.org/html/rfc5746 static { + // https://downloads.bouncycastle.org/fips-java/docs/BC-FJA-%28D%29TLSUserGuide-1.0.4.pdf Security.setProperty("jdk.tls.disabledAlgorithms", ""); Security.setProperty("jdk.tls.client.protocols", "TLSv1.3,TLSv1.2,TLSv1.1,TLSv1,SSLv3"); + System.setProperty("org.bouncycastle.jsse.client.dh.unrestrictedGroups", "true"); + System.setProperty("org.bouncycastle.jsse.client.dh.minimumPrimeBits", "1024"); } private EmailService() { @@ -1124,7 +1127,7 @@ public class EmailService implements AutoCloseable { } } - private static class SSLSocketFactoryService extends SSLSocketFactory { + static class SSLSocketFactoryService extends SSLSocketFactory { // openssl s_client -connect host:port < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin // nmap --script ssl-enum-ciphers -Pn -p port host private String server; @@ -1195,8 +1198,7 @@ public class EmailService implements AutoCloseable { @Override public Socket createSocket() throws IOException { - Log.e("createSocket"); - throw new IOException("createSocket"); + return configure(factory.createSocket()); } @Override diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java index 981576a032..da8b11197d 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java @@ -44,6 +44,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.Button; +import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; @@ -122,6 +123,8 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private EditText etHost; private RadioGroup rgEncryption; private EditText etPort; + private CheckBox cbInsecure; + private CheckBox cbDane; private Button btnCheck; private TextView tvNetworkInfo; @@ -196,6 +199,8 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre etHost = view.findViewById(R.id.etHost); rgEncryption = view.findViewById(R.id.rgEncryption); etPort = view.findViewById(R.id.etPort); + cbInsecure = view.findViewById(R.id.cbInsecure); + cbDane = view.findViewById(R.id.cbDane); btnCheck = view.findViewById(R.id.btnCheck); tvNetworkInfo = view.findViewById(R.id.tvNetworkInfo); @@ -545,12 +550,17 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre else encryption = "none"; + boolean insecure = cbInsecure.isChecked(); + boolean dane = cbDane.isChecked(); + int timeout = prefs.getInt("timeout", EmailService.DEFAULT_CONNECT_TIMEOUT) * 1000; Bundle args = new Bundle(); args.putString("host", host); args.putInt("port", port == null ? 0 : port); args.putString("encryption", encryption); + args.putBoolean("insecure", insecure); + args.getBoolean("dane", dane); args.putInt("timeout", timeout); new SimpleTask() { @@ -569,17 +579,30 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre String host = args.getString("host"); int port = args.getInt("port"); String encryption = args.getString("encryption"); + boolean insecure = args.getBoolean("insecure"); + boolean dane = args.getBoolean("dane"); int timeout = args.getInt("timeout"); + boolean ssl_harden = prefs.getBoolean("ssl_harden", false); + boolean ssl_harden_strict = prefs.getBoolean("ssl_harden_strict", false); + boolean cert_strict = prefs.getBoolean("cert_strict", true); + boolean cert_transparency = prefs.getBoolean("cert_transparency", false); + boolean check_names = prefs.getBoolean("check_names", !BuildConfig.PLAY_STORE_RELEASE); + boolean bc = prefs.getBoolean("bouncy_castle", false); + boolean fips = prefs.getBoolean("bc_fips", false); + StringBuilder sb = new StringBuilder(); sb.append("Host: ").append(host).append('\n'); sb.append("Port: ").append(port).append('\n'); sb.append("Encryption: ").append(encryption).append('\n'); InetSocketAddress address = new InetSocketAddress(host, port); + SSLSocketFactory sslFactory = new EmailService.SSLSocketFactoryService( + context, host, port, insecure, dane, + ssl_harden, ssl_harden_strict, cert_strict, cert_transparency, check_names, + bc, fips, null, null, null); SocketFactory factory = (!"ssl".equals(encryption) - ? SocketFactory.getDefault() - : SSLSocketFactory.getDefault()); + ? SocketFactory.getDefault() : sslFactory); try (Socket socket = factory.createSocket()) { socket.connect(address, timeout); socket.setSoTimeout(timeout); @@ -588,7 +611,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre SSLSocket sslSocket = null; try { if ("starttls".equals(encryption)) - sslSocket = ConnectionHelper.starttls(socket, host, port, context); + sslSocket = ConnectionHelper.starttls(sslFactory, socket, host, port, context); else sslSocket = (SSLSocket) socket; diff --git a/app/src/main/res/layout/fragment_options_connection.xml b/app/src/main/res/layout/fragment_options_connection.xml index 257f4377e0..42f9a81d78 100644 --- a/app/src/main/res/layout/fragment_options_connection.xml +++ b/app/src/main/res/layout/fragment_options_connection.xml @@ -917,6 +917,26 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvPort" /> + + + +