aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java
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 /src/main/java
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 'src/main/java')
-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) {