diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 189be5a93..1ddab1e38 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "lpconfig.h" #include "private.h" #include "conference_private.h" + #include #include #include @@ -88,6 +89,14 @@ static bool_t generate_b64_crypto_key(size_t key_length, char* key_out, size_t k return TRUE; } +static bool_t linphone_call_encryption_mandatory(LinphoneCall *call){ + if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { + ms_message("Forced encryption mandatory on call [%p] due to SRTP-DTLS",call); + return TRUE; + } + return call->params->encryption_mandatory; +} + LinphoneCore *linphone_call_get_core(const LinphoneCall *call){ return call->core; } @@ -186,7 +195,7 @@ static void propagate_encryption_changed(LinphoneCall *call){ ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism"); linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token); #ifdef VIDEO_ENABLED - if (call->current_params->encryption_mandatory && call->videostream && media_stream_started((MediaStream *)call->videostream)) { + if (linphone_call_encryption_mandatory(call) && call->videostream && media_stream_started((MediaStream *)call->videostream)) { video_stream_send_vfu(call->videostream); /*nothing could have been sent yet so generating key frame*/ } #endif @@ -524,7 +533,7 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ static void setup_zrtp_hash(LinphoneCall *call, SalMediaDescription *md) { int i; - if (ms_zrtp_available()) { /* set the hello hash for all streams */ + if (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP)) { /* set the hello hash for all streams */ for(i=0; istreams[i])) continue; if (call->sessions[i].zrtp_context!=NULL) { @@ -1215,7 +1224,7 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, S call->params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(call->core)*1000; } - if ((sal_media_description_has_zrtp(md) == TRUE) && (ms_zrtp_available() == TRUE)) { + if ((sal_media_description_has_zrtp(md) == TRUE) && (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP) == TRUE)) { call->params->media_encryption = LinphoneMediaEncryptionZRTP; }else if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) { call->params->media_encryption = LinphoneMediaEncryptionDTLS; @@ -2485,7 +2494,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ setup_dtls_params(call, &audiostream->ms); /* init zrtp even if we didn't explicitely set it, just in case peer offers it */ - if (ms_zrtp_available()) { + if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)) { char *uri = linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to); MSZrtpParams params; memset(¶ms,0,sizeof(MSZrtpParams)); @@ -2598,7 +2607,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); setup_dtls_params(call, &call->videostream->ms); /* init zrtp even if we didn't explicitely set it, just in case peer offers it */ - if (ms_zrtp_available()) { + if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)) { video_stream_enable_zrtp(call->videostream, call->audiostream); } @@ -3278,7 +3287,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta } } - ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions,call->current_params->encryption_mandatory); + ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions, linphone_call_encryption_mandatory(call)); if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){ int pause_time=500; @@ -3297,7 +3306,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta call->current_params->low_bandwidth=call->params->low_bandwidth; /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ - if (call->params->media_encryption==LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) { + if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP) && + (call->params->media_encryption == LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) ){ audio_stream_start_zrtp(call->audiostream); if (remote_stream->haveZrtpHash == 1) { int retval; @@ -3473,7 +3483,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta used_pt, &io); } } - ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,call->current_params->encryption_mandatory); + ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions, + linphone_call_encryption_mandatory(call)); _linphone_call_set_next_video_frame_decoded_trigger(call); /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */ @@ -3546,7 +3557,8 @@ static void linphone_call_start_text_stream(LinphoneCall *call) { text_stream_start(call->textstream, call->text_profile, rtp_addr, tstream->rtp_port, rtcp_addr, (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, used_pt); ms_filter_add_notify_callback(call->textstream->rttsink, real_time_text_character_received, call, FALSE); - ms_media_stream_sessions_set_encryption_mandatory(&call->textstream->ms.sessions,call->current_params->encryption_mandatory); + ms_media_stream_sessions_set_encryption_mandatory(&call->textstream->ms.sessions, + linphone_call_encryption_mandatory(call)); } else ms_warning("No text stream accepted."); } else { ms_message("No valid text stream defined."); @@ -3563,6 +3575,7 @@ static void linphone_call_set_symmetric_rtp(LinphoneCall *call, bool_t val){ } } + void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState next_state){ LinphoneCore *lc=call->core; bool_t use_arc = linphone_core_adaptive_rate_control_enabled(lc); @@ -3601,11 +3614,6 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex linphone_call_set_symmetric_rtp(call, FALSE); } - if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) { - call->current_params->encryption_mandatory = TRUE; - ms_message("Forcing encryption mandatory on call [%p]",call); - } - call->nb_media_starts++; #if defined(VIDEO_ENABLED) if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6a5229457..3c4284e97 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7344,7 +7344,7 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone case LinphoneMediaEncryptionDTLS: return ms_dtls_srtp_available(); case LinphoneMediaEncryptionZRTP: - return ms_zrtp_available(); + return ms_zrtp_available() && !lc->zrtp_not_available_simulation; case LinphoneMediaEncryptionNone: return TRUE; } @@ -7367,7 +7367,7 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption } break; case LinphoneMediaEncryptionZRTP: - if (!ms_zrtp_available()){ + if (!linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)){ ms_warning("ZRTP not supported by library."); type="none"; ret=-1; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 09bec45fb..0cb6ee9f0 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -494,7 +494,7 @@ static void initiate_incoming(MSFactory *factory, const SalStreamDescription *lo } if (remote_offer->haveZrtpHash == 1) { - if (ms_zrtp_available()) { /* if ZRTP is available, set the zrtp hash even if it is not selected */ + if (local_cap->zrtphash[0] != 0) { /* if ZRTP is available, set the zrtp hash even if it is not selected */ strncpy((char *)(result->zrtphash), (char *)(local_cap->zrtphash), sizeof(local_cap->zrtphash)); result->haveZrtpHash = 1; } diff --git a/coreapi/private.h b/coreapi/private.h index a6b91b04f..72da2a3c4 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1002,6 +1002,7 @@ struct _LinphoneCore bool_t send_call_stats_periodical_updates; bool_t forced_ice_relay; bool_t short_turn_refresh; + char localip[LINPHONE_IPADDR_SIZE]; int device_rotation; int max_calls; @@ -1041,6 +1042,9 @@ struct _LinphoneCore jmethodID multicast_lock_release_id; #endif LinphoneVcardContext *vcard_context; + + /*for tests only*/ + bool_t zrtp_not_available_simulation; }; diff --git a/mediastreamer2 b/mediastreamer2 index 7738a9ad4..3b23cf2dc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7738a9ad40ed35ceaa49fa2d69cd00dfc045ad5c +Subproject commit 3b23cf2dc42f2122a6f0a7bd7859fb2341a0f540 diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 750c63730..ed1d25e52 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -357,7 +357,9 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1); /* when caller is encryptionNone but callee is ZRTP, we expect ZRTP to take place */ - if ((linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionNone) && (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP)) { + if ((linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionNone) + && (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) + && linphone_core_media_encryption_supported(caller_mgr->lc, LinphoneMediaEncryptionZRTP)) { const LinphoneCallParams* call_param = linphone_call_get_current_params(callee_call); BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param), LinphoneMediaEncryptionZRTP, int, "%d"); call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); @@ -4792,6 +4794,58 @@ static void call_with_zrtp_configured_callee_side(void) { linphone_core_manager_destroy(pauline); } +static bool_t quick_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){ + linphone_core_invite_address(m1->lc, m2->identity); + if (!BC_ASSERT_TRUE(wait_for(m1->lc, m2->lc, &m2->stat.number_of_LinphoneCallIncomingReceived, 1))) + return FALSE; + linphone_core_accept_call(m2->lc, linphone_core_get_current_call(m2->lc)); + if (!BC_ASSERT_TRUE(wait_for(m1->lc, m2->lc, &m2->stat.number_of_LinphoneCallStreamsRunning, 1))) + return FALSE; + if (!BC_ASSERT_TRUE(wait_for(m1->lc, m2->lc, &m1->stat.number_of_LinphoneCallStreamsRunning, 1))) + return FALSE; + return TRUE; +} + +static void call_with_encryption_mandatory(bool_t caller_has_encryption_mandatory){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + /*marie doesn't support ZRTP at all*/ + marie->lc->zrtp_not_available_simulation=1; + + /*pauline requests encryption to be mandatory*/ + linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionZRTP); + linphone_core_set_media_encryption_mandatory(pauline->lc, TRUE); + + if (!caller_has_encryption_mandatory){ + if (!BC_ASSERT_TRUE(quick_call(marie, pauline))) goto end; + }else{ + if (!BC_ASSERT_TRUE(quick_call(pauline, marie))) goto end; + } + wait_for_until(pauline->lc, marie->lc, NULL, 0, 2000); + + /*assert that no RTP packets have been sent or received by Pauline*/ + /*testing packet_sent doesn't work, because packets dropped by the transport layer are counted as if they were sent.*/ +#if 0 + BC_ASSERT_EQUAL(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->rtp_stats.packet_sent, 0, int, "%i"); +#endif + /*however we can trust packet_recv from the other party instead */ + BC_ASSERT_EQUAL(linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc))->rtp_stats.packet_recv, 0, int, "%i"); + BC_ASSERT_EQUAL(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->rtp_stats.packet_recv, 0, int, "%i"); + end_call(marie, pauline); + + end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_from_plain_rtp_to_zrtp(void){ + call_with_encryption_mandatory(FALSE); +} + +static void call_from_zrtp_to_plain_rtp(void){ + call_with_encryption_mandatory(TRUE); +} static void v6_call_over_nat_64(void){ LinphoneCoreManager* marie; @@ -4963,8 +5017,10 @@ test_t call_tests[] = { TEST_ONE_TAG("Call with ICE with default candidate not stun", call_with_ice_with_default_candidate_not_stun, "ICE"), TEST_ONE_TAG("Call with ICE without stun server", call_with_ice_without_stun, "ICE"), TEST_ONE_TAG("Call with ICE without stun server one side", call_with_ice_without_stun2, "ICE"), - TEST_NO_TAG("call with ZRTP configured calling side only", call_with_zrtp_configured_calling_side), - TEST_NO_TAG("call with ZRTP configured receiver side only", call_with_zrtp_configured_callee_side) + TEST_NO_TAG("Call with ZRTP configured calling side only", call_with_zrtp_configured_calling_side), + TEST_NO_TAG("Call with ZRTP configured receiver side only", call_with_zrtp_configured_callee_side), + TEST_NO_TAG("Call from plain RTP to ZRTP mandatory should be silent", call_from_plain_rtp_to_zrtp), + TEST_NO_TAG("Call ZRTP mandatory to plain RTP should be silent", call_from_zrtp_to_plain_rtp) }; test_suite_t call_test_suite = {"Single Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,