1
0
Fork 0
mirror of https://github.com/M66B/FairEmail.git synced 2024-12-26 01:36:55 +00:00

Added untrusted exception

This commit is contained in:
M66B 2019-12-16 16:32:25 +01:00
parent 0b9a2b4235
commit e1091c4e19

View file

@ -16,6 +16,7 @@ import com.sun.mail.util.MailSSLSocketFactory;
import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralName;
import java.io.IOException;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
@ -24,6 +25,7 @@ import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -44,7 +46,6 @@ import javax.mail.Service;
import javax.mail.Session; import javax.mail.Session;
import javax.mail.Store; import javax.mail.Store;
import javax.mail.event.StoreListener; import javax.mail.event.StoreListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
public class MailService implements AutoCloseable { public class MailService implements AutoCloseable {
@ -52,13 +53,11 @@ public class MailService implements AutoCloseable {
private String protocol; private String protocol;
private boolean useip; private boolean useip;
private boolean debug; private boolean debug;
private String trustedFingerprint;
private Properties properties; private Properties properties;
private Session isession; private Session isession;
private Service iservice; private Service iservice;
private boolean configuring;
private String fingerprint;
private X509Certificate certificate; private X509Certificate certificate;
private boolean trusted;
private StoreListener listener; private StoreListener listener;
private ExecutorService executor = Helper.getBackgroundExecutor(0, "mail"); private ExecutorService executor = Helper.getBackgroundExecutor(0, "mail");
@ -104,40 +103,17 @@ public class MailService implements AutoCloseable {
certificate = (X509Certificate) certificates[0]; certificate = (X509Certificate) certificates[0];
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames(); boolean trusted = false;
if (altNames != null)
for (List altName : altNames)
if (altName.get(0).equals(GeneralName.dNSName)) {
String name = (String) altName.get(1);
Log.i("Trusted name=" + name);
if (name.startsWith("*.")) {
// Wildcard certificate
String domain = name.substring(2);
if (TextUtils.isEmpty(domain))
continue;
int dot = server.indexOf("."); String name = getDnsName(certificate);
if (dot < 0) if (name != null && matches(server, name))
continue; trusted = true;
String cdomain = server.substring(dot + 1);
if (TextUtils.isEmpty(cdomain))
continue;
Log.i("Trust " + domain + " =? " + cdomain); if (getFingerPrint(certificate).equals(trustedFingerprint))
if (domain.equalsIgnoreCase(cdomain))
trusted = true;
} else {
Log.i("Trust " + server + " =? " + name);
if (server.equalsIgnoreCase(name))
trusted = true;
}
}
if (fingerprint != null && fingerprint.equals(getFingerPrint()))
trusted = true; trusted = true;
Log.i("Is trusted? server=" + server + " trusted=" + trusted); Log.i("Is trusted? server=" + server + " trusted=" + trusted);
return (configuring || trusted); return trusted;
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(ex); Log.e(ex);
return false; return false;
@ -258,20 +234,8 @@ public class MailService implements AutoCloseable {
this.listener = listener; this.listener = listener;
} }
void setConfiguring() { void setTrustedFingerPrint(String value) {
configuring = true; trustedFingerprint = value;
}
void setFingerPrint(String value) {
fingerprint = value;
}
String getFingerPrint() throws CertificateEncodingException, NoSuchAlgorithmException {
return Helper.sha1(certificate.getEncoded());
}
boolean getTrusted() {
return trusted;
} }
public void connect(EntityAccount account) throws MessagingException { public void connect(EntityAccount account) throws MessagingException {
@ -347,6 +311,22 @@ public class MailService implements AutoCloseable {
} }
throw ex; throw ex;
} catch (MessagingException ex) {
if (ex.getCause() instanceof IOException &&
ex.getCause().getMessage() != null &&
ex.getCause().getMessage().startsWith("Server is not trusted:")) {
String name;
String fingerprint;
try {
name = getDnsName(certificate);
fingerprint = getFingerPrint(certificate);
} catch (Throwable ex1) {
Log.e(ex1);
throw ex;
}
throw new UntrustedException(name, fingerprint);
} else
throw ex;
} }
} }
@ -493,4 +473,66 @@ public class MailService implements AutoCloseable {
context = null; context = null;
} }
} }
static String getDnsName(X509Certificate certificate) throws CertificateParsingException {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
if (altNames == null)
return null;
for (List altName : altNames)
if (altName.get(0).equals(GeneralName.dNSName))
return (String) altName.get(1);
return null;
}
static String getFingerPrint(X509Certificate certificate) throws CertificateEncodingException, NoSuchAlgorithmException {
return Helper.sha1(certificate.getEncoded());
}
static boolean matches(String server, String name) {
if (name.startsWith("*.")) {
// Wildcard certificate
String domain = name.substring(2);
if (TextUtils.isEmpty(domain))
return false;
int dot = server.indexOf(".");
if (dot < 0)
return false;
String cdomain = server.substring(dot + 1);
if (TextUtils.isEmpty(cdomain))
return false;
Log.i("Trust " + domain + " =? " + cdomain);
return domain.equalsIgnoreCase(cdomain);
} else {
Log.i("Trust " + server + " =? " + name);
return server.equalsIgnoreCase(name);
}
}
class UntrustedException extends MessagingException {
private String name;
private String fingerprint;
UntrustedException(String name, String fingerprint) {
this.name = name;
this.fingerprint = fingerprint;
}
String getName() {
return name;
}
String getFingerprint() {
return fingerprint;
}
@Override
public synchronized String toString() {
return this.getClass().getName() + " name=" + name + " fingerprint=" + fingerprint;
}
}
} }