diff options
author | Vincent Lucas <chenzo@jitsi.org> | 2012-08-02 08:53:41 +0000 |
---|---|---|
committer | Vincent Lucas <chenzo@jitsi.org> | 2012-08-02 08:53:41 +0000 |
commit | a45b6e0940828aa008f07a37c264780585e6362a (patch) | |
tree | 4af6822966fc0a9dc63e8656efe6d8d2ea7fece1 /src/net/java/sip/communicator/impl | |
parent | c1366b5d7f88757ab5c95c414269894b619e03fa (diff) | |
download | jitsi-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')
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, |