From b519411d34da07d9b249f921548b079666b2cc18 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 11 Oct 2015 20:45:01 +0200 Subject: enable SASL EXTERNAL (certificate login --- .../siacs/conversations/crypto/sasl/External.java | 29 ++++++++++ .../siacs/conversations/xmpp/XmppConnection.java | 64 +++++++++++++++++++++- 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/crypto/sasl/External.java (limited to 'src/main/java/eu') diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java new file mode 100644 index 00000000..df92898c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java @@ -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); + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index b62c4e6b..fd2b221d 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -9,6 +9,8 @@ import android.os.Parcelable; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; +import android.security.KeyChain; +import android.security.KeyChainException; import android.util.Base64; import android.util.Log; import android.util.Pair; @@ -33,7 +35,12 @@ import java.net.UnknownHostException; import java.net.MalformedURLException; import java.net.URL; import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -45,14 +52,17 @@ import java.util.List; import java.util.Map.Entry; import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509KeyManager; import javax.net.ssl.X509TrustManager; import de.duenndns.ssl.MemorizingTrustManager; import eu.siacs.conversations.Config; 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.SaslMechanism; import eu.siacs.conversations.crypto.sasl.ScramSha1; @@ -126,6 +136,46 @@ public class XmppConnection implements Runnable { 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() { OnIqPacketReceived receiver = new OnIqPacketReceived() { @Override @@ -551,7 +601,13 @@ public class XmppConnection implements Runnable { try { final SSLContext sc = SSLContext.getInstance("TLS"); 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 HostnameVerifier verifier; if (mInteractive) { @@ -598,7 +654,7 @@ public class XmppConnection implements Runnable { processStream(tagReader.readTag()); sslSocket.close(); } 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(); } } @@ -622,7 +678,9 @@ public class XmppConnection implements Runnable { .findChild("mechanisms")); final Element auth = new Element("auth"); 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()); } else if (mechanisms.contains("PLAIN")) { saslMechanism = new Plain(tagWriter, account); -- cgit v1.2.3