parse hash token names
This commit is contained in:
parent
0cd416298d
commit
3378447f60
|
@ -60,7 +60,7 @@ public final class Config {
|
||||||
public static final long CONTACT_SYNC_RETRY_INTERVAL = 1000L * 60 * 5;
|
public static final long CONTACT_SYNC_RETRY_INTERVAL = 1000L * 60 * 5;
|
||||||
|
|
||||||
|
|
||||||
public static final boolean QUICKSTART_ENABLED = true;
|
public static final boolean QUICKSTART_ENABLED = false;
|
||||||
|
|
||||||
//Notification settings
|
//Notification settings
|
||||||
public static final boolean HIDE_MESSAGE_TEXT_IN_NOTIFICATION = false;
|
public static final boolean HIDE_MESSAGE_TEXT_IN_NOTIFICATION = false;
|
||||||
|
|
|
@ -6,7 +6,9 @@ import com.google.common.base.CaseFormat;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -23,6 +25,16 @@ public enum ChannelBinding {
|
||||||
TLS_SERVER_END_POINT,
|
TLS_SERVER_END_POINT,
|
||||||
TLS_UNIQUE;
|
TLS_UNIQUE;
|
||||||
|
|
||||||
|
public static final BiMap<ChannelBinding, String> SHORT_NAMES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final ImmutableBiMap.Builder<ChannelBinding, String> builder = ImmutableBiMap.builder();
|
||||||
|
for (final ChannelBinding cb : values()) {
|
||||||
|
builder.put(cb, shortName(cb));
|
||||||
|
}
|
||||||
|
SHORT_NAMES = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
public static Collection<ChannelBinding> of(final Element channelBinding) {
|
public static Collection<ChannelBinding> of(final Element channelBinding) {
|
||||||
Preconditions.checkArgument(
|
Preconditions.checkArgument(
|
||||||
channelBinding == null
|
channelBinding == null
|
||||||
|
@ -85,7 +97,24 @@ public enum ChannelBinding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean ensureBest(final ChannelBinding channelBinding, final SSLSockets.Version sslVersion) {
|
public static boolean ensureBest(
|
||||||
return ChannelBinding.best(Collections.singleton(channelBinding), sslVersion) == channelBinding;
|
final ChannelBinding channelBinding, final SSLSockets.Version sslVersion) {
|
||||||
|
return ChannelBinding.best(Collections.singleton(channelBinding), sslVersion)
|
||||||
|
== channelBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String shortName(final ChannelBinding channelBinding) {
|
||||||
|
switch (channelBinding) {
|
||||||
|
case TLS_UNIQUE:
|
||||||
|
return "UNIQ";
|
||||||
|
case TLS_EXPORTER:
|
||||||
|
return "EXPR";
|
||||||
|
case TLS_SERVER_END_POINT:
|
||||||
|
return "ENDP";
|
||||||
|
case NONE:
|
||||||
|
return "NONE";
|
||||||
|
default:
|
||||||
|
throw new AssertionError("Missing short name for " + channelBinding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
package eu.siacs.conversations.crypto.sasl;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.hash.HashFunction;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
import eu.siacs.conversations.utils.SSLSockets;
|
||||||
|
|
||||||
|
public abstract class HashedToken extends SaslMechanism {
|
||||||
|
|
||||||
|
private static List<String> HASH_FUNCTIONS = Arrays.asList("SHA-512", "SHA-256");
|
||||||
|
|
||||||
|
protected final ChannelBinding channelBinding;
|
||||||
|
|
||||||
|
protected HashedToken(final Account account, final ChannelBinding channelBinding) {
|
||||||
|
super(account);
|
||||||
|
this.channelBinding = channelBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClientFirstMessage() {
|
||||||
|
return null; // HMAC(token, "Initiator" || cb-data)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResponse(final String challenge, final SSLSocket socket)
|
||||||
|
throws AuthenticationException {
|
||||||
|
// todo verify that challenge matches HMAC(token, "Responder" || cb-data)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract HashFunction getHashFunction(final byte[] key);
|
||||||
|
|
||||||
|
public static final class Mechanism {
|
||||||
|
public final String hashFunction;
|
||||||
|
public final ChannelBinding channelBinding;
|
||||||
|
|
||||||
|
public Mechanism(String hashFunction, ChannelBinding channelBinding) {
|
||||||
|
this.hashFunction = hashFunction;
|
||||||
|
this.channelBinding = channelBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Mechanism of(final String mechanism) {
|
||||||
|
final int first = mechanism.indexOf('-');
|
||||||
|
final int last = mechanism.lastIndexOf('-');
|
||||||
|
if (last <= first || mechanism.length() <= last) {
|
||||||
|
throw new IllegalArgumentException("Not a valid HashedToken name");
|
||||||
|
}
|
||||||
|
if (mechanism.substring(0, first).equals("HT")) {
|
||||||
|
final String hashFunction = mechanism.substring(first + 1, last);
|
||||||
|
final String cbShortName = mechanism.substring(last + 1);
|
||||||
|
final ChannelBinding channelBinding =
|
||||||
|
ChannelBinding.SHORT_NAMES.inverse().get(cbShortName);
|
||||||
|
if (channelBinding == null) {
|
||||||
|
throw new IllegalArgumentException("Unknown channel binding " + cbShortName);
|
||||||
|
}
|
||||||
|
return new Mechanism(hashFunction, channelBinding);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("HashedToken name does not start with HT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Multimap<String, ChannelBinding> of(final Collection<String> mechanisms) {
|
||||||
|
final ImmutableMultimap.Builder<String, ChannelBinding> builder =
|
||||||
|
ImmutableMultimap.builder();
|
||||||
|
for (final String name : mechanisms) {
|
||||||
|
try {
|
||||||
|
final Mechanism mechanism = Mechanism.of(name);
|
||||||
|
builder.put(mechanism.hashFunction, mechanism.channelBinding);
|
||||||
|
} catch (final IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Mechanism best(
|
||||||
|
final Collection<String> mechanisms, final SSLSockets.Version sslVersion) {
|
||||||
|
final Multimap<String, ChannelBinding> multimap = of(mechanisms);
|
||||||
|
for (final String hashFunction : HASH_FUNCTIONS) {
|
||||||
|
final Collection<ChannelBinding> channelBindings = multimap.get(hashFunction);
|
||||||
|
if (channelBindings.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final ChannelBinding cb = ChannelBinding.best(channelBindings, sslVersion);
|
||||||
|
return new Mechanism(hashFunction, cb);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("hashFunction", hashFunction)
|
||||||
|
.add("channelBinding", channelBinding)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.siacs.conversations.crypto.sasl;
|
||||||
|
|
||||||
|
import com.google.common.hash.HashFunction;
|
||||||
|
import com.google.common.hash.Hashing;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
|
||||||
|
public class HashedTokenSha256 extends HashedToken {
|
||||||
|
|
||||||
|
public HashedTokenSha256(final Account account, final ChannelBinding channelBinding) {
|
||||||
|
super(account, channelBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HashFunction getHashFunction(final byte[] key) {
|
||||||
|
return Hashing.hmacSha256(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMechanism() {
|
||||||
|
final String cbShortName = ChannelBinding.SHORT_NAMES.get(this.channelBinding);
|
||||||
|
return String.format("HT-SHA-256-%s", cbShortName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,6 +63,7 @@ import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.crypto.sasl.ChannelBinding;
|
import eu.siacs.conversations.crypto.sasl.ChannelBinding;
|
||||||
|
import eu.siacs.conversations.crypto.sasl.HashedToken;
|
||||||
import eu.siacs.conversations.crypto.sasl.SaslMechanism;
|
import eu.siacs.conversations.crypto.sasl.SaslMechanism;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
@ -1344,7 +1345,7 @@ public class XmppConnection implements Runnable {
|
||||||
final boolean sm = inline != null && inline.hasChild("sm", "urn:xmpp:sm:3");
|
final boolean sm = inline != null && inline.hasChild("sm", "urn:xmpp:sm:3");
|
||||||
final Element fast = inline == null ? null : inline.findChild("fast", Namespace.FAST);
|
final Element fast = inline == null ? null : inline.findChild("fast", Namespace.FAST);
|
||||||
final Collection<String> fastMechanisms = SaslMechanism.mechanisms(fast);
|
final Collection<String> fastMechanisms = SaslMechanism.mechanisms(fast);
|
||||||
Log.d(Config.LOGTAG,"fast mechanisms: "+fastMechanisms);
|
Log.d(Config.LOGTAG,"fast mechanism: "+ HashedToken.Mechanism.best(fastMechanisms, SSLSockets.version(this.socket)));
|
||||||
final Collection<String> bindFeatures = Bind2.features(inline);
|
final Collection<String> bindFeatures = Bind2.features(inline);
|
||||||
quickStartAvailable =
|
quickStartAvailable =
|
||||||
sm
|
sm
|
||||||
|
|
Loading…
Reference in a new issue