enable SASL EXTERNAL (certificate login

This commit is contained in:
Daniel Gultsch 2015-10-11 20:45:01 +02:00
parent 7be331bbb2
commit b519411d34
2 changed files with 90 additions and 3 deletions

View file

@ -0,0 +1,29 @@
package eu.siacs.conversations.crypto.sasl;
import android.util.Base64;
import java.security.SecureRandom;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.xml.TagWriter;
public class External extends SaslMechanism {
public External(TagWriter tagWriter, Account account, SecureRandom rng) {
super(tagWriter, account, rng);
}
@Override
public int getPriority() {
return 25;
}
@Override
public String getMechanism() {
return "EXTERNAL";
}
@Override
public String getClientFirstMessage() {
return Base64.encodeToString(account.getJid().toBareJid().toString().getBytes(),Base64.NO_WRAP);
}
}

View file

@ -9,6 +9,8 @@ import android.os.Parcelable;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import android.os.SystemClock; import android.os.SystemClock;
import android.security.KeyChain;
import android.security.KeyChainException;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -33,7 +35,12 @@ import java.net.UnknownHostException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -45,14 +52,17 @@ import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import de.duenndns.ssl.MemorizingTrustManager; import de.duenndns.ssl.MemorizingTrustManager;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.sasl.DigestMd5; import eu.siacs.conversations.crypto.sasl.DigestMd5;
import eu.siacs.conversations.crypto.sasl.External;
import eu.siacs.conversations.crypto.sasl.Plain; import eu.siacs.conversations.crypto.sasl.Plain;
import eu.siacs.conversations.crypto.sasl.SaslMechanism; import eu.siacs.conversations.crypto.sasl.SaslMechanism;
import eu.siacs.conversations.crypto.sasl.ScramSha1; import eu.siacs.conversations.crypto.sasl.ScramSha1;
@ -126,6 +136,46 @@ public class XmppConnection implements Runnable {
private SaslMechanism saslMechanism; private SaslMechanism saslMechanism;
private X509KeyManager mKeyManager = new X509KeyManager() {
@Override
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
return account.getPrivateKeyAlias();
}
@Override
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
return null;
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
try {
return KeyChain.getCertificateChain(mXmppConnectionService, alias);
} catch (Exception e) {
return new X509Certificate[0];
}
}
@Override
public String[] getClientAliases(String s, Principal[] principals) {
return new String[0];
}
@Override
public String[] getServerAliases(String s, Principal[] principals) {
return new String[0];
}
@Override
public PrivateKey getPrivateKey(String alias) {
try {
return KeyChain.getPrivateKey(mXmppConnectionService, alias);
} catch (Exception e) {
return null;
}
}
};
private OnIqPacketReceived createPacketReceiveHandler() { private OnIqPacketReceived createPacketReceiveHandler() {
OnIqPacketReceived receiver = new OnIqPacketReceived() { OnIqPacketReceived receiver = new OnIqPacketReceived() {
@Override @Override
@ -551,7 +601,13 @@ public class XmppConnection implements Runnable {
try { try {
final SSLContext sc = SSLContext.getInstance("TLS"); final SSLContext sc = SSLContext.getInstance("TLS");
MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager(); MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
sc.init(null,new X509TrustManager[]{mInteractive ? trustManager : trustManager.getNonInteractive()},mXmppConnectionService.getRNG()); 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 SSLSocketFactory factory = sc.getSocketFactory();
final HostnameVerifier verifier; final HostnameVerifier verifier;
if (mInteractive) { if (mInteractive) {
@ -598,7 +654,7 @@ public class XmppConnection implements Runnable {
processStream(tagReader.readTag()); processStream(tagReader.readTag());
sslSocket.close(); sslSocket.close();
} catch (final NoSuchAlgorithmException | KeyManagementException e1) { } catch (final NoSuchAlgorithmException | KeyManagementException e1) {
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();
} }
} }
@ -622,7 +678,9 @@ public class XmppConnection implements Runnable {
.findChild("mechanisms")); .findChild("mechanisms"));
final Element auth = new Element("auth"); final Element auth = new Element("auth");
auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl"); auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
if (mechanisms.contains("SCRAM-SHA-1")) { if (mechanisms.contains("EXTERNAL")) {
saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG());
} else if (mechanisms.contains("SCRAM-SHA-1")) {
saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG()); saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG());
} else if (mechanisms.contains("PLAIN")) { } else if (mechanisms.contains("PLAIN")) {
saslMechanism = new Plain(tagWriter, account); saslMechanism = new Plain(tagWriter, account);