From f764b24ffc1089cad147887053d8b64d8207b248 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 5 Aug 2024 10:59:59 +0200 Subject: [PATCH] bump bc version. refactor XmppDomainVerifier to work with new api --- build.gradle | 4 +- .../crypto/XmppDomainVerifier.java | 74 ++++++++++++------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/build.gradle b/build.gradle index 2086c8c0274c66104e400be65c6693ecf2cd5b46..0b3510414ab0fbd069de75d283af023ec7ad2b3d 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ dependencies { implementation "androidx.emoji2:emoji2:1.4.0" freeImplementation "androidx.emoji2:emoji2-bundled:1.4.0" - implementation 'org.bouncycastle:bcmail-jdk15on:1.64' + implementation 'org.bouncycastle:bcmail-jdk18on:1.78.1' //zxing stopped supporting Java 7 so we have to stick with 3.3.3 //https://github.com/zxing/zxing/issues/1170 implementation 'com.google.zxing:core:3.3.3' @@ -243,7 +243,7 @@ android { } packagingOptions { resources { - excludes += ['META-INF/BCKEY.DSA', 'META-INF/BCKEY.SF'] + excludes += ['META-INF/BCKEY.DSA', 'META-INF/BCKEY.SF', 'META-INF/versions/9/OSGI-INF/MANIFEST.MF'] } } lint { diff --git a/src/main/java/eu/siacs/conversations/crypto/XmppDomainVerifier.java b/src/main/java/eu/siacs/conversations/crypto/XmppDomainVerifier.java index ed17c5695bcf4cbca881dd97882a39c376fb34c1..4e43dd93ab487f9159c7261d3aca2c8509b9b5a4 100644 --- a/src/main/java/eu/siacs/conversations/crypto/XmppDomainVerifier.java +++ b/src/main/java/eu/siacs/conversations/crypto/XmppDomainVerifier.java @@ -3,11 +3,13 @@ package eu.siacs.conversations.crypto; import android.util.Log; import android.util.Pair; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; +import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DLSequence; import org.bouncycastle.asn1.x500.RDN; @@ -37,13 +39,15 @@ public class XmppDomainVerifier { private static final String SRV_NAME = "1.3.6.1.5.5.7.8.7"; private static final String XMPP_ADDR = "1.3.6.1.5.5.7.8.5"; - private static List getCommonNames(X509Certificate certificate) { + private static List getCommonNames(final X509Certificate certificate) { List domains = new ArrayList<>(); try { X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject(); RDN[] rdns = x500name.getRDNs(BCStyle.CN); for (int i = 0; i < rdns.length; ++i) { - domains.add(IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[i].getFirst().getValue())); + domains.add( + IETFUtils.valueToString( + x500name.getRDNs(BCStyle.CN)[i].getFirst().getValue())); } return domains; } catch (CertificateEncodingException e) { @@ -51,26 +55,26 @@ public class XmppDomainVerifier { } } - private static Pair parseOtherName(byte[] otherName) { + private static Pair parseOtherName(final byte[] otherName) { try { ASN1Primitive asn1Primitive = ASN1Primitive.fromByteArray(otherName); - if (asn1Primitive instanceof DERTaggedObject) { - ASN1Primitive inner = ((DERTaggedObject) asn1Primitive).getObject(); - if (inner instanceof DLSequence) { - DLSequence sequence = (DLSequence) inner; - if (sequence.size() >= 2 && sequence.getObjectAt(1) instanceof DERTaggedObject) { - String oid = sequence.getObjectAt(0).toString(); - ASN1Primitive value = ((DERTaggedObject) sequence.getObjectAt(1)).getObject(); - if (value instanceof DERUTF8String) { - return new Pair<>(oid, ((DERUTF8String) value).getString()); - } else if (value instanceof DERIA5String) { - return new Pair<>(oid, ((DERIA5String) value).getString()); + if (asn1Primitive instanceof ASN1TaggedObject taggedObject) { + final ASN1Object inner = taggedObject.getBaseObject(); + if (inner instanceof DLSequence sequence) { + if (sequence.size() >= 2 + && sequence.getObjectAt(1) instanceof ASN1TaggedObject evenInner) { + final String oid = sequence.getObjectAt(0).toString(); + final ASN1Object value = evenInner.getBaseObject(); + if (value instanceof DERUTF8String derutf8String) { + return new Pair<>(oid, derutf8String.getString()); + } else if (value instanceof DERIA5String deria5String) { + return new Pair<>(oid, deria5String.getString()); } } } } return null; - } catch (IOException e) { + } catch (final IOException e) { return null; } } @@ -98,14 +102,15 @@ public class XmppDomainVerifier { return false; } - public boolean verify(final String unicodeDomain, final String unicodeHostname, SSLSession sslSession) throws SSLPeerUnverifiedException { + public boolean verify( + final String unicodeDomain, final String unicodeHostname, SSLSession sslSession) + throws SSLPeerUnverifiedException { final String domain = IDN.toASCII(unicodeDomain); final String hostname = unicodeHostname == null ? null : IDN.toASCII(unicodeHostname); final Certificate[] chain = sslSession.getPeerCertificates(); - if (chain.length == 0 || !(chain[0] instanceof X509Certificate)) { + if (chain.length == 0 || !(chain[0] instanceof X509Certificate certificate)) { return false; } - final X509Certificate certificate = (X509Certificate) chain[0]; final List commonNames = getCommonNames(certificate); if (isSelfSigned(certificate)) { if (commonNames.size() == 1 && matchDomain(domain, commonNames)) { @@ -115,11 +120,11 @@ public class XmppDomainVerifier { } try { final ValidDomains validDomains = parseValidDomains(certificate); - Log.d(LOGTAG, "searching for " + domain + " in srvNames: " + validDomains.srvNames + " xmppAddrs: " + validDomains.xmppAddrs + " domains:" + validDomains.domains); + Log.d(LOGTAG, "searching for " + domain + " in " + validDomains); if (hostname != null) { Log.d(LOGTAG, "also trying to verify hostname " + hostname); } - return validDomains.xmppAddrs.contains(domain) + return validDomains.xmppAddresses.contains(domain) || validDomains.srvNames.contains("_xmpp-client." + domain) || matchDomain(domain, validDomains.domains) || (hostname != null && matchDomain(hostname, validDomains.domains)); @@ -128,7 +133,8 @@ public class XmppDomainVerifier { } } - public static ValidDomains parseValidDomains(final X509Certificate certificate) throws CertificateParsingException { + public static ValidDomains parseValidDomains(final X509Certificate certificate) + throws CertificateParsingException { final List commonNames = getCommonNames(certificate); final Collection> alternativeNames = certificate.getSubjectAlternativeNames(); final List xmppAddrs = new ArrayList<>(); @@ -148,7 +154,9 @@ public class XmppDomainVerifier { xmppAddrs.add(otherName.second.toLowerCase(Locale.US)); break; default: - Log.d(LOGTAG, "oid: " + otherName.first + " value: " + otherName.second); + Log.d( + LOGTAG, + "oid: " + otherName.first + " value: " + otherName.second); } } } else if (type == 2) { @@ -159,30 +167,40 @@ public class XmppDomainVerifier { } } } - if (srvNames.size() == 0 && xmppAddrs.size() == 0 && domains.size() == 0) { + if (srvNames.isEmpty() && xmppAddrs.isEmpty() && domains.isEmpty()) { domains.addAll(commonNames); } return new ValidDomains(xmppAddrs, srvNames, domains); } public static final class ValidDomains { - final List xmppAddrs; + final List xmppAddresses; final List srvNames; final List domains; - private ValidDomains(List xmppAddrs, List srvNames, List domains) { - this.xmppAddrs = xmppAddrs; + private ValidDomains( + List xmppAddresses, List srvNames, List domains) { + this.xmppAddresses = xmppAddresses; this.srvNames = srvNames; this.domains = domains; } public List all() { ImmutableList.Builder all = new ImmutableList.Builder<>(); - all.addAll(xmppAddrs); + all.addAll(xmppAddresses); all.addAll(srvNames); all.addAll(domains); return all.build(); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("xmppAddresses", xmppAddresses) + .add("srvNames", srvNames) + .add("domains", domains) + .toString(); + } } private boolean isSelfSigned(X509Certificate certificate) {