request fast token

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/sasl/HashedToken.java       | 12 
src/main/java/eu/siacs/conversations/crypto/sasl/HashedTokenSha512.java | 24 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java           | 18 
3 files changed, 49 insertions(+), 5 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/sasl/HashedToken.java 🔗

@@ -18,7 +18,9 @@ import eu.siacs.conversations.utils.SSLSockets;
 
 public abstract class HashedToken extends SaslMechanism {
 
-    private static List<String> HASH_FUNCTIONS = Arrays.asList("SHA-512", "SHA-256");
+    private static final String PREFIX = "HT";
+
+    private static final List<String> HASH_FUNCTIONS = Arrays.asList("SHA-512", "SHA-256");
 
     protected final ChannelBinding channelBinding;
 
@@ -61,7 +63,7 @@ public abstract class HashedToken extends SaslMechanism {
             if (last <= first || mechanism.length() <= last) {
                 throw new IllegalArgumentException("Not a valid HashedToken name");
             }
-            if (mechanism.substring(0, first).equals("HT")) {
+            if (mechanism.substring(0, first).equals(PREFIX)) {
                 final String hashFunction = mechanism.substring(first + 1, last);
                 final String cbShortName = mechanism.substring(last + 1);
                 final ChannelBinding channelBinding =
@@ -110,5 +112,11 @@ public abstract class HashedToken extends SaslMechanism {
                     .add("channelBinding", channelBinding)
                     .toString();
         }
+
+        public String name() {
+            return String.format(
+                    "%s-%s-%s",
+                    PREFIX, hashFunction, ChannelBinding.SHORT_NAMES.get(channelBinding));
+        }
     }
 }

src/main/java/eu/siacs/conversations/crypto/sasl/HashedTokenSha512.java 🔗

@@ -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 HashedTokenSha512 extends HashedToken {
+
+    public HashedTokenSha512(final Account account, final ChannelBinding channelBinding) {
+        super(account, channelBinding);
+    }
+
+    @Override
+    protected HashFunction getHashFunction(final byte[] key) {
+        return Hashing.hmacSha512(key);
+    }
+
+    @Override
+    public String getMechanism() {
+        final String cbShortName = ChannelBinding.SHORT_NAMES.get(this.channelBinding);
+        return String.format("HT-SHA-512-%s", cbShortName);
+    }
+}

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -181,6 +181,7 @@ public class XmppConnection implements Runnable {
     private OnBindListener bindListener = null;
     private OnMessageAcknowledged acknowledgedListener = null;
     private SaslMechanism saslMechanism;
+    private HashedToken.Mechanism hashTokenRequest;
     private HttpUrl redirectionUrl = null;
     private String verifiedHostname = null;
     private volatile Thread mThread;
@@ -761,6 +762,8 @@ public class XmppConnection implements Runnable {
             final Element bound = success.findChild("bound", Namespace.BIND2);
             final Element resumed = success.findChild("resumed", "urn:xmpp:sm:3");
             final Element failed = success.findChild("failed", "urn:xmpp:sm:3");
+            final Element tokenWrapper = success.findChild("token", Namespace.FAST);
+            final String token = tokenWrapper == null ? null : tokenWrapper.getAttribute("token");
             if (bound != null && resumed != null) {
                 Log.d(
                         Config.LOGTAG,
@@ -795,6 +798,10 @@ public class XmppConnection implements Runnable {
                 }
                 sendPostBindInitialization(waitForDisco, carbonsEnabled != null);
             }
+            //TODO figure out name either by the existence of hashTokenRequest or if scramMechanism is of instance HashedToken
+            if (this.hashTokenRequest != null && !Strings.isNullOrEmpty(token)) {
+                Log.d(Config.LOGTAG,account.getJid().asBareJid()+": storing hashed token "+this.hashTokenRequest.name()+ " "+token);
+            }
         }
         this.quickStartInProgress = false;
         if (version == SaslMechanism.Version.SASL) {
@@ -1345,7 +1352,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 mechanism: "+ HashedToken.Mechanism.best(fastMechanisms, SSLSockets.version(this.socket)));
+            final HashedToken.Mechanism hashTokenRequest = HashedToken.Mechanism.best(fastMechanisms, SSLSockets.version(this.socket));
             final Collection<String> bindFeatures = Bind2.features(inline);
             quickStartAvailable =
                     sm
@@ -1362,7 +1369,8 @@ public class XmppConnection implements Runnable {
                     return;
                 }
             }
-            authenticate = generateAuthenticationRequest(firstMessage, bindFeatures, sm);
+            this.hashTokenRequest = hashTokenRequest;
+            authenticate = generateAuthenticationRequest(firstMessage, hashTokenRequest, bindFeatures, sm);
         } else {
             throw new AssertionError("Missing implementation for " + version);
         }
@@ -1383,11 +1391,12 @@ public class XmppConnection implements Runnable {
     }
 
     private Element generateAuthenticationRequest(final String firstMessage) {
-        return generateAuthenticationRequest(firstMessage, Bind2.QUICKSTART_FEATURES, true);
+        return generateAuthenticationRequest(firstMessage, null, Bind2.QUICKSTART_FEATURES, true);
     }
 
     private Element generateAuthenticationRequest(
             final String firstMessage,
+            final HashedToken.Mechanism hashedTokenRequest,
             final Collection<String> bind,
             final boolean inlineStreamManagement) {
         final Element authenticate = new Element("authenticate", Namespace.SASL_2);
@@ -1413,6 +1422,9 @@ public class XmppConnection implements Runnable {
             this.mWaitingForSmCatchup.set(true);
             authenticate.addChild(resume);
         }
+        if (hashedTokenRequest != null) {
+            authenticate.addChild("request-token", Namespace.FAST).setAttribute("mechanism", hashedTokenRequest.name());
+        }
         return authenticate;
     }