Commit 0a0f714c authored by johan's avatar johan
Browse files

improve ZRTP hash management

- start ZRTP on incoming zrtp-hash even when not selected locally
parent 83f861b3
......@@ -524,12 +524,16 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
static void setup_zrtp_hash(LinphoneCall *call, SalMediaDescription *md) {
int i;
if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) {
if (ms_zrtp_available()) { /* 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) {
ms_zrtp_getHelloHash(call->sessions[i].zrtp_context, md->streams[i].zrtphash, 128);
md->streams[i].haveZrtpHash = 1;
if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* turn on the flag to use it if ZRTP is set */
md->streams[i].haveZrtpHash = 1;
} else {
md->streams[i].haveZrtpHash = 0;
}
} else {
md->streams[i].haveZrtpHash = 0;
}
......@@ -1179,7 +1183,9 @@ 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_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) {
if ((sal_media_description_has_zrtp(md) == TRUE) && (ms_zrtp_available() == 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;
}else if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionSRTP;
......@@ -1815,7 +1821,12 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
}//else don't update the state if all streams are shutdown.
break;
case LinphoneMediaEncryptionNone:
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
/* check if we actually switched to ZRTP */
if (at_least_one_stream_started(call) && (all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) {
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
}
break;
}
call->current_params->avpf_enabled = linphone_call_all_streams_avpf_enabled(call) && sal_media_description_has_avpf(md);
......@@ -3360,6 +3371,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta
}
cam = linphone_call_get_video_device(call);
if (!is_inactive){
/* get remote stream description to check for zrtp-hash presence */
SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
const SalStreamDescription *remote_stream = sal_media_description_find_best_stream(remote_desc, SalVideo);
if (sal_stream_description_has_srtp(vstream) == TRUE) {
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
if (crypto_idx >= 0) {
......@@ -3412,11 +3427,17 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta
ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,call->current_params->encryption_mandatory);
_linphone_call_set_next_video_frame_decoded_trigger(call);
/* start ZRTP if needed */
if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) {
/* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */
if (call->params->media_encryption==LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) {
/*audio stream is already encrypted and video stream is active*/
if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
video_stream_start_zrtp(call->videostream);
if (remote_stream->haveZrtpHash == 1) {
int retval;
if ((retval = ms_zrtp_setPeerHelloHash(call->videostream->ms.sessions.zrtp_context, (uint8_t *)remote_stream->zrtphash, strlen((const char *)(remote_stream->zrtphash)))) != 0) {
ms_error("video stream ZRTP hash mismatch 0x%x", retval);
}
}
}
}
}
......
......@@ -489,11 +489,10 @@ static void initiate_incoming(MSFactory *factory, const SalStreamDescription *lo
}
if (remote_offer->haveZrtpHash == 1) {
if (local_cap->haveZrtpHash == 1) {
if (ms_zrtp_available()) { /* 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;
}
/* TODO: what if remote offer a zrtp-hash but we don't have it in local */
}
strcpy(result->ice_pwd, local_cap->ice_pwd);
......
......@@ -257,6 +257,11 @@ bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) {
return FALSE;
}
bool_t sal_stream_description_has_zrtp(const SalStreamDescription *sd) {
if (sd->haveZrtpHash==1) return TRUE;
return FALSE;
}
bool_t sal_media_description_has_avpf(const SalMediaDescription *md) {
int i;
if (md->nb_streams == 0) return FALSE;
......@@ -297,6 +302,16 @@ bool_t sal_media_description_has_dtls(const SalMediaDescription *md) {
return TRUE;
}
bool_t sal_media_description_has_zrtp(const SalMediaDescription *md) {
int i;
if (md->nb_streams == 0) return FALSE;
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
if (!sal_stream_description_active(&md->streams[i])) continue;
if (sal_stream_description_has_zrtp(&md->streams[i]) != TRUE) return FALSE;
}
return TRUE;
}
/*
static bool_t fmtp_equals(const char *p1, const char *p2){
if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
......
......@@ -330,6 +330,7 @@ bool_t sal_media_description_has_avpf(const SalMediaDescription *md);
bool_t sal_media_description_has_implicit_avpf(const SalMediaDescription *md);
bool_t sal_media_description_has_srtp(const SalMediaDescription *md);
bool_t sal_media_description_has_dtls(const SalMediaDescription *md);
bool_t sal_media_description_has_zrtp(const SalMediaDescription *md);
int sal_media_description_get_nb_active_streams(const SalMediaDescription *md);
struct SalOpBase;
......
......@@ -331,13 +331,22 @@ bool_t call_with_params2(LinphoneCoreManager* caller_mgr
|| linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) {
/*wait for encryption to be on, in case of zrtp or dtls, it can take a few seconds*/
if ( (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP)
|| (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) /* is callee is ZRTP, wait for it */
|| (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS))
wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1);
if ((linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP)
|| (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionDTLS)
|| (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP)
|| (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionDTLS) /*also take care of caller policy*/ )
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)) {
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));
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param), LinphoneMediaEncryptionZRTP, int, "%d");
}else { /* otherwise, final status shall stick to caller core parameter */
const LinphoneCallParams* call_param = linphone_call_get_current_params(callee_call);
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc), int, "%d");
call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc));
......@@ -3134,8 +3143,9 @@ void call_base_with_configfile(LinphoneMediaEncryption mode, bool_t enable_video
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
if (!call_ok) goto end;
if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP
&& linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) {
/* if caller set ZRTP or (callee set ZRTP and caller has no encryption requested), ZRTP shall take place, wait for the SAS */
if ((linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP)
|| ((linphone_core_get_media_encryption(marie->lc) == LinphoneMediaEncryptionZRTP) && (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionNone))) {
/*wait for SAS*/
int i;
for (i=0;i<100;i++) {
......@@ -6078,21 +6088,45 @@ static void call_with_ice_and_rtcp_mux_without_reinvite(void){
}
static void call_with_zrtp_configured_calling_base(LinphoneCoreManager *marie, LinphoneCoreManager *pauline) {
bool_t call_ok;
if (ms_zrtp_available()) {
bool_t call_ok;
linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionZRTP);
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionZRTP);
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
liblinphone_tester_check_rtcp(marie,pauline);
liblinphone_tester_check_rtcp(marie,pauline);
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))
, LinphoneMediaEncryptionNone, int, "%i");
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))
, LinphoneMediaEncryptionNone, int, "%i");
end_call(pauline, marie);
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))
, LinphoneMediaEncryptionZRTP, int, "%i");
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))
, LinphoneMediaEncryptionZRTP, int, "%i");
end_call(pauline, marie);
} else {
ms_warning("Test skipped, ZRTP not available");
}
}
static void call_with_zrtp_configured_callee_base(LinphoneCoreManager *marie, LinphoneCoreManager *pauline) {
if (ms_zrtp_available()) {
bool_t call_ok;
linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionZRTP);
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
liblinphone_tester_check_rtcp(marie,pauline);
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)))
, LinphoneMediaEncryptionZRTP, int, "%i");
BC_ASSERT_EQUAL(linphone_call_params_get_media_encryption(linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)))
, LinphoneMediaEncryptionZRTP, int, "%i");
end_call(pauline, marie);
} else {
ms_warning("Test skipped, ZRTP not available");
}
}
/*
* this test checks the 'dont_default_to_stun_candidates' mode, where the c= line is left to host
* ip instead of stun candidate when ice is enabled*/
......@@ -6137,6 +6171,16 @@ static void call_with_zrtp_configured_calling_side(void) {
call_with_zrtp_configured_calling_base(marie,pauline);
/* now set other encryptions mode for receiver(marie), we shall always fall back to caller preference: ZRTP */
linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionDTLS);
call_with_zrtp_configured_calling_base(marie,pauline);
linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP);
call_with_zrtp_configured_calling_base(marie,pauline);
linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionNone);
linphone_core_set_user_agent(pauline->lc, "Natted Linphone", NULL);
linphone_core_set_user_agent(marie->lc, "Natted Linphone", NULL);
call_with_zrtp_configured_calling_base(marie,pauline);
......@@ -6150,6 +6194,27 @@ static void call_with_zrtp_configured_calling_side(void) {
}
static void call_with_zrtp_configured_callee_side(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
call_with_zrtp_configured_callee_base(marie,pauline);
linphone_core_set_user_agent(pauline->lc, "Natted Linphone", NULL);
linphone_core_set_user_agent(marie->lc, "Natted Linphone", NULL);
call_with_zrtp_configured_callee_base(marie,pauline);
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
call_with_zrtp_configured_callee_base(marie,pauline);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
test_t call_tests[] = {
TEST_NO_TAG("Early declined call", early_declined_call),
TEST_NO_TAG("Call declined", call_declined),
......@@ -6331,7 +6396,8 @@ test_t call_tests[] = {
TEST_ONE_TAG("Call with ICE and rtcp-mux without ICE re-invite", call_with_ice_and_rtcp_mux_without_reinvite, "ICE"),
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_NO_TAG("call with ZRTP configured calling side only", call_with_zrtp_configured_calling_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_suite_t call_test_suite = {"Single Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment