invoke x509 verification upon receiving prekey message in rtp session
This commit is contained in:
parent
9c16af25fb
commit
ddf597e0d3
|
@ -8,7 +8,13 @@ import android.util.Pair;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
|
@ -733,58 +739,62 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
axolotlStore.setFingerprintStatus(fingerprint, status);
|
axolotlStore.setFingerprintStatus(fingerprint, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifySessionWithPEP(final XmppAxolotlSession session) {
|
private ListenableFuture<XmppAxolotlSession> verifySessionWithPEP(final XmppAxolotlSession session) {
|
||||||
Log.d(Config.LOGTAG, "trying to verify fresh session (" + session.getRemoteAddress().getName() + ") with pep");
|
Log.d(Config.LOGTAG, "trying to verify fresh session (" + session.getRemoteAddress().getName() + ") with pep");
|
||||||
final SignalProtocolAddress address = session.getRemoteAddress();
|
final SignalProtocolAddress address = session.getRemoteAddress();
|
||||||
final IdentityKey identityKey = session.getIdentityKey();
|
final IdentityKey identityKey = session.getIdentityKey();
|
||||||
|
final Jid jid;
|
||||||
try {
|
try {
|
||||||
IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveVerificationForDevice(Jid.of(address.getName()), address.getDeviceId());
|
jid = Jid.of(address.getName());
|
||||||
mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
} catch (final IllegalArgumentException e) {
|
||||||
@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");
|
|
||||||
String fingerprint = session.getFingerprint();
|
|
||||||
Log.d(Config.LOGTAG, "verified session with x.509 signature. fingerprint was: " + fingerprint);
|
|
||||||
setFingerprintTrust(fingerprint, FingerprintStatus.createActiveVerified(true));
|
|
||||||
axolotlStore.setFingerprintCertificate(fingerprint, verification.first[0]);
|
|
||||||
fetchStatusMap.put(address, FetchStatus.SUCCESS_VERIFIED);
|
|
||||||
Bundle information = CryptoHelper.extractCertificateInformation(verification.first[0]);
|
|
||||||
try {
|
|
||||||
final String cn = information.getString("subject_cn");
|
|
||||||
final Jid jid = Jid.of(address.getName());
|
|
||||||
Log.d(Config.LOGTAG, "setting common name for " + jid + " to " + cn);
|
|
||||||
account.getRoster().getContact(jid).setCommonName(cn);
|
|
||||||
} catch (final IllegalArgumentException ignored) {
|
|
||||||
//ignored
|
|
||||||
}
|
|
||||||
finishBuildingSessionsFromPEP(address);
|
|
||||||
return;
|
|
||||||
} 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, "no verification found");
|
|
||||||
}
|
|
||||||
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
|
||||||
finishBuildingSessionsFromPEP(address);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
||||||
finishBuildingSessionsFromPEP(address);
|
finishBuildingSessionsFromPEP(address);
|
||||||
|
return Futures.immediateFuture(session);
|
||||||
}
|
}
|
||||||
|
final SettableFuture<XmppAxolotlSession> future = SettableFuture.create();
|
||||||
|
final IqPacket packet = mXmppConnectionService.getIqGenerator().retrieveVerificationForDevice(jid, address.getDeviceId());
|
||||||
|
mXmppConnectionService.sendIqPacket(account, packet, (account, response) -> {
|
||||||
|
Pair<X509Certificate[], byte[]> verification = mXmppConnectionService.getIqParser().verification(response);
|
||||||
|
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");
|
||||||
|
String fingerprint = session.getFingerprint();
|
||||||
|
Log.d(Config.LOGTAG, "verified session with x.509 signature. fingerprint was: " + fingerprint);
|
||||||
|
setFingerprintTrust(fingerprint, FingerprintStatus.createActiveVerified(true));
|
||||||
|
axolotlStore.setFingerprintCertificate(fingerprint, verification.first[0]);
|
||||||
|
fetchStatusMap.put(address, FetchStatus.SUCCESS_VERIFIED);
|
||||||
|
Bundle information = CryptoHelper.extractCertificateInformation(verification.first[0]);
|
||||||
|
try {
|
||||||
|
final String cn = information.getString("subject_cn");
|
||||||
|
final Jid jid1 = Jid.of(address.getName());
|
||||||
|
Log.d(Config.LOGTAG, "setting common name for " + jid1 + " to " + cn);
|
||||||
|
account.getRoster().getContact(jid1).setCommonName(cn);
|
||||||
|
} catch (final IllegalArgumentException ignored) {
|
||||||
|
//ignored
|
||||||
|
}
|
||||||
|
finishBuildingSessionsFromPEP(address);
|
||||||
|
future.set(session);
|
||||||
|
return;
|
||||||
|
} 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, "no verification found");
|
||||||
|
}
|
||||||
|
fetchStatusMap.put(address, FetchStatus.SUCCESS);
|
||||||
|
finishBuildingSessionsFromPEP(address);
|
||||||
|
future.set(session);
|
||||||
|
});
|
||||||
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishBuildingSessionsFromPEP(final SignalProtocolAddress address) {
|
private void finishBuildingSessionsFromPEP(final SignalProtocolAddress address) {
|
||||||
|
@ -1255,12 +1265,18 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OmemoVerifiedPayload<RtpContentMap> decrypt(OmemoVerifiedRtpContentMap omemoVerifiedRtpContentMap, final Jid from) throws CryptoFailedException {
|
public ListenableFuture<OmemoVerifiedPayload<RtpContentMap>> decrypt(OmemoVerifiedRtpContentMap omemoVerifiedRtpContentMap, final Jid from) {
|
||||||
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();
|
||||||
|
final ImmutableList.Builder<ListenableFuture<XmppAxolotlSession>> pepVerificationFutures = new ImmutableList.Builder<>();
|
||||||
for (final Map.Entry<String, RtpContentMap.DescriptionTransport> content : omemoVerifiedRtpContentMap.contents.entrySet()) {
|
for (final Map.Entry<String, RtpContentMap.DescriptionTransport> content : omemoVerifiedRtpContentMap.contents.entrySet()) {
|
||||||
final RtpContentMap.DescriptionTransport descriptionTransport = content.getValue();
|
final RtpContentMap.DescriptionTransport descriptionTransport = content.getValue();
|
||||||
final OmemoVerifiedPayload<IceUdpTransportInfo> decryptedTransport = decrypt((OmemoVerifiedIceUdpTransportInfo) descriptionTransport.transport, from);
|
final OmemoVerifiedPayload<IceUdpTransportInfo> decryptedTransport;
|
||||||
|
try {
|
||||||
|
decryptedTransport = decrypt((OmemoVerifiedIceUdpTransportInfo) descriptionTransport.transport, from, pepVerificationFutures);
|
||||||
|
} catch (CryptoFailedException e) {
|
||||||
|
return Futures.immediateFailedFuture(e);
|
||||||
|
}
|
||||||
omemoVerification.setOrEnsureEqual(decryptedTransport);
|
omemoVerification.setOrEnsureEqual(decryptedTransport);
|
||||||
descriptionTransportBuilder.put(
|
descriptionTransportBuilder.put(
|
||||||
content.getKey(),
|
content.getKey(),
|
||||||
|
@ -1268,13 +1284,26 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
processPostponed();
|
processPostponed();
|
||||||
return new OmemoVerifiedPayload<>(
|
final ImmutableList<ListenableFuture<XmppAxolotlSession>> sessionFutures = pepVerificationFutures.build();
|
||||||
omemoVerification,
|
return Futures.transform(
|
||||||
new RtpContentMap(omemoVerifiedRtpContentMap.group, descriptionTransportBuilder.build())
|
Futures.allAsList(sessionFutures),
|
||||||
|
sessions -> {
|
||||||
|
if (Config.REQUIRE_RTP_VERIFICATION) {
|
||||||
|
for (XmppAxolotlSession session : sessions) {
|
||||||
|
requireVerification(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new OmemoVerifiedPayload<>(
|
||||||
|
omemoVerification,
|
||||||
|
new RtpContentMap(omemoVerifiedRtpContentMap.group, descriptionTransportBuilder.build())
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
MoreExecutors.directExecutor()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OmemoVerifiedPayload<IceUdpTransportInfo> decrypt(final OmemoVerifiedIceUdpTransportInfo verifiedIceUdpTransportInfo, final Jid from) throws CryptoFailedException {
|
private OmemoVerifiedPayload<IceUdpTransportInfo> decrypt(final OmemoVerifiedIceUdpTransportInfo verifiedIceUdpTransportInfo, final Jid from, ImmutableList.Builder<ListenableFuture<XmppAxolotlSession>> pepVerificationFutures) throws CryptoFailedException {
|
||||||
final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
|
final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
|
||||||
transportInfo.setAttributes(verifiedIceUdpTransportInfo.getAttributes());
|
transportInfo.setAttributes(verifiedIceUdpTransportInfo.getAttributes());
|
||||||
final OmemoVerification omemoVerification = new OmemoVerification();
|
final OmemoVerification omemoVerification = new OmemoVerification();
|
||||||
|
@ -1286,14 +1315,16 @@ 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) {
|
||||||
postponedSessions.add(session);
|
postponedSessions.add(session);
|
||||||
}
|
}
|
||||||
|
if (session.isFresh()) {
|
||||||
|
pepVerificationFutures.add(putFreshSession(session));
|
||||||
|
} else if (Config.REQUIRE_RTP_VERIFICATION) {
|
||||||
|
pepVerificationFutures.add(Futures.immediateFuture(session));
|
||||||
|
}
|
||||||
fingerprint.setContent(plaintext.getPlaintext());
|
fingerprint.setContent(plaintext.getPlaintext());
|
||||||
omemoVerification.setDeviceId(session.getRemoteAddress().getDeviceId());
|
omemoVerification.setDeviceId(session.getRemoteAddress().getDeviceId());
|
||||||
omemoVerification.setSessionFingerprint(plaintext.getFingerprint());
|
omemoVerification.setSessionFingerprint(plaintext.getFingerprint());
|
||||||
|
@ -1512,15 +1543,16 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
|
||||||
return keyTransportMessage;
|
return keyTransportMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putFreshSession(XmppAxolotlSession session) {
|
private ListenableFuture<XmppAxolotlSession> putFreshSession(XmppAxolotlSession session) {
|
||||||
sessions.put(session);
|
sessions.put(session);
|
||||||
if (Config.X509_VERIFICATION) {
|
if (Config.X509_VERIFICATION) {
|
||||||
if (session.getIdentityKey() != null) {
|
if (session.getIdentityKey() != null) {
|
||||||
verifySessionWithPEP(session);
|
return verifySessionWithPEP(session);
|
||||||
} else {
|
} else {
|
||||||
Log.e(Config.LOGTAG, account.getJid().asBareJid() + ": identity key was empty after reloading for x509 verification");
|
Log.e(Config.LOGTAG, account.getJid().asBareJid() + ": identity key was empty after reloading for x509 verification");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Futures.immediateFuture(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FetchStatus {
|
public enum FetchStatus {
|
||||||
|
|
|
@ -3,6 +3,9 @@ package eu.siacs.conversations.xmpp.jingle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
@ -12,7 +15,10 @@ import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
|
||||||
import org.webrtc.EglBase;
|
import org.webrtc.EglBase;
|
||||||
import org.webrtc.IceCandidate;
|
import org.webrtc.IceCandidate;
|
||||||
|
@ -243,7 +249,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveTransportInfo(final JinglePacket jinglePacket) {
|
private void receiveTransportInfo(final JinglePacket jinglePacket) {
|
||||||
if (isInState(State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED, State.SESSION_ACCEPTED)) {
|
//Due to the asynchronicity of processing session-init we might move from NULL|PROCEED to INITIALIZED only after transport-info has been received
|
||||||
|
if (isInState(State.NULL, State.PROCEED, State.SESSION_INITIALIZED, State.SESSION_INITIALIZED_PRE_APPROVED, State.SESSION_ACCEPTED)) {
|
||||||
respondOk(jinglePacket);
|
respondOk(jinglePacket);
|
||||||
final RtpContentMap contentMap;
|
final RtpContentMap contentMap;
|
||||||
try {
|
try {
|
||||||
|
@ -306,22 +313,19 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RtpContentMap receiveRtpContentMap(final JinglePacket jinglePacket, final boolean expectVerification) {
|
private ListenableFuture<RtpContentMap> receiveRtpContentMap(final JinglePacket jinglePacket, final boolean expectVerification) {
|
||||||
final RtpContentMap receivedContentMap = RtpContentMap.of(jinglePacket);
|
final RtpContentMap receivedContentMap = RtpContentMap.of(jinglePacket);
|
||||||
if (receivedContentMap instanceof OmemoVerifiedRtpContentMap) {
|
if (receivedContentMap instanceof OmemoVerifiedRtpContentMap) {
|
||||||
final AxolotlService.OmemoVerifiedPayload<RtpContentMap> omemoVerifiedPayload;
|
final ListenableFuture<AxolotlService.OmemoVerifiedPayload<RtpContentMap>> future = id.account.getAxolotlService().decrypt((OmemoVerifiedRtpContentMap) receivedContentMap, id.with);
|
||||||
try {
|
return Futures.transform(future, omemoVerifiedPayload -> {
|
||||||
omemoVerifiedPayload = id.account.getAxolotlService().decrypt((OmemoVerifiedRtpContentMap) receivedContentMap, id.with);
|
omemoVerification.setOrEnsureEqual(omemoVerifiedPayload);
|
||||||
} catch (final CryptoFailedException e) {
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received verifiable DTLS fingerprint via " + omemoVerification);
|
||||||
throw new SecurityException("Unable to verify DTLS Fingerprint with OMEMO", e);
|
return omemoVerifiedPayload.getPayload();
|
||||||
}
|
}, MoreExecutors.directExecutor());
|
||||||
this.omemoVerification.setOrEnsureEqual(omemoVerifiedPayload);
|
|
||||||
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received verifiable DTLS fingerprint via " + this.omemoVerification);
|
|
||||||
return omemoVerifiedPayload.getPayload();
|
|
||||||
} else if (expectVerification) {
|
} else if (expectVerification) {
|
||||||
throw new SecurityException("DTLS fingerprint was unexpectedly not verifiable");
|
throw new SecurityException("DTLS fingerprint was unexpectedly not verifiable");
|
||||||
} else {
|
} else {
|
||||||
return receivedContentMap;
|
return Futures.immediateFuture(receivedContentMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,9 +344,23 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final RtpContentMap contentMap;
|
final ListenableFuture<RtpContentMap> future = receiveRtpContentMap(jinglePacket, false);
|
||||||
|
Futures.addCallback(future, new FutureCallback<RtpContentMap>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable RtpContentMap rtpContentMap) {
|
||||||
|
receiveSessionInitiate(jinglePacket, rtpContentMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Throwable throwable) {
|
||||||
|
respondOk(jinglePacket);
|
||||||
|
sendSessionTerminate(Reason.ofThrowable(throwable), throwable.getMessage());
|
||||||
|
}
|
||||||
|
}, MoreExecutors.directExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveSessionInitiate(final JinglePacket jinglePacket, final RtpContentMap contentMap) {
|
||||||
try {
|
try {
|
||||||
contentMap = receiveRtpContentMap(jinglePacket, false);
|
|
||||||
contentMap.requireContentDescriptions();
|
contentMap.requireContentDescriptions();
|
||||||
contentMap.requireDTLSFingerprint();
|
contentMap.requireDTLSFingerprint();
|
||||||
} catch (final RuntimeException e) {
|
} catch (final RuntimeException e) {
|
||||||
|
@ -396,9 +414,25 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
terminateWithOutOfOrder(jinglePacket);
|
terminateWithOutOfOrder(jinglePacket);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final RtpContentMap contentMap;
|
final ListenableFuture<RtpContentMap> future = receiveRtpContentMap(jinglePacket, this.omemoVerification.hasFingerprint());
|
||||||
|
Futures.addCallback(future, new FutureCallback<RtpContentMap>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable RtpContentMap rtpContentMap) {
|
||||||
|
receiveSessionAccept(jinglePacket, rtpContentMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull final Throwable throwable) {
|
||||||
|
respondOk(jinglePacket);
|
||||||
|
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": improperly formatted contents in session-accept", throwable);
|
||||||
|
webRTCWrapper.close();
|
||||||
|
sendSessionTerminate(Reason.ofThrowable(throwable), throwable.getMessage());
|
||||||
|
}
|
||||||
|
}, MoreExecutors.directExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveSessionAccept(final JinglePacket jinglePacket, final RtpContentMap contentMap) {
|
||||||
try {
|
try {
|
||||||
contentMap = receiveRtpContentMap(jinglePacket, this.omemoVerification.hasFingerprint());
|
|
||||||
contentMap.requireContentDescriptions();
|
contentMap.requireContentDescriptions();
|
||||||
contentMap.requireDTLSFingerprint();
|
contentMap.requireDTLSFingerprint();
|
||||||
} catch (final RuntimeException e) {
|
} catch (final RuntimeException e) {
|
||||||
|
@ -762,7 +796,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();
|
||||||
sendRetract(Reason.ofException(e));
|
sendRetract(Reason.ofThrowable(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -774,7 +808,7 @@ 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);
|
final Reason reason = Reason.ofThrowable(e);
|
||||||
if (isInState(targetState)) {
|
if (isInState(targetState)) {
|
||||||
sendSessionTerminate(reason);
|
sendSessionTerminate(reason);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1010,7 +1044,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final FingerprintStatus status = id.account.getAxolotlService().getFingerprintTrust(fingerprint);
|
final FingerprintStatus status = id.account.getAxolotlService().getFingerprintTrust(fingerprint);
|
||||||
return status != null && status.getTrust() == FingerprintStatus.Trust.VERIFIED;
|
return status != null && status.isVerified();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void acceptCall() {
|
public synchronized void acceptCall() {
|
||||||
|
|
|
@ -54,8 +54,8 @@ public enum Reason {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Reason ofException(final Exception e) {
|
public static Reason ofThrowable(final Throwable throwable) {
|
||||||
final Throwable root = Throwables.getRootCause(e);
|
final Throwable root = Throwables.getRootCause(throwable);
|
||||||
if (root instanceof RuntimeException) {
|
if (root instanceof RuntimeException) {
|
||||||
return of((RuntimeException) root);
|
return of((RuntimeException) root);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue