From 7a578a895146a58371ad58264331c8a66500711f Mon Sep 17 00:00:00 2001
From: Brian West <brian@freeswitch.org>
Date: Mon, 10 Apr 2006 16:11:24 +0000
Subject: [PATCH] 1st pass to add secure RTP

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1102 d0543943-73ff-0310-b7d9-9358b9ac24b2
---
 src/include/switch_rtp.h                      |  2 +
 .../endpoints/mod_dingaling/mod_dingaling.c   |  1 +
 src/mod/endpoints/mod_exosip/mod_exosip.c     |  5 ++
 src/switch_rtp.c                              | 77 ++++++++++++++-----
 4 files changed, 65 insertions(+), 20 deletions(-)

diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h
index 8326828dce..4523105b10 100644
--- a/src/include/switch_rtp.h
+++ b/src/include/switch_rtp.h
@@ -85,6 +85,7 @@ SWITCH_DECLARE(switch_status)switch_rtp_create(switch_rtp **new_rtp_session,
 											   uint32_t packet_size,
 											   uint32_t ms_per_packet,
 											   switch_rtp_flag_t flags,
+											   char *crypto_key,
 											   const char **err,
 											   switch_memory_pool *pool);
 
@@ -111,6 +112,7 @@ SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_host,
 										   uint32_t packet_size,
 										   uint32_t ms_per_packet,
 										   switch_rtp_flag_t flags,
+										   char *crypto_key,
 										   const char **err,
 										   switch_memory_pool *pool);
 
diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c
index ea66d9dde6..201db84095 100644
--- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c
+++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c
@@ -1290,6 +1290,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
 																		 tech_pvt->read_codec.implementation->encoded_bytes_per_frame,
 																		 tech_pvt->read_codec.implementation->microseconds_per_frame,
 																		 0,
+																		 NULL,
 																		 &err, switch_core_session_get_pool(tech_pvt->session)))) {
 								switch_console_printf(SWITCH_CHANNEL_CONSOLE, "RTP ERROR %s\n", err);
 								switch_channel_hangup(channel);
diff --git a/src/mod/endpoints/mod_exosip/mod_exosip.c b/src/mod/endpoints/mod_exosip/mod_exosip.c
index 0d568aefa4..598da364ee 100644
--- a/src/mod/endpoints/mod_exosip/mod_exosip.c
+++ b/src/mod/endpoints/mod_exosip/mod_exosip.c
@@ -89,6 +89,7 @@ static struct {
 	int codec_ms;
 	int dtmf_duration;
 	unsigned int flags;
+	char *crypto_key;
 } globals;
 
 struct private_object {
@@ -137,6 +138,7 @@ SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_extip, globals.extip)
 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_ip, globals.ip)
 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string)
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_crypto_key, globals.crypto_key)
 
 static switch_status exosip_on_init(switch_core_session *session);
 static switch_status exosip_on_hangup(switch_core_session *session);
@@ -482,6 +484,7 @@ static switch_status activate_rtp(struct private_object *tech_pvt)
 										   tech_pvt->read_codec.implementation->encoded_bytes_per_frame,
 										   ms,
 										   0,
+										   globals.crypto_key,
 										   &err, switch_core_session_get_pool(tech_pvt->session));
 
 	if (tech_pvt->rtp_session) {
@@ -1572,6 +1575,8 @@ static int config_exosip(int reload)
 				set_global_ip(val);
 			} else if (!strcmp(var, "dialplan")) {
 				set_global_dialplan(val);
+			} else if (!strcmp(var, "crypto_key")) {
+				set_global_crypto_key(val);
 			} else if (!strcmp(var, "codec_prefs")) {
 				set_global_codec_string(val);
 				globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index f6846d13e1..c4fe85ccd4 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -44,6 +44,8 @@
 #define RTP_START_PORT 16384
 #define RTP_END_PORT 32768
 #define SWITCH_RTP_CNG_PAYLOAD 13
+#define MAX_KEY_LEN      64
+#define MASTER_KEY_LEN   30
 
 static switch_port_t NEXT_PORT = RTP_START_PORT;
 static switch_mutex_t *port_lock = NULL;
@@ -244,6 +246,7 @@ SWITCH_DECLARE(switch_status) switch_rtp_create(switch_rtp **new_rtp_session,
 												uint32_t packet_size,
 												uint32_t ms_per_packet,
 												switch_rtp_flag_t flags, 
+												char *crypto_key,
 												const char **err,
 												switch_memory_pool *pool)
 {
@@ -269,27 +272,60 @@ SWITCH_DECLARE(switch_status) switch_rtp_create(switch_rtp **new_rtp_session,
 	/* for from address on recvfrom calls */
 	switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, rtp_session->pool);
 	
+	memset(&policy, 0, sizeof(policy));
+	if (crypto_key) {
+		int len;
 
+		crypto_policy_set_rtp_default(&policy.rtp);
+		crypto_policy_set_rtcp_default(&policy.rtcp);
+		policy.ssrc.type  = ssrc_specific;
+		policy.ssrc.value = ssrc;
+		policy.key  = (uint8_t *) key;
+		policy.next = NULL;
+		policy.rtp.sec_serv = sec_serv_conf_and_auth;
+		policy.rtcp.sec_serv = sec_serv_none;  /* we don't do RTCP anyway */
 
-
-
-    policy.key                 = (uint8_t *)key;
-    policy.ssrc.type           = ssrc_specific;
-    policy.ssrc.value          = ssrc;
-    policy.rtp.cipher_type     = NULL_CIPHER;
-    policy.rtp.cipher_key_len  = 0; 
-    policy.rtp.auth_type       = NULL_AUTH;
-    policy.rtp.auth_key_len    = 0;
-    policy.rtp.auth_tag_len    = 0;
-    policy.rtp.sec_serv        = sec_serv_none;   
-    policy.rtcp.cipher_type    = NULL_CIPHER;
-    policy.rtcp.cipher_key_len = 0; 
-    policy.rtcp.auth_type      = NULL_AUTH;
-    policy.rtcp.auth_key_len   = 0;
-    policy.rtcp.auth_tag_len   = 0;
-    policy.rtcp.sec_serv       = sec_serv_none;   
-    policy.next                = NULL;
-
+		/*
+		 * read key from hexadecimal on command line into an octet string
+		 */
+		len = hex_string_to_octet_string(key, crypto_key, MASTER_KEY_LEN*2);
+    
+		/* check that hex string is the right length */
+		if (len < MASTER_KEY_LEN*2) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, 
+								  "error: too few digits in key/salt "
+								  "(should be %d hexadecimal digits, found %d)\n",
+								  MASTER_KEY_LEN*2, len);
+			return SWITCH_STATUS_FALSE;
+		} 
+		if (strlen(crypto_key) > MASTER_KEY_LEN*2) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, 
+								  "error: too many digits in key/salt "
+								  "(should be %d hexadecimal digits, found %u)\n",
+								  MASTER_KEY_LEN*2, (unsigned)strlen(crypto_key));
+			return SWITCH_STATUS_FALSE;
+		}
+    
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "set master key/salt to %s/", octet_string_hex_string(key, 16));
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s\n", octet_string_hex_string(key+16, 14));
+	} else {
+		policy.key                 = (uint8_t *)key;
+		policy.ssrc.type           = ssrc_specific;
+		policy.ssrc.value          = ssrc;
+		policy.rtp.cipher_type     = NULL_CIPHER;
+		policy.rtp.cipher_key_len  = 0; 
+		policy.rtp.auth_type       = NULL_AUTH;
+		policy.rtp.auth_key_len    = 0;
+		policy.rtp.auth_tag_len    = 0;
+		policy.rtp.sec_serv        = sec_serv_none;   
+		policy.rtcp.cipher_type    = NULL_CIPHER;
+		policy.rtcp.cipher_key_len = 0; 
+		policy.rtcp.auth_type      = NULL_AUTH;
+		policy.rtcp.auth_key_len   = 0;
+		policy.rtcp.auth_tag_len   = 0;
+		policy.rtcp.sec_serv       = sec_serv_none;   
+		policy.next                = NULL;
+	}
 	rtp_session->send_msg.header.ssrc    = htonl(ssrc);
 	rtp_session->send_msg.header.ts      = 0;
 	rtp_session->send_msg.header.seq     = (uint16_t) rand();
@@ -331,12 +367,13 @@ SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_host,
 										   uint32_t packet_size,
 										   uint32_t ms_per_packet,
 										   switch_rtp_flag_t flags,
+										   char *crypto_key,
 										   const char **err,
 										   switch_memory_pool *pool) 
 {
 	switch_rtp *rtp_session;
 
-	if (switch_rtp_create(&rtp_session, payload, packet_size, ms_per_packet, flags, err, pool) != SWITCH_STATUS_SUCCESS) {
+	if (switch_rtp_create(&rtp_session, payload, packet_size, ms_per_packet, flags, crypto_key, err, pool) != SWITCH_STATUS_SUCCESS) {
 		return NULL;
 	}