aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.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/eu/siacs/conversations/crypto/axolotl/AxolotlService.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/eu/siacs/conversations/crypto/axolotl/AxolotlService.java')
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java86
1 files changed, 67 insertions, 19 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);