diff --git a/src/include/switch_types.h b/src/include/switch_types.h index c711ad64eb..4fe49cc6c5 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -370,17 +370,20 @@ typedef enum { SWITCH_RTP_FLAG_IO = (1 << 1), SWITCH_RTP_FLAG_USE_TIMER = (1 << 2), SWITCH_RTP_FLAG_TIMER_RECLOCK = (1 << 3), - SWITCH_RTP_FLAG_SECURE = (1 << 4), - SWITCH_RTP_FLAG_AUTOADJ = (1 << 5), - SWITCH_RTP_FLAG_RAW_WRITE = (1 << 6), - SWITCH_RTP_FLAG_GOOGLEHACK = (1 << 7), - SWITCH_RTP_FLAG_VAD = (1 << 8), - SWITCH_RTP_FLAG_BREAK = (1 << 9), - SWITCH_RTP_FLAG_MINI = (1 << 10), - SWITCH_RTP_FLAG_DATAWAIT = (1 << 11), - SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 12), - SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 13), - SWITCH_RTP_FLAG_AUTO_CNG = (1 << 14) + SWITCH_RTP_FLAG_SECURE_SEND = (1 << 4), + SWITCH_RTP_FLAG_SECURE_RECV = (1 << 5), + SWITCH_RTP_FLAG_AUTOADJ = (1 << 6), + SWITCH_RTP_FLAG_RAW_WRITE = (1 << 7), + SWITCH_RTP_FLAG_GOOGLEHACK = (1 << 8), + SWITCH_RTP_FLAG_VAD = (1 << 9), + SWITCH_RTP_FLAG_BREAK = (1 << 10), + SWITCH_RTP_FLAG_MINI = (1 << 11), + SWITCH_RTP_FLAG_DATAWAIT = (1 << 12), + SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13), + SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14), + SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15), + SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16), + SWITCH_RTP_FLAG_SECURE_RECV_RESET = (1 << 17) } switch_rtp_flag_t; /*! diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a8af860e3c..655c419c15 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -82,15 +82,16 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32 tech_pvt->session_id++; switch_snprintf(buf, sizeof(buf), - "v=0\n" - "o=FreeSWITCH %010u %010u IN IP4 %s\n" - "s=FreeSWITCH\n" - "c=IN IP4 %s\n" "t=0 0\n" - "a=%s\n" - "m=audio %d RTP/AVP", tech_pvt->owner_id, tech_pvt->session_id, ip, ip, sr, port); + "v=0\n" + "o=FreeSWITCH %010u %010u IN IP4 %s\n" + "s=FreeSWITCH\n" + "c=IN IP4 %s\n" "t=0 0\n" + "a=%s\n" + "m=audio %d RTP/%sAVP", tech_pvt->owner_id, tech_pvt->session_id, ip, ip, sr, port, + (!switch_strlen_zero(tech_pvt->local_crypto_key) && switch_test_flag(tech_pvt, TFLAG_SECURE)) ? "S" : "" + ); - if (tech_pvt->rm_encoding) { switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt); } else if (tech_pvt->num_codecs) { @@ -184,9 +185,38 @@ 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"); + //switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=encryption:optional\n"); + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=audio %d RTP/AVP", 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) { + int i; + int already_did[128] = { 0 }; + for (i = 0; i < tech_pvt->num_codecs; i++) { + const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { + continue; + } + + if (imp->ianacode < 128) { + if (already_did[imp->ianacode]) { + continue; + } + + already_did[imp->ianacode] = 1; + } + + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode); + } + } + + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\na=crypto:%s\n", tech_pvt->local_crypto_key); + } if (switch_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding) { @@ -1455,6 +1485,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t * switch_channel_t *channel = NULL; const char *val; const char *crypto = NULL; + int got_crypto = 0; tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); @@ -1542,30 +1573,40 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t * if (m->m_type == sdp_media_audio) { sdp_rtpmap_t *map; - + for (a = m->m_attributes; a; a = a->a_next) { if (!strcasecmp(a->a_name, "ptime") && a->a_value) { ptime = atoi(a->a_value); - } else if (!strcasecmp(a->a_name, "crypto") && a->a_value) { + } else if (!got_crypto && !strcasecmp(a->a_name, "crypto") && !switch_strlen_zero(a->a_value)) { crypto = a->a_value; int crypto_tag = atoi(crypto); + if (tech_pvt->remote_crypto_key) { if (crypto_tag && crypto_tag == tech_pvt->crypto_tag) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Existing key is still valid.\n"); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto); - tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto); - tech_pvt->crypto_tag = crypto_tag; - 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); + const char *a = switch_stristr("AES", tech_pvt->remote_crypto_key); + const char *b = switch_stristr("AES", crypto); + + if (a && b && strncasecmp(a, b, 23)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Change Remote key to [%s]\n", crypto); + tech_pvt->remote_crypto_key = switch_core_session_strdup(tech_pvt->session, crypto); + tech_pvt->crypto_tag = crypto_tag; + 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_LOG, SWITCH_LOG_DEBUG, "Ignoring unacceptable 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); tech_pvt->crypto_tag = crypto_tag; - + got_crypto++; + 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); @@ -1577,6 +1618,16 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t * switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Crypto Setup Failed!.\n"); } } + + if (switch_rtp_ready(tech_pvt->rtp_session) && + !switch_strlen_zero(tech_pvt->local_crypto_key) && !switch_strlen_zero(tech_pvt->remote_crypto_key)) { + switch_set_flag_locked(tech_pvt, TFLAG_SECURE); + sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1); + 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_rtp_add_crypto_key(tech_pvt->rtp_session, SWITCH_RTP_CRYPTO_SEND, tech_pvt->crypto_tag, + tech_pvt->crypto_type, tech_pvt->local_raw_key, SWITCH_RTP_KEY_LEN); + } } } } diff --git a/src/switch_rtp.c b/src/switch_rtp.c index cada496ee6..962788f1b8 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -495,10 +495,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess switch_rtp_crypto_key_t *crypto_key; srtp_policy_t *policy; err_status_t stat; + switch_status_t status = SWITCH_STATUS_SUCCESS; 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; + if (direction == SWITCH_RTP_CRYPTO_RECV) { + policy = &rtp_session->recv_policy; + } else { + policy = &rtp_session->send_policy; + } crypto_key->type = type; @@ -509,7 +514,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess 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: @@ -532,21 +537,43 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess 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; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV)) { + switch_set_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET); + } else { + if ((stat = srtp_create(&rtp_session->recv_ctx, policy))) { + status = SWITCH_STATUS_FALSE; + } + + if (status == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP RECV\n"); + switch_set_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat); + return status; + } } - 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; + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) { + switch_set_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND_RESET); + } else { + if ((stat = srtp_create(&rtp_session->send_ctx, policy))) { + status = SWITCH_STATUS_FALSE; + } + + if (status == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP SEND\n"); + switch_set_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating srtp [%d]\n", stat); + return status; + } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Activating Secure RTP SEND\n"); + break; default: abort(); @@ -774,9 +801,20 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session) switch_rtp_disable_vad(*rtp_session); } - if (switch_test_flag((*rtp_session), SWITCH_RTP_FLAG_SECURE)) { - srtp_dealloc((*rtp_session)->recv_ctx); + if (switch_test_flag((*rtp_session), SWITCH_RTP_FLAG_SECURE_SEND)) { + switch_mutex_lock((*rtp_session)->flag_mutex); srtp_dealloc((*rtp_session)->send_ctx); + (*rtp_session)->send_ctx = NULL; + switch_clear_flag((*rtp_session), SWITCH_RTP_FLAG_SECURE_SEND); + switch_mutex_unlock((*rtp_session)->flag_mutex); + } + + if (switch_test_flag((*rtp_session), SWITCH_RTP_FLAG_SECURE_RECV)) { + switch_mutex_lock((*rtp_session)->flag_mutex); + srtp_dealloc((*rtp_session)->recv_ctx); + (*rtp_session)->recv_ctx = NULL; + switch_clear_flag((*rtp_session), SWITCH_RTP_FLAG_SECURE_RECV); + switch_mutex_unlock((*rtp_session)->flag_mutex); } if ((*rtp_session)->timer.timer_interface) { @@ -970,12 +1008,26 @@ 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)) { + if (bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV)) { int sbytes = (int) bytes; - err_status_t stat; + err_status_t stat = 0; + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET)) { + switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET); + srtp_dealloc(rtp_session->recv_ctx); + rtp_session->recv_ctx = NULL; + if ((stat = srtp_create(&rtp_session->recv_ctx, &rtp_session->recv_policy))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! RE-Activating Secure RTP RECV\n"); + return -1; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RE-Activating Secure RTP RECV\n"); + rtp_session->srtp_errs = 0; + } + } 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, @@ -1558,10 +1610,24 @@ static int rtp_common_write(switch_rtp_t *rtp_session, send_msg->header.seq = htons(++rtp_session->seq); - if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) { int sbytes = (int) bytes; err_status_t stat; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND_RESET)) { + switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND_RESET); + srtp_dealloc(rtp_session->send_ctx); + rtp_session->send_ctx = NULL; + if ((stat = srtp_create(&rtp_session->send_ctx, &rtp_session->send_policy))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! RE-Activating Secure RTP SEND\n"); + return -1; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RE-Activating Secure RTP SEND\n"); + } + } + + 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); @@ -1723,10 +1789,22 @@ SWITCH_DECLARE(int) switch_rtp_write_manual(switch_rtp_t *rtp_session, bytes = rtp_header_len + datalen; - if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE)) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) { int sbytes = (int) bytes; err_status_t stat; + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND_RESET)) { + switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND_RESET); + srtp_dealloc(rtp_session->send_ctx); + rtp_session->send_ctx = NULL; + if ((stat = srtp_create(&rtp_session->send_ctx, &rtp_session->send_policy))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! RE-Activating Secure RTP SEND\n"); + return -1; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RE-Activating Secure RTP SEND\n"); + } + } + stat = srtp_protect(rtp_session->send_ctx, &rtp_session->write_msg.header, &sbytes); if (stat) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error: srtp protection failed with code %d\n", stat);