From cfeb67d71da01bc95ed713d6591fa6e79fc08dd6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 16 Oct 2015 23:48:42 +0200 Subject: [PATCH] introduced code to verify omemo device keys with x509 certificates. cleaned up TrustKeysActivity to automatically close if there is nothing to do --- .../crypto/axolotl/AxolotlService.java | 86 +++++++++++++++---- .../siacs/conversations/entities/Account.java | 3 + .../conversations/generator/IqGenerator.java | 10 ++- .../siacs/conversations/parser/IqParser.java | 29 +++++++ .../services/XmppConnectionService.java | 9 +- .../conversations/ui/TrustKeysActivity.java | 80 ++++++++++------- .../conversations/utils/CryptoHelper.java | 28 +++++- .../conversations/xmpp/XmppConnection.java | 10 ++- 8 files changed, 190 insertions(+), 65 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 58e5a0957..ca75ec992 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -1,10 +1,10 @@ package eu.siacs.conversations.crypto.axolotl; import android.security.KeyChain; -import android.security.KeyChainException; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import android.util.Pair; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.whispersystems.libaxolotl.AxolotlAddress; @@ -20,11 +20,9 @@ import org.whispersystems.libaxolotl.state.PreKeyRecord; import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; import org.whispersystems.libaxolotl.util.KeyHelper; -import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Security; import java.security.Signature; -import java.security.SignatureException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashMap; @@ -43,12 +41,13 @@ import eu.siacs.conversations.parser.IqParser; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.SerialSingleThreadExecutor; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -public class AxolotlService { +public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { public static final String PEP_PREFIX = "eu.siacs.conversations.axolotl"; public static final String PEP_DEVICE_LIST = PEP_PREFIX + ".devicelist"; @@ -71,6 +70,15 @@ public class AxolotlService { private int numPublishTriesOnEmptyPep = 0; private boolean pepBroken = false; + @Override + public void onAdvancedStreamFeaturesAvailable(Account account) { + if (account.getXmppConnection().getFeatures().pep()) { + publishBundlesIfNeeded(true, false); + } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping OMEMO initialization"); + } + } + private static class AxolotlAddressMap { protected Map> map; protected final Object MAP_LOCK = new Object(); @@ -402,7 +410,6 @@ public class AxolotlService { byte[] signature = verifier.sign(); IqPacket packet = mXmppConnectionService.getIqGenerator().publishVerification(signature, chain, getOwnDeviceId()); Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ": publish verification for device "+getOwnDeviceId()); - Log.d(Config.LOGTAG,"verification : "+packet.toString()); mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { @@ -565,6 +572,50 @@ public class AxolotlService { axolotlStore.setFingerprintTrust(fingerprint, trust); } + private void verifySessionWithPEP(final XmppAxolotlSession session, final IdentityKey identityKey) { + final AxolotlAddress address = session.getRemoteAddress(); + try { + IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveVerificationForDevice(Jid.fromString(address.getName()), address.getDeviceId()); + mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + Pair verification = mXmppConnectionService.getIqParser().verification(packet); + if (verification != null) { + try { + Signature verifier = Signature.getInstance("sha256WithRSA"); + verifier.initVerify(verification.first[0]); + verifier.update(identityKey.serialize()); + if (verifier.verify(verification.second)) { + try { + mXmppConnectionService.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(verification.first, "RSA"); + Log.d(Config.LOGTAG, "verified session with x.509 signature"); + setFingerprintTrust(session.getFingerprint(), XmppAxolotlSession.Trust.TRUSTED); + } catch (Exception e) { + Log.d(Config.LOGTAG,"could not verify certificate"); + } + } + } catch (Exception e) { + Log.d(Config.LOGTAG, "error during verification " + e.getMessage()); + } + } else { + Log.d(Config.LOGTAG, " unable to parse verification"); + } + finishBuildingSessionsFromPEP(address); + } + }); + } catch (InvalidJidException e) { + finishBuildingSessionsFromPEP(address); + } + } + + private void finishBuildingSessionsFromPEP(final AxolotlAddress address) { + AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0); + if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING) + && !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) { + mXmppConnectionService.keyStatusUpdated(); + } + } + private void buildSessionFromPEP(final AxolotlAddress address) { Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building new sesstion for " + address.toString()); if (address.getDeviceId() == getOwnDeviceId()) { @@ -576,13 +627,6 @@ public class AxolotlService { Jid.fromString(address.getName()), address.getDeviceId()); Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Retrieving bundle: " + bundlesPacket); mXmppConnectionService.sendIqPacket(account, bundlesPacket, new OnIqPacketReceived() { - private void finish() { - AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0); - if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING) - && !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) { - mXmppConnectionService.keyStatusUpdated(); - } - } @Override public void onIqPacketReceived(Account account, IqPacket packet) { @@ -594,7 +638,7 @@ public class AxolotlService { if (preKeyBundleList.isEmpty() || bundle == null) { Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "preKey IQ packet invalid: " + packet); fetchStatusMap.put(address, FetchStatus.ERROR); - finish(); + finishBuildingSessionsFromPEP(address); return; } Random random = new Random(); @@ -602,7 +646,7 @@ public class AxolotlService { if (preKey == null) { //should never happen fetchStatusMap.put(address, FetchStatus.ERROR); - finish(); + finishBuildingSessionsFromPEP(address); return; } @@ -617,17 +661,21 @@ public class AxolotlService { XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", "")); sessions.put(address, session); fetchStatusMap.put(address, FetchStatus.SUCCESS); + if (Config.X509_VERIFICATION) { + verifySessionWithPEP(session, bundle.getIdentityKey()); + } else { + finishBuildingSessionsFromPEP(address); + } } catch (UntrustedIdentityException | InvalidKeyException e) { Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error building session for " + address + ": " + e.getClass().getName() + ", " + e.getMessage()); fetchStatusMap.put(address, FetchStatus.ERROR); + finishBuildingSessionsFromPEP(address); } - - finish(); } else { fetchStatusMap.put(address, FetchStatus.ERROR); Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while building session:" + packet.findChild("error")); - finish(); + finishBuildingSessionsFromPEP(address); } } }); @@ -699,9 +747,9 @@ public class AxolotlService { return newSessions; } - public boolean hasPendingKeyFetches(Conversation conversation) { + public boolean hasPendingKeyFetches(Account account, Contact contact) { AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toString(), 0); - AxolotlAddress foreignAddress = new AxolotlAddress(conversation.getJid().toBareJid().toString(), 0); + AxolotlAddress foreignAddress = new AxolotlAddress(contact.getJid().toBareJid().toString(), 0); return fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING) || fetchStatusMap.getAll(foreignAddress).containsValue(FetchStatus.PENDING); diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 0eb38c9fd..ebfd98055 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -297,6 +297,9 @@ public class Account extends AbstractEntity { public void initAccountServices(final XmppConnectionService context) { this.mOtrService = new OtrService(context, this); this.axolotlService = new AxolotlService(this, context); + if (xmppConnection != null) { + xmppConnection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService); + } } public OtrService getOtrService() { diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index fb69860db..7457cad8b 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -137,9 +137,13 @@ public class IqGenerator extends AbstractGenerator { public IqPacket retrieveBundlesForDevice(final Jid to, final int deviceid) { final IqPacket packet = retrieve(AxolotlService.PEP_BUNDLES+":"+deviceid, null); - if(to != null) { - packet.setTo(to); - } + packet.setTo(to); + return packet; + } + + public IqPacket retrieveVerificationForDevice(final Jid to, final int deviceid) { + final IqPacket packet = retrieve(AxolotlService.PEP_VERIFICATION+":"+deviceid, null); + packet.setTo(to); return packet; } diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index f6446cfd1..e26a493f5 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.parser; import android.support.annotation.NonNull; import android.util.Base64; import android.util.Log; +import android.util.Pair; import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.libaxolotl.InvalidKeyException; @@ -10,6 +11,10 @@ import org.whispersystems.libaxolotl.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.libaxolotl.state.PreKeyBundle; +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -204,6 +209,30 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { return preKeyRecords; } + public Pair verification(final IqPacket packet) { + Element item = getItem(packet); + Element verification = item != null ? item.findChild("verification",AxolotlService.PEP_PREFIX) : null; + Element chain = verification != null ? verification.findChild("chain") : null; + Element signature = verification != null ? verification.findChild("signature") : null; + if (chain != null && signature != null) { + List certElements = chain.getChildren(); + X509Certificate[] certificates = new X509Certificate[certElements.size()]; + try { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + int i = 0; + for(Element cert : certElements) { + certificates[i] = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(Base64.decode(cert.getContent(),Base64.DEFAULT))); + ++i; + } + return new Pair<>(certificates,Base64.decode(signature.getContent(),Base64.DEFAULT)); + } catch (CertificateException e) { + return null; + } + } else { + return null; + } + } + public PreKeyBundle bundle(final IqPacket bundle) { Element bundleItem = getItem(bundle); if(bundleItem == null) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index bb4a1ce96..5bfdd60fb 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -60,6 +60,7 @@ import de.duenndns.ssl.MemorizingTrustManager; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; +import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Blockable; @@ -256,7 +257,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa mMessageArchiveService.executePendingQueries(account); mJingleConnectionManager.cancelInTransmission(); syncDirtyContacts(account); - account.getAxolotlService().publishBundlesIfNeeded(true, false); } }; private OnStatusChanged statusListener = new OnStatusChanged() { @@ -459,7 +459,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa final String action = intent == null ? null : intent.getAction(); boolean interactive = false; if (action != null) { - Log.d(Config.LOGTAG, "action: " + action); switch (action) { case ConnectivityManager.CONNECTIVITY_ACTION: if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) { @@ -760,6 +759,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa connection.setOnBindListener(this.mOnBindListener); connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService); + AxolotlService axolotlService = account.getAxolotlService(); + if (axolotlService != null) { + connection.addOnAdvancedStreamFeaturesAvailableListener(axolotlService); + } return connection; } @@ -1066,8 +1069,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void run() { Log.d(Config.LOGTAG, "restoring roster"); for (Account account : accounts) { - databaseBackend.readRoster(account.getRoster()); account.initAccountServices(XmppConnectionService.this); + databaseBackend.readRoster(account.getRoster()); } getBitmapCache().evictAll(); Looper.prepare(); diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index ab3130748..99ab342d6 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -8,6 +8,7 @@ import android.widget.Button; import android.widget.CompoundButton; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import org.whispersystems.libaxolotl.IdentityKey; @@ -16,6 +17,7 @@ import java.util.Map; import java.util.Set; import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -27,11 +29,11 @@ import eu.siacs.conversations.xmpp.jid.Jid; public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated { private Jid accountJid; private Jid contactJid; - private boolean hasOtherTrustedKeys = false; - private boolean hasPendingFetches = false; + private boolean hasNoTrustedKeys = true; private Contact contact; + private Account mAccount; private TextView keyErrorMessage; private LinearLayout keyErrorMessageCard; private TextView ownKeysTitle; @@ -50,10 +52,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate @Override public void onClick(View v) { commitTrusts(); - Intent data = new Intent(); - data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID)); - setResult(RESULT_OK, data); - finish(); + finishOk(); } }; @@ -157,11 +156,11 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate foreignKeysTitle.setText(contactJid.toString()); foreignKeysCard.setVisibility(View.VISIBLE); } - if(hasPendingFetches) { + if(hasPendingKeyFetches()) { setFetching(); lock(); } else { - if (!hasForeignKeys && !hasOtherTrustedKeys) { + if (!hasForeignKeys && hasNoOtherTrustedKeys()) { keyErrorMessageCard.setVisibility(View.VISIBLE); keyErrorMessage.setText(R.string.error_no_keys_to_trust); ownKeys.removeAllViews(); ownKeysCard.setVisibility(View.GONE); @@ -172,12 +171,13 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } } - private void getFingerprints(final Account account) { - Set ownKeysSet = account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED); - Set foreignKeysSet = account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact); + private boolean reloadFingerprints() { + AxolotlService service = this.mAccount.getAxolotlService(); + Set ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED); + Set foreignKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact); if (hasNoTrustedKeys) { - ownKeysSet.addAll(account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED)); - foreignKeysSet.addAll(account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, contact)); + ownKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED)); + foreignKeysSet.addAll(service.getKeysWithTrust(XmppAxolotlSession.Trust.UNTRUSTED, contact)); } for(final IdentityKey identityKey : ownKeysSet) { if(!ownKeysToTrust.containsKey(identityKey)) { @@ -189,39 +189,55 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate foreignKeysToTrust.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); } } + return ownKeysSet.size() + foreignKeysSet.size() > 0; } @Override public void onBackendConnected() { if ((accountJid != null) && (contactJid != null)) { - final Account account = xmppConnectionService - .findAccountByJid(accountJid); - if (account == null) { + this.mAccount = xmppConnectionService.findAccountByJid(accountJid); + if (this.mAccount == null) { return; } - this.contact = account.getRoster().getContact(contactJid); + this.contact = this.mAccount.getRoster().getContact(contactJid); ownKeysToTrust.clear(); foreignKeysToTrust.clear(); - getFingerprints(account); - - if(account.getAxolotlService().getNumTrustedKeys(contact) > 0) { - hasOtherTrustedKeys = true; - } - Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, false); - if(account.getAxolotlService().hasPendingKeyFetches(conversation)) { - hasPendingFetches = true; - } - + reloadFingerprints(); populateView(); } } + private boolean hasNoOtherTrustedKeys() { + return mAccount == null || mAccount.getAxolotlService().getNumTrustedKeys(contact) == 0; + } + + private boolean hasPendingKeyFetches() { + return mAccount != null && contact != null && mAccount.getAxolotlService().hasPendingKeyFetches(mAccount,contact); + } + + @Override public void onKeyStatusUpdated() { - final Account account = xmppConnectionService.findAccountByJid(accountJid); - hasPendingFetches = false; - getFingerprints(account); - refreshUi(); + boolean keysToTrust = reloadFingerprints(); + if (keysToTrust || hasPendingKeyFetches() || hasNoOtherTrustedKeys()) { + refreshUi(); + } else { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(TrustKeysActivity.this, "Nothing to do", Toast.LENGTH_SHORT).show(); + finishOk(); + } + }); + + } + } + + private void finishOk() { + Intent data = new Intent(); + data.putExtra("choice", getIntent().getIntExtra("choice", ConversationActivity.ATTACHMENT_CHOICE_INVALID)); + setResult(RESULT_OK, data); + finish(); } private void commitTrusts() { @@ -248,7 +264,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } private void lockOrUnlockAsNeeded() { - if (!hasOtherTrustedKeys && !foreignKeysToTrust.values().contains(true)){ + if (hasNoOtherTrustedKeys() && !foreignKeysToTrust.values().contains(true)){ lock(); } else { unlock(); diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java index e9ad71971..8091a9966 100644 --- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java @@ -1,16 +1,21 @@ package eu.siacs.conversations.utils; +import android.util.Log; import android.util.Pair; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x500.style.IETFUtils; import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; +import org.bouncycastle.jce.PrincipalUtil; import java.security.SecureRandom; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; +import java.security.cert.X509Extension; import java.text.Normalizer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @@ -137,11 +142,26 @@ public final class CryptoHelper { } } - public static Pair extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException { + public static Pair extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException, CertificateParsingException { + Collection> alternativeNames = certificate.getSubjectAlternativeNames(); + List emails = new ArrayList<>(); + if (alternativeNames != null) { + for(List san : alternativeNames) { + Integer type = (Integer) san.get(0); + if (type == 1) { + emails.add((String) san.get(1)); + } + } + } X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject(); - //String xmpp = IETFUtils.valueToString(x500name.getRDNs(new ASN1ObjectIdentifier("1.3.6.1.5.5.7.8.5"))[0].getFirst().getValue()); - String email = IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue()); + if (emails.size() == 0) { + emails.add(IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue())); + } String name = IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue()); - return new Pair<>(Jid.fromString(email),name); + if (emails.size() >= 1) { + return new Pair<>(Jid.fromString(emails.get(0)), name); + } else { + return null; + } } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index f311688ec..186672488 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -947,11 +947,10 @@ public class XmppConnection implements Runnable { } } disco.put(jid, info); - if (account.getServer().equals(jid)) { + if ((jid.equals(account.getServer()) || jid.equals(account.getJid().toBareJid())) + && disco.containsKey(account.getServer()) + && disco.containsKey(account.getJid().toBareJid())) { enableAdvancedStreamFeatures(); - for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { - listener.onAdvancedStreamFeaturesAvailable(account); - } } } else { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not query disco info for "+jid.toString()); @@ -969,6 +968,9 @@ public class XmppConnection implements Runnable { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Requesting block list"); this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser()); } + for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) { + listener.onAdvancedStreamFeaturesAvailable(account); + } } private void sendServiceDiscoveryItems(final Jid server) {