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 boolean QUICKSTART_ENABLED = true;
|
||||
public static final boolean QUICKSTART_ENABLED = false;
|
||||
|
||||
//Notification settings
|
||||
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.Predicates;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -23,6 +25,16 @@ public enum ChannelBinding {
|
|||
TLS_SERVER_END_POINT,
|
||||
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) {
|
||||
Preconditions.checkArgument(
|
||||
channelBinding == null
|
||||
|
@ -85,7 +97,24 @@ public enum ChannelBinding {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean ensureBest(final ChannelBinding channelBinding, final SSLSockets.Version sslVersion) {
|
||||
return ChannelBinding.best(Collections.singleton(channelBinding), sslVersion) == channelBinding;
|
||||
public static boolean ensureBest(
|
||||
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.axolotl.AxolotlService;
|
||||
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.entities.Account;
|
||||
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 Element fast = inline == null ? null : inline.findChild("fast", Namespace.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);
|
||||
quickStartAvailable =
|
||||
sm
|
||||
|
|
Loading…
Reference in a new issue