extract channel binding types via XEP-0440
This commit is contained in:
parent
a210568a9c
commit
b78acb6fca
|
@ -0,0 +1,27 @@
|
|||
package eu.siacs.conversations.crypto.sasl;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
|
||||
public enum ChannelBinding {
|
||||
NONE,
|
||||
TLS_EXPORTER,
|
||||
TLS_SERVER_END_POINT,
|
||||
TLS_UNIQUE;
|
||||
|
||||
public static ChannelBinding of(final String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return valueOf(
|
||||
CaseFormat.LOWER_HYPHEN.converterTo(CaseFormat.UPPER_UNDERSCORE).convert(type));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
Log.d(Config.LOGTAG, type + " is not a known channel binding");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,7 +90,8 @@ public abstract class SaslMechanism {
|
|||
this.account = account;
|
||||
}
|
||||
|
||||
public SaslMechanism of(final Collection<String> mechanisms) {
|
||||
public SaslMechanism of(
|
||||
final Collection<String> mechanisms, final Collection<ChannelBinding> bindings) {
|
||||
if (mechanisms.contains(External.MECHANISM) && account.getPrivateKeyAlias() != null) {
|
||||
return new External(account);
|
||||
} else if (mechanisms.contains(ScramSha512.MECHANISM)) {
|
||||
|
|
|
@ -25,14 +25,15 @@ abstract class ScramMechanism extends SaslMechanism {
|
|||
private static final byte[] SERVER_KEY_BYTES = "Server Key".getBytes();
|
||||
private static final Cache<CacheKey, KeyPair> CACHE =
|
||||
CacheBuilder.newBuilder().maximumSize(10).build();
|
||||
protected final ChannelBinding channelBinding;
|
||||
private final String clientNonce;
|
||||
protected State state = State.INITIAL;
|
||||
private String clientFirstMessageBare;
|
||||
private byte[] serverSignature = null;
|
||||
|
||||
ScramMechanism(final Account account) {
|
||||
ScramMechanism(final Account account, final ChannelBinding channelBinding) {
|
||||
super(account);
|
||||
|
||||
this.channelBinding = channelBinding;
|
||||
// This nonce should be different for each authentication attempt.
|
||||
this.clientNonce = CryptoHelper.random(100);
|
||||
clientFirstMessageBare = "";
|
||||
|
|
|
@ -11,7 +11,7 @@ public class ScramSha1 extends ScramMechanism {
|
|||
public static final String MECHANISM = "SCRAM-SHA-1";
|
||||
|
||||
public ScramSha1(final Account account) {
|
||||
super(account);
|
||||
super(account, ChannelBinding.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,7 +11,7 @@ public class ScramSha256 extends ScramMechanism {
|
|||
public static final String MECHANISM = "SCRAM-SHA-256";
|
||||
|
||||
public ScramSha256(final Account account) {
|
||||
super(account);
|
||||
super(account, ChannelBinding.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,7 +11,7 @@ public class ScramSha512 extends ScramMechanism {
|
|||
public static final String MECHANISM = "SCRAM-SHA-512";
|
||||
|
||||
public ScramSha512(final Account account) {
|
||||
super(account);
|
||||
super(account, ChannelBinding.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,7 @@ public final class Namespace {
|
|||
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 CHANNEL_BINDING = "urn:xmpp:sasl-cb:0";
|
||||
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";
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.util.SparseArray;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Collections2;
|
||||
|
||||
|
@ -62,14 +63,8 @@ import eu.siacs.conversations.Config;
|
|||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.crypto.sasl.Anonymous;
|
||||
import eu.siacs.conversations.crypto.sasl.DigestMd5;
|
||||
import eu.siacs.conversations.crypto.sasl.External;
|
||||
import eu.siacs.conversations.crypto.sasl.Plain;
|
||||
import eu.siacs.conversations.crypto.sasl.ChannelBinding;
|
||||
import eu.siacs.conversations.crypto.sasl.SaslMechanism;
|
||||
import eu.siacs.conversations.crypto.sasl.ScramSha1;
|
||||
import eu.siacs.conversations.crypto.sasl.ScramSha256;
|
||||
import eu.siacs.conversations.crypto.sasl.ScramSha512;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||
|
@ -720,7 +715,7 @@ public class XmppConnection implements Runnable {
|
|||
Log.d(
|
||||
Config.LOGTAG,
|
||||
account.getJid().asBareJid().toString() + ": logged in (using " + version + ")");
|
||||
//TODO store mechanism name
|
||||
// TODO store mechanism name
|
||||
account.setKey(Account.PINNED_MECHANISM_KEY, String.valueOf(saslMechanism.getPriority()));
|
||||
if (version == SaslMechanism.Version.SASL_2) {
|
||||
final String authorizationIdentifier =
|
||||
|
@ -784,7 +779,7 @@ public class XmppConnection implements Runnable {
|
|||
account.getJid().asBareJid() + ": successfully enabled carbons");
|
||||
features.carbonsEnabled = true;
|
||||
}
|
||||
//TODO if both are set mark account ready for pipelining
|
||||
// TODO if both are set mark account ready for pipelining
|
||||
sendPostBindInitialization(streamManagementEnabled != null, carbonsEnabled != null);
|
||||
}
|
||||
}
|
||||
|
@ -1218,10 +1213,30 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
|
||||
private void authenticate(final SaslMechanism.Version version) throws IOException {
|
||||
final Element element = streamFeatures.findChild("mechanisms");
|
||||
final Collection<String> mechanisms = Collections2.transform(element.getChildren(), c -> c == null ? null : c.getContent());
|
||||
Log.d(Config.LOGTAG, "stream features: " + this.streamFeatures);
|
||||
final Element element =
|
||||
this.streamFeatures.findChild("mechanisms"); // TODO get from correct NS
|
||||
final Collection<String> mechanisms =
|
||||
Collections2.transform(
|
||||
Collections2.filter(
|
||||
element.getChildren(),
|
||||
c -> c != null && "mechanism".equals(c.getName())),
|
||||
c -> c == null ? null : c.getContent());
|
||||
final Element cbElement =
|
||||
this.streamFeatures.findChild("sasl-channel-binding", Namespace.CHANNEL_BINDING);
|
||||
final Collection<ChannelBinding> channelBindings =
|
||||
Collections2.filter(
|
||||
Collections2.transform(
|
||||
Collections2.filter(
|
||||
cbElement == null
|
||||
? Collections.emptyList()
|
||||
: cbElement.getChildren(),
|
||||
c -> c != null && "channel-binding".equals(c.getName())),
|
||||
c -> c == null ? null : ChannelBinding.of(c.getAttribute("type"))),
|
||||
Predicates.notNull());
|
||||
Log.d(Config.LOGTAG, "channel bindings: " + channelBindings);
|
||||
final SaslMechanism.Factory factory = new SaslMechanism.Factory(account);
|
||||
this.saslMechanism = factory.of(mechanisms);
|
||||
this.saslMechanism = factory.of(mechanisms, channelBindings);
|
||||
|
||||
if (saslMechanism == null) {
|
||||
Log.d(
|
||||
|
|
Loading…
Reference in a new issue