make media_encryption_mandatory work with zRTP - by silencing calls until they are secured.

Add non regression tests for this.
This commit is contained in:
Simon Morlat 2016-09-15 20:56:07 +02:00
parent 47ecf3daae
commit 0ca9c915ac
6 changed files with 89 additions and 21 deletions

View file

@ -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 <ortp/event.h>
#include <ortp/b64.h>
#include <math.h>
@ -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; i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
if (!sal_stream_description_active(&md->streams[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(&params,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){

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
};

@ -1 +1 @@
Subproject commit 7738a9ad40ed35ceaa49fa2d69cd00dfc045ad5c
Subproject commit 3b23cf2dc42f2122a6f0a7bd7859fb2341a0f540

View file

@ -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,