]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
RFC4568 support, you don't need the cone of silence anymore...
authorAnthony Minessale <anthony.minessale@gmail.com>
Wed, 16 Jan 2008 06:01:53 +0000 (06:01 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Wed, 16 Jan 2008 06:01:53 +0000 (06:01 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7244 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_rtp.h
src/include/switch_utils.h
src/mod/applications/mod_esf/mod_esf.c
src/mod/endpoints/mod_dingaling/mod_dingaling.c
src/mod/endpoints/mod_sofia/mod_sofia.c
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/switch_rtp.c
src/switch_utils.c

index 6bcac0034ec7c3bb89224bbdfd00cb05c7141144..4f5627a0484399c6f142f042a81d4f7aa73d68c4 100644 (file)
 
 SWITCH_BEGIN_EXTERN_C
 #define SWITCH_RTP_MAX_BUF_LEN 16384
+#define SWITCH_RTP_MAX_CRYPTO_LEN 64
+#define SWITCH_RTP_KEY_LEN 30
+#define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32"
+#define SWITCH_RTP_CRYPTO_KEY_80 "AES_CM_128_HMAC_SHA1_80"
+
+
+typedef enum {
+       SWITCH_RTP_CRYPTO_SEND,
+       SWITCH_RTP_CRYPTO_RECV,
+       SWITCH_RTP_CRYPTO_MAX
+} switch_rtp_crypto_direction_t;
+
+typedef enum {
+       NO_CRYPTO,
+       AES_CM_128_HMAC_SHA1_80,
+       AES_CM_128_HMAC_SHA1_32
+} switch_rtp_crypto_key_type_t;
+
+struct switch_rtp_crypto_key {
+       uint32_t index;
+       switch_rtp_crypto_key_type_t type;
+       unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
+       switch_size_t keylen;
+       struct switch_rtp_crypto_key *next;
+};
+typedef struct switch_rtp_crypto_key switch_rtp_crypto_key_t;
+
+
+
+SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session,
+                                                                                                                 switch_rtp_crypto_direction_t direction,
+                                                                                                                 uint32_t index,
+                                                                                                                 switch_rtp_crypto_key_type_t type,
+                                                                                                                 unsigned char *key,
+                                                                                                                 switch_size_t keylen);
+
 ///\defgroup rtp RTP (RealTime Transport Protocol)
 ///\ingroup core1
 ///\{
 typedef void (*switch_rtp_invalid_handler_t) (switch_rtp_t *rtp_session,
                                                                                          switch_socket_t * sock, void *data, switch_size_t datalen, switch_sockaddr_t * from_addr);
 
+
+SWITCH_DECLARE(void) switch_rtp_get_random(void *buf, uint32_t len);
 /*! 
   \brief Initilize the RTP System
   \param pool the memory pool to use for long term allocations
@@ -83,7 +121,6 @@ SWITCH_DECLARE(void) switch_rtp_release_port(const char *ip, switch_port_t port)
   \param samples_per_interval the default samples_per_interval
   \param ms_per_packet time in microseconds per packet
   \param flags flags to control behaviour
-  \param crypto_key optional crypto key
   \param timer_name timer interface to use
   \param err a pointer to resolve error messages
   \param pool a memory pool to use for the session
@@ -93,7 +130,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
                                                                                                  switch_payload_t payload,
                                                                                                  uint32_t samples_per_interval,
                                                                                                  uint32_t ms_per_packet,
-                                                                                                 switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err,
+                                                                                                 switch_rtp_flag_t flags,
+                                                                                                 char *timer_name, 
+                                                                                                 const char **err,
                                                                                                  switch_memory_pool_t *pool);
 
 
@@ -107,7 +146,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
   \param samples_per_interval the default samples_per_interval
   \param ms_per_packet time in microseconds per packet
   \param flags flags to control behaviour
-  \param crypto_key optional crypto key
   \param timer_name timer interface to use
   \param err a pointer to resolve error messages
   \param pool a memory pool to use for the session
@@ -120,7 +158,10 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host,
                                                                                          switch_payload_t payload,
                                                                                          uint32_t samples_per_interval,
                                                                                          uint32_t ms_per_packet,
-                                                                                         switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err, switch_memory_pool_t *pool);
+                                                                                         switch_rtp_flag_t flags,
+                                                                                         char *timer_name,
+                                                                                         const char **err,
+                                                                                         switch_memory_pool_t *pool);
 
 
 /*! 
index dbcc14c233b497b7ace0a34a6f20a280c52afd32..fcacd85f96fc0828dcd5cd29dba3875a43da8217 100644 (file)
@@ -56,7 +56,7 @@ SWITCH_BEGIN_EXTERN_C
 #endif
 
 SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen);
-SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_size_t olen);
+SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen);
 SWITCH_DECLARE(char *) switch_amp_encode(char *s, char *buf, switch_size_t len);
 
 static inline switch_bool_t switch_is_digit_string(const char *s) {
index a7ddf54309d16d75c21272c7a009d1fcfb2e1910..209c5b25c1d5720b698cc3c95562f65549ed8553 100644 (file)
@@ -167,7 +167,7 @@ SWITCH_STANDARD_APP(bcast_function)
                                                                         read_codec->implementation->samples_per_frame,
                                                                         read_codec->implementation->microseconds_per_frame,
                                                                         (switch_rtp_flag_t) flags,
-                                                                        NULL, "soft", &err, switch_core_session_get_pool(session));
+                                                                        "soft", &err, switch_core_session_get_pool(session));
        
                if (!switch_rtp_ready(rtp_session)) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error\n");
index 967d1766b1cbe9b5788053b7bae09a1c93e48e8d..37d4dea72afd234c3c1768d757207006176722c3 100644 (file)
@@ -877,7 +877,7 @@ static int activate_rtp(struct private_object *tech_pvt)
                                                                                                 tech_pvt->codec_num,
                                                                                                 tech_pvt->read_codec.implementation->samples_per_frame,
                                                                                                 tech_pvt->read_codec.implementation->microseconds_per_frame,
-                                                                                                flags, NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)))) {
+                                                                                                flags, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP ERROR %s\n", err);
                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                return 0;
index 3453c4e464f10dbf5576eb1fd9854bca95daa2eb..930428fb435f98370047dc71ad2ab5274552f3e1 100644 (file)
@@ -90,6 +90,19 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
        }
 
        if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+               const char *var;
+
+               if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && !switch_strlen_zero(var)) {
+                       if (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32)) {
+                               switch_set_flag_locked(tech_pvt, TFLAG_SECURE);
+                               sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+                       } else if (!strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_80)) {
+                               switch_set_flag_locked(tech_pvt, TFLAG_SECURE);
+                               sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
+                       }
+               }
+
+
                if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) {
                        switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                        return SWITCH_STATUS_FALSE;
@@ -786,6 +799,13 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
        switch_assert(tech_pvt != NULL);
 
+       if (msg->message_id == SWITCH_MESSAGE_INDICATE_ANSWER || msg->message_id == SWITCH_MESSAGE_INDICATE_PROGRESS) {
+               const char *var;
+               if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) {
+                       switch_set_flag_locked(tech_pvt, TFLAG_SECURE);
+               }
+       }
+
        switch (msg->message_id) {
        case SWITCH_MESSAGE_INDICATE_BROADCAST: {
                const char *ip = NULL, *port = NULL;
@@ -1746,6 +1766,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
        *pool = NULL;
 
   done:
+
        if (profile) {
                sofia_glue_release_profile(profile);
        }
index 9609f8a8f41c9084f9b87c8052cf89efc7effdac..69c5d1c87ba49fe76646a5df56468eb00214e6db 100644 (file)
@@ -73,6 +73,9 @@ typedef struct private_object private_object_t;
 #define SOFIA_DEFAULT_PORT "5060"
 #define SOFIA_DEFAULT_TLS_PORT "5061"
 #define SOFIA_REFER_TO_VARIABLE "sip_refer_to"
+#define SOFIA_SECURE_MEDIA_VARIABLE "sip_secure_media"
+#define SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE "sip_secure_media_confirmed"
+#define SOFIA_HAS_CRYPTO_VARIABLE "sip_has_crypto"
 
 #include <sofia-sip/nua.h>
 #include <sofia-sip/sip_status.h>
@@ -124,7 +127,8 @@ typedef enum {
        PFLAG_MULTIREG = (1 << 11),
        PFLAG_SUPRESS_CNG = (1 << 12),
        PFLAG_TLS = (1 << 13),
-       PFLAG_CHECKUSER = (1 << 14)
+       PFLAG_CHECKUSER = (1 << 14),
+       PFLAG_SECURE = (1 << 15)
 } PFLAGS;
 
 typedef enum {
@@ -339,6 +343,13 @@ struct private_object {
        char *invite_contact;
        char *local_url;
        char *gateway_name;
+       char *local_crypto_key;
+       char *remote_crypto_key;
+       unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
+       unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN];
+       switch_rtp_crypto_key_type_t crypto_send_type;
+       switch_rtp_crypto_key_type_t crypto_recv_type;
+       switch_rtp_crypto_key_type_t crypto_type;
        unsigned long rm_rate;
        switch_payload_t pt;
        switch_mutex_t *flag_mutex;
@@ -561,3 +572,4 @@ const char *sofia_glue_transport2str(const sofia_transport_t tp);
 
 int sofia_glue_transport_has_tls(const sofia_transport_t tp);
 const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name);
+switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction);
index 97209fd306a0f37d53162c40b0f9a578cdb8a6e4..494e9464255c5fdccaa6830fbeae99bc3ede9c89 100644 (file)
@@ -1010,6 +1010,10 @@ switch_status_t config_sofia(int reload, char *profile_name)
                                                if (switch_true(val)) {
                                                        profile->pflags |= PFLAG_PRESENCE;
                                                }
+                                       } else if (!strcasecmp(var, "require-secure-rtp")) {
+                                               if (switch_true(val)) {
+                                                       profile->pflags |= PFLAG_SECURE;
+                                               }
                                        } else if (!strcasecmp(var, "multiple-registrations")) {
                                                if (switch_true(val)) {
                                                        profile->pflags |= PFLAG_MULTIREG;
index c91e1bcf6322c60639fdc289c6ac1a1b740391a6..637f832bb99cdb59e7766d64e20b51761e7f113e 100644 (file)
@@ -89,6 +89,8 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
                         "a=%s\n" 
                         "m=audio %d RTP/AVP", tech_pvt->owner_id, tech_pvt->session_id, ip, ip, sr, port);
        
+
+
        if (tech_pvt->rm_encoding) {
                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
        } else if (tech_pvt->num_codecs) {
@@ -126,6 +128,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
 
        switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
 
+
        if (tech_pvt->rm_encoding) {
                rate = tech_pvt->rm_rate;
                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->pt, tech_pvt->rm_encoding, rate);
@@ -181,6 +184,11 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
                switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
        }
 
+       if (!switch_strlen_zero(tech_pvt->local_crypto_key) && switch_test_flag(tech_pvt, TFLAG_SECURE)) {
+               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=crypto:%s\n", tech_pvt->local_crypto_key);
+               switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n");
+       }
+
        if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) {
                sofia_glue_tech_choose_video_port(tech_pvt);
                if ((v_port = tech_pvt->adv_sdp_video_port)) {
@@ -928,7 +936,7 @@ void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt)
 
 void sofia_glue_deactivate_rtp(private_object_t *tech_pvt)
 {
-       int loops = 0;                          //, sock = -1;
+       int loops = 0;
        if (switch_rtp_ready(tech_pvt->rtp_session)) {
                while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
                        switch_yield(10000);
@@ -1077,6 +1085,102 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
        return SWITCH_STATUS_SUCCESS;
 }
 
+
+switch_status_t sofia_glue_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction)
+{
+       unsigned char b64_key[512] = "";
+       const char *type_str;
+       unsigned char *key;
+
+       char *p;
+
+       if (type == AES_CM_128_HMAC_SHA1_80) {
+               type_str = SWITCH_RTP_CRYPTO_KEY_80;
+       } else {
+               type_str = SWITCH_RTP_CRYPTO_KEY_32;
+       }
+
+       if (direction == SWITCH_RTP_CRYPTO_SEND) {
+               key = tech_pvt->local_raw_key;
+       } else {
+               key = tech_pvt->remote_raw_key;
+
+       }
+       
+       switch_rtp_get_random(key, SWITCH_RTP_KEY_LEN);
+       switch_b64_encode(key, SWITCH_RTP_KEY_LEN, b64_key, sizeof(b64_key));
+       p = strrchr((char *)b64_key, '=');
+
+       while(p && *p && *p == '=') {
+               *p-- = '\0';
+       }
+
+       tech_pvt->local_crypto_key = switch_core_session_sprintf(tech_pvt->session, "%d %s inline:%s", index, type_str, b64_key);
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Local Key [%s]\n", tech_pvt->local_crypto_key);
+       tech_pvt->crypto_type = type;
+
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t sofia_glue_add_crypto(private_object_t *tech_pvt, const char *key_str, switch_rtp_crypto_direction_t direction)
+{
+       unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN];
+       int index;
+       switch_rtp_crypto_key_type_t type;
+       char *p;
+
+
+       if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+               goto bad;
+       }
+       
+       index = atoi(key_str);
+
+       p = strchr(key_str, ' ');
+       
+       if (p && *p && *(p+1)) {
+               p++;
+               if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_32, strlen(SWITCH_RTP_CRYPTO_KEY_32))) {
+                       type = AES_CM_128_HMAC_SHA1_32;
+               } else if (!strncasecmp(p, SWITCH_RTP_CRYPTO_KEY_80, strlen(SWITCH_RTP_CRYPTO_KEY_80))) {
+                       type = AES_CM_128_HMAC_SHA1_80;
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
+                       goto bad;
+               }
+
+               p = strchr(p, ' ');
+               if (p && *p && *(p+1)) {
+                       p++;
+                       if (strncasecmp(p, "inline:", 7)) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error near [%s]\n", p);
+                               goto bad;
+                       }
+
+                       p += 7;
+                       switch_b64_decode(p, (char *)key, sizeof(key));
+                       
+                       if (direction == SWITCH_RTP_CRYPTO_SEND) {
+                               tech_pvt->crypto_send_type = type;
+                               memcpy(tech_pvt->local_raw_key, key, SWITCH_RTP_KEY_LEN);
+                       } else {
+                               tech_pvt->crypto_recv_type = type;
+                               memcpy(tech_pvt->remote_raw_key, key, SWITCH_RTP_KEY_LEN);
+                       }
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+       }
+       
+ bad:
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error!\n");
+       return SWITCH_STATUS_FALSE;
+
+}
+
+
 switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_flag_t myflags)
 {
        int bw, ms;
@@ -1175,8 +1279,10 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
                                                                                   tech_pvt->read_codec.implementation->samples_per_frame,
                                                                                   tech_pvt->codec_ms * 1000,
                                                                                   (switch_rtp_flag_t) flags,
-                                                                                  NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session));
-
+                                                                                  tech_pvt->profile->timer_name,
+                                                                                  &err,
+                                                                                  switch_core_session_get_pool(tech_pvt->session));
+       
        if (switch_rtp_ready(tech_pvt->rtp_session)) {
                uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
                uint8_t vad_out = switch_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
@@ -1243,6 +1349,14 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
                        switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
                }
                
+               if (tech_pvt->remote_crypto_key && switch_test_flag(tech_pvt, TFLAG_SECURE)) {
+                       sofia_glue_add_crypto(tech_pvt, tech_pvt->remote_crypto_key, SWITCH_RTP_CRYPTO_RECV);
+                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, tech_pvt->crypto_type, tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN);
+                       switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_RECV, 1, tech_pvt->crypto_type, tech_pvt->remote_raw_key, SWITCH_RTP_KEY_LEN);
+                       switch_channel_set_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE, "true");
+               }
+
+
                sofia_glue_check_video_codecs(tech_pvt);
 
                if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) {
@@ -1250,16 +1364,16 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
                        sofia_glue_tech_set_video_codec(tech_pvt, 0);
 
                        tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
-                                                                                                        tech_pvt->local_sdp_video_port,
-                                                                                                        tech_pvt->remote_sdp_video_ip,
-                                                                                                        tech_pvt->remote_sdp_video_port,
-                                                                                                        tech_pvt->video_agreed_pt,
-                                                                                                        tech_pvt->video_read_codec.implementation->samples_per_frame,
-                                                                                                        0,
-                                                                                                        (switch_rtp_flag_t) flags,
-                                                                                                        NULL, 
-                                                                                                        NULL,
-                                                                                                        &err, switch_core_session_get_pool(tech_pvt->session));
+                                                                                                                tech_pvt->local_sdp_video_port,
+                                                                                                                tech_pvt->remote_sdp_video_ip,
+                                                                                                                tech_pvt->remote_sdp_video_port,
+                                                                                                                tech_pvt->video_agreed_pt,
+                                                                                                                tech_pvt->video_read_codec.implementation->samples_per_frame,
+                                                                                                                0,
+                                                                                                                (switch_rtp_flag_t) flags,
+                                                                                                                NULL,
+                                                                                                                &err, 
+                                                                                                                switch_core_session_get_pool(tech_pvt->session));
 
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
                                                          switch_channel_get_name(tech_pvt->channel),
@@ -1396,7 +1510,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                        }
 
                        if (stream) {
-                               //switch_ivr_displace_session(tech_pvt->session, stream, 0, "rl");
                                switch_ivr_broadcast(switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE), stream, SMF_ECHO_ALEG | SMF_LOOP);
                        }
                }
@@ -1405,8 +1518,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                        const char *uuid;
                        switch_core_session_t *b_session;
                        
-                       //const char *stream;
-
                        if (tech_pvt->max_missed_packets) {
                                switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets);
                        }
@@ -1418,14 +1529,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                                switch_core_session_rwunlock(b_session);
                        }
 
-                       //if (!(stream = switch_channel_get_variable(tech_pvt->channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
-                       //stream = tech_pvt->profile->hold_music;
-            //}
-
-                       //if (stream) {
-                       //switch_ivr_stop_displace_session(tech_pvt->session, stream);
-                       //}
-
                        switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
                        switch_channel_presence(tech_pvt->channel, "unknown", "unhold");
                }
@@ -1444,6 +1547,24 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                                        ptime = atoi(a->a_value);
                                } else if (!strcasecmp(a->a_name, "crypto") && a->a_value) {
                                        crypto = a->a_value;
+                                       if (tech_pvt->remote_crypto_key) {
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already have a key\n");
+                                       } else {
+                                               tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto);
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", tech_pvt->remote_crypto_key);
+
+                                               if (switch_strlen_zero(tech_pvt->local_crypto_key)) {
+                                                       if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) {
+                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_32);
+                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND);
+                                                       } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) {
+                                                               switch_channel_set_variable(tech_pvt->channel, SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_RTP_CRYPTO_KEY_80);
+                                                               sofia_glue_build_crypto(tech_pvt, atoi(crypto), AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND);
+                                                       } else {
+                                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n");
+                                                       }
+                                               }
+                                       }
                                }
                        }
 
@@ -1461,7 +1582,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                greed:
                        x = 0;
 
-                       //xxxxxx
                        if (tech_pvt->rm_encoding) {
                                for (map = m->m_rtpmaps; map; map = map->rm_next) {
                                        if (map->rm_pt < 96) {
@@ -1486,7 +1606,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                                const char *rm_encoding;
                                
                                if (x++ < skip) {
-                                       //printf("skip %s\n", map->rm_encoding);
                                        continue;
                                }
 
index 5c6ce7e64bab0a37066fa1770e47f4e425b2a2d3..7f4d610b2ec4ba149d74c264fad182507f1db2b5 100644 (file)
 #undef inline
 #include <datatypes.h>
 #include <srtp.h>
+
+
 #include "stfu.h"
-#define MAX_KEY_LEN      64
+
 #define rtp_header_len 12
 #define RTP_START_PORT 16384
 #define RTP_END_PORT 32768
-#define MAX_KEY_LEN      64
 #define MASTER_KEY_LEN   30
 #define RTP_MAGIC_NUMBER 42
+#define MAX_SRTP_ERRS 10
 
 static switch_port_t START_PORT = RTP_START_PORT;
 static switch_port_t END_PORT = RTP_END_PORT;
@@ -121,14 +123,19 @@ struct switch_rtp {
 
        switch_sockaddr_t *local_addr;
        rtp_msg_t send_msg;
-       srtp_ctx_t *send_ctx;
 
        switch_sockaddr_t *remote_addr;
        rtp_msg_t recv_msg;
-       srtp_ctx_t *recv_ctx;
+
        uint32_t autoadj_window;
        uint32_t autoadj_tally;
 
+       srtp_ctx_t *send_ctx;
+       srtp_ctx_t *recv_ctx;
+       srtp_policy_t send_policy;
+       srtp_policy_t recv_policy;
+       uint32_t srtp_errs;
+       
        uint16_t seq;
        uint32_t ssrc;
        uint8_t sending_dtmf;
@@ -168,6 +175,7 @@ struct switch_rtp {
        uint32_t max_missed_packets;
        uint32_t missed_count;
        rtp_msg_t write_msg;
+       switch_rtp_crypto_key_t *crypto_keys[SWITCH_RTP_CRYPTO_MAX];
 };
 
 static int global_init = 0;
@@ -277,6 +285,12 @@ SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool)
        global_init = 1;
 }
 
+SWITCH_DECLARE(void) switch_rtp_get_random(void *buf, uint32_t len)
+{
+       crypto_get_random(buf, len);
+}
+
+
 SWITCH_DECLARE(void) switch_rtp_shutdown(void)
 {
        switch_core_hash_destroy(&alloc_hash);
@@ -470,16 +484,89 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_
        return SWITCH_STATUS_SUCCESS;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_session,
+                                                                                                                 switch_rtp_crypto_direction_t direction,
+                                                                                                                 uint32_t index,
+                                                                                                                 switch_rtp_crypto_key_type_t type,
+                                                                                                                 unsigned char *key,
+                                                                                                                 switch_size_t keylen) 
+{
+       
+       switch_rtp_crypto_key_t *crypto_key;
+       srtp_policy_t *policy;
+       err_status_t stat;
+
+       crypto_key = switch_core_alloc(rtp_session->pool, sizeof(*crypto_key));
+       
+       policy = direction == SWITCH_RTP_CRYPTO_RECV ? &rtp_session->recv_policy : &rtp_session->send_policy;
+       
+
+       crypto_key->type = type;
+       crypto_key->index = index;
+       memcpy(crypto_key->key, key, keylen);
+       crypto_key->next = rtp_session->crypto_keys[direction];
+       rtp_session->crypto_keys[direction] = crypto_key;
+
+
+       memset(policy, 0, sizeof(*policy));
+       switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE);
+
+       switch(crypto_key->type) {
+       case AES_CM_128_HMAC_SHA1_80:
+               crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy->rtp);
+               break;
+       case AES_CM_128_HMAC_SHA1_32:
+               crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy->rtp);
+               break;
+       default:
+               break;
+       }
+
+       
+       policy->next = NULL;    
+       policy->key = (uint8_t *) crypto_key->key;
+       crypto_policy_set_rtcp_default(&policy->rtcp);
+       policy->rtcp.sec_serv = sec_serv_none;
+
+       policy->rtp.sec_serv = sec_serv_conf_and_auth;
+       switch(direction) {
+       case SWITCH_RTP_CRYPTO_RECV:
+               policy->ssrc.type = ssrc_any_inbound;
+               if ((stat = srtp_create(&rtp_session->recv_ctx, policy))) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
+                       return SWITCH_STATUS_FALSE;
+               }
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP RECV\n");
+               break;
+       case SWITCH_RTP_CRYPTO_SEND:
+               policy->ssrc.type = ssrc_specific;
+               policy->ssrc.value = rtp_session->ssrc;
+
+               if ((stat = srtp_create(&rtp_session->send_ctx, policy))) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
+                       return SWITCH_STATUS_FALSE;
+               }
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP SEND\n");
+               break;
+       default:
+               abort();
+               break;
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+
+}
+
 SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session,
                                                                                                  switch_payload_t payload,
                                                                                                  uint32_t samples_per_interval,
                                                                                                  uint32_t ms_per_packet,
-                                                                                                 switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err,
+                                                                                                 switch_rtp_flag_t flags, 
+                                                                                                 char *timer_name, 
+                                                                                                 const char **err,
                                                                                                  switch_memory_pool_t *pool)
 {
        switch_rtp_t *rtp_session = NULL;
-       srtp_policy_t policy;
-       char key[MAX_KEY_LEN];
        uint32_t ssrc = rand() & 0xffff;
 
        *new_rtp_session = NULL;
@@ -507,44 +594,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
        /* for from address on recvfrom calls */
        switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
 
-       memset(&policy, 0, sizeof(policy));
-       if (crypto_key) {
-               int len;
-
-               switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE);
-               crypto_policy_set_rtp_default(&policy.rtp);
-               crypto_policy_set_rtcp_default(&policy.rtcp);
-               policy.ssrc.type = ssrc_any_inbound;
-               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;
-
-               /* 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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
-                                                         "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", MASTER_KEY_LEN * 2, len);
-                       *err = "Crypt Error";
-                       return SWITCH_STATUS_FALSE;
-               }
-               if (strlen(crypto_key) > MASTER_KEY_LEN * 2) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
-                                                         "error: too many digits in key/salt "
-                                                         "(should be %d hexadecimal digits, found %u)\n", MASTER_KEY_LEN * 2, (unsigned) strlen(crypto_key));
-                       *err = "Crypt Error";
-                       return SWITCH_STATUS_FALSE;
-               }
-
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP!\n");
-       }
 
        rtp_session->seq = (uint16_t) rand();
        rtp_session->ssrc = ssrc;
-       rtp_session->send_msg.header.ssrc = htonl(ssrc);
+       rtp_session->send_msg.header.ssrc = htonl(rtp_session->ssrc);
        rtp_session->send_msg.header.ts = 0;
        rtp_session->send_msg.header.m = 0;
        rtp_session->send_msg.header.pt = (switch_payload_t) htonl(payload);
@@ -553,7 +606,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
        rtp_session->send_msg.header.x = 0;
        rtp_session->send_msg.header.cc = 0;
 
-       rtp_session->recv_msg.header.ssrc = htonl(ssrc);
+       rtp_session->recv_msg.header.ssrc = 0;
        rtp_session->recv_msg.header.ts = 0;
        rtp_session->recv_msg.header.seq = 0;
        rtp_session->recv_msg.header.m = 0;
@@ -568,20 +621,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
        rtp_session->samples_per_interval = rtp_session->conf_samples_per_interval = samples_per_interval;
        rtp_session->timer_name = switch_core_strdup(pool, timer_name);
 
-       if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
-               err_status_t stat;
-
-               if ((stat = srtp_create(&rtp_session->recv_ctx, &policy))) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
-                       *err = "Crypt Error";
-                       return SWITCH_STATUS_FALSE;
-               }
-               if ((stat = srtp_create(&rtp_session->send_ctx, &policy))) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat);
-                       *err = "Crypt Error";
-                       return SWITCH_STATUS_FALSE;
-               }
-       }
 
        if (!switch_strlen_zero(timer_name)) {
                switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
@@ -615,11 +654,14 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host,
                                                                                          switch_payload_t payload,
                                                                                          uint32_t samples_per_interval,
                                                                                          uint32_t ms_per_packet,
-                                                                                         switch_rtp_flag_t flags, char *crypto_key, char *timer_name, const char **err, switch_memory_pool_t *pool)
+                                                                                         switch_rtp_flag_t flags,
+                                                                                         char *timer_name, 
+                                                                                         const char **err, 
+                                                                                         switch_memory_pool_t *pool)
 {
        switch_rtp_t *rtp_session = NULL;
        
-       if (switch_rtp_create(&rtp_session, payload, samples_per_interval, ms_per_packet, flags, crypto_key, timer_name, err, pool) != SWITCH_STATUS_SUCCESS) {
+       if (switch_rtp_create(&rtp_session, payload, samples_per_interval, ms_per_packet, flags, timer_name, err, pool) != SWITCH_STATUS_SUCCESS) {
                goto end;
        }
        
@@ -928,6 +970,29 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                        return -1;
                }
 
+               if (bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
+                       int sbytes = (int) bytes;
+                       err_status_t stat;
+
+
+                       stat = srtp_unprotect(rtp_session->recv_ctx, &rtp_session->recv_msg.header, &sbytes);
+                       if (stat && rtp_session->recv_msg.header.pt != rtp_session->te && rtp_session->recv_msg.header.pt != rtp_session->cng_pt) {
+                               if (++rtp_session->srtp_errs >= MAX_SRTP_ERRS) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+                                                                         "error: srtp unprotection failed with code %d%s\n", stat,
+                                                                         stat == err_status_replay_fail ? " (replay check failed)" : stat == err_status_auth_fail ? " (auth check failed)" : "");
+                                       return -1;
+                               } else {
+                                       sbytes = 0;
+                               }
+                       } else {
+                               rtp_session->srtp_errs = 0;
+                       }
+
+                       bytes = sbytes;
+
+               }
+
                if (rtp_session->jb && bytes && rtp_session->recv_msg.header.pt == rtp_session->payload) {
                        if (rtp_session->recv_msg.header.m) {
                                stfu_n_reset(rtp_session->jb);
@@ -1028,20 +1093,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                        return 2 + rtp_header_len;
                }
 
-               if (bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
-                       int sbytes = (int) bytes;
-                       err_status_t stat;
-
-                       stat = srtp_unprotect(rtp_session->recv_ctx, &rtp_session->recv_msg.header, &sbytes);
-                       if (stat) {
-                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
-                                                                 "error: srtp unprotection failed with code %d%s\n", stat,
-                                                                 stat == err_status_replay_fail ? " (replay check failed)" : stat == err_status_auth_fail ? " (auth check failed)" : "");
-                               return -1;
-                       }
-                       bytes = sbytes;
-               }
-
                if (bytes > 0) {
                        rtp_session->missed_count = 0;
                }
@@ -1356,7 +1407,6 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
                if (flags && *flags & SFF_RFC2833) {
                        send_msg->header.pt = rtp_session->te;
                }
-               send_msg->header.ssrc = htonl(rtp_session->ssrc);
        } else {
                uint8_t m = 0;
                
@@ -1392,17 +1442,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
                bytes = datalen + rtp_header_len;
        }
 
-       if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
-               int sbytes = (int) bytes;
-               err_status_t stat;
-
-               stat = srtp_protect(rtp_session->send_ctx, &send_msg->header, &sbytes);
-               if (stat) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error: srtp protection failed with code %d\n", stat);
-               }
-
-               bytes = sbytes;
-       }
+       send_msg->header.ssrc = htonl(rtp_session->ssrc);
 
        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_GOOGLEHACK) && rtp_session->send_msg.header.pt == 97) {
                rtp_session->recv_msg.header.pt = 102;
@@ -1517,6 +1557,19 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
        if (send) {
                send_msg->header.seq = htons(++rtp_session->seq);
                
+
+               if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) {
+                       int sbytes = (int) bytes;
+                       err_status_t stat;
+                       
+                       stat = srtp_protect(rtp_session->send_ctx, &send_msg->header, &sbytes);
+                       if (stat) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error: srtp protection failed with code %d\n", stat);
+                       }
+                       
+                       bytes = sbytes;
+               }
+
                if (switch_socket_sendto(rtp_session->sock, rtp_session->remote_addr, 0, (void *) send_msg, &bytes) != SWITCH_STATUS_SUCCESS) {
                        rtp_session->seq--;
                        return -1;
index 7ffc08dac01ae82427891b2bbbfdc8ffafcb3383..a33214e1b0b767b6bb9a09a95de0a9b1f0d047de 100644 (file)
@@ -166,7 +166,7 @@ SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size
 }
 
 
-SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_size_t olen)
+SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen)
 {
 
        char l64[256];
@@ -203,7 +203,7 @@ SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_si
 
        op[ol++] = '\0';
 
-       return SWITCH_STATUS_SUCCESS;
+       return ol;
 }