[svn-commits] kmoore: trunk r395121 - in /trunk: channels/ include/asterisk/ res/ res/res_sip/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 23 08:52:09 CDT 2013


Author: kmoore
Date: Tue Jul 23 08:52:06 2013
New Revision: 395121

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395121
Log:
Add DTLS-SRTP support to chan_pjsip

This patch introduces DTLS-SRTP support to chan_pjsip and the options
necessary to configure it including an option to allow choosing between
32 and 80 byte SRTP tag lengths.

During the implementation and testing of this patch, three other bugs
were found and their fixes are included with this patch. The two in
chan_sip were a segfault relating to DTLS setup and mistaken call
rejection. The third bug fix prevents chan_pjsip from attempting to
perform bridge optimization between two endpoints if either of them is
running any form of SRTP.

Review: https://reviewboard.asterisk.org/r/2683/
(closes issue ASTERISK-21419)

Modified:
    trunk/channels/chan_gulp.c
    trunk/channels/chan_sip.c
    trunk/include/asterisk/res_sip.h
    trunk/include/asterisk/res_sip_session.h
    trunk/res/res_sip.c
    trunk/res/res_sip/sip_configuration.c
    trunk/res/res_sip_sdp_rtp.c
    trunk/res/res_sip_session.c

Modified: trunk/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_gulp.c?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/channels/chan_gulp.c (original)
+++ trunk/channels/chan_gulp.c Tue Jul 23 08:52:06 2013
@@ -384,6 +384,10 @@
 	ao2_ref(*instance, +1);
 
 	ast_assert(endpoint != NULL);
+	if (endpoint->media_encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
+		return AST_RTP_GLUE_RESULT_FORBID;
+	}
+
 	if (endpoint->direct_media) {
 		return AST_RTP_GLUE_RESULT_REMOTE;
 	}
@@ -396,13 +400,21 @@
 {
 	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
 	struct gulp_pvt *pvt = channel->pvt;
+	struct ast_sip_endpoint *endpoint;
 
 	if (!pvt || !channel->session || !pvt->media[SIP_MEDIA_VIDEO]->rtp) {
 		return AST_RTP_GLUE_RESULT_FORBID;
 	}
 
+	endpoint = channel->session->endpoint;
+
 	*instance = pvt->media[SIP_MEDIA_VIDEO]->rtp;
 	ao2_ref(*instance, +1);
+
+	ast_assert(endpoint != NULL);
+	if (endpoint->media_encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
+		return AST_RTP_GLUE_RESULT_FORBID;
+	}
 
 	return AST_RTP_GLUE_RESULT_LOCAL;
 }

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Tue Jul 23 08:52:06 2013
@@ -10193,6 +10193,7 @@
 				} else if (!strcmp(protocol, "UDP/TLS/RTP/SAVP") || !strcmp(protocol, "UDP/TLS/RTP/SAVPF")) {
 					secure_audio = 1;
 
+					processed_crypto = 1;
 					if (p->srtp) {
 						ast_set_flag(p->srtp, AST_SRTP_CRYPTO_OFFER_OK);
 					}
@@ -10275,6 +10276,7 @@
 				} else if (!strcmp(protocol, "UDP/TLS/RTP/SAVP") || !strcmp(protocol, "UDP/TLS/RTP/SAVPF")) {
 					secure_video = 1;
 
+					processed_crypto = 1;
 					if (p->vsrtp || (p->vsrtp = ast_sdp_srtp_alloc())) {
 						ast_set_flag(p->vsrtp, AST_SRTP_CRYPTO_OFFER_OK);
 					}
@@ -13036,13 +13038,17 @@
 static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
 {
 	char *a_crypto;
-	char *orig_crypto;
-
-	if (!srtp) {
+	const char *orig_crypto;
+
+	if (!srtp || dtls_enabled) {
 		return NULL;
 	}
 
-	orig_crypto = ast_strdupa(ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32));
+	orig_crypto = ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32);
+	if (ast_strlen_zero(orig_crypto)) {
+		return NULL;
+	}
+
 	if (ast_asprintf(&a_crypto, "a=crypto:%s\r\n", orig_crypto) == -1) {
 		return NULL;
 	}

Modified: trunk/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/res_sip.h?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/include/asterisk/res_sip.h (original)
+++ trunk/include/asterisk/res_sip.h Tue Jul 23 08:52:06 2013
@@ -34,6 +34,8 @@
 #include "asterisk/endpoints.h"
 /* Needed for pj_sockaddr */
 #include <pjlib.h>
+/* Needed for ast_rtp_dtls_cfg struct */
+#include "asterisk/rtp_engine.h"
 
 /* Forward declarations of PJSIP stuff */
 struct pjsip_rx_data;
@@ -446,6 +448,10 @@
 	unsigned int allowsubscribe;
 	/*! The minimum allowed expiration for subscriptions from endpoint */
 	unsigned int subminexpiry;
+	/*! \brief DTLS-SRTP configuration information */
+	struct ast_rtp_dtls_cfg dtls_cfg;
+	/*! Should SRTP use a 32 byte tag instead of an 80 byte tag? */
+	unsigned int srtp_tag_32;
 };
 
 /*!

Modified: trunk/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/res_sip_session.h?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/include/asterisk/res_sip_session.h (original)
+++ trunk/include/asterisk/res_sip_session.h Tue Jul 23 08:52:06 2013
@@ -26,7 +26,7 @@
 #include "asterisk/channel.h"
 /* Needed for ast_sockaddr struct */
 #include "asterisk/netsock.h"
-/* Neeed for ast_sdp_srtp struct */
+/* Needed for ast_sdp_srtp struct */
 #include "asterisk/sdp_srtp.h"
 
 /* Forward declarations */
@@ -42,7 +42,6 @@
 struct ast_party_id;
 struct pjmedia_sdp_media;
 struct pjmedia_sdp_session;
-struct ast_rtp_instance;
 struct ast_dsp;
 
 struct ast_sip_session_sdp_handler;

Modified: trunk/res/res_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_sip.c?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/res/res_sip.c (original)
+++ trunk/res/res_sip.c Tue Jul 23 08:52:06 2013
@@ -336,6 +336,9 @@
 								transport should be used in conjunction with this option to prevent
 								exposure of media encryption keys.
 							</para></enum>
+							<enum name="dtls"><para>
+								res_sip will offer DTLS-SRTP setup.
+							</para></enum>
 						</enumlist>
 					</description>
 				</configOption>
@@ -475,6 +478,87 @@
 				</configOption>
 				<configOption name="fromdomain">
 					<synopsis>Domain to user in From header for requests to this endpoint.</synopsis>
+				</configOption>
+				<configOption name="dtlsverify">
+					<synopsis>Verify that the provided peer certificate is valid</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para></description>
+				</configOption>
+				<configOption name="dtlsrekey">
+					<synopsis>Interval at which to renegotiate the TLS session and rekey the SRTP session</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para><para>
+						If this is not set or the value provided is 0 rekeying will be disabled.
+					</para></description>
+				</configOption>
+				<configOption name="dtlscertfile">
+					<synopsis>Path to certificate file to present to peer</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para></description>
+				</configOption>
+				<configOption name="dtlsprivatekey">
+					<synopsis>Path to private key for certificate file</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para></description>
+				</configOption>
+				<configOption name="dtlscipher">
+					<synopsis>Cipher to use for DTLS negotiation</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para><para>
+						Many options for acceptable ciphers. See link for more:
+						http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
+					</para></description>
+				</configOption>
+				<configOption name="dtlscafile">
+					<synopsis>Path to certificate authority certificate</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para></description>
+				</configOption>
+				<configOption name="dtlscapath">
+					<synopsis>Path to a directory containing certificate authority certificates</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>dtls</literal>.
+					</para></description>
+				</configOption>
+				<configOption name="dtlssetup">
+					<synopsis>Whether we are willing to accept connections, connect to the other party, or both.</synopsis>
+					<description>
+						<para>
+							This option only applies if <replaceable>media_encryption</replaceable> is
+							set to <literal>dtls</literal>.
+						</para>
+						<enumlist>
+							<enum name="active"><para>
+								res_sip will make a connection to the peer.
+							</para></enum>
+							<enum name="passive"><para>
+								res_sip will accept connections from the peer.
+							</para></enum>
+							<enum name="actpass"><para>
+								res_sip will offer and accept connections from the peer.
+							</para></enum>
+						</enumlist>
+					</description>
+				</configOption>
+				<configOption name="srtp_tag_32">
+					<synopsis>Determines whether 32 byte tags should be used instead of 80 byte tags.</synopsis>
+					<description><para>
+						This option only applies if <replaceable>media_encryption</replaceable> is
+						set to <literal>sdes</literal> or <literal>dtls</literal>.
+					</para></description>
 				</configOption>
 			</configObject>
 			<configObject name="auth">

Modified: trunk/res/res_sip/sip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_sip/sip_configuration.c?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/res/res_sip/sip_configuration.c (original)
+++ trunk/res/res_sip/sip_configuration.c Tue Jul 23 08:52:06 2013
@@ -467,8 +467,9 @@
 		endpoint->media_encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
 	} else if (!strcasecmp("sdes", var->value)) {
 		endpoint->media_encryption = AST_SIP_MEDIA_ENCRYPT_SDES;
-	/*} else if (!strcasecmp("dtls", var->value)) {
-		endpoint->media_encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;*/
+	} else if (!strcasecmp("dtls", var->value)) {
+		endpoint->media_encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
+		ast_rtp_dtls_cfg_parse(&endpoint->dtls_cfg, "dtlsenable", "yes");
 	} else {
 		return -1;
 	}
@@ -516,6 +517,14 @@
 	}
 
 	return 0;
+}
+
+static int dtls_handler(const struct aco_option *opt,
+			 struct ast_variable *var, void *obj)
+{
+	struct ast_sip_endpoint *endpoint = obj;
+
+	return ast_rtp_dtls_cfg_parse(&endpoint->dtls_cfg, var->name, var->value);
 }
 
 static void *sip_nat_hook_alloc(const char *name)
@@ -676,6 +685,15 @@
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fromuser", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fromdomain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwifromuser", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mwi_from));
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlsverify", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlsrekey", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlscertfile", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlsprivatekey", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlscipher", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlscafile", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlscapath", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtlssetup", "", dtls_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "srtp_tag_32", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, srtp_tag_32));
 
 	if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
 		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");

Modified: trunk/res/res_sip_sdp_rtp.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_sip_sdp_rtp.c?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/res/res_sip_sdp_rtp.c (original)
+++ trunk/res/res_sip_sdp_rtp.c Tue Jul 23 08:52:06 2013
@@ -525,16 +525,114 @@
 	}
 
 	incoming_encryption = get_media_encryption_type(stream->desc.transport);
-	if (incoming_encryption == AST_SIP_MEDIA_ENCRYPT_DTLS) {
-		/* DTLS not yet supported */
-		return AST_SIP_MEDIA_TRANSPORT_INVALID;
-	}
 
 	if (incoming_encryption == endpoint->media_encryption) {
 		return incoming_encryption;
 	}
 
 	return AST_SIP_MEDIA_TRANSPORT_INVALID;
+}
+
+static int setup_srtp(struct ast_sip_session_media *session_media)
+{
+	if (!session_media->srtp) {
+		session_media->srtp = ast_sdp_srtp_alloc();
+		if (!session_media->srtp) {
+			return -1;
+		}
+	}
+
+	if (!session_media->srtp->crypto) {
+		session_media->srtp->crypto = ast_sdp_crypto_alloc();
+		if (!session_media->srtp->crypto) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int setup_dtls_srtp(struct ast_sip_session *session,
+	struct ast_sip_session_media *session_media)
+{
+	struct ast_rtp_engine_dtls *dtls;
+
+	if (!session->endpoint->dtls_cfg.enabled || !session_media->rtp) {
+		return -1;
+	}
+
+	dtls = ast_rtp_instance_get_dtls(session_media->rtp);
+	if (!dtls) {
+		return -1;
+	}
+
+	session->endpoint->dtls_cfg.suite = ((session->endpoint->srtp_tag_32) ? AST_AES_CM_128_HMAC_SHA1_32 : AST_AES_CM_128_HMAC_SHA1_80);
+	if (dtls->set_configuration(session_media->rtp, &session->endpoint->dtls_cfg)) {
+		ast_log(LOG_ERROR, "Attempted to set an invalid DTLS-SRTP configuration on RTP instance '%p'\n",
+			session_media->rtp);
+		return -1;
+	}
+
+	if (setup_srtp(session_media)) {
+		return -1;
+	}
+	return 0;
+}
+
+static int parse_dtls_attrib(struct ast_sip_session_media *session_media,
+	const struct pjmedia_sdp_media *stream)
+{
+	int i;
+	struct ast_rtp_engine_dtls *dtls = ast_rtp_instance_get_dtls(session_media->rtp);
+
+	for (i = 0; i < stream->attr_count; i++) {
+		pjmedia_sdp_attr *attr = stream->attr[i];
+		pj_str_t *value;
+
+		if (!attr->value.ptr) {
+			continue;
+		}
+
+		value = pj_strtrim(&attr->value);
+
+		if (!pj_strcmp2(&attr->name, "setup")) {
+			if (!pj_stricmp2(value, "active")) {
+				dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTIVE);
+			} else if (!pj_stricmp2(value, "passive")) {
+				dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_PASSIVE);
+			} else if (!pj_stricmp2(value, "actpass")) {
+				dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTPASS);
+			} else if (!pj_stricmp2(value, "holdconn")) {
+				dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_HOLDCONN);
+			} else {
+				ast_log(LOG_WARNING, "Unsupported setup attribute value '%*s'\n", (int)value->slen, value->ptr);
+			}
+		} else if (!pj_strcmp2(&attr->name, "connection")) {
+			if (!pj_stricmp2(value, "new")) {
+				dtls->reset(session_media->rtp);
+			} else if (!pj_stricmp2(value, "existing")) {
+				/* Do nothing */
+			} else {
+				ast_log(LOG_WARNING, "Unsupported connection attribute value '%*s'\n", (int)value->slen, value->ptr);
+			}
+		} else if (!pj_strcmp2(&attr->name, "fingerprint")) {
+			char hash_value[256], hash[6];
+			char fingerprint_text[value->slen + 1];
+			ast_copy_pj_str(fingerprint_text, value, sizeof(fingerprint_text));
+
+			if (sscanf(fingerprint_text, "%5s %255s", hash, hash_value) == 2) {
+				if (!strcasecmp(hash, "sha-1")) {
+					dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1, hash_value);
+				} else {
+					ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s'\n",
+					hash);
+				}
+			}
+		}
+	}
+	ast_set_flag(session_media->srtp, AST_SRTP_CRYPTO_OFFER_OK);
+
+	return 0;
 }
 
 static int setup_sdes_srtp(struct ast_sip_session_media *session_media,
@@ -557,6 +655,106 @@
 			return -1;
 		}
 
+		if (setup_srtp(session_media)) {
+			return -1;
+		}
+
+		if (!ast_sdp_crypto_process(session_media->rtp, session_media->srtp, crypto_str)) {
+			/* found a valid crypto attribute */
+			return 0;
+		}
+
+		ast_debug(1, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);
+	}
+
+	/* no usable crypto attributes found */
+	return -1;
+}
+
+static int setup_media_encryption(struct ast_sip_session *session,
+	struct ast_sip_session_media *session_media,
+	const struct pjmedia_sdp_media *stream)
+{
+	switch (session->endpoint->media_encryption) {
+	case AST_SIP_MEDIA_ENCRYPT_SDES:
+		if (setup_sdes_srtp(session_media, stream)) {
+			return -1;
+		}
+		break;
+	case AST_SIP_MEDIA_ENCRYPT_DTLS:
+		if (setup_dtls_srtp(session, session_media)) {
+			return -1;
+		}
+		if (parse_dtls_attrib(session_media, stream)) {
+			return -1;
+		}
+		break;
+	case AST_SIP_MEDIA_TRANSPORT_INVALID:
+	case AST_SIP_MEDIA_ENCRYPT_NONE:
+		break;
+	}
+
+	return 0;
+}
+
+/*! \brief Function which negotiates an incoming media stream */
+static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
+{
+	char host[NI_MAXHOST];
+	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+	enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
+
+	/* If no type formats have been configured reject this stream */
+	if (!ast_format_cap_has_type(session->endpoint->codecs, media_type)) {
+		return 0;
+	}
+
+	/* Ensure incoming transport is compatible with the endpoint's configuration */
+	if (check_endpoint_media_transport(session->endpoint, stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
+		return -1;
+	}
+
+	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
+
+	/* Ensure that the address provided is valid */
+	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
+		/* The provided host was actually invalid so we error out this negotiation */
+		return -1;
+	}
+
+	/* Using the connection information create an appropriate RTP instance */
+	if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
+		return -1;
+	}
+
+	if (setup_media_encryption(session, session_media, stream)) {
+		return -1;
+	}
+
+	return set_caps(session, session_media, stream);
+}
+
+static int add_crypto_to_stream(struct ast_sip_session *session,
+	struct ast_sip_session_media *session_media,
+	pj_pool_t *pool, pjmedia_sdp_media *media)
+{
+	pj_str_t stmp;
+	pjmedia_sdp_attr *attr;
+	const char *crypto_attribute;
+	struct ast_rtp_engine_dtls *dtls;
+	static const pj_str_t STR_NEW = { "new", 3 };
+	static const pj_str_t STR_EXISTING = { "existing", 8 };
+	static const pj_str_t STR_ACTIVE = { "active", 6 };
+	static const pj_str_t STR_PASSIVE = { "passive", 7 };
+	static const pj_str_t STR_ACTPASS = { "actpass", 7 };
+	static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };
+
+	switch (session->endpoint->media_encryption) {
+	case AST_SIP_MEDIA_ENCRYPT_NONE:
+	case AST_SIP_MEDIA_TRANSPORT_INVALID:
+		break;
+	case AST_SIP_MEDIA_ENCRYPT_SDES:
 		if (!session_media->srtp) {
 			session_media->srtp = ast_sdp_srtp_alloc();
 			if (!session_media->srtp) {
@@ -564,91 +762,75 @@
 			}
 		}
 
-		if (!session_media->srtp->crypto) {
-			session_media->srtp->crypto = ast_sdp_crypto_alloc();
-			if (!session_media->srtp->crypto) {
+		crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp,
+			0 /* DTLS running? No */,
+			session->endpoint->srtp_tag_32 /* 32 byte tag length? */);
+		if (!crypto_attribute) {
+			/* No crypto attribute to add, bad news */
+			return -1;
+		}
+
+		attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute));
+		media->attr[media->attr_count++] = attr;
+		break;
+	case AST_SIP_MEDIA_ENCRYPT_DTLS:
+		if (setup_dtls_srtp(session, session_media)) {
+			return -1;
+		}
+
+		dtls = ast_rtp_instance_get_dtls(session_media->rtp);
+		if (!dtls) {
+			return -1;
+		}
+
+		switch (dtls->get_connection(session_media->rtp)) {
+		case AST_RTP_DTLS_CONNECTION_NEW:
+			attr = pjmedia_sdp_attr_create(pool, "connection", &STR_NEW);
+			media->attr[media->attr_count++] = attr;
+			break;
+		case AST_RTP_DTLS_CONNECTION_EXISTING:
+			attr = pjmedia_sdp_attr_create(pool, "connection", &STR_EXISTING);
+			media->attr[media->attr_count++] = attr;
+			break;
+		default:
+			break;
+		}
+
+		switch (dtls->get_setup(session_media->rtp)) {
+		case AST_RTP_DTLS_SETUP_ACTIVE:
+			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE);
+			media->attr[media->attr_count++] = attr;
+			break;
+		case AST_RTP_DTLS_SETUP_PASSIVE:
+			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_PASSIVE);
+			media->attr[media->attr_count++] = attr;
+			break;
+		case AST_RTP_DTLS_SETUP_ACTPASS:
+			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTPASS);
+			media->attr[media->attr_count++] = attr;
+			break;
+		case AST_RTP_DTLS_SETUP_HOLDCONN:
+			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN);
+			media->attr[media->attr_count++] = attr;
+			break;
+		default:
+			break;
+		}
+
+		if ((crypto_attribute = dtls->get_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1))) {
+			RAII_VAR(struct ast_str *, fingerprint, ast_str_create(64), ast_free);
+			if (!fingerprint) {
 				return -1;
 			}
-		}
-
-		if (!ast_sdp_crypto_process(session_media->rtp, session_media->srtp, crypto_str)) {
-			/* found a valid crypto attribute */
-			return 0;
-		}
-
-		ast_debug(1, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);
-	}
-
-	/* no usable crypto attributes found */
-	return -1;
-}
-
-/*! \brief Function which negotiates an incoming media stream */
-static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
-					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
-{
-	char host[NI_MAXHOST];
-	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
-	enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
-	enum ast_sip_session_media_encryption incoming_encryption;
-
-	/* If no type formats have been configured reject this stream */
-	if (!ast_format_cap_has_type(session->endpoint->codecs, media_type)) {
-		return 0;
-	}
-
-	/* Ensure incoming transport is compatible with the endpoint's configuration */
-	incoming_encryption = check_endpoint_media_transport(session->endpoint, stream);
-	if (incoming_encryption == AST_SIP_MEDIA_TRANSPORT_INVALID) {
-		return -1;
-	}
-
-	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
-
-	/* Ensure that the address provided is valid */
-	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
-		/* The provided host was actually invalid so we error out this negotiation */
-		return -1;
-	}
-
-	/* Using the connection information create an appropriate RTP instance */
-	if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
-		return -1;
-	}
-
-	if (incoming_encryption == AST_SIP_MEDIA_ENCRYPT_SDES
-			&& setup_sdes_srtp(session_media, stream)) {
-		return -1;
-	}
-
-	return set_caps(session, session_media, stream);
-}
-
-static int add_crypto_to_stream(struct ast_sip_session *session,
-	struct ast_sip_session_media *session_media,
-	pj_pool_t *pool, pjmedia_sdp_media *media)
-{
-	pj_str_t stmp;
-	pjmedia_sdp_attr *attr;
-	const char *crypto_attribute;
-
-	if (!session_media->srtp && session->endpoint->media_encryption != AST_SIP_MEDIA_ENCRYPT_NONE) {
-		session_media->srtp = ast_sdp_srtp_alloc();
-		if (!session_media->srtp) {
-			return -1;
-		}
-	}
-
-	crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp,
-		0 /* DTLS can not be enabled for res_sip */,
-		0 /* don't prefer 32byte tag length */);
-	if (!crypto_attribute) {
-		/* No crypto attribute to add */
-		return -1;
-	}
-
-	attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute));
-	media->attr[media->attr_count++] = attr;
+
+			ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute);
+
+			attr = pjmedia_sdp_attr_create(pool, "fingerprint", pj_cstr(&stmp, ast_str_buffer(fingerprint)));
+			media->attr[media->attr_count++] = attr;
+		}
+		break;
+	}
+
 	return 0;
 }
 
@@ -672,7 +854,6 @@
 	struct ast_format format;
 	RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy);
 	enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
-	int crypto_res;
 
 	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
 		!ast_format_cap_is_empty(session->direct_media_cap);
@@ -694,11 +875,14 @@
 		return -1;
 	}
 
-	crypto_res = add_crypto_to_stream(session, session_media, pool, media);
+	if (add_crypto_to_stream(session, session_media, pool, media)) {
+		return -1;
+	}
 
 	media->desc.media = pj_str(session_media->stream_type);
 	media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
-		!crypto_res, session_media->rtp, session->endpoint->use_avpf));
+		session->endpoint->media_encryption == AST_SIP_MEDIA_ENCRYPT_SDES,
+		session_media->rtp, session->endpoint->use_avpf));
 
 	/* Add connection level details */
 	if (direct_media_enabled) {
@@ -823,8 +1007,17 @@
 		return 1;
 	}
 
+	/* Ensure incoming transport is compatible with the endpoint's configuration */
+	if (check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) {
+		return -1;
+	}
+
 	/* Create an RTP instance if need be */
 	if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->rtp_ipv6)) {
+		return -1;
+	}
+
+	if (setup_media_encryption(session, session_media, remote_stream)) {
 		return -1;
 	}
 

Modified: trunk/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_sip_session.c?view=diff&rev=395121&r1=395120&r2=395121
==============================================================================
--- trunk/res/res_sip_session.c (original)
+++ trunk/res/res_sip_session.c Tue Jul 23 08:52:06 2013
@@ -854,6 +854,7 @@
 	ast_taskprocessor_unreference(session->serializer);
 	ao2_cleanup(session->datastores);
 	ao2_cleanup(session->media);
+
 	AST_LIST_HEAD_DESTROY(&session->supplements);
 	while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
 		ast_free(delay);




More information about the svn-commits mailing list