diff --git a/src/main/java/eu/siacs/conversations/AppSettings.java b/src/main/java/eu/siacs/conversations/AppSettings.java index ac239ff5c..cb25a2335 100644 --- a/src/main/java/eu/siacs/conversations/AppSettings.java +++ b/src/main/java/eu/siacs/conversations/AppSettings.java @@ -119,4 +119,8 @@ public class AppSettings { PreferenceManager.getDefaultSharedPreferences(context); sharedPreferences.edit().putBoolean(SEND_CRASH_REPORTS, value).apply(); } + + public boolean isRequireChannelBinding() { + return getBooleanPreference(REQUIRE_CHANNEL_BINDING, R.bool.require_channel_binding); + } } 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 b8d1d0465..93c722e37 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java @@ -6,17 +6,17 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Collections2; -import java.util.Collection; -import java.util.Collections; - -import javax.net.ssl.SSLSocket; - import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.utils.SSLSockets; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; +import java.util.Collection; +import java.util.Collections; + +import javax.net.ssl.SSLSocket; + public abstract class SaslMechanism { protected final Account account; @@ -170,7 +170,9 @@ public abstract class SaslMechanism { } public static SaslMechanism ensureAvailable( - final SaslMechanism mechanism, final SSLSockets.Version sslVersion) { + final SaslMechanism mechanism, + final SSLSockets.Version sslVersion, + final boolean requireChannelBinding) { if (mechanism instanceof ChannelBindingMechanism) { final ChannelBinding cb = ((ChannelBindingMechanism) mechanism).getChannelBinding(); if (ChannelBinding.isAvailable(cb, sslVersion)) { @@ -181,6 +183,9 @@ public abstract class SaslMechanism { "pinned channel binding method " + cb + " no longer available"); return null; } + } else if (requireChannelBinding) { + Log.d(Config.LOGTAG, "pinned mechanism did not provide channel binding"); + return null; } else { return mechanism; } diff --git a/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java b/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java index 66bc8bb15..0abe88838 100644 --- a/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/fragment/settings/SecuritySettingsFragment.java @@ -70,7 +70,9 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment { requireService().updateMemorizingTrustManager(); reconnectAccounts(); } - case AppSettings.REQUIRE_CHANNEL_BINDING -> {} + case AppSettings.REQUIRE_CHANNEL_BINDING -> { + reconnectAccounts(); + } } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 58f9e5644..6390e891c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -22,6 +22,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.XmppDomainVerifier; @@ -157,6 +158,7 @@ public class XmppConnection implements Runnable { new Hashtable<>(); private final Set advancedStreamFeaturesLoadedListeners = new HashSet<>(); + private final AppSettings appSettings; private final XmppConnectionService mXmppConnectionService; private Socket socket; private XmlReader tagReader; @@ -203,9 +205,10 @@ public class XmppConnection implements Runnable { public XmppConnection(final Account account, final XmppConnectionService service) { this.account = account; this.mXmppConnectionService = service; + this.appSettings = new AppSettings(mXmppConnectionService.getApplicationContext()); } - private static void fixResource(Context context, Account account) { + private static void fixResource(final Context context, final Account account) { String resource = account.getResource(); int fixedPartLength = context.getString(R.string.app_name).length() + 1; // include the trailing dot @@ -1646,6 +1649,7 @@ public class XmppConnection implements Runnable { + mechanisms); throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER); } + validateRequireChannelBinding(saslMechanism); if (SaslMechanism.hashedToken(saslMechanism)) { return; } @@ -1664,6 +1668,17 @@ public class XmppConnection implements Runnable { } } + private void validateRequireChannelBinding(@NonNull final SaslMechanism mechanism) + throws StateChangingException { + if (appSettings.isRequireChannelBinding()) { + if (mechanism instanceof ChannelBindingMechanism) { + return; + } + Log.d(Config.LOGTAG, account.getJid() + ": server did not offer channel binding"); + throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER); + } + } + private Element generateAuthenticationRequest( final String firstMessage, final boolean usingFast) { return generateAuthenticationRequest( @@ -2365,7 +2380,10 @@ public class XmppConnection implements Runnable { final SaslMechanism quickStartMechanism; if (secureConnection) { quickStartMechanism = - SaslMechanism.ensureAvailable(account.getQuickStartMechanism(), sslVersion); + SaslMechanism.ensureAvailable( + account.getQuickStartMechanism(), + sslVersion, + appSettings.isRequireChannelBinding()); } else { quickStartMechanism = null; } diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index 7433ad68b..40179e6e3 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -44,4 +44,5 @@ true up.conversations.im none + false diff --git a/src/main/res/xml/preferences_security.xml b/src/main/res/xml/preferences_security.xml index 86bd6c87e..2ca87b504 100644 --- a/src/main/res/xml/preferences_security.xml +++ b/src/main/res/xml/preferences_security.xml @@ -30,6 +30,7 @@ android:title="@string/pref_remove_trusted_certificates_title" />