diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index ac265d502f..100eca1ee6 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -20,7 +20,10 @@ import net.openid.appauth.ClientAuthentication; import net.openid.appauth.ClientSecretPost; import net.openid.appauth.NoClientAuthentication; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -306,7 +309,7 @@ public class EmailService implements AutoCloseable { Throwable ce = ex; while (ce != null) { if (factory != null && ce instanceof CertificateException) - throw new UntrustedException(factory.getFingerPrint(), ex); + throw new UntrustedException(factory.getFingerPrintSelect(), ex); if (ce instanceof IOException) ioError = true; ce = ce.getCause(); @@ -563,6 +566,8 @@ public class EmailService implements AutoCloseable { final X509TrustManager rtm = (X509TrustManager) tms[0]; X509TrustManager tm = new X509TrustManager() { + // openssl s_client -connect + @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (secure) @@ -574,16 +579,8 @@ public class EmailService implements AutoCloseable { certificate = chain[0]; if (secure) { - // Get certificate fingerprint - String fingerprint; - try { - fingerprint = getFingerPrint(certificate); - } catch (Throwable ex) { - throw new CertificateException(ex); - } - // Check if selected fingerprint - if (fingerprint.equals(trustedFingerprint)) { + if (trustedFingerprint != null && matches(certificate, trustedFingerprint)) { Log.i("Trusted selected fingerprint"); return; } @@ -731,13 +728,48 @@ public class EmailService implements AutoCloseable { return result; } + private static boolean matches(X509Certificate certificate, @NonNull String trustedFingerprint) { + // Get certificate fingerprint + try { + String fingerprint = getFingerPrint(certificate); + int slash = trustedFingerprint.indexOf('/'); + if (slash < 0) + return trustedFingerprint.equals(fingerprint); + else { + String keyId = getKeyId(certificate); + if (trustedFingerprint.substring(slash + 1).equals(keyId)) + return true; + return trustedFingerprint.substring(0, slash).equals(fingerprint); + } + } catch (Throwable ex) { + Log.w(ex); + return false; + } + } + + private static String getKeyId(X509Certificate certificate) { + try { + byte[] extension = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId()); + if (extension == null) + return null; + byte[] bytes = DEROctetString.getInstance(extension).getOctets(); + SubjectKeyIdentifier keyId = SubjectKeyIdentifier.getInstance(bytes); + return Helper.hex(keyId.getKeyIdentifier()); + } catch (Throwable ex) { + Log.e(ex); + return null; + } + } + private static String getFingerPrint(X509Certificate certificate) throws CertificateEncodingException, NoSuchAlgorithmException { return Helper.sha1(certificate.getEncoded()); } - String getFingerPrint() { + String getFingerPrintSelect() { try { - return getFingerPrint(certificate); + String keyId = getKeyId(certificate); + String fingerPrint = getFingerPrint(certificate); + return fingerPrint + (keyId == null ? "" : "/" + keyId); } catch (Throwable ex) { Log.e(ex); return null; diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java index 669090c634..35745febdc 100644 --- a/app/src/main/java/eu/faircode/email/Helper.java +++ b/app/src/main/java/eu/faircode/email/Helper.java @@ -829,6 +829,10 @@ public class Helper { static String sha(String digest, byte[] data) throws NoSuchAlgorithmException { byte[] bytes = MessageDigest.getInstance(digest).digest(data); + return hex(bytes); + } + + static String hex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) sb.append(String.format("%02x", b));