do not attempt unique/exporter channel binding on non conscrypt sockets
This commit is contained in:
parent
e5cffa11be
commit
9ad5b68d57
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue