From 0a246d1cb467c4f5a966fa3be971dcbf1000c703 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 18 Dec 2012 20:35:44 -0600 Subject: [PATCH] pull srtp negotiation stuff into the core stage 1 --- src/include/switch_core_media.h | 13 +- src/include/switch_types.h | 3 + src/mod/endpoints/mod_sofia/mod_sofia.c | 13 +- src/mod/endpoints/mod_sofia/mod_sofia.h | 13 +- src/mod/endpoints/mod_sofia/sofia.c | 5 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 67 +---- src/mod/endpoints/mod_sofia/sofia_media.c | 133 +--------- src/switch_core_media.c | 284 +++++++++++++++++++++- 8 files changed, 323 insertions(+), 208 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 976de00aa0..b0374e0990 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -39,7 +39,8 @@ SWITCH_BEGIN_EXTERN_C typedef enum { SM_NDLB_ALLOW_BAD_IANANAME = (1 << 0), SM_NDLB_ALLOW_NONDUP_SDP = (1 << 1), - SM_NDLB_ALLOW_CRYPTO_IN_AVP = (1 << 2) + SM_NDLB_ALLOW_CRYPTO_IN_AVP = (1 << 2), + SM_NDLB_DISABLE_SRTP_AUTH = (1 << 3) } switch_core_media_NDLB_t; struct switch_media_handle_s; @@ -52,6 +53,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_media_handle_ready(switch_co SWITCH_DECLARE(void) switch_media_handle_set_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag); SWITCH_DECLARE(void) switch_media_handle_clear_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag); SWITCH_DECLARE(int32_t) switch_media_handle_test_ndlb(switch_media_handle_t *smh, switch_core_media_NDLB_t flag); +SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_session_t *session, const char *sec_var); +SWITCH_DECLARE(const char *) switch_core_sesson_local_crypto_key(switch_core_session_t *session, switch_media_type_t type); +SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_session_t *session, + const char *varname, + switch_media_type_t type, const char *crypto, int crypto_tag); + +SWITCH_DECLARE(void) switch_core_session_apply_crypto(switch_core_session_t *session, switch_media_type_t type, const char *varname); +SWITCH_DECLARE(void) switch_core_session_get_recovery_crypto_key(switch_core_session_t *session, switch_media_type_t type, const char *varname); + +SWITCH_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *session, switch_media_type_t type, switch_rtp_t *rtp_session); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 5a35f81e4b..50e3377671 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1280,6 +1280,8 @@ typedef enum { CF_EARLY_OK, CF_MEDIA_TRANS, CF_HOLD_ON_BRIDGE, + CF_SECURE, + CF_CRYPTO_RECOVER, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX @@ -1463,6 +1465,7 @@ typedef enum { SWITCH_MEDIA_TYPE_AUDIO, SWITCH_MEDIA_TYPE_VIDEO } switch_media_type_t; +#define SWITCH_MEDIA_TYPE_TOTAL 2 /*! diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index edd4711549..da88a181cd 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -93,17 +93,8 @@ static switch_status_t sofia_on_init(switch_core_session_t *session) } if (sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { - const char *var; - if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && !zstr(var)) { - if (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32)) { - sofia_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)) { - sofia_set_flag_locked(tech_pvt, TFLAG_SECURE); - sofia_glue_build_crypto(tech_pvt, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); - } - } + switch_core_session_check_outgoing_crypto(session, SOFIA_SECURE_MEDIA_VARIABLE); if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) { @@ -1871,7 +1862,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if ((var = switch_channel_get_variable(channel, SOFIA_SECURE_MEDIA_VARIABLE)) && (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_80))) { - sofia_set_flag_locked(tech_pvt, TFLAG_SECURE); + switch_channel_set_flag(tech_pvt->channel, CF_SECURE); } if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING)) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 93fe66c8b9..abcfebbcac 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -224,7 +224,6 @@ typedef enum { PFLAG_RECIEVED_IN_NAT_REG_CONTACT, PFLAG_3PCC, PFLAG_DISABLE_RTP_AUTOADJ, - PFLAG_DISABLE_SRTP_AUTH, PFLAG_FUNNY_STUN, PFLAG_STUN_ENABLED, PFLAG_STUN_AUTO_DISABLE, @@ -309,7 +308,6 @@ typedef enum { TFLAG_BYE, TFLAG_ANS, TFLAG_EARLY_MEDIA, - TFLAG_SECURE, TFLAG_VAD_IN, TFLAG_VAD_OUT, TFLAG_VAD, @@ -349,7 +347,6 @@ typedef enum { TFLAG_SLA_BARGE, TFLAG_SLA_BARGING, TFLAG_PASS_ACK, - TFLAG_CRYPTO_RECOVER, TFLAG_DROP_DTMF, /* No new flags below this line */ TFLAG_MAX @@ -754,12 +751,6 @@ struct private_object { char *rm_fmtp; char *fmtp_out; char *remote_sdp_str; - int crypto_tag; - 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; char *early_sdp; char *local_sdp_str; char *last_sdp_str; @@ -777,8 +768,6 @@ struct private_object { char *invite_contact; char *local_url; char *gateway_name; - char *local_crypto_key; - char *remote_crypto_key; char *record_route; char *extrtpip; char *stun_ip; @@ -1125,7 +1114,7 @@ char *sofia_glue_strip_uri(const char *str); int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip); 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); +switch_status_t sofia_media_build_crypto(private_object_t *tech_pvt, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction); void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt); switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt, const char *sdp_str); void sofia_presence_event_thread_start(void); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index b6296ac37e..a0a998ccfa 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -3923,7 +3923,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else if (!strcasecmp(var, "disable-rtp-auto-adjust") && switch_true(val)) { sofia_set_pflag(profile, PFLAG_DISABLE_RTP_AUTOADJ); } else if (!strcasecmp(var, "NDLB-support-asterisk-missing-srtp-auth") && switch_true(val)) { - sofia_set_pflag(profile, PFLAG_DISABLE_SRTP_AUTH); + profile->ndlb |= SM_NDLB_DISABLE_SRTP_AUTH; } else if (!strcasecmp(var, "NDLB-funny-stun")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_FUNNY_STUN); @@ -6187,7 +6187,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (is_ok) { - if (tech_pvt->local_crypto_key) { + + if (switch_core_sesson_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) { sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); } if (sofia_use_soa(tech_pvt)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a4cfebbcbf..7d57e6eb7f 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -186,6 +186,7 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, int rate; int already_did[128] = { 0 }; int ptime = 0, noptime = 0; + const char *local_audio_crypto_key = switch_core_sesson_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d RTP/%sAVP", port, secure ? "S" : ""); @@ -323,7 +324,7 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, } if (secure) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=crypto:%s\n", tech_pvt->local_crypto_key); + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); } @@ -395,7 +396,8 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch switch_event_t *map = NULL, *ptmap = NULL; const char *b_sdp = NULL; int verbose_sdp = 0; - + const char *local_audio_crypto_key = switch_core_sesson_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); + switch_zmalloc(buf, SDPBUFLEN); sofia_glue_check_dtmf_type(tech_pvt); @@ -513,7 +515,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch if (tech_pvt->rm_encoding) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=audio %d RTP/%sAVP", - port, (!zstr(tech_pvt->local_crypto_key) && sofia_test_flag(tech_pvt, TFLAG_SECURE)) ? "S" : ""); + port, (!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) ? "S" : ""); switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->pt); @@ -571,8 +573,8 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=%s\n", sr); } - if (!zstr(tech_pvt->local_crypto_key) && sofia_test_flag(tech_pvt, TFLAG_SECURE)) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", tech_pvt->local_crypto_key); + if (!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=crypto:%s\n", local_audio_crypto_key); //switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=encryption:optional\n"); } @@ -595,7 +597,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch char *bp = buf; int both = 1; - if ((!zstr(tech_pvt->local_crypto_key) && sofia_test_flag(tech_pvt, TFLAG_SECURE))) { + if ((!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE))) { generate_m(tech_pvt, buf, SDPBUFLEN, port, 0, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 1); bp = (buf + strlen(buf)); @@ -631,7 +633,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch cur_ptime = this_ptime; - if ((!zstr(tech_pvt->local_crypto_key) && sofia_test_flag(tech_pvt, TFLAG_SECURE))) { + if ((!zstr(local_audio_crypto_key) && switch_channel_test_flag(tech_pvt->channel, CF_SECURE))) { generate_m(tech_pvt, bp, SDPBUFLEN - strlen(buf), port, cur_ptime, append_audio, sr, use_cng, cng_type, map, verbose_sdp, 1); bp = (buf + strlen(buf)); @@ -3109,51 +3111,6 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) } -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; - const char *val; - - 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_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Local Key [%s]\n", tech_pvt->local_crypto_key); - - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_SRTP_AUTH) && - !((val = switch_channel_get_variable(tech_pvt->channel, "NDLB_support_asterisk_missing_srtp_auth")) && switch_true(val))) { - tech_pvt->crypto_type = type; - } else { - tech_pvt->crypto_type = AES_CM_128_NULL_AUTH; - } - - return SWITCH_STATUS_SUCCESS; -} - - - static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen) { int codec_ms = ptime; @@ -4131,10 +4088,8 @@ int sofia_recover_callback(switch_core_session_t *session) sofia_glue_attach_private(session, profile, tech_pvt, NULL); switch_channel_set_name(tech_pvt->channel, switch_channel_get_variable(channel, "channel_name")); - if ((tmp = switch_channel_get_variable(channel, "srtp_remote_audio_crypto_key"))) { - tech_pvt->remote_crypto_key = switch_core_session_strdup(session, tmp); - sofia_set_flag(tech_pvt, TFLAG_CRYPTO_RECOVER); - } + + switch_core_session_get_recovery_crypto_key(session, SWITCH_MEDIA_TYPE_AUDIO, "srtp_remote_audio_crypto_key"); if ((tmp = switch_channel_get_variable(channel, "sip_local_sdp_str"))) { tech_pvt->local_sdp_str = switch_core_session_strdup(session, tmp); diff --git a/src/mod/endpoints/mod_sofia/sofia_media.c b/src/mod/endpoints/mod_sofia/sofia_media.c index d9d72c6a48..5d3704b872 100644 --- a/src/mod/endpoints/mod_sofia/sofia_media.c +++ b/src/mod/endpoints/mod_sofia/sofia_media.c @@ -311,61 +311,6 @@ switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *sess } -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]; - switch_rtp_crypto_key_type_t type; - char *p; - - - if (!switch_rtp_ready(tech_pvt->rtp_session)) { - goto bad; - } - - 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_SESSION_LOG(tech_pvt->session), 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_SESSION_LOG(tech_pvt->session), 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_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Error!\n"); - return SWITCH_STATUS_FALSE; - -} - - uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_sdp) { @@ -676,67 +621,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s crypto = attr->a_value; crypto_tag = atoi(crypto); - if (tech_pvt->remote_crypto_key && switch_rtp_ready(tech_pvt->rtp_session)) { - /* Compare all the key. The tag may remain the same even if key changed */ - if (crypto && !strcmp(crypto, tech_pvt->remote_crypto_key)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Existing key is still valid.\n"); - } else { - const char *a = switch_stristr("AES", tech_pvt->remote_crypto_key); - const char *b = switch_stristr("AES", crypto); + got_crypto = switch_core_session_check_incoming_crypto(tech_pvt->session, + SOFIA_HAS_CRYPTO_VARIABLE, SWITCH_MEDIA_TYPE_AUDIO, crypto, crypto_tag); - /* Change our key every time we can */ - - if (sofia_test_flag(tech_pvt, TFLAG_CRYPTO_RECOVER)) { - sofia_clear_flag(tech_pvt, TFLAG_CRYPTO_RECOVER); - } else 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); - switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type, - tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN); - } 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); - switch_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), tech_pvt->crypto_type, - tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n"); - } - - if (a && b && !strncasecmp(a, b, 23)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto); - tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto); - switch_channel_set_variable(tech_pvt->channel, "srtp_remote_audio_crypto_key", crypto); - tech_pvt->crypto_tag = crypto_tag; - - if (switch_rtp_ready(tech_pvt->rtp_session) && sofia_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_RECV, tech_pvt->crypto_tag, - tech_pvt->crypto_type, tech_pvt->remote_raw_key, SWITCH_RTP_KEY_LEN); - } - got_crypto++; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring unacceptable key\n"); - } - } - } else if (!switch_rtp_ready(tech_pvt->rtp_session)) { - tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", tech_pvt->remote_crypto_key); - switch_channel_set_variable(tech_pvt->channel, "srtp_remote_audio_crypto_key", crypto); - tech_pvt->crypto_tag = crypto_tag; - got_crypto++; - - if (zstr(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_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n"); - } - } - } } } @@ -1171,7 +1058,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) } if ((var = switch_channel_get_variable(tech_pvt->channel, SOFIA_SECURE_MEDIA_VARIABLE)) && switch_true(var)) { - sofia_set_flag_locked(tech_pvt, TFLAG_SECURE); + switch_channel_set_flag(tech_pvt->channel, CF_SECURE); } if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) { @@ -1376,6 +1263,9 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) uint32_t stun_ping = 0; const char *ssrc; + switch_core_media_set_rtp_session(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, tech_pvt->rtp_session); + + if ((ssrc = switch_channel_get_variable(tech_pvt->channel, "rtp_use_ssrc"))) { uint32_t ssrc_ul = (uint32_t) strtoul(ssrc, NULL, 10); switch_rtp_set_ssrc(tech_pvt->rtp_session, ssrc_ul); @@ -1582,15 +1472,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); } - if (tech_pvt->remote_crypto_key && sofia_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, tech_pvt->crypto_tag, 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"); - } - + switch_core_session_apply_crypto(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE); switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip); @@ -1754,6 +1636,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) if (switch_rtp_ready(tech_pvt->video_rtp_session)) { switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); + switch_core_media_set_rtp_session(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, tech_pvt->video_rtp_session); } if (switch_rtp_ready(tech_pvt->video_rtp_session)) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 970620fa56..61bed621a0 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -46,13 +46,295 @@ typedef enum { } smh_flag_t; +typedef struct secure_settings_s { + int crypto_tag; + 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; + char *local_crypto_key; + char *remote_crypto_key; +} switch_secure_settings_t; + +typedef struct switch_rtp_engine_s { + switch_secure_settings_t ssec; + switch_rtp_t *rtp_session; + switch_media_type_t type; +} switch_rtp_engine_t; + + struct switch_media_handle_s { switch_core_session_t *session; switch_core_media_NDLB_t ndlb; smh_flag_t flags; + switch_rtp_engine_t engines[SWITCH_MEDIA_TYPE_TOTAL]; }; +SWITCH_DECLARE(const char *) switch_core_sesson_local_crypto_key(switch_core_session_t *session, switch_media_type_t type) +{ + if (!session->media_handle) { + return NULL; + } + + return session->media_handle->engines[type].ssec.local_crypto_key; + +} + + +switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh, + switch_secure_settings_t *ssec, + 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; + const char *val; + switch_channel_t *channel; + char *p; + + switch_assert(smh); + channel = switch_core_session_get_channel(smh->session); + + 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 = ssec->local_raw_key; + } else { + key = ssec->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'; + } + + ssec->local_crypto_key = switch_core_session_sprintf(smh->session, "%d %s inline:%s", index, type_str, b64_key); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Set Local Key [%s]\n", ssec->local_crypto_key); + + if (!(smh->ndlb & SM_NDLB_DISABLE_SRTP_AUTH) && + !((val = switch_channel_get_variable(channel, "NDLB_support_asterisk_missing_srtp_auth")) && switch_true(val))) { + ssec->crypto_type = type; + } else { + ssec->crypto_type = AES_CM_128_NULL_AUTH; + } + + return SWITCH_STATUS_SUCCESS; +} + + + + + +switch_status_t switch_core_media_add_crypto(switch_secure_settings_t *ssec, const char *key_str, switch_rtp_crypto_direction_t direction) +{ + unsigned char key[SWITCH_RTP_MAX_CRYPTO_LEN]; + switch_rtp_crypto_key_type_t type; + char *p; + + + 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) { + ssec->crypto_send_type = type; + memcpy(ssec->local_raw_key, key, SWITCH_RTP_KEY_LEN); + } else { + ssec->crypto_recv_type = type; + memcpy(ssec->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_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *session, switch_media_type_t type, switch_rtp_t *rtp_session) +{ + switch_rtp_engine_t *engine; + if (!session->media_handle) return; + engine = &session->media_handle->engines[type]; + engine->rtp_session = rtp_session; +} + + +SWITCH_DECLARE(void) switch_core_session_get_recovery_crypto_key(switch_core_session_t *session, switch_media_type_t type, const char *varname) +{ + const char *tmp; + switch_rtp_engine_t *engine; + if (!session->media_handle) return; + engine = &session->media_handle->engines[type]; + + if ((tmp = switch_channel_get_variable(session->channel, varname))) { + engine->ssec.remote_crypto_key = switch_core_session_strdup(session, tmp); + switch_channel_set_flag(session->channel, CF_CRYPTO_RECOVER); + } +} + + +SWITCH_DECLARE(void) switch_core_session_apply_crypto(switch_core_session_t *session, switch_media_type_t type, const char *varname) +{ + switch_rtp_engine_t *engine; + if (!session->media_handle) return; + engine = &session->media_handle->engines[type]; + + + if (engine->ssec.remote_crypto_key && switch_channel_test_flag(session->channel, CF_SECURE)) { + switch_core_media_add_crypto(&engine->ssec, engine->ssec.remote_crypto_key, SWITCH_RTP_CRYPTO_RECV); + + + switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, 1, + engine->ssec.crypto_type, engine->ssec.local_raw_key, SWITCH_RTP_KEY_LEN); + + switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec.crypto_tag, + engine->ssec.crypto_type, engine->ssec.remote_raw_key, SWITCH_RTP_KEY_LEN); + + switch_channel_set_variable(session->channel, varname, "true"); + } + +} + + +SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_session_t *session, + const char *varname, + switch_media_type_t type, const char *crypto, int crypto_tag) +{ + int got_crypto = 0; + + switch_rtp_engine_t *engine; + if (!session->media_handle) return 0; + engine = &session->media_handle->engines[type]; + + if (engine->ssec.remote_crypto_key && switch_rtp_ready(engine->rtp_session)) { + /* Compare all the key. The tag may remain the same even if key changed */ + if (crypto && !strcmp(crypto, engine->ssec.remote_crypto_key)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Existing key is still valid.\n"); + } else { + const char *a = switch_stristr("AES", engine->ssec.remote_crypto_key); + const char *b = switch_stristr("AES", crypto); + + /* Change our key every time we can */ + + if (switch_channel_test_flag(session->channel, CF_CRYPTO_RECOVER)) { + switch_channel_clear_flag(session->channel, CF_CRYPTO_RECOVER); + } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) { + switch_channel_set_variable(session->channel, varname, SWITCH_RTP_CRYPTO_KEY_32); + + switch_core_media_build_crypto(session->media_handle, &engine->ssec, crypto_tag, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND); + switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), engine->ssec.crypto_type, + engine->ssec.local_raw_key, SWITCH_RTP_KEY_LEN); + } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) { + + switch_channel_set_variable(session->channel, varname, SWITCH_RTP_CRYPTO_KEY_80); + switch_core_media_build_crypto(session->media_handle, &engine->ssec, crypto_tag, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_SEND, atoi(crypto), engine->ssec.crypto_type, + engine->ssec.local_raw_key, SWITCH_RTP_KEY_LEN); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n"); + } + + if (a && b && !strncasecmp(a, b, 23)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto); + engine->ssec.remote_crypto_key = switch_core_session_strdup(session, crypto); + switch_channel_set_variable(session->channel, "srtp_remote_audio_crypto_key", crypto); + engine->ssec.crypto_tag = crypto_tag; + + if (switch_rtp_ready(engine->rtp_session) && switch_channel_test_flag(session->channel, CF_SECURE)) { + switch_core_media_add_crypto(&engine->ssec, engine->ssec.remote_crypto_key, SWITCH_RTP_CRYPTO_RECV); + switch_rtp_add_crypto_key(engine->rtp_session, SWITCH_RTP_CRYPTO_RECV, engine->ssec.crypto_tag, + engine->ssec.crypto_type, engine->ssec.remote_raw_key, SWITCH_RTP_KEY_LEN); + } + got_crypto++; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring unacceptable key\n"); + } + } + } else if (!switch_rtp_ready(engine->rtp_session)) { + engine->ssec.remote_crypto_key = switch_core_session_strdup(session, crypto); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Remote Key [%s]\n", engine->ssec.remote_crypto_key); + switch_channel_set_variable(session->channel, "srtp_remote_audio_crypto_key", crypto); + engine->ssec.crypto_tag = crypto_tag; + got_crypto++; + + if (zstr(engine->ssec.local_crypto_key)) { + if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_32, crypto)) { + switch_channel_set_variable(session->channel, varname, SWITCH_RTP_CRYPTO_KEY_32); + switch_core_media_build_crypto(session->media_handle, &engine->ssec, crypto_tag, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND); + } else if (switch_stristr(SWITCH_RTP_CRYPTO_KEY_80, crypto)) { + switch_channel_set_variable(session->channel, varname, SWITCH_RTP_CRYPTO_KEY_80); + switch_core_media_build_crypto(session->media_handle, &engine->ssec, crypto_tag, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n"); + } + } + } + + return got_crypto; +} + + +SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_session_t *session, const char *sec_var) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *var; + + if (!switch_core_session_media_handle_ready(session)) return; + + if ((var = switch_channel_get_variable(channel, sec_var)) && !zstr(var)) { + if (switch_true(var) || !strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_32)) { + switch_channel_set_flag(channel, CF_SECURE); + switch_core_media_build_crypto(session->media_handle, + &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec, 1, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND); + switch_core_media_build_crypto(session->media_handle, + &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec, 1, AES_CM_128_HMAC_SHA1_32, SWITCH_RTP_CRYPTO_SEND); + } else if (!strcasecmp(var, SWITCH_RTP_CRYPTO_KEY_80)) { + switch_channel_set_flag(channel, CF_SECURE); + switch_core_media_build_crypto(session->media_handle, + &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + switch_core_media_build_crypto(session->media_handle, + &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec, 1, AES_CM_128_HMAC_SHA1_80, SWITCH_RTP_CRYPTO_SEND); + } + } + +} + + SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t **smhp, switch_core_session_t *session) { switch_status_t status = SWITCH_STATUS_FALSE; @@ -61,7 +343,7 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t *smhp = NULL; if ((session->media_handle = switch_core_session_alloc(session, (sizeof(*smh))))) { - + session->media_handle->session = session; *smhp = session->media_handle; switch_set_flag(session->media_handle, SMH_INIT); status = SWITCH_STATUS_SUCCESS;