aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl
diff options
context:
space:
mode:
authorVincent Lucas <chenzo@jitsi.org>2012-08-02 08:53:41 +0000
committerVincent Lucas <chenzo@jitsi.org>2012-08-02 08:53:41 +0000
commita45b6e0940828aa008f07a37c264780585e6362a (patch)
tree4af6822966fc0a9dc63e8656efe6d8d2ea7fece1 /src/net/java/sip/communicator/impl
parentc1366b5d7f88757ab5c95c414269894b619e03fa (diff)
downloadjitsi-a45b6e0940828aa008f07a37c264780585e6362a.zip
jitsi-a45b6e0940828aa008f07a37c264780585e6362a.tar.gz
jitsi-a45b6e0940828aa008f07a37c264780585e6362a.tar.bz2
Adds SDES for XMPP. Works with Jingle and GTalk (only for gmail web app, doesn not work on "talk" for android).
Diffstat (limited to 'src/net/java/sip/communicator/impl')
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java454
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java86
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java183
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java5
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java3
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java238
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/EncryptionPacketExtension.java30
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java7
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf3
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java166
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf3
11 files changed, 923 insertions, 255 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java
index 541e140..0600d97 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java
@@ -6,7 +6,20 @@
*/
package net.java.sip.communicator.impl.protocol.jabber;
+import ch.imvs.sdes4j.srtp.*;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
+import net.java.sip.communicator.impl.protocol.jabber.jinglesdp.*;
+import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.media.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.impl.neomedia.transform.sdes.*;
+import org.jitsi.service.neomedia.*;
+
+import org.jivesoftware.smack.packet.*;
/**
* An implementation of the <tt>CallPeerMediaHandler</tt> abstract class for the
@@ -19,6 +32,13 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
extends CallPeerMediaHandler<T>
{
/**
+ * The <tt>Logger</tt> used by the <tt>CallPeerMediaHandlerJabberImpl</tt>
+ * class and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(AbstractCallPeerMediaHandlerJabberGTalkImpl.class);
+
+ /**
* Indicates if the <tt>CallPeer</tt> will support </tt>inputevt</tt>
* extension (i.e. will be able to be remote-controlled).
*/
@@ -56,4 +76,438 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
{
localInputEvtAware = enable;
}
+
+ /**
+ * Detects and adds ZRTP available encryption method present in the
+ * description given in parameter.
+ *
+ * @param isInitiator True if the local call instance is the initiator of
+ * the call. False otherwise.
+ * @param description The DESCRIPTION element of the JINGLE element which
+ * contains the PAYLOAD-TYPE and (more important here) the ENCRYPTION.
+ * @param mediaType The type of media (AUDIO or VIDEO).
+ */
+ protected void addZRTPAdvertisedEncryptions(
+ boolean isInitiator,
+ RtpDescriptionPacketExtension description,
+ MediaType mediaType)
+ {
+ // Conforming to XEP-0167 schema there is 0 or 1 ENCRYPTION element for
+ // a given DESCRIPTION.
+ EncryptionPacketExtension encryptionPacketExtension
+ = description.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(encryptionPacketExtension != null)
+ {
+ AccountID accountID
+ = getPeer().getProtocolProvider().getAccountID();
+
+ // ZRTP
+ ZrtpHashPacketExtension zrtpHashPacketExtension =
+ encryptionPacketExtension.getFirstChildOfType(
+ ZrtpHashPacketExtension.class);
+
+ if(zrtpHashPacketExtension != null
+ && zrtpHashPacketExtension.getValue() != null
+ && accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true)
+ && getPeer().getCall().isSipZrtpAttribute())
+ {
+ addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
+ }
+ }
+ }
+
+ /**
+ * Detects and adds SDES available encryption method present in the
+ * description given in parameter.
+ *
+ * @param isInitiator True if the local call instance is the initiator of
+ * the call. False otherwise.
+ * @param description The DESCRIPTION element of the JINGLE element which
+ * contains the PAYLOAD-TYPE and (more important here) the ENCRYPTION.
+ * @param mediaType The type of media (AUDIO or VIDEO).
+ */
+ protected void addSDESAdvertisedEncryptions(
+ boolean isInitiator,
+ RtpDescriptionPacketExtension description,
+ MediaType mediaType)
+ {
+ // Conforming to XEP-0167 schema there is 0 or 1 ENCRYPTION element for
+ // a given DESCRIPTION.
+ EncryptionPacketExtension encryptionPacketExtension
+ = description.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(encryptionPacketExtension != null)
+ {
+ AccountID accountID
+ = getPeer().getProtocolProvider().getAccountID();
+
+ // SDES
+ if(accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.SDES_ENABLED,
+ false)
+ && accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true))
+ {
+ Map<MediaTypeSrtpControl, SrtpControl> srtpControls
+ = getSrtpControls();
+ MediaTypeSrtpControl key
+ = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
+ SrtpControl control = srtpControls.get(key);
+ if(control == null)
+ {
+ control
+ = JabberActivator.getMediaService().createSDesControl();
+ srtpControls.put(key, control);
+ }
+
+ SDesControl tmpSDesControl = (SDesControl) control;
+ SrtpCryptoAttribute selectedSdes = selectSdesCryptoSuite(
+ isInitiator,
+ tmpSDesControl,
+ encryptionPacketExtension);
+
+ if(selectedSdes != null)
+ {
+ //found an SDES answer, remove all other controls
+ Iterator<Map.Entry<MediaTypeSrtpControl, SrtpControl>> iter
+ = srtpControls.entrySet().iterator();
+
+ while (iter.hasNext())
+ {
+ Map.Entry<MediaTypeSrtpControl, SrtpControl> entry
+ = iter.next();
+ MediaTypeSrtpControl mtsc = entry.getKey();
+
+ if ((mtsc.mediaType == mediaType)
+ && (mtsc.srtpControlType != SrtpControlType.SDES))
+ {
+ entry.getValue().cleanup();
+ iter.remove();
+ }
+ }
+
+ addAdvertisedEncryptionMethod(SrtpControlType.SDES);
+ }
+ else
+ {
+ control.cleanup();
+ srtpControls.remove(key);
+ }
+ }
+ }
+ // If we were initiating the encryption, and the remote peer does not
+ // manage it, then we must remove the unusable SDES srtpControl.
+ else if(isInitiator)
+ {
+ AccountID accountID
+ = getPeer().getProtocolProvider().getAccountID();
+
+ // SDES
+ if(accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.SDES_ENABLED,
+ false)
+ && accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true))
+ {
+ Map<MediaTypeSrtpControl, SrtpControl> srtpControls
+ = getSrtpControls();
+ MediaTypeSrtpControl key
+ = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
+ SrtpControl control = srtpControls.get(key);
+ if(control != null)
+ {
+ control.cleanup();
+ srtpControls.remove(key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the selected SDES crypto suite selected.
+ *
+ * @param isInitiator True if the local call instance is the initiator of
+ * the call. False otherwise.
+ * @param sDesControl The SDES based SRTP MediaStream encryption
+ * control.
+ * @param encryptionPacketExtension The ENCRYPTION element received from the
+ * remote peer. This may contain the SDES crypto suites available for the
+ * remote peer.
+ *
+ * @return The selected SDES crypto suite supported by both the local and
+ * the remote peer. Or null, if there is no crypto suite supported by both
+ * of the peers.
+ */
+ protected SrtpCryptoAttribute selectSdesCryptoSuite(
+ boolean isInitiator,
+ SDesControl sDesControl,
+ EncryptionPacketExtension encryptionPacketExtension)
+ {
+ List<CryptoPacketExtension> cryptoPacketExtensions =
+ encryptionPacketExtension.getCryptoList();
+ Vector<SrtpCryptoAttribute> peerAttributes
+ = new Vector<SrtpCryptoAttribute>(cryptoPacketExtensions.size());
+
+ for(int i = 0; i < cryptoPacketExtensions.size(); ++i)
+ {
+ peerAttributes.add(
+ cryptoPacketExtensions.get(i).toSrtpCryptoAttribute());
+ }
+
+ if(peerAttributes == null)
+ {
+ return null;
+ }
+
+ if(isInitiator)
+ {
+ return sDesControl.initiatorSelectAttribute(peerAttributes);
+ }
+ else
+ {
+ return sDesControl.responderSelectAttribute(peerAttributes);
+ }
+ }
+
+ /**
+ * Returns if the remote peer supports ZRTP.
+ *
+ * @param encryptionPacketExtension The ENCRYPTION element received from
+ * the remote peer. This may contain the ZRTP acket element for the remote
+ * peer.
+ *
+ * @return True if the remote peer supports ZRTP. False, otherwise.
+ */
+ protected boolean isRemoteZrtpCapable(
+ EncryptionPacketExtension encryptionPacketExtension)
+ {
+ List<? extends PacketExtension> packetExtensions =
+ encryptionPacketExtension.getChildExtensions();
+
+ for(int i = 0; i < packetExtensions.size(); ++i)
+ {
+ if(packetExtensions.get(i) instanceof ZrtpHashPacketExtension)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets ZRTP element to the ENCRYPTION element of the DESCRIPTION for a
+ * given media.
+ *
+ * @param mediaType The type of media we are modifying the DESCRIPTION to
+ * integrate the ENCRYPTION element.
+ * @param description The element containing the media DESCRIPTION and its
+ * encryption.
+ * @param remoteDescription The element containing the media DESCRIPTION and
+ * its encryption for the remote peer. Null, if the local peer is the
+ * initiator of the call.
+ *
+ * @return True if the ZRTP element has been added to encryption. False,
+ * otherwise.
+ */
+ protected boolean setZrtpEncryptionToDescription(
+ MediaType mediaType,
+ RtpDescriptionPacketExtension description,
+ RtpDescriptionPacketExtension remoteDescription)
+ {
+ boolean isRemoteZrtpCapable = (remoteDescription == null);
+ if(remoteDescription != null)
+ {
+ // Conforming to XEP-0167 schema there is 0 or 1 ENCRYPTION
+ // element for a given DESCRIPTION.
+ EncryptionPacketExtension remoteEncryption
+ = remoteDescription.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(remoteEncryption != null
+ && isRemoteZrtpCapable(remoteEncryption))
+ {
+ isRemoteZrtpCapable = true;
+ }
+ }
+
+ if(getPeer().getProtocolProvider().getAccountID()
+ .getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true)
+ && getPeer().getCall().isSipZrtpAttribute()
+ && isRemoteZrtpCapable)
+ {
+ Map<MediaTypeSrtpControl, SrtpControl> srtpControls
+ = getSrtpControls();
+ MediaTypeSrtpControl key
+ = new MediaTypeSrtpControl(mediaType, SrtpControlType.ZRTP);
+ SrtpControl control = srtpControls.get(key);
+
+ if(control == null)
+ {
+ control = JabberActivator.getMediaService().createZrtpControl();
+ srtpControls.put(key, control);
+ }
+
+ String helloHash[] = ((ZrtpControl)control).getHelloHashSep();
+
+ if(helloHash != null && helloHash[1].length() > 0)
+ {
+ ZrtpHashPacketExtension hash = new ZrtpHashPacketExtension();
+ hash.setVersion(helloHash[0]);
+ hash.setValue(helloHash[1]);
+
+ EncryptionPacketExtension encryption
+ = description.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(encryption == null)
+ {
+ encryption = new EncryptionPacketExtension();
+ description.addChildExtension(encryption);
+ }
+ encryption.addChildExtension(hash);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets SDES element(s) to the ENCRYPTION element of the DESCRIPTION for a
+ * given media.
+ *
+ * @param mediaType The type of media we are modifying the DESCRIPTION to
+ * integrate the ENCRYPTION element.
+ * @param description The element containing the media DESCRIPTION and its
+ * encryption.
+ * @param remoteDescription The element containing the media DESCRIPTION and
+ * its encryption for the remote peer. Null, if the local peer is the
+ * initiator of the call.
+ *
+ * @return True if the crypto element has been added to encryption. False,
+ * otherwise.
+ */
+ protected boolean setSDesEncryptionToDescription(
+ MediaType mediaType,
+ RtpDescriptionPacketExtension localDescription,
+ RtpDescriptionPacketExtension remoteDescription)
+ {
+ AccountID accountID = getPeer().getProtocolProvider().getAccountID();
+
+ // check if SDES and encryption is enabled at all
+ if(accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.SDES_ENABLED,
+ false)
+ && accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true))
+ {
+ // get or create the control
+ Map<MediaTypeSrtpControl, SrtpControl> srtpControls
+ = getSrtpControls();
+ MediaTypeSrtpControl key
+ = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
+ SrtpControl control = srtpControls.get(key);
+
+ if (control == null)
+ {
+ control = JabberActivator.getMediaService().createSDesControl();
+ srtpControls.put(key, control);
+ }
+
+ // set the enabled ciphers suites
+ SDesControl sdcontrol = (SDesControl) control;
+ String ciphers
+ = accountID.getAccountPropertyString(
+ ProtocolProviderFactory.SDES_CIPHER_SUITES);
+
+ if (ciphers == null)
+ {
+ ciphers =
+ JabberActivator.getResources().getSettingsString(
+ SDesControl.SDES_CIPHER_SUITES);
+ }
+ sdcontrol.setEnabledCiphers(Arrays.asList(ciphers.split(",")));
+
+ // act as initiator
+ if (remoteDescription == null)
+ {
+ EncryptionPacketExtension localEncryption
+ = localDescription.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(localEncryption == null)
+ {
+ localEncryption = new EncryptionPacketExtension();
+ localDescription.addChildExtension(localEncryption);
+ }
+
+ for(SrtpCryptoAttribute ca:
+ sdcontrol.getInitiatorCryptoAttributes())
+ {
+ CryptoPacketExtension crypto
+ = new CryptoPacketExtension(ca);
+ localEncryption.addChildExtension(crypto);
+ }
+
+ return true;
+ }
+ // act as responder
+ else
+ {
+ // Conforming to XEP-0167 schema there is 0 or 1 ENCRYPTION
+ // element for a given DESCRIPTION.
+ EncryptionPacketExtension remoteEncryption
+ = remoteDescription.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(remoteEncryption != null)
+ {
+ SrtpCryptoAttribute selectedSdes = selectSdesCryptoSuite(
+ false,
+ sdcontrol,
+ remoteEncryption);
+
+ if(selectedSdes != null)
+ {
+ EncryptionPacketExtension localEncryption
+ = localDescription.getFirstChildOfType(
+ EncryptionPacketExtension.class);
+ if(localEncryption == null)
+ {
+ localEncryption = new EncryptionPacketExtension();
+ localDescription.addChildExtension(localEncryption);
+ }
+ CryptoPacketExtension crypto
+ = new CryptoPacketExtension(selectedSdes);
+ localEncryption.addChildExtension(crypto);
+
+ return true;
+ }
+ else
+ {
+ // none of the offered suites match, destroy the sdes
+ // control
+ sdcontrol.cleanup();
+ srtpControls.remove(key);
+ logger.warn(
+ "Received unsupported sdes crypto attribute");
+ }
+ }
+ else
+ {
+ // peer doesn't offer any SDES attribute, destroy the sdes
+ // control
+ sdcontrol.cleanup();
+ srtpControls.remove(key);
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java
index 5f45da7..45a191e 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java
@@ -54,12 +54,9 @@ public class CallPeerMediaHandlerGTalkImpl
= new LinkedHashMap<String, List<PayloadTypePacketExtension> >();
/**
- * The current description of the streams that the remote side has with us.
- * We use {@link LinkedHashMap}s to make sure that we preserve
- * the order of the individual content extensions.
+ * The remote DESCRIPTION.
*/
- private Map<String, List<PayloadTypePacketExtension> > remoteContentMap
- = new LinkedHashMap<String, List<PayloadTypePacketExtension> >();
+ private RtpDescriptionPacketExtension remoteDescription = null;
/**
* The <tt>TransportManager</tt> implementation handling our address
@@ -125,6 +122,8 @@ public class CallPeerMediaHandlerGTalkImpl
throws OperationFailedException,
IllegalArgumentException
{
+ this.remoteDescription = offer;
+
List<PayloadTypePacketExtension> payloadTypes = offer.getPayloadTypes();
boolean atLeastOneValidDescription = false;
List<PayloadTypePacketExtension> answer =
@@ -149,21 +148,6 @@ public class CallPeerMediaHandlerGTalkImpl
}
}
- EncryptionPacketExtension encryptionPacketExtension
- = offer.getFirstChildOfType(EncryptionPacketExtension.class);
- if(encryptionPacketExtension != null)
- {
- ZrtpHashPacketExtension zrtpHashPacketExtension =
- encryptionPacketExtension.getFirstChildOfType(
- ZrtpHashPacketExtension.class);
-
- if(zrtpHashPacketExtension != null
- && zrtpHashPacketExtension.getValue() != null)
- {
- addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
- }
- }
-
for(MediaType mediaType : MediaType.values())
{
if(!(isAudio && mediaType == MediaType.AUDIO) &&
@@ -172,8 +156,6 @@ public class CallPeerMediaHandlerGTalkImpl
continue;
}
- remoteContentMap.put(mediaType.toString(), payloadTypes);
-
MediaDevice dev = getDefaultDevice(mediaType);
MediaDirection devDirection
@@ -321,6 +303,31 @@ public class CallPeerMediaHandlerGTalkImpl
}
}
+ // ZRTP
+ boolean isZRTPAddedToDescription = setZrtpEncryptionToDescription(
+ mediaType,
+ description,
+ remoteDescription);
+ if(isZRTPAddedToDescription)
+ {
+ addZRTPAdvertisedEncryptions(
+ false,
+ remoteDescription,
+ mediaType);
+ }
+ else
+ {
+ // SDES
+ addSDESAdvertisedEncryptions(
+ false,
+ remoteDescription,
+ mediaType);
+ setSDesEncryptionToDescription(
+ mediaType,
+ description,
+ remoteDescription);
+ }
+
initStream(mediaName, connector, dev, format, target,
direction, rtpExtensions, masterStream);
}
@@ -349,21 +356,6 @@ public class CallPeerMediaHandlerGTalkImpl
{
List<PayloadTypePacketExtension> lst = answer.getPayloadTypes();
- EncryptionPacketExtension encryptionPacketExtension
- = answer.getFirstChildOfType(EncryptionPacketExtension.class);
- if(encryptionPacketExtension != null)
- {
- ZrtpHashPacketExtension zrtpHashPacketExtension =
- encryptionPacketExtension.getFirstChildOfType(
- ZrtpHashPacketExtension.class);
-
- if(zrtpHashPacketExtension != null
- && zrtpHashPacketExtension.getValue() != null)
- {
- addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
- }
- }
-
boolean masterStreamSet = true;
for(MediaType mediaType : MediaType.values())
{
@@ -386,6 +378,9 @@ public class CallPeerMediaHandlerGTalkImpl
if(format == null)
continue;
+ addZRTPAdvertisedEncryptions(true, answer, mediaType);
+ addSDESAdvertisedEncryptions(true, answer, mediaType);
+
// stream connector
StreamConnector connector
= transportManager.getStreamConnector(mediaType);
@@ -528,6 +523,23 @@ public class CallPeerMediaHandlerGTalkImpl
mediaDescs.add(ext);
}
}
+
+ if(mediaType == MediaType.AUDIO || isVideo)
+ {
+ //SDES
+ // It is important to set SDES before ZRTP in order to make
+ // GTALK application able to work with SDES.
+ setSDesEncryptionToDescription(
+ mediaType,
+ description,
+ null);
+
+ //ZRTP
+ setZrtpEncryptionToDescription(
+ mediaType,
+ description,
+ null);
+ }
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
index 30c242a..54643bc 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.protocol.jabber;
+import ch.imvs.sdes4j.srtp.*;
+
import java.lang.reflect.*;
import java.util.*;
@@ -346,38 +348,26 @@ public class CallPeerMediaHandlerJabberImpl
getDynamicPayloadTypes(),
getRtpExtensionsRegistry());
+ RtpDescriptionPacketExtension localDescription =
+ JingleUtils.getRtpDescription(ourContent);
+
// ZRTP
- if(getPeer().getCall().isSipZrtpAttribute())
+ boolean isZRTPAddedToDescription = setZrtpEncryptionToDescription(
+ mediaType,
+ localDescription,
+ description);
+ if(isZRTPAddedToDescription)
{
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.ZRTP);
- SrtpControl control = srtpControls.get(key);
-
- if(control == null)
- {
- control
- = JabberActivator.getMediaService().createZrtpControl();
- srtpControls.put(key, control);
- }
-
- String helloHash[] = ((ZrtpControl)control).getHelloHashSep();
-
- if(helloHash != null && helloHash[1].length() > 0)
- {
- EncryptionPacketExtension encryption = new
- EncryptionPacketExtension();
- ZrtpHashPacketExtension hash
- = new ZrtpHashPacketExtension();
- hash.setVersion(helloHash[0]);
- hash.setValue(helloHash[1]);
-
- encryption.addChildExtension(hash);
- RtpDescriptionPacketExtension rtpDescription =
- JingleUtils.getRtpDescription(ourContent);
- rtpDescription.setEncryption(encryption);
- }
+ addZRTPAdvertisedEncryptions(false, description, mediaType);
+ }
+ else
+ {
+ // SDES
+ addSDESAdvertisedEncryptions(false, description, mediaType);
+ setSDesEncryptionToDescription(
+ mediaType,
+ localDescription,
+ description);
}
// got an content which have inputevt, it means that peer requests
@@ -392,22 +382,6 @@ public class CallPeerMediaHandlerJabberImpl
localContentMap.put(content.getName(), ourContent);
atLeastOneValidDescription = true;
-
- EncryptionPacketExtension encryptionPacketExtension
- = description.getFirstChildOfType(
- EncryptionPacketExtension.class);
- if(encryptionPacketExtension != null)
- {
- ZrtpHashPacketExtension zrtpHashPacketExtension =
- encryptionPacketExtension.getFirstChildOfType(
- ZrtpHashPacketExtension.class);
-
- if(zrtpHashPacketExtension != null
- && zrtpHashPacketExtension.getValue() != null)
- {
- addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
- }
- }
}
if (!atLeastOneValidDescription)
@@ -627,42 +601,22 @@ public class CallPeerMediaHandlerJabberImpl
receiveQualityPreset), direction,
dev.getSupportedExtensions());
- //ZRTP
- if(getPeer().getCall().isSipZrtpAttribute())
- {
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(
- dev.getMediaType(),
- SrtpControlType.ZRTP);
- SrtpControl control = srtpControls.get(key);
-
- if(control == null)
- {
- control
- = JabberActivator.getMediaService().createZrtpControl();
- srtpControls.put(key, control);
- }
-
- String helloHash[] = ((ZrtpControl)control).getHelloHashSep();
+ RtpDescriptionPacketExtension description =
+ JingleUtils.getRtpDescription(content);
- if(helloHash != null && helloHash[1].length() > 0)
- {
- EncryptionPacketExtension encryption = new
- EncryptionPacketExtension();
- ZrtpHashPacketExtension hash
- = new ZrtpHashPacketExtension();
+ //SDES
+ // It is important to set SDES before ZRTP in order to make GTALK
+ // application able to work with SDES.
+ setSDesEncryptionToDescription(
+ dev.getMediaType(),
+ description,
+ null);
- hash.setVersion(helloHash[0]);
- hash.setValue(helloHash[1]);
-
- encryption.addChildExtension(hash);
- RtpDescriptionPacketExtension description =
- JingleUtils.getRtpDescription(content);
- description.setEncryption(encryption);
- }
- }
+ //ZRTP
+ setZrtpEncryptionToDescription(
+ dev.getMediaType(),
+ description,
+ null);
return content;
}
@@ -790,49 +744,26 @@ public class CallPeerMediaHandlerJabberImpl
direction,
dev.getSupportedExtensions());
- //ZRTP
- if(getPeer().getCall().isSipZrtpAttribute())
- {
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(
- mediaType,
- SrtpControlType.ZRTP);
- SrtpControl control = srtpControls.get(key);
-
- if(control == null)
- {
- control
- = JabberActivator.getMediaService()
- .createZrtpControl();
- srtpControls.put(key, control);
- }
+ RtpDescriptionPacketExtension description =
+ JingleUtils.getRtpDescription(content);
- String helloHash[] =
- ((ZrtpControl) control).getHelloHashSep();
+ //SDES
+ // It is important to set SDES before ZRTP in order to make
+ // GTALK application able to work with SDES.
+ setSDesEncryptionToDescription(
+ mediaType,
+ description,
+ null);
- if(helloHash != null && helloHash[1].length() > 0)
- {
- EncryptionPacketExtension encryption = new
- EncryptionPacketExtension();
- ZrtpHashPacketExtension hash
- = new ZrtpHashPacketExtension();
- hash.setVersion(helloHash[0]);
- hash.setValue(helloHash[1]);
-
- encryption.addChildExtension(hash);
- RtpDescriptionPacketExtension description =
- JingleUtils.getRtpDescription(content);
- description.setEncryption(encryption);
- }
- }
+ //ZRTP
+ setZrtpEncryptionToDescription(
+ mediaType,
+ description,
+ null);
/* we request a desktop sharing session so add the inputevt
* extension in the "video" content
*/
- RtpDescriptionPacketExtension description
- = JingleUtils.getRtpDescription(content);
if(description.getMedia().equals(MediaType.VIDEO.toString())
&& getLocalInputEvtAware())
{
@@ -1105,6 +1036,9 @@ public class CallPeerMediaHandlerJabberImpl
OperationFailedException.ILLEGAL_ARGUMENT, null, logger);
}
+ addZRTPAdvertisedEncryptions(true, description, mediaType);
+ addSDESAdvertisedEncryptions(true, description, mediaType);
+
StreamConnector connector
= transportManager.getStreamConnector(mediaType);
@@ -1175,21 +1109,6 @@ public class CallPeerMediaHandlerJabberImpl
}
}
- EncryptionPacketExtension encryptionPacketExtension
- = description.getFirstChildOfType(EncryptionPacketExtension.class);
- if(encryptionPacketExtension != null)
- {
- ZrtpHashPacketExtension zrtpHashPacketExtension =
- encryptionPacketExtension.getFirstChildOfType(
- ZrtpHashPacketExtension.class);
-
- if(zrtpHashPacketExtension != null
- && zrtpHashPacketExtension.getValue() != null)
- {
- addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
- }
- }
-
// create the corresponding stream...
initStream(content.getName(), connector, dev,
supportedFormats.get(0), target, direction, rtpExtensions,
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java
index acf1f74..373d3fe 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java
@@ -38,6 +38,7 @@ public class OperationSetBasicTelephonyJabberImpl
implements RegistrationStateChangeListener,
PacketListener,
PacketFilter,
+ OperationSetSecureSDesTelephony,
OperationSetSecureZrtpTelephony,
OperationSetAdvancedTelephony<ProtocolProviderServiceJabberImpl>
{
@@ -401,8 +402,8 @@ public class OperationSetBasicTelephonyJabberImpl
}
}
}
- else if (protocolProvider.isGTalkTesting() /* test GTALK property */
- /* see if peer supports Google Talk voice */
+ else if (protocolProvider.isGTalkTesting() // test GTALK property
+ // see if peer supports Google Talk voice
&& (hasGtalkCaps || alwaysCallGtalk))
{
if(priority > bestPriority)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index 3a8197d..d6947d7 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -1710,6 +1710,9 @@ public class ProtocolProviderServiceJabberImpl
addSupportedOperationSet(
OperationSetSecureZrtpTelephony.class,
basicTelephony);
+ addSupportedOperationSet(
+ OperationSetSecureSDesTelephony.class,
+ basicTelephony);
// initialize video telephony OperationSet
addSupportedOperationSet(
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java
index f8e7ba9..673e922 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/CryptoPacketExtension.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
+import ch.imvs.sdes4j.srtp.*;
+
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
/**
@@ -13,11 +15,24 @@ import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
* used during a jingle session.
*
* @author Emil Ivov
+ * @author Vincent Lucas
*/
public class CryptoPacketExtension
extends AbstractPacketExtension
{
/**
+ * The name of the "crypto" element.
+ */
+ public static final String ELEMENT_NAME = "crypto";
+
+ /**
+ * The namespace for the "crypto" element.
+ * It it set to "not null" only for Gtalk SDES support (may be set to null
+ * once gtalk supports jingle).
+ */
+ public static final String NAMESPACE = "urn:xmpp:jingle:apps:rtp:1";
+
+ /**
* The name of the 'crypto-suite' argument.
*/
public static final String CRYPTO_SUITE_ATTR_NAME = "crypto-suite";
@@ -43,7 +58,67 @@ public class CryptoPacketExtension
*/
public CryptoPacketExtension()
{
- super(null, "crypto");
+ super(NAMESPACE, ELEMENT_NAME);
+ }
+
+ /**
+ * Creates a new {@link CryptoPacketExtension} instance with the proper
+ * element name and namespace and initialises it with the parameters
+ * contained by the cryptoAttribute.
+ *
+ * @param cryptoAttribute The cryptoAttribute containing the crypto-suite,
+ * key-params, session-params and key information.
+ */
+ public CryptoPacketExtension(SrtpCryptoAttribute cryptoAttribute)
+ {
+ this();
+
+ initialize(cryptoAttribute);
+ }
+
+ /**
+ * Initialises it with the parameters contained by the cryptoAttribute.
+ *
+ * @param cryptoAttribute The cryptoAttribute containing the crypto-suite,
+ * key-params, session-params and key information.
+ */
+ private void initialize(SrtpCryptoAttribute cryptoAttribute)
+ {
+ // Encode the tag element.
+ this.setTag(Integer.toString(cryptoAttribute.getTag()));
+
+ // Encode the crypto-suite element.
+ this.setCryptoSuite(cryptoAttribute.getCryptoSuite().encode());
+
+ // Encode the key-params element.
+ StringBuffer keyParamsString = new StringBuffer();
+ SrtpKeyParam[] keyParams = cryptoAttribute.getKeyParams();
+ for(int i = 0; i < keyParams.length; ++i)
+ {
+ keyParamsString.append(keyParams[i].encode());
+ if (i < keyParams.length - 1)
+ {
+ keyParamsString.append(';');
+ }
+ }
+ this.setKeyParams(keyParamsString.toString());
+
+ // Encode the session-params element (optional).
+ SrtpSessionParam[] sessionParams = cryptoAttribute.getSessionParams();
+ if (sessionParams != null)
+ {
+ StringBuffer sessionParamsString = new StringBuffer();
+ for(int i = 0; i < sessionParams.length; ++i)
+ {
+ sessionParamsString.append(
+ sessionParams[i].encode());
+ if (i < sessionParams.length - 1)
+ {
+ sessionParamsString.append(' ');
+ }
+ }
+ this.setSessionParams(sessionParamsString.toString());
+ }
}
/**
@@ -70,6 +145,23 @@ public class CryptoPacketExtension
}
/**
+ * Returns if the current crypto suite equals the one given in parameter.
+ *
+ * @param cryptoSuite a <tt>String</tt> that describes the encryption and
+ * authentication algorithms.
+ *
+ * @return True if the current crypto suite equals the one given in
+ * parameter. False, otherwise.
+ */
+ public boolean equalsCryptoSuite(String cryptoSuite)
+ {
+ String currentCryptoSuite = this.getCryptoSuite();
+ return CryptoPacketExtension.equalsStrings(
+ currentCryptoSuite,
+ cryptoSuite);
+ }
+
+ /**
* Sets the value of the <tt>key-params</tt> attribute that provides one or
* more sets of keying material for the crypto-suite in question).
*
@@ -87,12 +179,29 @@ public class CryptoPacketExtension
* @return a <tt>String</tt> that provides one or more sets of keying
* material for the crypto-suite in question).
*/
- public String getKeyPaams()
+ public String getKeyParams()
{
return getAttributeAsString(KEY_PARAMS_ATTR_NAME);
}
/**
+ * Returns if the current key params equals the one given in parameter.
+ *
+ * @param keyParams a <tt>String</tt> that provides one or more sets of
+ * keying material for the crypto-suite in question.
+ *
+ * @return True if the current key params equals the one given in
+ * parameter. False, otherwise.
+ */
+ public boolean equalsKeyParams(String keyParams)
+ {
+ String currentKeyParams = this.getKeyParams();
+ return CryptoPacketExtension.equalsStrings(
+ currentKeyParams,
+ keyParams);
+ }
+
+ /**
* Sets the value of the <tt>session-params</tt> attribute that provides
* transport-specific parameters for SRTP negotiation.
*
@@ -110,12 +219,29 @@ public class CryptoPacketExtension
* @return a <tt>String</tt> that provides transport-specific parameters
* for SRTP negotiation.
*/
- public String getSessionPaams()
+ public String getSessionParams()
{
return getAttributeAsString(SESSION_PARAMS_ATTR_NAME);
}
/**
+ * Returns if the current session params equals the one given in parameter.
+ *
+ * @param sessionParams a <tt>String</tt> that provides transport-specific
+ * parameters for SRTP negotiation.
+ *
+ * @return True if the current session params equals the one given in
+ * parameter. False, otherwise.
+ */
+ public boolean equalsSessionParams(String sessionParams)
+ {
+ String currentSessionParams = this.getSessionParams();
+ return CryptoPacketExtension.equalsStrings(
+ currentSessionParams,
+ sessionParams);
+ }
+
+ /**
* Sets the value of the <tt>tag</tt> attribute: a decimal number used as
* an identifier for a particular crypto element.
*
@@ -137,4 +263,110 @@ public class CryptoPacketExtension
{
return getAttributeAsString(TAG_ATTR_NAME);
}
+
+ /**
+ * Returns if the current tag equals the one given in parameter.
+ *
+ * @param tag a <tt>String</tt> containing a decimal number used as an
+ * identifier for a particular crypto element.
+ *
+ * @return True if the current tag equals the one given in parameter. False,
+ * otherwise.
+ */
+ public boolean equalsTag(String tag)
+ {
+ String currentTag = this.getTag();
+ return CryptoPacketExtension.equalsStrings(
+ currentTag,
+ tag);
+ }
+
+ /**
+ * Returns a SrtpCryptoAttribute corresponding to this
+ * CryptoPAcketExtension.
+ *
+ * @return A SrtpCryptoAttribute corresponding to this
+ * CryptoPAcketExtension.
+ */
+ public SrtpCryptoAttribute toSrtpCryptoAttribute()
+ {
+ // Decode the tag element.
+ int tag = Integer.parseInt(this.getTag());
+
+ // Decode the crypto-suite element.
+ SrtpCryptoSuite cryptoSuite
+ = new SrtpCryptoSuite(this.getCryptoSuite());
+
+ // Decode the key-params element.
+ String[] stringKeyParams = this.getKeyParams().split(";");
+ SrtpKeyParam[] keyParams = new SrtpKeyParam[stringKeyParams.length];
+ for(int i = 0; i < stringKeyParams.length; ++i)
+ {
+ keyParams[i] = new SrtpKeyParam(stringKeyParams[i]);
+ }
+
+ // Decode the session-params element (optional).
+ String tmpStringSessionParams = this.getSessionParams();
+ SrtpSessionParam[] sessionParams = null;
+ if(tmpStringSessionParams != null)
+ {
+ String[] stringSessionParams = tmpStringSessionParams.split(" ");
+ sessionParams = new SrtpSessionParam[stringSessionParams.length];
+ for(int i = 0; i < stringSessionParams.length; ++i)
+ {
+ sessionParams[i]
+ = SrtpSessionParam.create(stringSessionParams[i]);
+ }
+ }
+
+ // Creaates the new SrtpCryptoAttribute.
+ return new SrtpCryptoAttribute(
+ tag,
+ cryptoSuite,
+ keyParams,
+ sessionParams);
+ }
+
+ /**
+ * Returns if the first String equals the second one.
+ *
+ * @param string1 A String to be compared with the second one.
+ * @param string2 A String to be compared with the fisrt one.
+ *
+ * @return True if both strings are null, or if they represent the same
+ * sequane of characters. False, otherwise.
+ */
+ private static boolean equalsStrings(String string1, String string2)
+ {
+ return (
+ ((string1 == null) && (string2 == null))
+ || string1.equals(string2)
+ );
+ }
+
+ /**
+ * Returns if the current CryptoPacketExtension equals the one given in
+ * parameter.
+ *
+ * @param obj an object which might be an instance of CryptoPacketExtension.
+ *
+ * @return True if the object in parameter is a CryptoPAcketExtension with
+ * all fields (crypto-suite, key-params, session-params and tag)
+ * corresponding to the current one. False, otherwsise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(obj instanceof CryptoPacketExtension)
+ {
+ CryptoPacketExtension crypto = (CryptoPacketExtension) obj;
+
+ return (
+ crypto.equalsCryptoSuite(this.getCryptoSuite())
+ && crypto.equalsKeyParams(this.getKeyParams())
+ && crypto.equalsSessionParams(this.getSessionParams())
+ && crypto.equalsTag(this.getTag())
+ );
+ }
+ return false;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/EncryptionPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/EncryptionPacketExtension.java
index 9fc07cc..9d07609 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/EncryptionPacketExtension.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/EncryptionPacketExtension.java
@@ -23,8 +23,10 @@ public class EncryptionPacketExtension
{
/**
* The namespace of the "encryption" element.
+ * It it set to "not null" only for Gtalk SDES support (may be set to null
+ * once gtalk supports jingle).
*/
- public static final String NAMESPACE = null;
+ public static final String NAMESPACE = "urn:xmpp:jingle:apps:rtp:1";
/**
* The name of the "encryption" element.
@@ -58,7 +60,10 @@ public class EncryptionPacketExtension
*/
public void addCrypto(CryptoPacketExtension crypto)
{
- cryptoList.add(crypto);
+ if(!cryptoList.contains(crypto))
+ {
+ cryptoList.add(crypto);
+ }
}
/**
@@ -111,8 +116,27 @@ public class EncryptionPacketExtension
{
List<PacketExtension> ret = new ArrayList<PacketExtension>();
- ret.addAll(getCryptoList());
ret.addAll(super.getChildExtensions());
return ret;
}
+
+ /**
+ * Adds the specified <tt>childExtension</tt> to the list of extensions
+ * registered with this packet.
+ * <p/>
+ * Overriding extensions may need to override this method if they would like
+ * to have anything more elaborate than just a list of extensions (e.g.
+ * casting separate instances to more specific.
+ *
+ * @param childExtension the extension we'd like to add here.
+ */
+ public void addChildExtension(PacketExtension childExtension)
+ {
+ super.addChildExtension(childExtension);
+
+ if(childExtension instanceof CryptoPacketExtension)
+ {
+ this.addCrypto(((CryptoPacketExtension) childExtension));
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
index e1ab9f3..4b36b56 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
@@ -72,6 +72,13 @@ public class JingleIQProvider implements IQProvider
new DefaultPacketExtensionProvider
<ZrtpHashPacketExtension>(ZrtpHashPacketExtension.class));
+ //<crypto/> provider
+ providerManager.addExtensionProvider(
+ CryptoPacketExtension.ELEMENT_NAME,
+ RtpDescriptionPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <CryptoPacketExtension>(CryptoPacketExtension.class));
+
//ice-udp transport
providerManager.addExtensionProvider(
IceUdpTransportPacketExtension.ELEMENT_NAME,
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
index 5406148..e08292b 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
@@ -4,7 +4,8 @@ Bundle-Description: An Jabber implementation of the Protocol Provider Service.
Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
System-Bundle: yes
-Import-Package: javax.net,
+Import-Package: ch.imvs.sdes4j.srtp,
+ javax.net,
javax.net.ssl,
javax.security.auth.callback,
javax.security.sasl,
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
index 8de5f07..b6c0a09 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.protocol.sip;
+import ch.imvs.sdes4j.srtp.*;
+
import java.net.*;
import java.util.*;
@@ -586,8 +588,10 @@ public class CallPeerMediaHandlerSipImpl
mutuallySupportedFormats, connector,
direction, rtpExtensions);
- if(!updateMediaDescriptionForSDes(mediaType, md, mediaDescription))
- updateMediaDescriptionForZrtp(mediaType, md);
+ if(!updateMediaDescriptionForZrtp(mediaType, md))
+ {
+ updateMediaDescriptionForSDes(mediaType, md, mediaDescription);
+ }
// create the corresponding stream...
MediaFormat fmt = findMediaFormat(remoteFormats,
@@ -640,8 +644,10 @@ public class CallPeerMediaHandlerSipImpl
*
* @param mediaType the media type.
* @param md the description to be updated.
+ *
+ * @return True if ZRTP is added tp the media description. False, otherwise.
*/
- private void updateMediaDescriptionForZrtp(
+ private boolean updateMediaDescriptionForZrtp(
MediaType mediaType, MediaDescription md)
{
MediaAwareCallPeer<?, ?, ?> peer = getPeer();
@@ -670,13 +676,17 @@ public class CallPeerMediaHandlerSipImpl
String helloHash = zcontrol.getHelloHash();
if(helloHash != null && helloHash.length() > 0)
+ {
md.setAttribute(SdpUtils.ZRTP_HASH_ATTR, helloHash);
+ return true;
+ }
}
catch (SdpException ex)
{
logger.error("Cannot add zrtp-hash to sdp", ex);
}
}
+ return false;
}
/**
@@ -685,6 +695,8 @@ public class CallPeerMediaHandlerSipImpl
* @param mediaType the media type.
* @param localMd the description of the local peer.
* @param remoteMd the description of the remote peer.
+ *
+ * @return True if SDES is added tp the media description. False, otherwise.
*/
private boolean updateMediaDescriptionForSDes(
MediaType mediaType,
@@ -736,64 +748,37 @@ public class CallPeerMediaHandlerSipImpl
@SuppressWarnings("unchecked")
Vector<Attribute> atts = localMd.getAttributes(true);
- for (String ca : sdcontrol.getInitiatorCryptoAttributes())
- atts.add(SdpUtils.createAttribute("crypto", ca));
+ for(SrtpCryptoAttribute ca:
+ sdcontrol.getInitiatorCryptoAttributes())
+ atts.add(SdpUtils.createAttribute("crypto", ca.encode()));
return true;
}
// act as responder
else
{
- @SuppressWarnings("unchecked")
- Vector<Attribute> atts = remoteMd.getAttributes(true);
- List<String> peerAttributes = new LinkedList<String>();
+ SrtpCryptoAttribute localAttr
+ = selectSdesCryptoSuite(false, sdcontrol, remoteMd);
- for (Attribute a : atts)
+ if (localAttr != null)
{
try
{
- if (a.getName().equals("crypto"))
- peerAttributes.add(a.getValue());
- }
- catch (SdpParseException e)
- {
- logger.error("received an uparsable sdp attribute", e);
- }
- }
- if (peerAttributes.size() > 0)
- {
- String localAttr
- = sdcontrol.responderSelectAttribute(peerAttributes);
-
- if (localAttr != null)
- {
- try
- {
- localMd.setAttribute("crypto", localAttr);
- return true;
- }
- catch (SdpException e)
- {
- logger.error("unable to add crypto to answer", e);
- }
+ localMd.setAttribute("crypto", localAttr.encode());
+ return true;
}
- else
+ catch (SdpException e)
{
- // none of the offered suites match, destroy the sdes
- // control
- sdcontrol.cleanup();
- srtpControls.remove(key);
- logger.warn(
- "Received unsupported sdes crypto attribute "
- + peerAttributes);
+ logger.error("unable to add crypto to answer", e);
}
}
else
{
- // peer doesn't offer any SDES attribute, destroy the sdes
+ // none of the offered suites match, destroy the sdes
// control
sdcontrol.cleanup();
srtpControls.remove(key);
+ logger.warn("Received unsupported sdes crypto attribute.");
}
return false;
}
@@ -874,8 +859,6 @@ public class CallPeerMediaHandlerSipImpl
this.setCallInfoURL(SdpUtils.getCallInfoURL(answer));
boolean masterStreamSet = false;
- boolean hasZrtp = false;
- boolean hasSdes = false;
List<MediaType> seenMediaTypes = new ArrayList<MediaType>();
for (MediaDescription mediaDescription : remoteDescriptions)
{
@@ -979,33 +962,14 @@ public class CallPeerMediaHandlerSipImpl
if(scontrol != null)
{
- List<String> peerAttributes = new LinkedList<String>();
- @SuppressWarnings("unchecked")
- Vector<Attribute> attrs = mediaDescription.getAttributes(true);
-
- for (Attribute a : attrs)
- {
- try
- {
- if (a.getName().equals("crypto"))
- {
- peerAttributes.add(a.getValue());
- }
- }
- catch (SdpParseException e)
- {
- logger.error("received an unparsable sdp attribute", e);
- }
- }
- if(!((SDesControl) scontrol).initiatorSelectAttribute(
- peerAttributes))
+ if(selectSdesCryptoSuite(
+ true,
+ (SDesControl) scontrol,
+ mediaDescription) == null)
{
scontrol.cleanup();
srtpControls.remove(key);
- if(peerAttributes.size() > 0)
- logger
- .warn("Received unsupported sdes crypto attribute: "
- + peerAttributes);
+ logger.warn("Received unsupported sdes crypto attribute.");
}
else
{
@@ -1028,7 +992,7 @@ public class CallPeerMediaHandlerSipImpl
}
}
- hasSdes = true;
+ addAdvertisedEncryptionMethod(SrtpControlType.SDES);
}
}
@@ -1053,8 +1017,11 @@ public class CallPeerMediaHandlerSipImpl
try
{
- hasZrtp = mediaDescription.getAttribute(
- SdpUtils.ZRTP_HASH_ATTR) != null;
+ if(mediaDescription.getAttribute(SdpUtils.ZRTP_HASH_ATTR)
+ != null)
+ {
+ addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
+ }
}
catch (SdpParseException e)
{
@@ -1065,11 +1032,6 @@ public class CallPeerMediaHandlerSipImpl
initStream(connector, dev, supportedFormats.get(0), target,
direction, rtpExtensions, masterStream);
}
-
- if(hasSdes)
- addAdvertisedEncryptionMethod(SrtpControlType.SDES);
- if(hasZrtp)
- addAdvertisedEncryptionMethod(SrtpControlType.ZRTP);
}
/**
@@ -1239,4 +1201,56 @@ public class CallPeerMediaHandlerSipImpl
{
this.supportQualityControls = value;
}
+
+ /**
+ * Returns the selected crypto suite selected.
+ *
+ * @param isInitiator True if the local call instance is the initiator of
+ * the call. False otherwise.
+ * @param sDesControl The SDES based SRTP MediaStream encryption control.
+ * @param encryptionPacketExtension The ENCRYPTION element received from the
+ * remote peer. This contains the SDES crypto suites available for the
+ * remote peer.
+ *
+ * @return The selected SDES crypto suite supported by both the local and
+ * the remote peer. Or null, if there is no crypto suite supported by both
+ * of the peers.
+ */
+ protected SrtpCryptoAttribute selectSdesCryptoSuite(
+ boolean isInitiator,
+ SDesControl sDesControl,
+ MediaDescription mediaDescription)
+ {
+ @SuppressWarnings("unchecked")
+ Vector<Attribute> attrs = mediaDescription.getAttributes(true);
+ Vector<SrtpCryptoAttribute> peerAttributes
+ = new Vector<SrtpCryptoAttribute>(attrs.size());
+
+ Attribute a;
+ for(int i = 0; i < attrs.size(); ++i)
+ {
+ try
+ {
+ a = attrs.get(i);
+ if (a.getName().equals("crypto"))
+ {
+ peerAttributes.add(
+ SrtpCryptoAttribute.create(a.getValue()));
+ }
+ }
+ catch (SdpParseException e)
+ {
+ logger.error("received an unparsable sdp attribute", e);
+ }
+ }
+
+ if(isInitiator)
+ {
+ return sDesControl.initiatorSelectAttribute(peerAttributes);
+ }
+ else
+ {
+ return sDesControl.responderSelectAttribute(peerAttributes);
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
index 16eeb65..4d7a9db 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
@@ -4,7 +4,8 @@ Bundle-Description: A bundle that implements the Protocol Provider package over
Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
System-Bundle: yes
-Import-Package: javax.net,
+Import-Package: ch.imvs.sdes4j.srtp,
+ javax.net,
javax.net.ssl,
javax.security.auth.x500,
javax.xml.datatype,