add require channel binding
This commit is contained in:
parent
7bdd924dd8
commit
32de58ce65
|
@ -119,4 +119,8 @@ public class AppSettings {
|
||||||
PreferenceManager.getDefaultSharedPreferences(context);
|
PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
sharedPreferences.edit().putBoolean(SEND_CRASH_REPORTS, value).apply();
|
sharedPreferences.edit().putBoolean(SEND_CRASH_REPORTS, value).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRequireChannelBinding() {
|
||||||
|
return getBooleanPreference(REQUIRE_CHANNEL_BINDING, R.bool.require_channel_binding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@ import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Collections2;
|
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.Config;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.utils.SSLSockets;
|
import eu.siacs.conversations.utils.SSLSockets;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
|
||||||
public abstract class SaslMechanism {
|
public abstract class SaslMechanism {
|
||||||
|
|
||||||
protected final Account account;
|
protected final Account account;
|
||||||
|
@ -170,7 +170,9 @@ public abstract class SaslMechanism {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaslMechanism ensureAvailable(
|
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) {
|
if (mechanism instanceof ChannelBindingMechanism) {
|
||||||
final ChannelBinding cb = ((ChannelBindingMechanism) mechanism).getChannelBinding();
|
final ChannelBinding cb = ((ChannelBindingMechanism) mechanism).getChannelBinding();
|
||||||
if (ChannelBinding.isAvailable(cb, sslVersion)) {
|
if (ChannelBinding.isAvailable(cb, sslVersion)) {
|
||||||
|
@ -181,6 +183,9 @@ public abstract class SaslMechanism {
|
||||||
"pinned channel binding method " + cb + " no longer available");
|
"pinned channel binding method " + cb + " no longer available");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
} else if (requireChannelBinding) {
|
||||||
|
Log.d(Config.LOGTAG, "pinned mechanism did not provide channel binding");
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return mechanism;
|
return mechanism;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,9 @@ public class SecuritySettingsFragment extends XmppPreferenceFragment {
|
||||||
requireService().updateMemorizingTrustManager();
|
requireService().updateMemorizingTrustManager();
|
||||||
reconnectAccounts();
|
reconnectAccounts();
|
||||||
}
|
}
|
||||||
case AppSettings.REQUIRE_CHANNEL_BINDING -> {}
|
case AppSettings.REQUIRE_CHANNEL_BINDING -> {
|
||||||
|
reconnectAccounts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.AppSettings;
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
||||||
|
@ -157,6 +158,7 @@ public class XmppConnection implements Runnable {
|
||||||
new Hashtable<>();
|
new Hashtable<>();
|
||||||
private final Set<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners =
|
private final Set<OnAdvancedStreamFeaturesLoaded> advancedStreamFeaturesLoadedListeners =
|
||||||
new HashSet<>();
|
new HashSet<>();
|
||||||
|
private final AppSettings appSettings;
|
||||||
private final XmppConnectionService mXmppConnectionService;
|
private final XmppConnectionService mXmppConnectionService;
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private XmlReader tagReader;
|
private XmlReader tagReader;
|
||||||
|
@ -203,9 +205,10 @@ public class XmppConnection implements Runnable {
|
||||||
public XmppConnection(final Account account, final XmppConnectionService service) {
|
public XmppConnection(final Account account, final XmppConnectionService service) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.mXmppConnectionService = service;
|
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();
|
String resource = account.getResource();
|
||||||
int fixedPartLength =
|
int fixedPartLength =
|
||||||
context.getString(R.string.app_name).length() + 1; // include the trailing dot
|
context.getString(R.string.app_name).length() + 1; // include the trailing dot
|
||||||
|
@ -1646,6 +1649,7 @@ public class XmppConnection implements Runnable {
|
||||||
+ mechanisms);
|
+ mechanisms);
|
||||||
throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER);
|
throw new StateChangingException(Account.State.INCOMPATIBLE_SERVER);
|
||||||
}
|
}
|
||||||
|
validateRequireChannelBinding(saslMechanism);
|
||||||
if (SaslMechanism.hashedToken(saslMechanism)) {
|
if (SaslMechanism.hashedToken(saslMechanism)) {
|
||||||
return;
|
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(
|
private Element generateAuthenticationRequest(
|
||||||
final String firstMessage, final boolean usingFast) {
|
final String firstMessage, final boolean usingFast) {
|
||||||
return generateAuthenticationRequest(
|
return generateAuthenticationRequest(
|
||||||
|
@ -2365,7 +2380,10 @@ public class XmppConnection implements Runnable {
|
||||||
final SaslMechanism quickStartMechanism;
|
final SaslMechanism quickStartMechanism;
|
||||||
if (secureConnection) {
|
if (secureConnection) {
|
||||||
quickStartMechanism =
|
quickStartMechanism =
|
||||||
SaslMechanism.ensureAvailable(account.getQuickStartMechanism(), sslVersion);
|
SaslMechanism.ensureAvailable(
|
||||||
|
account.getQuickStartMechanism(),
|
||||||
|
sslVersion,
|
||||||
|
appSettings.isRequireChannelBinding());
|
||||||
} else {
|
} else {
|
||||||
quickStartMechanism = null;
|
quickStartMechanism = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,4 +44,5 @@
|
||||||
<bool name="allow_screenshots">true</bool>
|
<bool name="allow_screenshots">true</bool>
|
||||||
<string name="default_push_server">up.conversations.im</string>
|
<string name="default_push_server">up.conversations.im</string>
|
||||||
<string name="default_push_account">none</string>
|
<string name="default_push_account">none</string>
|
||||||
|
<bool name="require_channel_binding">false</bool>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
android:title="@string/pref_remove_trusted_certificates_title" />
|
android:title="@string/pref_remove_trusted_certificates_title" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="@bool/require_channel_binding"
|
||||||
android:icon="@drawable/ic_private_connectivity_24dp"
|
android:icon="@drawable/ic_private_connectivity_24dp"
|
||||||
android:key="channel_binding_required"
|
android:key="channel_binding_required"
|
||||||
android:summary="@string/detect_mim_summary"
|
android:summary="@string/detect_mim_summary"
|
||||||
|
@ -37,8 +38,8 @@
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/pref_category_on_this_device">
|
<PreferenceCategory android:title="@string/pref_category_on_this_device">
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:icon="@drawable/ic_auto_delete_24dp"
|
|
||||||
android:defaultValue="@integer/automatic_message_deletion"
|
android:defaultValue="@integer/automatic_message_deletion"
|
||||||
|
android:icon="@drawable/ic_auto_delete_24dp"
|
||||||
android:key="automatic_message_deletion"
|
android:key="automatic_message_deletion"
|
||||||
android:summary="@string/pref_automatically_delete_messages_description"
|
android:summary="@string/pref_automatically_delete_messages_description"
|
||||||
android:title="@string/pref_automatically_delete_messages" />
|
android:title="@string/pref_automatically_delete_messages" />
|
||||||
|
|
Loading…
Reference in a new issue