From a717917b3de98b8d88bed4145dae15fd968f5f00 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 29 Aug 2022 15:09:53 +0200 Subject: [PATCH] explicitly search for namespaces when processing stream features --- .../crypto/sasl/SaslMechanism.java | 4 ++ .../eu/siacs/conversations/xml/Namespace.java | 2 + .../conversations/xmpp/XmppConnection.java | 48 ++++++++++++++----- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java index 86fd6524e..f6024210a 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java @@ -66,4 +66,8 @@ public abstract class SaslMechanism { public String getResponse(final String challenge) throws AuthenticationException { return ""; } + + public enum Version { + SASL, SASL_2 + } } diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 72c35a92f..c2a7af607 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -7,6 +7,7 @@ public final class Namespace { public static final String BLOCKING = "urn:xmpp:blocking"; public static final String ROSTER = "jabber:iq:roster"; public static final String REGISTER = "jabber:iq:register"; + public static final String REGISTER_STREAM_FEATURE = "http://jabber.org/features/iq-register"; public static final String BYTE_STREAMS = "http://jabber.org/protocol/bytestreams"; public static final String HTTP_UPLOAD = "urn:xmpp:http:upload:0"; public static final String HTTP_UPLOAD_LEGACY = "urn:xmpp:http:upload"; @@ -15,6 +16,7 @@ public final class Namespace { public static final String DATA = "jabber:x:data"; public static final String OOB = "jabber:x:oob"; public static final String SASL = "urn:ietf:params:xml:ns:xmpp-sasl"; + public static final String SASL_2 = "urn:xmpp:sasl:1"; public static final String TLS = "urn:ietf:params:xml:ns:xmpp-tls"; public static final String PUBSUB = "http://jabber.org/protocol/pubsub"; public static final String PUBSUB_PUBLISH_OPTIONS = PUBSUB + "#publish-options"; diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 06195aaed..2222da3e2 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -848,40 +848,64 @@ public class XmppConnection implements Runnable { private void processStreamFeatures(final Tag currentTag) throws IOException { this.streamFeatures = tagReader.readElement(currentTag); - final boolean isSecure = features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS || account.isOnion(); + Log.d(Config.LOGTAG, this.streamFeatures.toString()); + final boolean isSecure = + features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS || account.isOnion(); final boolean needsBinding = !isBound && !account.isOptionSet(Account.OPTION_REGISTER); - if (this.streamFeatures.hasChild("starttls") && !features.encryptionEnabled) { + if (this.streamFeatures.hasChild("starttls", Namespace.TLS) + && !features.encryptionEnabled) { sendStartTLS(); - } else if (this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER)) { + } else if (this.streamFeatures.hasChild("register", Namespace.REGISTER_STREAM_FEATURE) + && account.isOptionSet(Account.OPTION_REGISTER)) { if (isSecure) { register(); } else { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to find STARTTLS for registration process " + XmlHelper.printElementNames(this.streamFeatures)); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": unable to find STARTTLS for registration process " + + XmlHelper.printElementNames(this.streamFeatures)); throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER); } - } else if (!this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER)) { + } else if (!this.streamFeatures.hasChild("register", Namespace.REGISTER_STREAM_FEATURE) + && account.isOptionSet(Account.OPTION_REGISTER)) { throw new StateChangingException(Account.State.REGISTRATION_NOT_SUPPORTED); - } else if (this.streamFeatures.hasChild("mechanisms") && shouldAuthenticate && isSecure) { - authenticate(); - } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) { + } else if (this.streamFeatures.hasChild("mechanisms", Namespace.SASL_2) + && shouldAuthenticate + && isSecure) { + authenticate(SaslMechanism.Version.SASL_2); + } else if (this.streamFeatures.hasChild("mechanisms", Namespace.SASL) + && shouldAuthenticate + && isSecure) { + authenticate(SaslMechanism.Version.SASL); + } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) + && streamId != null) { if (Config.EXTENDED_SM_LOGGING) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": resuming after stanza #" + stanzasReceived); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": resuming after stanza #" + + stanzasReceived); } final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion); this.mSmCatchupMessageCounter.set(0); this.mWaitingForSmCatchup.set(true); this.tagWriter.writeStanzaAsync(resume); } else if (needsBinding) { - if (this.streamFeatures.hasChild("bind") && isSecure) { + if (this.streamFeatures.hasChild("bind", Namespace.BIND) && isSecure) { sendBindRequest(); } else { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to find bind feature " + XmlHelper.printElementNames(this.streamFeatures)); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": unable to find bind feature " + + XmlHelper.printElementNames(this.streamFeatures)); throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER); } } } - private void authenticate() throws IOException { + private void authenticate(final SaslMechanism.Version version) throws IOException { final List mechanisms = extractMechanisms(streamFeatures.findChild("mechanisms")); final Element auth = new Element("auth", Namespace.SASL); if (mechanisms.contains(External.MECHANISM) && account.getPrivateKeyAlias() != null) {