mirror of
https://github.com/M66B/FairEmail.git
synced 2026-04-03 15:46:34 +02:00
Switch to BC on unsupported protocol
This commit is contained in:
@@ -73,6 +73,7 @@ import javax.mail.MessagingException;
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
@@ -504,6 +505,17 @@ public class ConnectionHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isUnsupportedProtocol(Throwable ex) {
|
||||
while (ex != null) {
|
||||
if (ex instanceof SSLHandshakeException &&
|
||||
ex.getMessage() != null &&
|
||||
ex.getMessage().contains("UNSUPPORTED_PROTOCOL"))
|
||||
return true;
|
||||
ex = ex.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isAborted(Throwable ex) {
|
||||
while (ex != null) {
|
||||
String msg = ex.getMessage();
|
||||
|
||||
@@ -742,80 +742,99 @@ public class EmailService implements AutoCloseable {
|
||||
((ErrnoException) ex.getCause().getCause()).errno == OsConstants.EACCES)
|
||||
throw new SecurityException("EACCES Please check 'Restrict data usage' in the Android app settings", ex);
|
||||
|
||||
boolean ioError = false;
|
||||
Throwable ce = ex;
|
||||
while (ce != null) {
|
||||
if (factory != null &&
|
||||
(ce instanceof CertificateException ||
|
||||
ce instanceof CertPathValidatorException))
|
||||
throw new UntrustedException(ex, factory.certificate);
|
||||
if (ce instanceof IOException)
|
||||
ioError = true;
|
||||
ce = ce.getCause();
|
||||
}
|
||||
|
||||
if (ioError) {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Connect ex=" +
|
||||
ex.getClass().getName() + ":" +
|
||||
ex + "\n" + android.util.Log.getStackTraceString(ex));
|
||||
if (!ssl_harden && ConnectionHelper.isUnsupportedProtocol(ex)) {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Unsuported protocol");
|
||||
try {
|
||||
// Some devices resolve IPv6 addresses while not having IPv6 connectivity
|
||||
InetAddress[] iaddrs = DnsHelper.getAllByName(context, host, dnssec);
|
||||
int ip4 = (main instanceof Inet4Address ? 1 : 0);
|
||||
int ip6 = (main instanceof Inet6Address ? 1 : 0);
|
||||
this.insecure = true;
|
||||
factory = new SSLSocketFactoryService(context,
|
||||
host, port, true, false,
|
||||
false, false, false, false,
|
||||
false,
|
||||
true, true,
|
||||
factory.key, factory.chain, factory.trustedFingerprint);
|
||||
properties.put("mail." + protocol + ".ssl.socketFactory", factory);
|
||||
_connect(main, port, require_id, user, factory);
|
||||
return;
|
||||
} catch (GeneralSecurityException ex1) {
|
||||
Log.e(ex1);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
boolean ioError = false;
|
||||
Throwable ce = ex;
|
||||
while (ce != null) {
|
||||
if (factory != null &&
|
||||
(ce instanceof CertificateException ||
|
||||
ce instanceof CertPathValidatorException))
|
||||
throw new UntrustedException(ex, factory.certificate);
|
||||
if (ce instanceof IOException)
|
||||
ioError = true;
|
||||
ce = ce.getCause();
|
||||
}
|
||||
|
||||
boolean[] has46 = ConnectionHelper.has46(context);
|
||||
if (ioError) {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Connect ex=" +
|
||||
ex.getClass().getName() + ":" +
|
||||
ex + "\n" + android.util.Log.getStackTraceString(ex));
|
||||
try {
|
||||
// Some devices resolve IPv6 addresses while not having IPv6 connectivity
|
||||
InetAddress[] iaddrs = DnsHelper.getAllByName(context, host, dnssec);
|
||||
int ip4 = (main instanceof Inet4Address ? 1 : 0);
|
||||
int ip6 = (main instanceof Inet6Address ? 1 : 0);
|
||||
|
||||
boolean prefer_ip4 = prefs.getBoolean("prefer_ip4", true);
|
||||
boolean prefer_ip6 = !prefer_ip4 && prefs.getBoolean("prefer_ip6", false);
|
||||
boolean[] has46 = ConnectionHelper.has46(context);
|
||||
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Address main=" + main +
|
||||
" count=" + iaddrs.length +
|
||||
" ip4=" + ip4 + " max4=" + MAX_IPV4 + " has4=" + has46[0] + " pref4=" + prefer_ip4 +
|
||||
" ip6=" + ip6 + " max6=" + MAX_IPV6 + " has6=" + has46[1] + " pref6=" + prefer_ip6);
|
||||
boolean prefer_ip4 = prefs.getBoolean("prefer_ip4", true);
|
||||
boolean prefer_ip6 = !prefer_ip4 && prefs.getBoolean("prefer_ip6", false);
|
||||
|
||||
if (prefer_ip4 || prefer_ip6)
|
||||
Arrays.sort(iaddrs, new Comparator<InetAddress>() {
|
||||
@Override
|
||||
public int compare(InetAddress a1, InetAddress a2) {
|
||||
int s = Boolean.compare(a1 instanceof Inet4Address, a2 instanceof Inet4Address);
|
||||
if (prefer_ip4)
|
||||
s = -s;
|
||||
return s;
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Address main=" + main +
|
||||
" count=" + iaddrs.length +
|
||||
" ip4=" + ip4 + " max4=" + MAX_IPV4 + " has4=" + has46[0] + " pref4=" + prefer_ip4 +
|
||||
" ip6=" + ip6 + " max6=" + MAX_IPV6 + " has6=" + has46[1] + " pref6=" + prefer_ip6);
|
||||
|
||||
if (prefer_ip4 || prefer_ip6)
|
||||
Arrays.sort(iaddrs, new Comparator<InetAddress>() {
|
||||
@Override
|
||||
public int compare(InetAddress a1, InetAddress a2) {
|
||||
int s = Boolean.compare(a1 instanceof Inet4Address, a2 instanceof Inet4Address);
|
||||
if (prefer_ip4)
|
||||
s = -s;
|
||||
return s;
|
||||
}
|
||||
});
|
||||
|
||||
for (InetAddress iaddr : iaddrs) {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Address resolved=" + iaddr);
|
||||
|
||||
if (iaddr.equals(main))
|
||||
continue;
|
||||
|
||||
if (iaddr instanceof Inet4Address) {
|
||||
if (!has46[0] || ip4 >= MAX_IPV4)
|
||||
continue;
|
||||
ip4++;
|
||||
}
|
||||
});
|
||||
|
||||
for (InetAddress iaddr : iaddrs) {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Address resolved=" + iaddr);
|
||||
if (iaddr instanceof Inet6Address) {
|
||||
if (!has46[1] || ip6 >= MAX_IPV6)
|
||||
continue;
|
||||
ip6++;
|
||||
}
|
||||
|
||||
if (iaddr.equals(main))
|
||||
continue;
|
||||
|
||||
if (iaddr instanceof Inet4Address) {
|
||||
if (!has46[0] || ip4 >= MAX_IPV4)
|
||||
continue;
|
||||
ip4++;
|
||||
}
|
||||
|
||||
if (iaddr instanceof Inet6Address) {
|
||||
if (!has46[1] || ip6 >= MAX_IPV6)
|
||||
continue;
|
||||
ip6++;
|
||||
}
|
||||
|
||||
try {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Falling back to " + iaddr);
|
||||
_connect(iaddr, port, require_id, user, factory);
|
||||
return;
|
||||
} catch (MessagingException ex1) {
|
||||
ex = ex1;
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Fallback ex=" +
|
||||
ex1.getClass().getName() + ":" +
|
||||
ex1 + " " + android.util.Log.getStackTraceString(ex1));
|
||||
try {
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Falling back to " + iaddr);
|
||||
_connect(iaddr, port, require_id, user, factory);
|
||||
return;
|
||||
} catch (MessagingException ex1) {
|
||||
ex = ex1;
|
||||
EntityLog.log(context, EntityLog.Type.Network, "Fallback ex=" +
|
||||
ex1.getClass().getName() + ":" +
|
||||
ex1 + " " + android.util.Log.getStackTraceString(ex1));
|
||||
}
|
||||
}
|
||||
} catch (IOException ex1) {
|
||||
throw new MessagingException(ex1.getMessage(), ex1);
|
||||
}
|
||||
} catch (IOException ex1) {
|
||||
throw new MessagingException(ex1.getMessage(), ex1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,6 +1130,8 @@ public class EmailService implements AutoCloseable {
|
||||
private boolean secure;
|
||||
private boolean ssl_harden;
|
||||
private boolean ssl_harden_strict;
|
||||
private PrivateKey key;
|
||||
private X509Certificate[] chain;
|
||||
private String trustedFingerprint;
|
||||
private SSLSocketFactory factory;
|
||||
private X509Certificate certificate;
|
||||
@@ -1125,6 +1146,8 @@ public class EmailService implements AutoCloseable {
|
||||
this.secure = !insecure;
|
||||
this.ssl_harden = ssl_harden;
|
||||
this.ssl_harden_strict = ssl_harden_strict;
|
||||
this.key = key;
|
||||
this.chain = chain;
|
||||
this.trustedFingerprint = fingerprint;
|
||||
|
||||
TrustManager[] tms = SSLHelper.getTrustManagers(
|
||||
|
||||
Reference in New Issue
Block a user