aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2015-10-16 23:48:42 +0200
committerDaniel Gultsch <daniel@gultsch.de>2015-10-16 23:48:42 +0200
commitcfeb67d71da01bc95ed713d6591fa6e79fc08dd6 (patch)
treed070a0c490ae4244ddd43f12b3ab3cf6ed905e2c
parentfb7359e6a3aaa3ee0b985358c044de2a5594d45b (diff)
introduced code to verify omemo device keys with x509 certificates.
cleaned up TrustKeysActivity to automatically close if there is nothing to do
Diffstat (limited to '')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java86
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java3
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java10
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java29
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java9
-rw-r--r--src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java80
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java28
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java10
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 58e5a095..ca75ec99 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<T> {
protected Map<String, Map<Integer, T>> 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<X509Certificate[],byte[]> 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 0eb38c9f..ebfd9805 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 fb69860d..7457cad8 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 f6446cfd..e26a493f 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<X509Certificate[],byte[]> 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<Element> 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 bb4a1ce9..5bfdd60f 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 ab313074..99ab342d 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<IdentityKey> ownKeysSet = account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED);
- Set<IdentityKey> foreignKeysSet = account.getAxolotlService().getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, contact);
+ private boolean reloadFingerprints() {
+ AxolotlService service = this.mAccount.getAxolotlService();
+ Set<IdentityKey> ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED);
+ Set<IdentityKey> 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 e9ad7197..8091a996 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<Jid,String> extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException {
+ public static Pair<Jid,String> extractJidAndName(X509Certificate certificate) throws CertificateEncodingException, InvalidJidException, CertificateParsingException {
+ Collection<List<?>> alternativeNames = certificate.getSubjectAlternativeNames();
+ List<String> 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 f311688e..18667248 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) {