[asterisk-commits] branch oej/securertp-trunk r32521 - in /team/oej/securertp-trunk: ./ channels...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Jun 6 02:03:52 MST 2006


Author: oej
Date: Tue Jun  6 04:03:51 2006
New Revision: 32521

URL: http://svn.digium.com/view/asterisk?rev=32521&view=rev
Log:
Update

Modified:
    team/oej/securertp-trunk/channels/chan_sip.c
    team/oej/securertp-trunk/include/asterisk/rtp.h
    team/oej/securertp-trunk/rtp.c

Modified: team/oej/securertp-trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/channels/chan_sip.c?rev=32521&r1=32520&r2=32521&view=diff
==============================================================================
--- team/oej/securertp-trunk/channels/chan_sip.c (original)
+++ team/oej/securertp-trunk/channels/chan_sip.c Tue Jun  6 04:03:51 2006
@@ -161,6 +161,19 @@
 #define DEFAULT_MAX_EXPIRY	3600
 #define DEFAULT_REGISTRATION_TIMEOUT	20
 #define DEFAULT_MAX_FORWARDS	"70"
+
+#define SRTP_MASTER_LEN 30
+#define SRTP_MASTERKEY_LEN 16
+#define SRTP_MASTERSALT_LEN (SRTP_MASTER_LEN - SRTP_MASTERKEY_LEN)
+#define SRTP_MASTER_LEN64 ((SRTP_MASTER_LEN * 8 + 5) / 6 + 1)
+
+/*! \brief structure for secure RTP audio */
+struct sip_srtp {
+	char *a_crypto;
+	unsigned char local_key[SRTP_MASTER_LEN];
+	char local_key64[SRTP_MASTER_LEN64];
+};
+
 
 /* guard limit must be larger than guard secs */
 /* guard min must be < 1000, and should be >= 250 */
@@ -857,6 +870,7 @@
 	struct ast_variable *chanvars;		/*!< Channel variables to set for inbound call */
 	struct sip_pvt *next;			/*!< Next dialog in chain */
 	struct sip_invite_param *options;	/*!< Options for INVITE */
+	struct sip_srtp *srtp;			/*!< Structure for Secure RTP session data */
 } *iflist = NULL;
 
 #define FLAG_RESPONSE (1 << 0)
@@ -1260,6 +1274,19 @@
 static int sip_get_codec(struct ast_channel *chan);
 static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p);
 
+/*----- SRTP interface functions */
+static struct sip_srtp *sip_srtp_alloc(void);
+static void sip_srtp_destroy(struct sip_srtp *srtp);
+static int setup_crypto(struct sip_pvt *p);
+static int set_crypto_policy(struct ast_srtp_policy *policy,
+			     int suite_val, const unsigned char *master_key,
+			     unsigned long ssrc, int inbound);
+static int activate_crypto(struct sip_pvt *p, int suite_val, unsigned char *remote_key);
+static int process_crypto(struct sip_pvt *p, const char *attr);
+
+
+
+
 /*! \brief Definition of this channel for PBX channel registration */
 static const struct ast_channel_tech sip_tech = {
 	.type = "SIP",
@@ -2415,6 +2442,18 @@
 		} else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER_REPLACES")) {
 			/* We're replacing a call. */
 			p->options->replaces = ast_var_value(current);
+		} else if (!strncasecmp(ast_var_name(current), "SIP_SRTP_SDES", strlen("SIP_SRTP_SDES"))) {
+			if (!ast_srtp_is_registered()) {
+				ast_log(LOG_WARNING, "SIP_SRTP_SDES set but SRTP is not available\n");
+				return -1;
+			}
+
+			if (!p->srtp) {
+				if (setup_crypto(p) < 0) {
+					ast_log(LOG_WARNING, "SIP SRTP sdes setup failed\n");
+					return -1;
+				}
+			}
 		}
 	}
 	
@@ -2561,6 +2600,10 @@
 	if (p->chanvars) {
 		ast_variables_destroy(p->chanvars);
 		p->chanvars = NULL;
+	}
+	if (p->srtp) {
+		sip_srtp_destroy(p->srtp);
+		p->srtp = NULL;
 	}
 	ast_mutex_destroy(&p->lock);
 
@@ -2656,6 +2699,7 @@
 						ASTOBJ_UNREF(p, sip_destroy_peer);
 					return -1; 
 				}
+
 			}
 			if (inringing && (event == INC_CALL_RINGING)) {
 				if (!ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
@@ -4065,6 +4109,7 @@
 	int x, y;
 	int debug = sip_debug_test_pvt(p);
 	struct ast_channel *bridgepeer = NULL;
+	int secure_audio = FALSE;
 
 	if (!p->rtp) {
 		ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
@@ -4095,8 +4140,20 @@
 	ast_set_flag(&p->flags[0], SIP_NOVIDEO);	
 	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
 		int found = 0;
-		if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2) ||
-		    (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1)) {
+		char protocol[5] = "";
+		len = -1;
+		if ((sscanf(m, "audio %d/%d RTP/%4s %n", &x, &y, protocol, &len) == 3) ||
+		    (sscanf(m, "audio %d RTP/%4s %n", &x, protocol, &len) == 2)) {
+			if (!strcmp(protocol, "SAVP"))
+				secure_audio = 1;
+			else if (strcmp(protocol, "AVP")) {
+				ast_log(LOG_WARNING, "Unknown SDP media protocol in offer: %s\n", protocol);
+				continue;
+			}
+			if (len < 0) {
+				ast_log(LOG_WARNING, "Unknown SDP media type in offer: %s\n", m);
+				continue;
+			}
 			found = 1;
 			portno = x;
 			/* Scan through the RTP payload types specified in a "m=" line: */
@@ -4196,10 +4253,13 @@
 		if (!strcasecmp(a, "sendonly")) {
 			sendonly=1;
 			continue;
-		}
-		if (!strcasecmp(a, "sendrecv")) {
+		} else if (!strcasecmp(a, "sendrecv")) {
 		  	sendonly=0;
-		}
+		} else if (!strncasecmp(a, "crypto:", 7)) {
+			process_crypto(p, a);
+			continue;
+		}
+
 		if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
 		if (debug)
 			ast_verbose("Found description format %s\n", mimeSubtype);
@@ -4207,6 +4267,11 @@
 		ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
 		if (p->vrtp)
 			ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
+
+		if (secure_audio && !(p->srtp && p->srtp->a_crypto)) {
+			ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
+			return -2;
+		}
 	}
 
 	/* Now gather all of the codecs that were asked for: */
@@ -4944,6 +5009,8 @@
 	char m_video[256];
 	char a_audio[1024];
 	char a_video[1024];
+	char crypto_buf[128];
+	const char *a_crypto = NULL;
 	char *m_audio_next = m_audio;
 	char *m_video_next = m_video;
 	size_t m_audio_left = sizeof(m_audio);
@@ -4958,6 +5025,8 @@
 	struct sockaddr_in dest;
 	struct sockaddr_in vdest = { 0, };
 	int debug;
+	const char *protocol = NULL;
+	struct sip_srtp *srtp = p->srtp;
 	
 	debug = sip_debug_test_pvt(p);
 
@@ -5003,6 +5072,24 @@
 			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(vsin.sin_port));	
 	}
 
+	if (srtp) {
+		if (srtp->a_crypto) {
+			a_crypto = srtp->a_crypto;
+		} else {
+			const char *crypto_suite = "AES_CM_128_HMAC_SHA1_80";
+			snprintf(crypto_buf, sizeof(crypto_buf),
+				 "a=crypto:1 %s inline:%s\r\n",
+				 crypto_suite, srtp->local_key64);
+			a_crypto = crypto_buf;
+		}
+	}
+
+	if (a_crypto) {
+		protocol = "SAVP";
+	} else {
+		protocol = "AVP";
+	}
+
 	/* We break with the "recommendation" and send our IP, in order that our
 	   peer doesn't have to ast_gethostbyname() us */
 
@@ -5016,8 +5103,8 @@
 		snprintf(b, sizeof(b), "b=CT:%d\r\n", p->maxcallbitrate);	
 	snprintf(t, sizeof(t), "t=0 0\r\n");
 
-	ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
-	ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+	ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/%s", ntohs(dest.sin_port), protocol);
+	ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/%s", ntohs(vdest.sin_port), protocol);
 
 	if (ast_test_flag(&p->flags[0], SIP_CALL_ONHOLD))
 		hold = "a=recvonly\r\n";
@@ -5110,6 +5197,9 @@
 	    (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
 		len += strlen(m_video) + strlen(a_video) + strlen(b) + strlen(hold);
 
+	if (a_crypto)
+		len += strlen(a_crypto);
+
 	add_header(resp, "Content-Type", "application/sdp");
 	add_header_contentLength(resp, len);
 	add_line(resp, v);
@@ -5123,6 +5213,8 @@
 	add_line(resp, t);
 	add_line(resp, m_audio);
 	add_line(resp, a_audio);
+	if (a_crypto)
+		len += strlen(a_crypto);
 	add_line(resp, hold);
 	if ((p->vrtp) &&
 	    (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
@@ -14964,6 +15056,239 @@
 	);
 }
 
+
+/*
+ * SRTP sdescriptions
+ * Specified in: draft-ietf-mmusic-sdescriptions-12.txt
+ */
+
+static struct sip_srtp *sip_srtp_alloc(void)
+{
+	struct sip_srtp *srtp = malloc(sizeof(*srtp));
+
+	if (srtp)
+		memset(srtp, 0, sizeof(*srtp));
+	else
+		ast_log(LOG_ERROR, "Out of memory, can't allocate srtp structure\n");
+
+	return srtp;
+}
+
+static void sip_srtp_destroy(struct sip_srtp *srtp)
+{
+	free(srtp->a_crypto);
+	srtp->a_crypto = NULL;
+}
+
+
+static int setup_crypto(struct sip_pvt *p)
+{
+	if (!ast_srtp_is_registered()) {
+		ast_log(LOG_ERROR, "No SRTP module loaded, can't setup SRTP session.\n");
+		return -1;
+	}
+
+	p->srtp = sip_srtp_alloc();	/* Allocate SRTP data structure */
+	if (!p->srtp)
+		return -1;
+
+	if (ast_srtp_get_random(p->srtp->local_key, sizeof(p->srtp->local_key)) < 0) {
+		sip_srtp_destroy(p->srtp);
+		p->srtp = NULL;
+		return -1;
+	}
+
+	ast_base64encode(p->srtp->local_key64, p->srtp->local_key,
+			 SRTP_MASTER_LEN, sizeof(p->srtp->local_key64));
+	return 0;
+}
+
+static int set_crypto_policy(struct ast_srtp_policy *policy,
+			     int suite_val, const unsigned char *master_key,
+			     unsigned long ssrc, int inbound)
+{
+	const unsigned char *master_salt = NULL;
+
+	master_salt = master_key + SRTP_MASTERKEY_LEN;
+	if (ast_srtp_policy_set_master_key(policy,
+					   master_key, SRTP_MASTERKEY_LEN,
+					   master_salt, SRTP_MASTERSALT_LEN) < 0)
+		return -1;
+
+
+	if (ast_srtp_policy_set_suite(policy, suite_val)) {
+		ast_log(LOG_WARNING, "Could not set remote SRTP suite\n");
+		return -1;
+	}
+
+	ast_srtp_policy_set_ssrc(policy, ssrc, inbound);
+
+	return 0;
+}
+
+static int activate_crypto(struct sip_pvt *p, int suite_val,
+			   unsigned char *remote_key)
+{
+	struct ast_srtp_policy *local_policy = NULL;
+	struct ast_srtp_policy *remote_policy = NULL;
+	int res = -1;
+	struct sip_srtp *srtp = p->srtp;
+
+	if (!srtp)
+		return -1;
+
+	local_policy = ast_srtp_policy_alloc();
+	if (!local_policy)
+		goto err;
+
+	remote_policy = ast_srtp_policy_alloc();
+	if (!remote_policy) {
+		goto err;
+	}
+
+	if (set_crypto_policy(local_policy, suite_val, srtp->local_key,
+			      ast_rtp_get_ssrc(p->rtp), 0) < 0)
+		goto err;
+	
+	if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0)
+		goto err;
+
+	if (ast_rtp_add_srtp_policy(p->rtp, local_policy)) {
+		ast_log(LOG_WARNING, "Could not set local SRTP policy\n");
+		goto err;
+	}
+
+	if (ast_rtp_add_srtp_policy(p->rtp, remote_policy)) {
+		ast_log(LOG_WARNING, "Could not set remote SRTP policy\n");
+		goto err;
+	}
+
+
+	if (option_debug > 1)
+		ast_log(LOG_DEBUG, "SRTP policy activated\n");
+	res = 0;
+
+err:
+	if (local_policy)
+		ast_srtp_policy_destroy(local_policy);
+
+	if (remote_policy)
+		ast_srtp_policy_destroy(remote_policy);
+	return res;
+}
+
+static int process_crypto(struct sip_pvt *p, const char *attr)
+{
+	char *str = NULL;
+	char *name = NULL;
+	char *tag = NULL;
+	char *suite = NULL;
+	char *key_params = NULL;
+	char *key_param = NULL;
+	char *session_params = NULL;
+	char *key_salt = NULL;
+	char *lifetime = NULL;
+	int found = 0;
+	int attr_len = strlen(attr);
+	int key_len = 0;
+	unsigned char remote_key[SRTP_MASTER_LEN];
+	int suite_val = 0;
+	struct sip_srtp *srtp = p->srtp;
+
+	if (!ast_srtp_is_registered())
+		return -1;
+
+	/* Crypto already accepted */
+	if (srtp && srtp->a_crypto)
+		return -1;
+
+	str = ast_strdupa(attr);
+
+	name = strsep(&str, ":");
+	tag = strsep(&str, " ");
+	suite = strsep(&str, " ");
+	key_params = strsep(&str, " ");
+	session_params = strsep(&str, " ");
+
+	if (!tag || !suite) {
+		ast_log(LOG_WARNING, "Unrecognized a=%s", attr);
+		return -1;
+	}
+
+	if (session_params) {
+		ast_log(LOG_WARNING, "Unsupported crypto parameters: %s",
+			session_params);
+		return -1;
+	}
+
+	if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) {
+		suite_val = AST_AES_CM_128_HMAC_SHA1_80;
+	} else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) {
+		suite_val = AST_AES_CM_128_HMAC_SHA1_32;
+	} else {
+		ast_log(LOG_WARNING, "Unsupported crypto suite: %s",
+			suite);
+		return -1;
+	}
+
+	while ((key_param = strsep(&key_params, ";"))) {
+		char *method = NULL;
+		char *info = NULL;
+
+		method = strsep(&key_param, ":");
+		info = strsep(&key_param, ";");
+
+		if (!strcmp(method, "inline")) {
+			key_salt = strsep(&info, "|");
+			lifetime = strsep(&info, "|");
+
+			if (lifetime) {
+				ast_log(LOG_NOTICE, "Crypto life time unsupported: %s\n",
+					attr);
+				continue;
+			}
+
+/* 			if (info || strncmp(lifetime, "2^", 2)) { */
+/* 				ast_log(LOG_NOTICE, "MKI unsupported: %s\n", */
+/* 					attr); */
+/* 				continue; */
+/* 			} */
+
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		ast_log(LOG_NOTICE, "SRTP crypto offer not acceptable\n");
+		return -1;
+	}
+
+	if (!srtp) {
+		setup_crypto(p);
+		srtp = p->srtp;
+	}
+
+	key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key));
+	if (key_len != SRTP_MASTER_LEN) {
+		ast_log(LOG_WARNING, "SRTP sdescriptions key %d != %d\n",
+			key_len, SRTP_MASTER_LEN);
+		return -1;
+	}
+
+	if (activate_crypto(p, suite_val, remote_key) < 0)
+		return -1;
+
+	srtp->a_crypto = malloc(attr_len+11);
+	snprintf(srtp->a_crypto, attr_len+10,
+		 "a=crypto:%s %s inline:%s\r\n",
+		 tag, suite, srtp->local_key64);
+
+	return 0;
+}
+ 
+ 
+
 /*! \brief Reload module */
 static int sip_do_reload(enum channelreloadreason reason)
 {

Modified: team/oej/securertp-trunk/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/include/asterisk/rtp.h?rev=32521&r1=32520&r2=32521&view=diff
==============================================================================
--- team/oej/securertp-trunk/include/asterisk/rtp.h (original)
+++ team/oej/securertp-trunk/include/asterisk/rtp.h Tue Jun  6 04:03:51 2006
@@ -71,6 +71,66 @@
  * RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP.  A participant may be involved in multiple RTP sessions at the same time [...]"
  *
  */
+struct ast_srtp;
+
+struct ast_srtp_policy;
+
+struct ast_srtp_cb {
+	int (*no_ctx)(struct ast_rtp *rtp, unsigned long ssrc, void *data);
+};
+
+struct ast_srtp_res {
+	int (*create)(struct ast_srtp **srtp, struct ast_rtp *rtp,
+		      struct ast_srtp_policy *policy);
+	void (*destroy)(struct ast_srtp *srtp);
+	int (*add_stream)(struct ast_srtp *srtp, struct ast_srtp_policy *policy);
+	void (*set_cb)(struct ast_srtp *srtp,
+		       const struct ast_srtp_cb *cb, void *data);
+	int (*unprotect)(struct ast_srtp *srtp, void *buf, int *size);
+	int (*protect)(struct ast_srtp *srtp, void **buf, int *size);
+	int (*get_random)(unsigned char *key, size_t len);
+};
+
+/* Crypto suites */
+enum ast_srtp_suite {
+	AST_AES_CM_128_HMAC_SHA1_80 = 1,
+	AST_AES_CM_128_HMAC_SHA1_32 = 2,
+	AST_F8_128_HMAC_SHA1_80     = 3
+};
+
+enum ast_srtp_ealg {
+	AST_MIKEY_SRTP_EALG_NULL    = 0,
+	AST_MIKEY_SRTP_EALG_AESCM   = 1
+};
+
+enum ast_srtp_aalg {
+	AST_MIKEY_SRTP_AALG_NULL     = 0,
+	AST_MIKEY_SRTP_AALG_SHA1HMAC = 1
+};
+
+struct ast_srtp_policy_res {
+	struct ast_srtp_policy *(*alloc)(void);
+	void (*destroy)(struct ast_srtp_policy *policy);
+	int (*set_suite)(struct ast_srtp_policy *policy,
+			 enum ast_srtp_suite suite);
+	int (*set_master_key)(struct ast_srtp_policy *policy,
+			      const unsigned char *key, size_t key_len,
+			      const unsigned char *salt, size_t salt_len);
+	int (*set_encr_alg)(struct ast_srtp_policy *policy,
+			    enum ast_srtp_ealg  ealg);
+	int (*set_auth_alg)(struct ast_srtp_policy *policy,
+			    enum ast_srtp_aalg aalg);
+	void (*set_encr_keylen)(struct ast_srtp_policy *policy, int ekeyl);
+	void (*set_auth_keylen)(struct ast_srtp_policy *policy, int akeyl);
+	void (*set_srtp_auth_taglen)(struct ast_srtp_policy *policy, int autht);
+	void (*set_srtp_encr_enable)(struct ast_srtp_policy *policy, int enable);
+	void (*set_srtcp_encr_enable)(struct ast_srtp_policy *policy, int enable);
+	void (*set_srtp_auth_enable)(struct ast_srtp_policy *policy, int enable);
+	void (*set_ssrc)(struct ast_srtp_policy *policy, unsigned long ssrc,
+			 int inbound);
+};
+
+typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
 
 /*! \brief The value of each payload format mapping: */
 struct rtpPayloadType {
@@ -130,6 +190,7 @@
 	int rtp_lookup_code_cache_code;
 	int rtp_lookup_code_cache_result;
 	struct ast_rtcp *rtcp;
+	struct ast_srtp *srtp;		/*!< Secure RTP data */
 };
 
 /*!
@@ -238,6 +299,33 @@
 
 int ast_rtp_reload(void);
 
+int ast_rtp_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res);
+
+int ast_rtp_unregister_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res);
+
+int ast_srtp_is_registered(void);
+
+unsigned int ast_rtp_get_ssrc(struct ast_rtp *rtp);
+void ast_rtp_set_srtp_cb(struct ast_rtp *rtp, const struct ast_srtp_cb *cb,
+	void *data);
+int ast_rtp_add_srtp_policy(struct ast_rtp *rtp, struct ast_srtp_policy *policy);
+struct ast_srtp_policy *ast_srtp_policy_alloc(void);
+int ast_srtp_policy_set_suite(struct ast_srtp_policy *policy, enum ast_srtp_suite suite);
+int ast_srtp_policy_set_master_key(struct ast_srtp_policy *policy, const unsigned char *key, size_t key_len, const unsigned char *salt, size_t salt_len);
+int ast_srtp_policy_set_encr_alg(struct ast_srtp_policy *policy, enum ast_srtp_ealg ealg);
+int ast_srtp_policy_set_auth_alg(struct ast_srtp_policy *policy, enum ast_srtp_aalg aalg);
+void ast_srtp_policy_set_encr_keylen(struct ast_srtp_policy *policy, int ekeyl);
+void ast_srtp_policy_set_auth_keylen(struct ast_srtp_policy *policy, int akeyl);
+void ast_srtp_policy_set_srtp_auth_taglen(struct ast_srtp_policy *policy, int autht);
+void ast_srtp_policy_set_srtp_encr_enable(struct ast_srtp_policy *policy, int enable);
+void ast_srtp_policy_set_srtcp_encr_enable(struct ast_srtp_policy *policy, int enable);
+void ast_srtp_policy_set_srtp_auth_enable(struct ast_srtp_policy *policy, int enable);
+void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy, unsigned long ssrc, int inbound);
+
+void ast_srtp_policy_destroy(struct ast_srtp_policy *policy);
+int ast_srtp_get_random(unsigned char *key, size_t len);
+
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/oej/securertp-trunk/rtp.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/rtp.c?rev=32521&r1=32520&r2=32521&view=diff
==============================================================================
--- team/oej/securertp-trunk/rtp.c (original)
+++ team/oej/securertp-trunk/rtp.c Tue Jun  6 04:03:51 2006
@@ -89,6 +89,9 @@
 #ifdef SO_NO_CHECK
 static int nochecksums = 0;
 #endif
+
+struct ast_srtp_res *g_srtp_res;
+struct ast_srtp_policy_res *g_policy_res;
 
 /* Forward declarations */
 static int ast_rtcp_write(void *data);
@@ -643,6 +646,224 @@
 	rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
 	f = &rtp->f;
 	return f;
+}
+
+/*! \brief Register SRTP module in res_srtp to rtp core */
+int ast_rtp_register_srtp(struct ast_srtp_res *srtp_res,
+			   struct ast_srtp_policy_res *policy_res)
+{
+	if (g_srtp_res || g_policy_res)
+		return -1;
+
+	if (!srtp_res || !policy_res)
+		return -1;
+
+	g_srtp_res = srtp_res;
+	g_policy_res = policy_res;
+	return 0;
+}
+
+int ast_rtp_unregister_srtp(struct ast_srtp_res *srtp_res,
+			     struct ast_srtp_policy_res *policy_res)
+{
+	g_srtp_res = NULL;
+	g_policy_res = NULL;
+	return 0;
+}
+
+/*! \brief Check if there's a SRTP module registred and available */
+int ast_srtp_is_registered(void)
+{
+	return g_srtp_res && g_policy_res;
+}
+
+unsigned int ast_rtp_get_ssrc(struct ast_rtp *rtp)
+{
+	return rtp->ssrc;
+}
+
+void ast_rtp_set_srtp_cb(struct ast_rtp *rtp, const struct ast_srtp_cb *cb,
+			 void *data)
+{
+	if (!g_srtp_res || !rtp->srtp)
+		return;
+
+	g_srtp_res->set_cb(rtp->srtp, cb, data);
+}
+
+void ast_srtp_policy_set_ssrc(struct ast_srtp_policy *policy, unsigned long ssrc, int inbound)
+{
+	if (!g_policy_res)
+		return;
+
+	g_policy_res->set_ssrc(policy, ssrc, inbound);
+}
+
+int ast_rtp_add_srtp_policy(struct ast_rtp *rtp, struct ast_srtp_policy *policy)
+{
+	int res;
+	
+	if (!g_srtp_res)
+		return -1;
+
+	if (!rtp->srtp) {
+		res = g_srtp_res->create(&rtp->srtp, rtp, policy);
+	} else {
+		res = g_srtp_res->add_stream(rtp->srtp, policy);
+	}
+
+	return res;
+}
+
+struct ast_srtp_policy *ast_srtp_policy_alloc()
+{
+	if (!g_policy_res)
+		return NULL;
+
+	return g_policy_res->alloc();
+}
+
+void ast_srtp_policy_destroy(struct ast_srtp_policy *policy)
+{
+	if (!g_policy_res)
+		return;
+
+	g_policy_res->destroy(policy);
+}
+
+int ast_srtp_policy_set_suite(struct ast_srtp_policy *policy,
+		enum ast_srtp_suite suite)
+{
+	if (!g_policy_res)
+		return -1;
+
+	return g_policy_res->set_suite(policy, suite);
+}
+
+int ast_srtp_policy_set_master_key(struct ast_srtp_policy *policy,
+		const unsigned char *key, size_t key_len,
+		const unsigned char *salt, size_t salt_len)
+{
+	if (!g_policy_res)
+		return -1;
+
+	return g_policy_res->set_master_key(policy, key, key_len, salt, salt_len);
+}
+
+int ast_srtp_policy_set_encr_alg(struct ast_srtp_policy *policy,
+	      enum ast_srtp_ealg ealg)
+{
+	if (!g_policy_res)
+		return -1;
+
+	return g_policy_res->set_encr_alg(policy, ealg);
+}
+
+int ast_srtp_policy_set_auth_alg(struct ast_srtp_policy *policy,
+			      enum ast_srtp_aalg aalg)
+{
+	if (!g_policy_res)
+		return -1;
+
+	return g_policy_res->set_auth_alg(policy, aalg);
+}
+
+void ast_srtp_policy_set_encr_keylen(struct ast_srtp_policy *policy, int ekeyl)
+{
+	if (!g_policy_res)
+		return;
+
+	return g_policy_res->set_encr_keylen(policy, ekeyl);
+}
+
+void ast_srtp_policy_set_auth_keylen(struct ast_srtp_policy *policy,
+				 int akeyl)
+{
+	if (!g_policy_res)
+		return;
+
+	return g_policy_res->set_auth_keylen(policy, akeyl);
+}
+
+void ast_srtp_policy_set_srtp_auth_taglen(struct ast_srtp_policy *policy,
+				      int autht)
+{
+	if (!g_policy_res)
+		return;
+
+	return g_policy_res->set_srtp_auth_taglen(policy, autht);
+}
+
+void ast_srtp_policy_set_srtp_encr_enable(struct ast_srtp_policy *policy,
+				      int enable)
+{
+	if (!g_policy_res)
+		return;
+
+	return g_policy_res->set_srtp_encr_enable(policy, enable);
+}
+
+void ast_srtp_policy_set_srtcp_encr_enable(struct ast_srtp_policy *policy,
+				       int enable)
+{
+	if (!g_policy_res)
+		return;
+
+	return g_policy_res->set_srtcp_encr_enable(policy, enable);
+}
+
+void ast_srtp_policy_set_srtp_auth_enable(struct ast_srtp_policy *policy,
+				      int enable)
+{
+	if (!g_policy_res)
+		return;
+
+	return g_policy_res->set_srtp_auth_enable(policy, enable);
+}
+
+int ast_srtp_get_random(unsigned char *key, size_t len)
+{
+	if (!g_srtp_res)
+		return -1;
+
+	return g_srtp_res->get_random(key, len);
+}
+
+static int rtp_recvfrom(struct ast_rtp *rtp, void *buf, size_t size,
+			int flags, struct sockaddr *sa, socklen_t *salen)
+{
+	int len;
+
+	len = recvfrom(rtp->s, buf, size, flags, sa, salen);
+
+	if (len < 0)
+		return len;
+
+	if (g_srtp_res && rtp->srtp) {
+		int res;
+		
+		res = g_srtp_res->unprotect(rtp->srtp, buf, &len);
+		if (res < 0)
+			return -1;
+	}
+
+	return len;
+}
+
+static int rtp_sendto(struct ast_rtp *rtp, void *buf, size_t size,
+		      int flags, struct sockaddr *sa, socklen_t salen)
+{
+	int len = size;
+	void *temp = buf;
+
+	if (g_srtp_res && rtp->srtp) {
+		int res = g_srtp_res->protect(rtp->srtp, &temp, &len);
+
+		if (res < 0)
+			return -1;
+	}
+
+	return sendto(rtp->s, temp, len, flags, sa, salen);
 }
 
 static int rtpread(int *id, int fd, short events, void *cbdata)
@@ -1760,6 +1981,10 @@
 		free(rtp->rtcp);
 		rtp->rtcp=NULL;
 	}
+	if (g_srtp_res && rtp->srtp) {
+		g_srtp_res->destroy(rtp->srtp);
+		rtp->srtp = NULL;
+	}
 	free(rtp);
 }
 
@@ -1822,7 +2047,7 @@
 	rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
 	for (x = 0; x < 6; x++) {
 		if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
-			res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+			res = rtp_sendto(rtp, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
 			if (res < 0) 
 				ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
 					ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr),
@@ -2126,7 +2351,7 @@
 	rtpheader[2] = htonl(rtp->ssrc); 
 	data[12] = level;
 	if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
-		res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
+		res = rtp_sendto(rtp, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
 		if (res <0) 
 			ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s:%d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
 		if (rtp_debug_test_addr(&rtp->them))
@@ -2199,7 +2424,7 @@
 	put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc)); 
 
 	if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
-		res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
+		res = rtp_sendto(rtp, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
 		if (res <0) {
 			if (!rtp->nat || (rtp->nat && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
 				ast_log(LOG_DEBUG, "RTP Transmission error of packet %d to %s:%d: %s\n", rtp->seqno, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
@@ -2454,17 +2679,31 @@
 
 	/* Get audio and video interface (if native bridge is possible) */
 	p0 = pr0->get_rtp_info(c0);
-	vp0 = pr0->get_vrtp_info ? pr0->get_vrtp_info(c0) : NULL;
+	if (pr0->get_vrtp_info)
+		vp0 = pr0->get_vrtp_info(c0);
+	else
+		vp0 = NULL;
 	p1 = pr1->get_rtp_info(c1);
-	vp1 = pr1->get_vrtp_info ? pr1->get_vrtp_info(c1) : NULL;
+	if (pr1->get_vrtp_info)
+		vp1 = pr1->get_vrtp_info(c1);
+	else
+		vp1 = NULL;
 
 	/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
 	if (!p0 || !p1) {
 		/* Somebody doesn't want to play... */
-		ast_channel_unlock(c0);
-		ast_channel_unlock(c1);
+		ast_mutex_unlock(&c0->lock);
+		ast_mutex_unlock(&c1->lock);
 		return AST_BRIDGE_FAILED_NOWARN;
 	}
+
+	if (p0->srtp || p1->srtp) {
+		ast_log(LOG_NOTICE, "Cannot native bridge in SRTP.\n");
+		ast_mutex_unlock(&c0->lock);
+		ast_mutex_unlock(&c1->lock);
+		return AST_BRIDGE_FAILED_NOWARN;
+	}
+
 
 	if (ast_test_flag(p0, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
 		/* can't bridge, we are carrying DTMF for this channel and the bridge
@@ -2485,21 +2724,24 @@
 	}
 
 	/* Get codecs from both sides */
-	codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
-	codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;
+	if (pr0->get_codec)
+		codec0 = pr0->get_codec(c0);
+	else
+		codec0 = 0;
+	if (pr1->get_codec)
+		codec1 = pr1->get_codec(c1);
+	else
+		codec1 = 0;
 	if (pr0->get_codec && pr1->get_codec) {
 		/* Hey, we can't do reinvite if both parties speak different codecs */
 		if (!(codec0 & codec1)) {
 			if (option_debug)
 				ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
-			ast_channel_unlock(c0);
-			ast_channel_unlock(c1);
+			ast_mutex_unlock(&c0->lock);
+			ast_mutex_unlock(&c1->lock);
 			return AST_BRIDGE_FAILED_NOWARN;
 		}
 	}
-
-	if (option_verbose > 2) 
-		ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
 
 	/* Ok, we should be able to redirect the media. Start with one channel */
 	if (pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 



More information about the asterisk-commits mailing list