Merge branch '2.13.x'

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/sasl/ChannelBinding.java          | 29 
src/main/java/eu/siacs/conversations/crypto/sasl/ChannelBindingMechanism.java | 17 
src/main/java/eu/siacs/conversations/utils/SSLSockets.java                    | 56 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java                 |  8 
4 files changed, 58 insertions(+), 52 deletions(-)

Detailed changes

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

@@ -10,15 +10,15 @@ 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;
-import java.util.Collections;
-
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.utils.SSLSockets;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Namespace;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
 public enum ChannelBinding {
     NONE,
     TLS_EXPORTER,
@@ -104,22 +104,17 @@ public enum 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);
-        }
+        return switch (channelBinding) {
+            case TLS_UNIQUE -> "UNIQ";
+            case TLS_EXPORTER -> "EXPR";
+            case TLS_SERVER_END_POINT -> "ENDP";
+            case NONE -> "NONE";
+            default -> throw new AssertionError("Missing short name for " + channelBinding);
+        };
     }
 
     public static int priority(final ChannelBinding channelBinding) {
-        if (Arrays.asList(TLS_EXPORTER,TLS_UNIQUE).contains(channelBinding)) {
+        if (Arrays.asList(TLS_EXPORTER, TLS_UNIQUE).contains(channelBinding)) {
             return 2;
         } else if (channelBinding == ChannelBinding.TLS_SERVER_END_POINT) {
             return 1;

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

@@ -20,12 +20,18 @@ public interface ChannelBindingMechanism {
 
     ChannelBinding getChannelBinding();
 
-    static byte[] getChannelBindingData(final SSLSocket sslSocket, final ChannelBinding channelBinding)
+    static byte[] getChannelBindingData(
+            final SSLSocket sslSocket, final ChannelBinding channelBinding)
             throws SaslMechanism.AuthenticationException {
         if (sslSocket == null) {
-            throw new SaslMechanism.AuthenticationException("Channel binding attempt on non secure socket");
+            throw new SaslMechanism.AuthenticationException(
+                    "Channel binding attempt on non secure socket");
         }
         if (channelBinding == ChannelBinding.TLS_EXPORTER) {
+            if (!Conscrypt.isConscrypt(sslSocket)) {
+                throw new SaslMechanism.AuthenticationException(
+                        "Channel binding attempt on non supporting socket");
+            }
             final byte[] keyingMaterial;
             try {
                 keyingMaterial =
@@ -39,6 +45,10 @@ public interface ChannelBindingMechanism {
             }
             return keyingMaterial;
         } else if (channelBinding == ChannelBinding.TLS_UNIQUE) {
+            if (!Conscrypt.isConscrypt(sslSocket)) {
+                throw new SaslMechanism.AuthenticationException(
+                        "Channel binding attempt on non supporting socket");
+            }
             final byte[] unique = Conscrypt.getTlsUnique(sslSocket);
             if (unique == null) {
                 throw new SaslMechanism.AuthenticationException(
@@ -99,8 +109,7 @@ public interface ChannelBindingMechanism {
     }
 
     static int getPriority(final SaslMechanism mechanism) {
-        if (mechanism instanceof ChannelBindingMechanism) {
-            final ChannelBindingMechanism channelBindingMechanism = (ChannelBindingMechanism) mechanism;
+        if (mechanism instanceof ChannelBindingMechanism channelBindingMechanism) {
             return ChannelBinding.priority(channelBindingMechanism.getChannelBinding());
         } else {
             return 0;

src/main/java/eu/siacs/conversations/utils/SSLSockets.java 🔗

@@ -7,6 +7,9 @@ import androidx.annotation.RequiresApi;
 
 import com.google.common.base.Strings;
 
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.entities.Account;
+
 import org.conscrypt.Conscrypt;
 
 import java.lang.reflect.Method;
@@ -24,22 +27,19 @@ import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.entities.Account;
-
 public class SSLSockets {
 
     public static void setSecurity(final SSLSocket sslSocket) {
         final String[] supportProtocols;
-        final Collection<String> supportedProtocols = new LinkedList<>(
-                Arrays.asList(sslSocket.getSupportedProtocols()));
+        final Collection<String> supportedProtocols =
+                new LinkedList<>(Arrays.asList(sslSocket.getSupportedProtocols()));
         supportedProtocols.remove("SSLv3");
         supportProtocols = supportedProtocols.toArray(new String[0]);
 
         sslSocket.setEnabledProtocols(supportProtocols);
 
-        final String[] cipherSuites = CryptoHelper.getOrderedCipherSuites(
-                sslSocket.getSupportedCipherSuites());
+        final String[] cipherSuites =
+                CryptoHelper.getOrderedCipherSuites(sslSocket.getSupportedCipherSuites());
         if (cipherSuites.length > 0) {
             sslSocket.setEnabledCipherSuites(cipherSuites);
         }
@@ -70,7 +70,8 @@ public class SSLSockets {
         socket.setSSLParameters(parameters);
     }
 
-    private static void setApplicationProtocolReflection(final SSLSocket socket, final String protocol) {
+    private static void setApplicationProtocolReflection(
+            final SSLSocket socket, final String protocol) {
         try {
             final Method method = socket.getClass().getMethod("setAlpnProtocols", byte[].class);
             // the concatenation of 8-bit, length prefixed protocol names, just one in our case...
@@ -78,16 +79,17 @@ public class SSLSockets {
             final byte[] protocolUTF8Bytes = protocol.getBytes(StandardCharsets.UTF_8);
             final byte[] lengthPrefixedProtocols = new byte[protocolUTF8Bytes.length + 1];
             lengthPrefixedProtocols[0] = (byte) protocol.length(); // cannot be over 255 anyhow
-            System.arraycopy(protocolUTF8Bytes, 0, lengthPrefixedProtocols, 1, protocolUTF8Bytes.length);
-            method.invoke(socket, new Object[]{lengthPrefixedProtocols});
+            System.arraycopy(
+                    protocolUTF8Bytes, 0, lengthPrefixedProtocols, 1, protocolUTF8Bytes.length);
+            method.invoke(socket, new Object[] {lengthPrefixedProtocols});
         } catch (Throwable e) {
-            Log.e(Config.LOGTAG,"unable to set ALPN on socket",e);
+            Log.e(Config.LOGTAG, "unable to set ALPN on socket", e);
         }
     }
 
     public static void setApplicationProtocol(final SSLSocket socket, final String protocol) {
         if (Conscrypt.isConscrypt(socket)) {
-            Conscrypt.setApplicationProtocols(socket, new String[]{protocol});
+            Conscrypt.setApplicationProtocols(socket, new String[] {protocol});
         } else {
             setApplicationProtocolReflection(socket, protocol);
         }
@@ -113,9 +115,12 @@ public class SSLSockets {
     }
 
     public static Version version(final Socket socket) {
-        if (socket instanceof SSLSocket) {
-            final SSLSocket sslSocket = (SSLSocket) socket;
-            return Version.of(sslSocket.getSession().getProtocol());
+        if (socket instanceof SSLSocket sslSocket) {
+            if (Conscrypt.isConscrypt(sslSocket)) {
+                return Version.of(sslSocket.getSession().getProtocol());
+            } else {
+                return Version.TLS_UNSUPPORTED_VERSION;
+            }
         } else {
             return Version.NONE;
         }
@@ -126,22 +131,17 @@ public class SSLSockets {
         TLS_1_1,
         TLS_1_2,
         TLS_1_3,
-        UNKNOWN,
+        TLS_UNSUPPORTED_VERSION,
         NONE;
 
         private static Version of(final String protocol) {
-            switch (Strings.nullToEmpty(protocol)) {
-                case "TLSv1":
-                    return TLS_1_0;
-                case "TLSv1.1":
-                    return TLS_1_1;
-                case "TLSv1.2":
-                    return TLS_1_2;
-                case "TLSv1.3":
-                    return TLS_1_3;
-                default:
-                    return UNKNOWN;
-            }
+            return switch (Strings.nullToEmpty(protocol)) {
+                case "TLSv1" -> TLS_1_0;
+                case "TLSv1.1" -> TLS_1_1;
+                case "TLSv1.2" -> TLS_1_2;
+                case "TLSv1.3" -> TLS_1_3;
+                default -> TLS_UNSUPPORTED_VERSION;
+            };
         }
     }
 }

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

@@ -936,7 +936,8 @@ public class XmppConnection implements Runnable {
 
     private void resetOutboundStanzaQueue() {
         synchronized (this.mStanzaQueue) {
-            final List<AbstractAcknowledgeableStanza> intermediateStanzas = new ArrayList<>();
+            final ImmutableList.Builder<AbstractAcknowledgeableStanza> intermediateStanzasBuilder =
+                    new ImmutableList.Builder<>();
             if (Config.EXTENDED_SM_LOGGING) {
                 Log.d(
                         Config.LOGTAG,
@@ -947,12 +948,13 @@ public class XmppConnection implements Runnable {
             for (int i = this.stanzasSentBeforeAuthentication + 1; i <= this.stanzasSent; ++i) {
                 final AbstractAcknowledgeableStanza stanza = this.mStanzaQueue.get(i);
                 if (stanza != null) {
-                    intermediateStanzas.add(stanza);
+                    intermediateStanzasBuilder.add(stanza);
                 }
             }
             this.mStanzaQueue.clear();
+            final var intermediateStanzas = intermediateStanzasBuilder.build();
             for (int i = 0; i < intermediateStanzas.size(); ++i) {
-                this.mStanzaQueue.put(i, intermediateStanzas.get(i));
+                this.mStanzaQueue.append(i + 1, intermediateStanzas.get(i));
             }
             this.stanzasSent = intermediateStanzas.size();
             if (Config.EXTENDED_SM_LOGGING) {