Implement XEP-0368: SRV records for XMPP over TLS

This commit is contained in:
Travis Burtrum 2016-01-11 17:25:16 -05:00
parent 20ec9ff2c6
commit 217f6603c0
2 changed files with 218 additions and 102 deletions

View File

@ -19,6 +19,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import de.measite.minidns.Client; import de.measite.minidns.Client;
@ -57,7 +58,7 @@ public class DNSHelper {
if (!b.containsKey("values")) { if (!b.containsKey("values")) {
Log.d(Config.LOGTAG,"all dns queries failed. provide fallback A record"); Log.d(Config.LOGTAG,"all dns queries failed. provide fallback A record");
ArrayList<Parcelable> values = new ArrayList<>(); ArrayList<Parcelable> values = new ArrayList<>();
values.add(createNamePortBundle(host,5222)); values.add(createNamePortBundle(host, 5222, false));
b.putParcelableArrayList("values",values); b.putParcelableArrayList("values",values);
} }
return b; return b;
@ -96,57 +97,73 @@ public class DNSHelper {
return servers; return servers;
} }
private static class TlsSrv {
private final SRV srv;
private final boolean tls;
public TlsSrv(SRV srv, boolean tls) {
this.srv = srv;
this.tls = tls;
}
}
private static void fillSrvMaps(final String qname, final InetAddress dnsServer, final Map<Integer, List<TlsSrv>> priorities, final Map<String, List<String>> ips4, final Map<String, List<String>> ips6, final boolean tls) throws IOException {
final DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN, dnsServer.getHostAddress());
for (Record[] rrset : new Record[][] { message.getAnswers(), message.getAdditionalResourceRecords() }) {
for (Record rr : rrset) {
Data d = rr.getPayload();
if (d instanceof SRV && NameUtil.idnEquals(qname, rr.getName())) {
SRV srv = (SRV) d;
if (!priorities.containsKey(srv.getPriority())) {
priorities.put(srv.getPriority(),new ArrayList<TlsSrv>());
}
priorities.get(srv.getPriority()).add(new TlsSrv(srv, tls));
}
if (d instanceof A) {
A a = (A) d;
if (!ips4.containsKey(rr.getName())) {
ips4.put(rr.getName(), new ArrayList<String>());
}
ips4.get(rr.getName()).add(a.toString());
}
if (d instanceof AAAA) {
AAAA aaaa = (AAAA) d;
if (!ips6.containsKey(rr.getName())) {
ips6.put(rr.getName(), new ArrayList<String>());
}
ips6.get(rr.getName()).add("[" + aaaa.toString() + "]");
}
}
}
}
public static Bundle queryDNS(String host, InetAddress dnsServer) { public static Bundle queryDNS(String host, InetAddress dnsServer) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
try { try {
client.setTimeout(Config.PING_TIMEOUT * 1000); client.setTimeout(Config.PING_TIMEOUT * 1000);
String qname = "_xmpp-client._tcp." + host; final String qname = "_xmpp-client._tcp." + host;
final String tlsQname = "_xmpps-client._tcp." + host;
Log.d(Config.LOGTAG, "using dns server: " + dnsServer.getHostAddress() + " to look up " + host); Log.d(Config.LOGTAG, "using dns server: " + dnsServer.getHostAddress() + " to look up " + host);
DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN, dnsServer.getHostAddress());
TreeMap<Integer, ArrayList<SRV>> priorities = new TreeMap<>(); final Map<Integer, List<TlsSrv>> priorities = new TreeMap<>();
TreeMap<String, ArrayList<String>> ips4 = new TreeMap<>(); final Map<String, List<String>> ips4 = new TreeMap<>();
TreeMap<String, ArrayList<String>> ips6 = new TreeMap<>(); final Map<String, List<String>> ips6 = new TreeMap<>();
for (Record[] rrset : new Record[][] { message.getAnswers(), message.getAdditionalResourceRecords() }) { fillSrvMaps(qname, dnsServer, priorities, ips4, ips6, false);
for (Record rr : rrset) { fillSrvMaps(tlsQname, dnsServer, priorities, ips4, ips6, true);
Data d = rr.getPayload();
if (d instanceof SRV && NameUtil.idnEquals(qname, rr.getName())) {
SRV srv = (SRV) d;
if (!priorities.containsKey(srv.getPriority())) {
priorities.put(srv.getPriority(),new ArrayList<SRV>());
}
priorities.get(srv.getPriority()).add(srv);
}
if (d instanceof A) {
A a = (A) d;
if (!ips4.containsKey(rr.getName())) {
ips4.put(rr.getName(), new ArrayList<String>());
}
ips4.get(rr.getName()).add(a.toString());
}
if (d instanceof AAAA) {
AAAA aaaa = (AAAA) d;
if (!ips6.containsKey(rr.getName())) {
ips6.put(rr.getName(), new ArrayList<String>());
}
ips6.get(rr.getName()).add("[" + aaaa.toString() + "]");
}
}
}
ArrayList<SRV> result = new ArrayList<>(); final List<TlsSrv> result = new ArrayList<>();
for (ArrayList<SRV> s : priorities.values()) { for (final List<TlsSrv> s : priorities.values()) {
result.addAll(s); result.addAll(s);
} }
ArrayList<Bundle> values = new ArrayList<>(); final ArrayList<Bundle> values = new ArrayList<>();
if (result.size() == 0) { if (result.size() == 0) {
DNSMessage response; DNSMessage response;
try { try {
response = client.query(host, TYPE.A, CLASS.IN, dnsServer.getHostAddress()); response = client.query(host, TYPE.A, CLASS.IN, dnsServer.getHostAddress());
for (int i = 0; i < response.getAnswers().length; ++i) { for (int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload())); values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload(), false));
} }
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
Log.d(Config.LOGTAG,"ignoring timeout exception when querying A record on "+dnsServer.getHostAddress()); Log.d(Config.LOGTAG,"ignoring timeout exception when querying A record on "+dnsServer.getHostAddress());
@ -154,37 +171,38 @@ public class DNSHelper {
try { try {
response = client.query(host, TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress()); response = client.query(host, TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress());
for (int i = 0; i < response.getAnswers().length; ++i) { for (int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload())); values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload(), false));
} }
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress()); Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress());
} }
values.add(createNamePortBundle(host,5222)); values.add(createNamePortBundle(host, 5222, false));
bundle.putParcelableArrayList("values", values); bundle.putParcelableArrayList("values", values);
return bundle; return bundle;
} }
for (SRV srv : result) { for (final TlsSrv tlsSrv : result) {
final SRV srv = tlsSrv.srv;
if (ips6.containsKey(srv.getName())) { if (ips6.containsKey(srv.getName())) {
values.add(createNamePortBundle(srv.getName(),srv.getPort(),ips6)); values.add(createNamePortBundle(srv.getName(),srv.getPort(),ips6, tlsSrv.tls));
} else { } else {
try { try {
DNSMessage response = client.query(srv.getName(), TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress()); DNSMessage response = client.query(srv.getName(), TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress());
for (int i = 0; i < response.getAnswers().length; ++i) { for (int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(srv.getName(), srv.getPort(), response.getAnswers()[i].getPayload())); values.add(createNamePortBundle(srv.getName(), srv.getPort(), response.getAnswers()[i].getPayload(), tlsSrv.tls));
} }
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress()); Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress());
} }
} }
if (ips4.containsKey(srv.getName())) { if (ips4.containsKey(srv.getName())) {
values.add(createNamePortBundle(srv.getName(),srv.getPort(),ips4)); values.add(createNamePortBundle(srv.getName(),srv.getPort(),ips4, tlsSrv.tls));
} else { } else {
DNSMessage response = client.query(srv.getName(), TYPE.A, CLASS.IN, dnsServer.getHostAddress()); DNSMessage response = client.query(srv.getName(), TYPE.A, CLASS.IN, dnsServer.getHostAddress());
for(int i = 0; i < response.getAnswers().length; ++i) { for(int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(srv.getName(),srv.getPort(),response.getAnswers()[i].getPayload())); values.add(createNamePortBundle(srv.getName(),srv.getPort(),response.getAnswers()[i].getPayload(), tlsSrv.tls));
} }
} }
values.add(createNamePortBundle(srv.getName(), srv.getPort())); values.add(createNamePortBundle(srv.getName(), srv.getPort(), tlsSrv.tls));
} }
bundle.putParcelableArrayList("values", values); bundle.putParcelableArrayList("values", values);
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
@ -195,28 +213,31 @@ public class DNSHelper {
return bundle; return bundle;
} }
private static Bundle createNamePortBundle(String name, int port) { private static Bundle createNamePortBundle(String name, int port, final boolean tls) {
Bundle namePort = new Bundle(); Bundle namePort = new Bundle();
namePort.putString("name", name); namePort.putString("name", name);
namePort.putBoolean("tls", tls);
namePort.putInt("port", port); namePort.putInt("port", port);
return namePort; return namePort;
} }
private static Bundle createNamePortBundle(String name, int port, TreeMap<String, ArrayList<String>> ips) { private static Bundle createNamePortBundle(String name, int port, Map<String, List<String>> ips, final boolean tls) {
Bundle namePort = new Bundle(); Bundle namePort = new Bundle();
namePort.putString("name", name); namePort.putString("name", name);
namePort.putBoolean("tls", tls);
namePort.putInt("port", port); namePort.putInt("port", port);
if (ips!=null) { if (ips!=null) {
ArrayList<String> ip = ips.get(name); List<String> ip = ips.get(name);
Collections.shuffle(ip, new Random()); Collections.shuffle(ip, new Random());
namePort.putString("ip", ip.get(0)); namePort.putString("ip", ip.get(0));
} }
return namePort; return namePort;
} }
private static Bundle createNamePortBundle(String name, int port, Data data) { private static Bundle createNamePortBundle(String name, int port, Data data, final boolean tls) {
Bundle namePort = new Bundle(); Bundle namePort = new Bundle();
namePort.putString("name", name); namePort.putString("name", name);
namePort.putBoolean("tls", tls);
namePort.putInt("port", port); namePort.putInt("port", port);
if (data instanceof A) { if (data instanceof A) {
namePort.putString("ip", data.toString()); namePort.putString("ip", data.toString());

View File

@ -20,7 +20,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.lang.reflect.Method;
import java.math.BigInteger; import java.math.BigInteger;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.IDN; import java.net.IDN;
@ -247,6 +247,7 @@ public class XmppConnection implements Runnable {
} }
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": connect to "+destination+" via TOR"); Log.d(Config.LOGTAG,account.getJid().toBareJid()+": connect to "+destination+" via TOR");
socket = SocksSocketFactory.createSocketOverTor(destination,account.getPort()); socket = SocksSocketFactory.createSocketOverTor(destination,account.getPort());
startXmpp();
} else if (DNSHelper.isIp(account.getServer().toString())) { } else if (DNSHelper.isIp(account.getServer().toString())) {
socket = new Socket(); socket = new Socket();
try { try {
@ -254,6 +255,7 @@ public class XmppConnection implements Runnable {
} catch (IOException e) { } catch (IOException e) {
throw new UnknownHostException(); throw new UnknownHostException();
} }
startXmpp();
} else { } else {
final Bundle result = DNSHelper.getSRVRecord(account.getServer(), mXmppConnectionService); final Bundle result = DNSHelper.getSRVRecord(account.getServer(), mXmppConnectionService);
final ArrayList<Parcelable>values = result.getParcelableArrayList("values"); final ArrayList<Parcelable>values = result.getParcelableArrayList("values");
@ -269,24 +271,46 @@ public class XmppConnection implements Runnable {
} }
final int srvRecordPort = namePort.getInt("port"); final int srvRecordPort = namePort.getInt("port");
final String srvIpServer = namePort.getString("ip"); final String srvIpServer = namePort.getString("ip");
// if tls is true, encryption is implied and must not be started
features.encryptionEnabled = namePort.getBoolean("tls");
final InetSocketAddress addr; final InetSocketAddress addr;
if (srvIpServer != null) { if (srvIpServer != null) {
addr = new InetSocketAddress(srvIpServer, srvRecordPort); addr = new InetSocketAddress(srvIpServer, srvRecordPort);
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": using values from dns " + srvRecordServer + ": using values from dns " + srvRecordServer
+ "[" + srvIpServer + "]:" + srvRecordPort); + "[" + srvIpServer + "]:" + srvRecordPort + " tls: " + features.encryptionEnabled);
} else { } else {
addr = new InetSocketAddress(srvRecordServer, srvRecordPort); addr = new InetSocketAddress(srvRecordServer, srvRecordPort);
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": using values from dns " + ": using values from dns "
+ srvRecordServer + ":" + srvRecordPort); + srvRecordServer + ":" + srvRecordPort + " tls: " + features.encryptionEnabled);
} }
socket = new Socket();
socket.connect(addr, Config.SOCKET_TIMEOUT * 1000); if (!features.encryptionEnabled) {
tagWriter.setOutputStream(socket.getOutputStream()); socket = new Socket();
tagReader.setInputStream(socket.getInputStream()); socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
tagWriter.beginDocument(); } else {
sendStartStream(); final TlsFactoryVerifier tlsFactoryVerifier = getTlsFactoryVerifier();
socket = tlsFactoryVerifier.factory.createSocket();
if (socket == null) {
throw new IOException("could not initialize ssl socket");
}
setSSLSocketSecurity((SSLSocket) socket);
this.setSNIHost(tlsFactoryVerifier.factory, (SSLSocket) socket, account.getServer().getDomainpart());
this.setAlpnProtocol(tlsFactoryVerifier.factory, (SSLSocket) socket, "xmpp-client");
socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), ((SSLSocket) socket).getSession())) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": TLS certificate verification failed");
throw new SecurityException();
}
}
if(startXmpp())
break; // successfully connected to server that speaks xmpp
} catch (final Throwable e) { } catch (final Throwable e) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage() +"("+e.getClass().getName()+")"); Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage() +"("+e.getClass().getName()+")");
if (!iterator.hasNext()) { if (!iterator.hasNext()) {
@ -295,18 +319,7 @@ public class XmppConnection implements Runnable {
} }
} }
} }
Tag nextTag; processStream();
while ((nextTag = tagReader.readTag()) != null) {
if (nextTag.isStart("stream")) {
processStream();
break;
} else {
throw new IOException("unknown tag on connect");
}
}
if (socket.isConnected()) {
socket.close();
}
} catch (final IncompatibleServerException e) { } catch (final IncompatibleServerException e) {
this.changeStatus(Account.State.INCOMPATIBLE_SERVER); this.changeStatus(Account.State.INCOMPATIBLE_SERVER);
} catch (final SecurityException e) { } catch (final SecurityException e) {
@ -338,6 +351,99 @@ public class XmppConnection implements Runnable {
} }
} }
/**
* Starts xmpp protocol, call after connecting to socket
* @return true if server returns with valid xmpp, false otherwise
* @throws IOException Unknown tag on connect
* @throws XmlPullParserException Bad Xml
* @throws NoSuchAlgorithmException Other error
*/
private boolean startXmpp() throws IOException, XmlPullParserException, NoSuchAlgorithmException {
tagWriter.setOutputStream(socket.getOutputStream());
tagReader.setInputStream(socket.getInputStream());
tagWriter.beginDocument();
sendStartStream();
Tag nextTag;
while ((nextTag = tagReader.readTag()) != null) {
if (nextTag.isStart("stream")) {
return true;
} else {
throw new IOException("unknown tag on connect");
}
}
if (socket.isConnected()) {
socket.close();
}
return false;
}
private void setSNIHost(final SSLSocketFactory factory, final SSLSocket socket, final String hostname) {
if (factory instanceof android.net.SSLCertificateSocketFactory && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
((android.net.SSLCertificateSocketFactory) factory).setHostname(socket, hostname);
} else {
try {
socket.getClass().getMethod("setHostname", String.class).invoke(socket, hostname);
} catch (Throwable e) {
// ignore any error, we just can't set the hostname...
}
}
}
private void setAlpnProtocol(final SSLSocketFactory factory, final SSLSocket socket, final String protocol) {
try {
if (factory instanceof android.net.SSLCertificateSocketFactory && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
// can't call directly because of @hide?
//((android.net.SSLCertificateSocketFactory)factory).setAlpnProtocols(new byte[][]{protocol.getBytes("UTF-8")});
android.net.SSLCertificateSocketFactory.class.getMethod("setAlpnProtocols", byte[][].class).invoke(socket, new Object[]{new byte[][]{protocol.getBytes("UTF-8")}});
} else {
final Method method = socket.getClass().getMethod("setAlpnProtocols", byte[].class);
// the concatenation of 8-bit, length prefixed protocol names, just one in our case...
// http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04#page-4
final byte[] protocolUTF8Bytes = protocol.getBytes("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});
}
} catch (Throwable e) {
// ignore any error, we just can't set the alpn protocol...
}
}
private static class TlsFactoryVerifier {
private final SSLSocketFactory factory;
private final HostnameVerifier verifier;
public TlsFactoryVerifier(final SSLSocketFactory factory, final HostnameVerifier verifier) throws IOException {
this.factory = factory;
this.verifier = verifier;
if (factory == null || verifier == null) {
throw new IOException("could not setup ssl");
}
}
}
private TlsFactoryVerifier getTlsFactoryVerifier() throws NoSuchAlgorithmException, KeyManagementException, IOException {
final SSLContext sc = SSLContext.getInstance("TLS");
MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
KeyManager[] keyManager;
if (account.getPrivateKeyAlias() != null && account.getPassword().isEmpty()) {
keyManager = new KeyManager[]{mKeyManager};
} else {
keyManager = null;
}
sc.init(keyManager, new X509TrustManager[]{mInteractive ? trustManager : trustManager.getNonInteractive()}, mXmppConnectionService.getRNG());
final SSLSocketFactory factory = sc.getSocketFactory();
final HostnameVerifier verifier;
if (mInteractive) {
verifier = trustManager.wrapHostnameVerifier(new XmppDomainVerifier());
} else {
verifier = trustManager.wrapHostnameVerifierNonInteractive(new XmppDomainVerifier());
}
return new TlsFactoryVerifier(factory, verifier);
}
@Override @Override
public void run() { public void run() {
try { try {
@ -599,53 +705,42 @@ public class XmppConnection implements Runnable {
tagWriter.writeTag(startTLS); tagWriter.writeTag(startTLS);
} }
private void setSSLSocketSecurity(final SSLSocket sslSocket) throws NoSuchAlgorithmException {
final String[] supportProtocols;
final Collection<String> supportedProtocols = new LinkedList<>(
Arrays.asList(sslSocket.getSupportedProtocols()));
supportedProtocols.remove("SSLv3");
supportProtocols = supportedProtocols.toArray(new String[supportedProtocols.size()]);
sslSocket.setEnabledProtocols(supportProtocols);
final String[] cipherSuites = CryptoHelper.getOrderedCipherSuites(
sslSocket.getSupportedCipherSuites());
//Log.d(Config.LOGTAG, "Using ciphers: " + Arrays.toString(cipherSuites));
if (cipherSuites.length > 0) {
sslSocket.setEnabledCipherSuites(cipherSuites);
}
}
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException { private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
tagReader.readTag(); tagReader.readTag();
try { try {
final SSLContext sc = SSLContext.getInstance("TLS"); final TlsFactoryVerifier tlsFactoryVerifier = getTlsFactoryVerifier();
MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
KeyManager[] keyManager;
if (account.getPrivateKeyAlias() != null && account.getPassword().isEmpty()) {
keyManager = new KeyManager[]{ mKeyManager };
} else {
keyManager = null;
}
sc.init(keyManager,new X509TrustManager[]{mInteractive ? trustManager : trustManager.getNonInteractive()},mXmppConnectionService.getRNG());
final SSLSocketFactory factory = sc.getSocketFactory();
final HostnameVerifier verifier;
if (mInteractive) {
verifier = trustManager.wrapHostnameVerifier(new XmppDomainVerifier());
} else {
verifier = trustManager.wrapHostnameVerifierNonInteractive(new XmppDomainVerifier());
}
final InetAddress address = socket == null ? null : socket.getInetAddress(); final InetAddress address = socket == null ? null : socket.getInetAddress();
if (factory == null || address == null || verifier == null) { if (address == null) {
throw new IOException("could not setup ssl"); throw new IOException("could not setup ssl");
} }
final SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,address.getHostAddress(), socket.getPort(),true); final SSLSocket sslSocket = (SSLSocket) tlsFactoryVerifier.factory.createSocket(socket, address.getHostAddress(), socket.getPort(), true);
if (sslSocket == null) { if (sslSocket == null) {
throw new IOException("could not initialize ssl socket"); throw new IOException("could not initialize ssl socket");
} }
final String[] supportProtocols; setSSLSocketSecurity(sslSocket);
final Collection<String> supportedProtocols = new LinkedList<>(
Arrays.asList(sslSocket.getSupportedProtocols()));
supportedProtocols.remove("SSLv3");
supportProtocols = supportedProtocols.toArray(new String[supportedProtocols.size()]);
sslSocket.setEnabledProtocols(supportProtocols); if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), sslSocket.getSession())) {
final String[] cipherSuites = CryptoHelper.getOrderedCipherSuites(
sslSocket.getSupportedCipherSuites());
//Log.d(Config.LOGTAG, "Using ciphers: " + Arrays.toString(cipherSuites));
if (cipherSuites.length > 0) {
sslSocket.setEnabledCipherSuites(cipherSuites);
}
if (!verifier.verify(account.getServer().getDomainpart(),sslSocket.getSession())) {
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed"); Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed");
throw new SecurityException(); throw new SecurityException();
} }