@@ -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 {
@@ -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<String> getCommonNames(X509Certificate certificate) {
+ private static List<String> getCommonNames(final X509Certificate certificate) {
List<String> 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<String, String> parseOtherName(byte[] otherName) {
+ private static Pair<String, String> 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<String> 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<String> commonNames = getCommonNames(certificate);
final Collection<List<?>> alternativeNames = certificate.getSubjectAlternativeNames();
final List<String> 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<String> xmppAddrs;
+ final List<String> xmppAddresses;
final List<String> srvNames;
final List<String> domains;
- private ValidDomains(List<String> xmppAddrs, List<String> srvNames, List<String> domains) {
- this.xmppAddrs = xmppAddrs;
+ private ValidDomains(
+ List<String> xmppAddresses, List<String> srvNames, List<String> domains) {
+ this.xmppAddresses = xmppAddresses;
this.srvNames = srvNames;
this.domains = domains;
}
public List<String> all() {
ImmutableList.Builder<String> 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) {