make sure omemo sessions are verified if the the respective config flag is set

This commit is contained in:
Daniel Gultsch 2021-05-04 19:04:01 +02:00
parent 9544b994dc
commit e2324209ed
3 changed files with 46 additions and 9 deletions

View file

@ -1234,6 +1234,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if (session == null) { if (session == null) {
throw new CryptoFailedException(String.format("No session found for %d", deviceId)); throw new CryptoFailedException(String.format("No session found for %d", deviceId));
} }
if (Config.REQUIRE_RTP_VERIFICATION) {
requireVerification(session);
}
final ImmutableMap.Builder<String, RtpContentMap.DescriptionTransport> descriptionTransportBuilder = new ImmutableMap.Builder<>(); final ImmutableMap.Builder<String, RtpContentMap.DescriptionTransport> descriptionTransportBuilder = new ImmutableMap.Builder<>();
final OmemoVerification omemoVerification = new OmemoVerification(); final OmemoVerification omemoVerification = new OmemoVerification();
omemoVerification.setDeviceId(deviceId); omemoVerification.setDeviceId(deviceId);
@ -1283,6 +1286,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
final Element encrypted = child.findChildEnsureSingle(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX); final Element encrypted = child.findChildEnsureSingle(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
final XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, from.asBareJid()); final XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, from.asBareJid());
final XmppAxolotlSession session = getReceivingSession(xmppAxolotlMessage); final XmppAxolotlSession session = getReceivingSession(xmppAxolotlMessage);
if (Config.REQUIRE_RTP_VERIFICATION) {
requireVerification(session);
}
final XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintext = xmppAxolotlMessage.decrypt(session, getOwnDeviceId()); final XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintext = xmppAxolotlMessage.decrypt(session, getOwnDeviceId());
final Integer preKeyId = session.getPreKeyIdAndReset(); final Integer preKeyId = session.getPreKeyIdAndReset();
if (preKeyId != null) { if (preKeyId != null) {
@ -1299,6 +1305,16 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
return new OmemoVerifiedPayload<>(omemoVerification, transportInfo); return new OmemoVerifiedPayload<>(omemoVerification, transportInfo);
} }
private static void requireVerification(final XmppAxolotlSession session) {
if (session.getTrust().isVerified()) {
return;
}
throw new NotVerifiedException(String.format(
"session with %s was not verified",
session.getFingerprint()
));
}
public void prepareKeyTransportMessage(final Conversation conversation, final OnMessageCreatedCallback onMessageCreatedCallback) { public void prepareKeyTransportMessage(final Conversation conversation, final OnMessageCreatedCallback onMessageCreatedCallback) {
executor.execute(new Runnable() { executor.execute(new Runnable() {
@Override @Override
@ -1690,4 +1706,12 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
return payload; return payload;
} }
} }
public static class NotVerifiedException extends SecurityException {
public NotVerifiedException(String message) {
super(message);
}
}
} }

View file

@ -762,9 +762,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
} catch (final WebRTCWrapper.InitializationException e) { } catch (final WebRTCWrapper.InitializationException e) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to initialize WebRTC"); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to initialize WebRTC");
webRTCWrapper.close(); webRTCWrapper.close();
sendJingleMessage("retract", id.with.asBareJid()); sendRetract(Reason.ofException(e));
transitionOrThrow(State.TERMINATED_APPLICATION_FAILURE);
this.finish();
return; return;
} }
try { try {
@ -776,22 +774,27 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
} catch (final Exception e) { } catch (final Exception e) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to sendSessionInitiate", Throwables.getRootCause(e)); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to sendSessionInitiate", Throwables.getRootCause(e));
webRTCWrapper.close(); webRTCWrapper.close();
final Reason reason = Reason.ofException(e);
if (isInState(targetState)) { if (isInState(targetState)) {
sendSessionTerminate(Reason.FAILED_APPLICATION); sendSessionTerminate(reason);
} else { } else {
sendJingleMessage("retract", id.with.asBareJid()); sendRetract(reason);
transitionOrThrow(State.TERMINATED_APPLICATION_FAILURE);
this.finish();
} }
} }
} }
private void sendRetract(final Reason reason) {
//TODO embed reason into retract
sendJingleMessage("retract", id.with.asBareJid());
transitionOrThrow(reasonToState(reason));
this.finish();
}
private void sendSessionInitiate(final RtpContentMap rtpContentMap, final State targetState) { private void sendSessionInitiate(final RtpContentMap rtpContentMap, final State targetState) {
this.initiatorRtpContentMap = rtpContentMap; this.initiatorRtpContentMap = rtpContentMap;
this.transitionOrThrow(targetState);
//TODO do on background thread?
final RtpContentMap outgoingContentMap = encryptSessionInitiate(rtpContentMap); final RtpContentMap outgoingContentMap = encryptSessionInitiate(rtpContentMap);
final JinglePacket sessionInitiate = outgoingContentMap.toJinglePacket(JinglePacket.Action.SESSION_INITIATE, id.sessionId); final JinglePacket sessionInitiate = outgoingContentMap.toJinglePacket(JinglePacket.Action.SESSION_INITIATE, id.sessionId);
this.transitionOrThrow(targetState);
send(sessionInitiate); send(sessionInitiate);
} }

View file

@ -3,7 +3,9 @@ package eu.siacs.conversations.xmpp.jingle.stanzas;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Throwables;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.xmpp.jingle.RtpContentMap; import eu.siacs.conversations.xmpp.jingle.RtpContentMap;
public enum Reason { public enum Reason {
@ -51,4 +53,12 @@ public enum Reason {
return FAILED_APPLICATION; return FAILED_APPLICATION;
} }
} }
public static Reason ofException(final Exception e) {
final Throwable root = Throwables.getRootCause(e);
if (root instanceof RuntimeException) {
return of((RuntimeException) root);
}
return FAILED_APPLICATION;
}
} }