do not attempt unique/exporter channel binding on non conscrypt sockets

This commit is contained in:
Daniel Gultsch 2024-03-10 17:40:41 +01:00
parent e5cffa11be
commit 9ad5b68d57
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
3 changed files with 53 additions and 49 deletions

View file

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

View file

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

View file

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