[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "srtp-support" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Jul 11 12:38:30 CDT 2011


branch "srtp-support" has been updated
       via  726751650fb57aea3497979a4e3a43d97ca99e3a (commit)
      from  924f082ff8ef9321b4b652a6f506f3ad8777ecd2 (commit)

Summary of changes:
 config/SipConfigurator.py                          |   30 ++++
 .../SipSessionManager/SipConfigurationIf.ice       |   62 +++++++++
 src/PJSipSessionModule.cpp                         |   24 +++-
 src/SipConfiguration.cpp                           |   33 +++++
 src/SipEndpoint.cpp                                |    5 +
 src/SipEndpoint.h                                  |   25 ++++
 src/SipSession.cpp                                 |  141 +++++++++++++++++++-
 src/SipSession.h                                   |    6 +
 8 files changed, 318 insertions(+), 8 deletions(-)


- Log -----------------------------------------------------------------
commit 726751650fb57aea3497979a4e3a43d97ca99e3a
Author: Brent Eagles <beagles at digium.com>
Date:   Mon Jul 11 15:07:24 2011 -0230

    More SIP SRTP changes (this time with the crypto details being set in the right
        place)

diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
index 284c30d..5138459 100755
--- a/config/SipConfigurator.py
+++ b/config/SipConfigurator.py
@@ -25,6 +25,7 @@ import Ice, Configurator, sys, os
 Ice.loadSlice("-I" + os.environ["ASTSCF_HOME"] + " -I" + Ice.getSliceDir() + " --all ../slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice")
 import AsteriskSCF.Configuration.SipSessionManager.V1
 
+
 # Add our own visitor implementations for the sections we support
 class SipSectionVisitors(Configurator.SectionVisitors):
     def visit_general(self, config, section):
@@ -125,6 +126,35 @@ class SipSectionVisitors(Configurator.SectionVisitors):
         mapper.map('enablertpoverice', item, 'enableICE', 'enableRTPICE', config.get, None)
         mapper.map('enableturn', item, 'enableTURN', 'enableRTPICE', config.get, None)
 
+        item = AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoItem()
+        
+        class MapSRTPSupportToValues:
+            def __init__(self, config):
+                self.config = config
+
+            def get(self, section, item):
+                stringVal = self.config.get(section, item)
+                if stringVal == None:
+                    return AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoSupportOptions.SRTP_DISABLED
+                v = stringVal.lower()
+                if v == 'disabled'
+                    return AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoSupportOptions.SRTP_DISABLED
+                elif v == 'optional':
+                    return AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoSupportOptions.SRTP_OPTIONAL
+                elif v == 'required':
+                    return AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoSupportOptions.SRTP_REQUIRED
+                else:
+                    print 'Unrecognized value for SRTP support option. Valid options are disabled, optional or required. Disabling'
+                    return AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoSupportOptions.SRTP_DISABLED
+                
+        srtpSupportMapper = MapSRTPSupportToValues(config)
+        item.cryptoKeys = [ AsteriskSCF.Configuration.SipSessionManager.V1.SRTPCryptoKey() ]
+        mapper.map('srtpsupport', item, 'srtpSupportOptions', 'srtpCryptoSettings', srtpSupportMapper.get, None)
+        mapper.map('disableauth', item, 'disableAuthentication', 'srtpCryptoSettings', config.get, None)
+        mapper.map('disableencrption', item, 'disableEncryption', 'srtpCrytpoSettings', config.get, None)
+        mapper.map('ciphersuite', item.cryptoKeys[0], 'suite', 'srtpCryptoSettings', config.get, None)
+        mapper.map('cryptokey', item.cryptoKeys[0], 'cryptoKey', 'srtpCryptoSettings', config.get, None)
+
         class AllowableCallDirectionTransformer():
             def __init__(self, config):
                 self.config = config
diff --git a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
index c8855d3..37cc7a4 100644
--- a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
@@ -245,6 +245,68 @@ class SipCryptoItem extends SipConfigurationItem
     int timeout = 0;
 };
 
+/** 
+ * SRTP support options.
+ */
+enum SRTPCryptoSupportOptions
+{
+    /**
+     * SRTP is completely disabled for this endpoint.
+     */
+    SRTP_DISABLED, 
+    /**
+     * SRTP is optional. This implies media will be encrypted if both ends of a
+     * media flow are properly configured for SRTP, but will still flow even if
+     * they are not.
+     */
+    SRTP_OPTIONAL,
+    /**
+     * SRTP is absolutely required. Media should not flow unless both ends
+     * of a media flow are properly configured for SRTP.
+     */
+    SRTP_REQUIRED
+};
+    
+/**
+ * SRTP Crypto Key information.
+ */
+class SRTPCryptoKey
+{
+    /**
+     * The cipher suite name.
+     */
+    string suite;
+
+    /**
+     * The key information for the suite.
+     */
+    string cryptoKey;
+};
+
+sequence<SRTPCryptoKey> SRTPCryptoKeySeq;
+
+/**
+ * SRTP crypto configuration.
+ */
+class SRTPCryptoItem extends SipConfigurationItem
+{
+    /**
+     * Options for the crypto function support.
+     */
+    SRTPCryptoSupportOptions srtpSupportOptions;
+
+    /**
+     * Most of the time the following values will be false. They can be overrident to be true however.
+     */
+    bool disableAuthentication;
+    bool disableEncryption;
+
+    /**
+     * The suites and keys supported by this endpoint.
+     */
+    SRTPCryptoKeySeq cryptoKeys;
+};
+
 /**
  * Routing service configuration item
  */
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index b6719d5..c49776f 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -969,8 +969,14 @@ void PJSipSessionModule::on_tsx_state(pjsip_transaction*, pjsip_event*)
 class HandleInviteResponseOperation : public SipQueueableOperation
 {
 public:
-    HandleInviteResponseOperation(int respCode, const int invState, const SipSessionPtr& session)
-        : mRespCode(respCode), mInvState(invState), mSession(session) { }
+    HandleInviteResponseOperation(pjsip_inv_session* inv, int respCode, const int invState,
+            const SipSessionPtr& session) :
+        mInviteSession(inv),
+        mRespCode(respCode),
+        mInvState(invState),
+        mSession(session)
+    {
+    }
 
 protected:
     SuspendableWorkResult initial(const SuspendableWorkListenerPtr&)
@@ -1070,7 +1076,8 @@ protected:
         }
         return Complete;
     }
-private:   
+private:
+    pjsip_inv_session* mInviteSession;
     int mRespCode;
     const int mInvState;
     SipSessionPtr mSession;
@@ -1091,7 +1098,7 @@ void PJSipSessionModule::handleInviteResponse(pjsip_inv_session* inv,
     //to add code to handle.
 
     lg(Debug) << "Queuing a HandleInviteResponseOperation";
-    enqueueSessionWork(new HandleInviteResponseOperation(respCode, inv->state, session), inv);
+    enqueueSessionWork(new HandleInviteResponseOperation(inv, respCode, inv->state, session), inv);
 }
 
 class TransactionStateOperation : public SipQueueableOperation
@@ -1396,6 +1403,15 @@ protected:
 	try
 	{
 	    session->setRemoteDetails(destination, remote_sdp->media[0]->desc.port);
+            const pjmedia_sdp_session* local;
+            pj_status_t result = pjmedia_sdp_neg_get_active_local(mInv->neg, &local);
+            if (result == PJ_SUCCESS)
+            {
+                if (result == PJ_SUCCESS)
+                {
+                    session->startMedia(local, remote_sdp);
+                }
+            }
 	}
 	catch (const AsteriskSCF::Media::RTP::V1::InvalidAddress&)
 	{
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index 42e505e..9e5cf97 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -294,6 +294,39 @@ public:
 	mEndpoint->setSecureTransport(translateCallDirection(transport->secureTransport));
     }
 
+    void updateSRTP(const SRTPCryptoItemPtr& srtpOptions)
+    {
+        SipEndpointMediaSRTPConfig srtpConfig;
+        switch (srtpOptions->srtpSupportOptions)
+        {
+        case SRTP_DISABLED:
+            srtpConfig.supportOptions = SipEndpointMediaSRTPConfig::Disabled;
+            break;
+
+        case SRTP_OPTIONAL:
+            srtpConfig.supportOptions = SipEndpointMediaSRTPConfig::Optional;
+            break;
+
+        case SRTP_REQUIRED:
+            srtpConfig.supportOptions = SipEndpointMediaSRTPConfig::Required;
+            break;
+
+        default:
+            assert("Unexpected value" == 0);
+        }
+        srtpConfig.enableEncryption != srtpOptions->disableEncryption;
+        srtpConfig.enableAuthentication != srtpOptions->disableAuthentication;
+        srtpConfig.cryptoKeys.clear();
+        if (!srtpOptions->cryptoKeys.empty())
+        {
+            CryptoKey newKey;
+            newKey.suite = srtpOptions->cryptoKeys[0]->suite;
+            newKey.cryptoKey = srtpOptions->cryptoKeys[0]->cryptoKey;
+            srtpConfig.cryptoKeys.push_back(newKey);
+        }
+        mEndpoint->setSRTPOptions(srtpConfig);
+    }
+
     void updateMediaNATOptions(const SipMediaNATItemPtr& item)
     {
         mEndpoint->setMediaNATOptions(item->enableICE, item->enableTURN);
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index cffd2c1..b3a7dc8 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -151,6 +151,11 @@ void SipEndpoint::setMediaNATOptions(bool useICE, bool useTURN)
     mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN = useTURN;
 }
 
+void SipEndpoint::setSRTPOptions(const SipEndpointMediaSRTPConfig& srtpConfig)
+{
+    mImplPriv->mConfig.srtpConfig = srtpConfig;
+}
+
 void SipEndpoint::setSignalingNATOptions(bool enable)
 {
     mImplPriv->mConfig.transportConfig.enableNAT = enable;
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 64391b8..89f110b 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -173,6 +173,29 @@ public:
     }
 };
 
+class CryptoKey
+{
+public:
+    std::string suite;
+    std::string cryptoKey;
+};
+typedef std::vector<CryptoKey> CryptoKeys;
+
+class SipEndpointMediaSRTPConfig
+{
+public:
+    enum 
+    {
+        Disabled,
+        Optional,
+        Required
+    } supportOptions;
+
+    bool enableAuthentication;
+    bool enableEncryption;
+    CryptoKeys cryptoKeys;
+};
+
 /**
  * Media options. Deals with types of media
  * supported by an endpoint. Currently only
@@ -224,6 +247,7 @@ public:
     SipEndpointRegistrationConfig registrationConfig;
     SipEndpointSessionConfig sessionConfig;
     SipEndpointMediaConfig mediaConfig;
+    SipEndpointMediaSRTPConfig srtpConfig;
     SipEndpointSubscriptionConfig subscriptionConfig;
 
     /* Convert a specified direction string into its proper
@@ -292,6 +316,7 @@ public:
     void setRTPOverIPv6(bool);
 
     void setMediaNATOptions(bool useICE, bool useTURN);
+    void setSRTPOptions(const SipEndpointMediaSRTPConfig& srtpConfig);
     void setSignalingNATOptions(bool enable);
 
 private:
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 4e7c9da..d9bba00 100644
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -32,6 +32,7 @@
 
 using namespace AsteriskSCF::System::Logging;
 using namespace AsteriskSCF::System::NAT::V1;
+using namespace AsteriskSCF::Media::RTP::V1;
 using namespace std;
 
 namespace
@@ -1101,7 +1102,7 @@ public:
                 {
                     lg(Error) << "Exception caught while trying to release a media session\n" << ex.what();
                 }
-            }
+           }
         }
         mSessionPriv->mEndpoint->removeSession(mSession);
         return Complete;
@@ -1163,6 +1164,8 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
     sdp->conn->net_type = sdp->origin.net_type;
     sdp->conn->addr_type = sdp->origin.addr_type;
     pj_strdup2(mImplPriv->mDialog->pool, &sdp->conn->addr, address.c_str());
+    
+    SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
 
     // Add a single media stream
     sdp->media_count = 1;
@@ -1172,7 +1175,14 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
     pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, "audio");
     media->desc.port = (pj_uint16_t) stream->getLocalPort();
     media->desc.port_count = 1;
-    pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
+    if (config.srtpConfig.supportOptions == SipEndpointMediaSRTPConfig::Disabled)
+    {
+        pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
+    }
+    else
+    {
+        pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/SAVP");
+    }
 
     // Populate the stream with codec details
     sdp->media[0]->desc.fmt_count = 1;
@@ -1182,6 +1192,33 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
     pjmedia_sdp_rtpmap rtpmap;
     pjmedia_sdp_attr *attr;
 
+    if (config.srtpConfig.supportOptions != SipEndpointMediaSRTPConfig::Disabled &&
+            !config.srtpConfig.cryptoKeys.empty())
+    {
+        //
+        // NOTE: AFAICT, we should really be able to supply multiple potential cyphersuites and keys.
+        // However, the configuration tool doesn't currently support that so what we'll do for now
+        // is provide support in the code and deal with the configuration issue later.
+        //
+        int index = 1;
+        for (CryptoKeys::const_iterator i = config.srtpConfig.cryptoKeys.begin();
+             i != config.srtpConfig.cryptoKeys.end(); ++i)
+        {
+            char attrbuf[1024];
+            if (i->cryptoKey.empty())
+            {
+                pj_ansi_sprintf(attrbuf, "%d %s", index++, i->suite.c_str());
+            }
+            else
+            {
+                pj_ansi_sprintf(attrbuf, "%d %s inline:%s", index++, i->suite.c_str(), i->cryptoKey.c_str());
+            }
+            pj_str_t srtpAttr = pj_str(attrbuf);
+            pjmedia_sdp_attr* a = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "crypto", &srtpAttr);
+            pjmedia_sdp_attr_add(&sdp->media[0]->attr_count, sdp->media[0]->attr, a);
+        }
+    }
+
     // This is hardcoded value for ULAW for now
     pj_strdup2(mImplPriv->mDialog->pool, &media->desc.fmt[0], "0");
     rtpmap.pt = media->desc.fmt[0];
@@ -1196,7 +1233,6 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
     pj_strdup2(mImplPriv->mDialog->pool, &attr->name, "sendrecv");
     sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
         
-    SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
     if (config.sessionConfig.rtpOverICE)
     {
         lg(Debug) << "RTP over ICE enabled, retrieving and encoding candidates";
@@ -1219,8 +1255,9 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
                     // TODO: proper enum mapping function, just in case!
                     //
                     pj_ansi_sprintf(natTypeBuf, "%d", static_cast<unsigned>(natFacet->getNATType()));
+                    natTypeStr = pj_str(natTypeBuf);
                     pjmedia_sdp_attr* a = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "X-nat", &natTypeStr);
-                    pjmedia_sdp_attr_add(&sdp->attr_count,  sdp->attr, a);
+                    pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
                     sdpAttrSet = true;
                 }
                 ///
@@ -1282,6 +1319,8 @@ void SipSession::requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats,
 
     AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParamsPtr params;
 
+    SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
+
     //
     // We allocate streams with ICE features enabled by providing alternate
     // parameters to locate and allocate methods.
@@ -1301,6 +1340,7 @@ void SipSession::requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats,
     params->category = "rtp";
     params->formats = formats;
     params->ipv6 = ipv6;
+    params->srtpCapable = (config.srtpConfig.supportOptions != SipEndpointMediaSRTPConfig::Disabled);
 
     AsteriskSCF::Media::RTP::V1::RTPMediaServicePrx factory =
         AsteriskSCF::Media::RTP::V1::RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
@@ -1339,6 +1379,23 @@ void SipSession::requestRTPSessions(AsteriskSCF::Media::V1::FormatSeq& formats,
     payloads.insert(std::make_pair(0, format));
 
     session->associatePayloads(payloads);
+
+    if (params->srtpCapable && !config.srtpConfig.cryptoKeys.empty())
+    {
+        SRTPSessionPrx srtpPrx = SRTPSessionPrx::checkedCast(session);
+        if (!srtpPrx && config.srtpConfig.supportOptions == SipEndpointMediaSRTPConfig::Required)
+        {
+            //
+            // TODO throw.
+            //
+            assert("Cannot access SRTP functionality in the RTPSession." == 0);
+        }
+        //
+        // This effectively treats this as if it is required SRTP.
+        //
+        srtpPrx->setOptions(config.srtpConfig.cryptoKeys[0].suite, config.srtpConfig.cryptoKeys[0].cryptoKey,
+                config.srtpConfig.enableAuthentication, config.srtpConfig.enableEncryption);
+    }
 }
 
 /**
@@ -1421,6 +1478,82 @@ std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> SipSessi
     return mImplPriv->mListeners;
 }
 
+void SipSession::startMedia(const pjmedia_sdp_session*, const pjmedia_sdp_session* remote)
+{
+    //
+    // XXX: we aren't going to do anything with local just yet. We only have the one attribute
+    // after all.
+    //
+
+    //
+    // First check to see if we are supporting crypto!
+    //
+    SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
+    if (config.srtpConfig.supportOptions != SipEndpointMediaSRTPConfig::Disabled &&
+            !config.srtpConfig.cryptoKeys.empty())
+    {
+        if (!mImplPriv->mRTPSessions.empty())
+        {
+            //
+            // XXX: need to accomodate multiple RTP sessions.
+            //
+            SRTPSessionPrx srtpSession = SRTPSessionPrx::checkedCast(mImplPriv->mRTPSessions[0]);
+            if (!srtpSession)
+            {
+                //
+                // Ok, well.. the rest of the code in this method won't be much use then.
+                //
+            }
+            const pjmedia_sdp_attr* cryptoAttr =
+                pjmedia_sdp_media_find_attr2(remote->media[0], "crypto", 0);
+            if (cryptoAttr != 0)
+            {
+                string candidateLine(cryptoAttr->value.ptr, cryptoAttr->value.slen);
+                istringstream is(candidateLine);
+                int index;
+                if (!(is >> index))
+                {
+                }
+
+                string suite;
+                if (!(is >> suite))
+                {
+                    lg(Error) << "Problem extracting cipher suite value from attribute :" << candidateLine;
+                    return;
+                }
+
+                string key;
+                if (!(is >> key))
+                {
+                    lg(Debug) << "No key information for cipher suite";
+                }
+                else
+                {
+                    string inlineString("inline:");
+                    if (key.substr(0, inlineString.size()) != inlineString)
+                    {
+                        lg(Debug) << "Possible malformed crypto attribute : " << candidateLine;
+                    }
+                    key = key.substr(inlineString.size());
+                    lg(Debug) << "Starting up crypto media stream with remote cipher suite " << suite << " and key " <<
+                        key;
+                
+                }
+                srtpSession->start(suite, key, config.srtpConfig.enableAuthentication,
+                        config.srtpConfig.enableEncryption);
+            }
+            else if (config.srtpConfig.supportOptions == SipEndpointMediaSRTPConfig::Required)
+            {
+                //
+                // XXX
+                // Basically this means that our local endpoint requires crypto, but the
+                // remote hasn't agreed so something needs to happen here.
+                //
+            }
+        }
+    }
+}
+
 /**
  * Internal function which gets the endpoint associated with the session.
  */
diff --git a/src/SipSession.h b/src/SipSession.h
index 0e3119a..ebca7d4 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -201,6 +201,12 @@ public:
 
     std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> getListeners();
 
+    //
+    // Final notification to the media components (if necessary) that the connection has been completely established.
+    // This should happen after the sdp negotiation is complete.
+    //
+    void startMedia(const pjmedia_sdp_session* local, const pjmedia_sdp_session* remote);
+
     SipEndpointPtr getEndpoint();
 
     AsteriskSCF::SessionCommunications::V1::SessionPrx& getSessionProxy();

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list