Switch to BC on unsupported protocol

master
M66B 2 days ago
parent 170cfce52d
commit 7a987e71e7

@ -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);
boolean[] has46 = ConnectionHelper.has46(context);
boolean prefer_ip4 = prefs.getBoolean("prefer_ip4", true);
boolean prefer_ip6 = !prefer_ip4 && prefs.getBoolean("prefer_ip6", false);
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;
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();
}
if (iaddr instanceof Inet4Address) {
if (!has46[0] || ip4 >= MAX_IPV4)
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[] has46 = ConnectionHelper.has46(context);
boolean prefer_ip4 = prefs.getBoolean("prefer_ip4", true);
boolean prefer_ip6 = !prefer_ip4 && prefs.getBoolean("prefer_ip6", false);
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;
ip4++;
}
if (iaddr instanceof Inet6Address) {
if (!has46[1] || ip6 >= MAX_IPV6)
continue;
ip6++;
}
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(

Loading…
Cancel
Save