[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