Commit b986af37 authored by johan's avatar johan
Browse files

Add dtls srtp

parent 7e32b85f
......@@ -585,6 +585,16 @@ AC_ARG_ENABLE(zrtp,
[zrtp=false]
)
AC_ARG_ENABLE(dtls,
[AS_HELP_STRING([--enable-dtls], [Turn on dtls support - requires polarssl > 1.4])],
[case "${enableval}" in
yes) dtls=true ;;
no) dtls=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-dtls) ;;
esac],
[dtls=false]
)
dnl build console if required
AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue)
......@@ -595,6 +605,7 @@ dnl compilation of gtk user interface
AM_CONDITIONAL(BUILD_GTK_UI, [test x$gtk_ui = xtrue ] )
AM_CONDITIONAL(BUILD_WIN32, test x$mingw_found = xyes )
AM_CONDITIONAL(BUILD_ZRTP, test x$zrtp = xtrue)
AM_CONDITIONAL(BUILD_DTLS, test x$dtls = xtrue)
dnl check getenv
AH_TEMPLATE([HAVE_GETENV])
......@@ -943,6 +954,7 @@ printf "* %-30s %s\n" "Console interface" $console_ui
printf "* %-30s %s\n" "Tools" $build_tools
printf "* %-30s %s\n" "Message storage" $enable_msg_storage
printf "* %-30s %s\n" "zRTP encryption" $zrtp
printf "* %-30s %s\n" "DTLS encryption" $dtls
printf "* %-30s %s\n" "uPnP support" $build_upnp
printf "* %-30s %s\n" "LDAP support" $enable_ldap
......
......@@ -1060,6 +1060,42 @@ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const
if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key);
}
/**
* Parse a directory to get a certificate with the given subject common name
*
*/
void sal_certificates_chain_parse_directory(unsigned char **certificate_pem, unsigned char **key_pem, unsigned char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) {
belle_sip_certificates_chain_t *certificate = NULL;
belle_sip_signing_key_t *key = NULL;
*certificate_pem = NULL;
*key_pem = NULL;
if (belle_sip_get_certificate_and_pkey_in_dir(path, subject, &certificate, &key, (belle_sip_certificate_raw_format_t)format) == 0) {
*certificate_pem = belle_sip_get_certificates_pem(certificate);
*key_pem = belle_sip_get_key_pem(key);
ms_message("Retrieve certificate with CN=%s successful\n", subject);
} else {
if (generate_certificate == TRUE) {
if ( belle_sip_generate_self_signed_certificate(path, subject, &certificate, &key) == 0) {
*certificate_pem = belle_sip_get_certificates_pem(certificate);
*key_pem = belle_sip_get_key_pem(key);
ms_message("Generate self-signed certificate with CN=%s successful\n", subject);
}
}
}
/* generate the fingerprint as described in RFC4572 if needed */
if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) {
*fingerprint = belle_sip_generate_certificate_fingerprint(certificate);
}
/* free key and certificate */
if ( certificate != NULL ) {
belle_sip_object_unref(certificate);
}
if ( key != NULL ) {
belle_sip_object_unref(key);
}
}
unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){
return belle_sip_random_bytes(ret,size);
}
......
......@@ -233,6 +233,26 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
}else break;
}
}
/* insert DTLS session attribute if needed */
if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) {
if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) {
switch(stream->dtls_role) {
case SalDtlsRoleIsClient:
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","active"));
break;
case SalDtlsRoleIsServer:
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","passive"));
break;
case SalDtlsRoleUnset:
default:
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","actpass"));
break;
}
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint));
}
}
switch ( stream->dir ) {
case SalStreamSendRecv:
/*dir="sendrecv";*/
......@@ -351,6 +371,23 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd));
if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag));
/* insert DTLS session attribute if needed */
if ((desc->dtls_role != SalDtlsRoleInvalid) && (strlen(desc->dtls_fingerprint)>0)) {
switch(desc->dtls_role) {
case SalDtlsRoleIsClient:
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","active"));
break;
case SalDtlsRoleIsServer:
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","passive"));
break;
case SalDtlsRoleUnset:
default:
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("setup","actpass"));
break;
}
belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("fingerprint",desc->dtls_fingerprint));
}
if (desc->rtcp_xr.enabled == TRUE) {
belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr));
}
......@@ -646,6 +683,10 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
stream->proto = SalProtoRtpAvpf;
} else if (strcasecmp(proto, "RTP/SAVPF") == 0) {
stream->proto = SalProtoRtpSavpf;
} else if (strcasecmp(proto, "UDP/TLS/RTP/SAVP") == 0) {
stream->proto = SalProtoUdpTlsRtpSavp;
} else if (strcasecmp(proto, "UDP/TLS/RTP/SAVPF") == 0) {
stream->proto = SalProtoUdpTlsRtpSavpf;
} else {
strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1);
}
......@@ -701,6 +742,36 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
}
/* Read DTLS specific attributes : check is some are found in the stream description otherwise copy the session description one(which are at least set to Invalid) */
stream->dtls_role = SalDtlsRoleInvalid;
stream->dtls_fingerprint[0] = '\0';
if (((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp))) {
attribute=belle_sdp_media_description_get_attribute(media_desc,"setup");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
if (strncmp(value, "actpass", 7) == 0) {
stream->dtls_role = SalDtlsRoleUnset;
} else if (strncmp(value, "active", 6) == 0) {
stream->dtls_role = SalDtlsRoleIsClient;
} else if (strncmp(value, "passive", 7) == 0) {
stream->dtls_role = SalDtlsRoleIsServer;
}
if (stream->dtls_role != SalDtlsRoleInvalid) {
attribute=belle_sdp_media_description_get_attribute(media_desc,"fingerprint");
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
strncpy(stream->dtls_fingerprint, value, strlen(value)+1);
} else {
/* no valid stream attributes, get them from session */
stream->dtls_role = md->dtls_role;
strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1);
}
}
} else { /* no setup attribute found in the stream, get the one from the session */
stream->dtls_role = md->dtls_role;
strncpy(stream->dtls_fingerprint, md->dtls_fingerprint, strlen(md->dtls_fingerprint)+1);
}
}
/* Read crypto lines if any */
if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) {
sdp_parse_media_crypto_parameters(media_desc, stream);
......@@ -756,6 +827,33 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
desc->dir=SalStreamInactive;
}
/* Read dtls specific session attributes if any (setup and fingerprint - rfc5763) */
/* Presence of a valid dtls offer(setup and fingerprint attribute) is set in media Description by a dtls_fingerprint string longer than 0
* and a dtls_role != SalDtlsRoleInvalid */
desc->dtls_role = SalDtlsRoleInvalid;
desc->dtls_fingerprint[0] = '\0';
value=belle_sdp_session_description_get_attribute_value(session_desc,"setup");
if (value){
if (strncmp(value, "actpass", 7) == 0) {
desc->dtls_role = SalDtlsRoleUnset;
} else if (strncmp(value, "active", 6) == 0) {
desc->dtls_role = SalDtlsRoleIsClient;
} else if (strncmp(value, "passive", 7) == 0) {
desc->dtls_role = SalDtlsRoleIsServer;
}
}
if (desc->dtls_role != SalDtlsRoleInvalid) {
value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint");
if (value){
strncpy(desc->dtls_fingerprint, value, strlen(value)+1);
} else {
desc->dtls_role = SalDtlsRoleInvalid;
}
}
/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag");
if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1);
......
......@@ -27,6 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) {
if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp;
if ((params->media_encryption == LinphoneMediaEncryptionDTLS) && params->avpf_enabled) return SalProtoUdpTlsRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp;
if (params->avpf_enabled) return SalProtoRtpAvpf;
return SalProtoRtpAvp;
}
......
......@@ -158,8 +158,12 @@ static void propagate_encryption_changed(LinphoneCall *call){
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token);
} else {
ms_message("All streams are encrypted");
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
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");
if (call->auth_token) {/* ZRTP only is using auth_token */
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else { /* otherwise it must be DTLS as SDES doesn't go through this function */
call->current_params->media_encryption=LinphoneMediaEncryptionDTLS;
}
linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token);
}
}
......@@ -171,8 +175,10 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr
call = (LinphoneCall *)data;
if (encrypted) {
snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
linphone_core_notify_display_status(call->core, status);
if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */
snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
linphone_core_notify_display_status(call->core, status);
}
}
propagate_encryption_changed(call);
......@@ -472,6 +478,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
}
setup_encryption_keys(call,md);
/* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */
if ((call->params->media_encryption==LinphoneMediaEncryptionDTLS) && (call->dtls_certificate_fingerprint!= NULL)) {
memcpy(md->dtls_fingerprint, call->dtls_certificate_fingerprint, strlen((const char *)(call->dtls_certificate_fingerprint))); /* get the self fingerprint from call(it's computed at stream init) */
md->dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */
} else {
md->dtls_fingerprint[0] = '\0';
md->dtls_role = SalDtlsRoleInvalid;
}
setup_rtcp_fb(call, md);
setup_rtcp_xr(call, md);
......@@ -572,6 +586,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->camera_enabled=TRUE;
call->current_params = linphone_call_params_new();
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
call->dtls_certificate_fingerprint = NULL;
linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
port_config_set(call,0,min_port,max_port);
......@@ -735,7 +750,7 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call){
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) {
call->params->has_video &= linphone_core_media_description_contains_video_stream(md);
/* Handle AVPF and SRTP. */
/* Handle AVPF, SRTP and DTLS. */
call->params->avpf_enabled = sal_media_description_has_avpf(md);
if (call->params->avpf_enabled == TRUE) {
if (call->dest_proxy != NULL) {
......@@ -744,6 +759,9 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c
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)) {
call->params->media_encryption = LinphoneMediaEncryptionDTLS;
}
if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) {
call->params->media_encryption = LinphoneMediaEncryptionSRTP;
}
......@@ -917,8 +935,19 @@ static void linphone_call_set_terminated(LinphoneCall *call){
void linphone_call_fix_call_parameters(LinphoneCall *call){
call->params->has_video=call->current_params->has_video;
if (call->params->media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/
call->params->media_encryption=call->current_params->media_encryption;
switch(call->params->media_encryption) {
case LinphoneMediaEncryptionZRTP:
case LinphoneMediaEncryptionDTLS:
case LinphoneMediaEncryptionNone:
/* do nothing */
break;
case LinphoneMediaEncryptionSRTP:
call->params->media_encryption=call->current_params->media_encryption;
break;
default:
ms_fatal("Unknown media encryption type on call [%p]", call);
break;
}
}
const char *linphone_call_state_to_string(LinphoneCallState cs){
......@@ -1066,6 +1095,10 @@ static void linphone_call_destroy(LinphoneCall *obj){
ms_free(obj->auth_token);
obj->auth_token=NULL;
}
if (obj->dtls_certificate_fingerprint) {
ms_free(obj->dtls_certificate_fingerprint);
obj->dtls_certificate_fingerprint=NULL;
}
if (obj->dtmfs_timer) {
linphone_call_cancel_dtmfs(obj);
}
......@@ -1118,11 +1151,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
#endif
if (linphone_call_all_streams_encrypted(call)) {
if (linphone_call_get_authentication_token(call)) {
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionSRTP;
}
if (linphone_call_get_authentication_token(call)) {
call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
} else {
/* TODO : check this or presence of dtls_fingerprint in the call? */
if (call->params->media_encryption == LinphoneMediaEncryptionDTLS) {
call->current_params->media_encryption=LinphoneMediaEncryptionDTLS;
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionSRTP;
}
}
} else {
call->current_params->media_encryption=LinphoneMediaEncryptionNone;
}
......@@ -1553,6 +1591,34 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
if (call->sessions[0].rtp_session==NULL){
call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
MSDtlsSrtpParams params;
unsigned char *certificate, *key;
memset(&params,0,sizeof(MSDtlsSrtpParams));
/* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or defautl celui par default linphone-dtls-default-identity */
/* This will parse the directory to find a matching fingerprint or generate it if not found */
/* returned string must be freed */
sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE);
if (key!= NULL && certificate!=NULL) {
params.pem_certificate = (char *)certificate;
params.pem_pkey = (char *)key;
params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */
audio_stream_enable_dtls(call->audiostream,&params);
ms_free(certificate);
ms_free(key);
} else {
ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled");
/* TODO : check if encryption forced, if yes, stop call */
}
#if TODO_DTLS_VIDEO_ENCRYPTION //VIDEO_ENABLED
if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
/*audio stream is already encrypted and video stream is active*/
memset(&params,0,sizeof(MSDtlsSrtpParams));
video_stream_enable_dtls(call->videostream,call->audiostream,&params);
}
#endif
}
}else{
call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
}
......@@ -2241,9 +2307,32 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut
video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
}
#endif
}else{
} else if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
/* DTLS engine was already initialised during stream init. Before starting it we must be sure that the role(client or server) is set.
* Role may have already been set to server if we initiate the call and already received a packet from peer, in that case do nothing */
SalDtlsRole salRole = call->resultdesc->streams[0].dtls_role; /* TODO: is streams[0] necessary the audiostream in the media description ? */
if (salRole==SalDtlsRoleInvalid) { /* it's invalid in streams[0] but check also at session level */
salRole = call->resultdesc->dtls_role;
}
if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */
/* give the peer certificate fingerprint to dtls context */
SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
ms_dtls_srtp_set_peer_fingerprint(call->audiostream->ms.sessions.dtls_context, remote_desc->streams[0].dtls_fingerprint);
} else {
ms_warning("unable to start DTLS engine, Dtls role in resulting media description is invalid\n");
}
if (salRole == SalDtlsRoleIsClient) { /* local endpoint is client */
ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsClient); /* set the role to client */
ms_dtls_srtp_start(call->audiostream->ms.sessions.dtls_context); /* then start the engine, it will send the DTLS client Hello */
} else if (salRole == SalDtlsRoleIsServer) { /* local endpoint is server */
ms_dtls_srtp_set_role(call->audiostream->ms.sessions.dtls_context, MSDtlsSrtpRoleIsServer); /* this may complete the server setup */
/* no need to start engine, we are waiting for DTLS Client Hello */
}
} else {
call->current_params->media_encryption=linphone_call_all_streams_encrypted(call) ?
LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
}
if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
......@@ -2968,7 +3057,12 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
if (ms->type==AudioStreamType)
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
} else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
} else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) {
if (ms->type==AudioStreamType)
linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted);
else if (ms->type==VideoStreamType)
propagate_encryption_changed(call);
}else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
|| (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
handle_ice_events(call, ev);
} else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
......
......@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <sys/stat.h>
#include <ortp/telephonyevents.h>
#include <mediastreamer2/zrtp.h>
#include <mediastreamer2/dtls_srtp.h>
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/mseventqueue.h"
#include "mediastreamer2/msvolume.h"
......@@ -1487,6 +1488,11 @@ static void misc_config_read(LinphoneCore *lc) {
lp_config_set_string(config,"misc","uuid",tmp);
}else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
sal_set_uuid(lc->sal, uuid);
/* DTLS: if media_encryption is DTLS, get or create the certificate directory */
if (linphone_core_get_media_encryption(lc) == LinphoneMediaEncryptionDTLS) {
/* TODO*/
}
}
static void linphone_core_start(LinphoneCore * lc) {
......@@ -6253,6 +6259,9 @@ static void linphone_core_uninit(LinphoneCore *lc)
if(lc->zrtp_secrets_cache != NULL) {
ms_free(lc->zrtp_secrets_cache);
}
if(lc->user_certificates_path != NULL) {
ms_free(lc->user_certificates_path);
}
if(lc->play_file!=NULL){
ms_free(lc->play_file);
}
......@@ -6685,6 +6694,17 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){
return lc->zrtp_secrets_cache;
}
void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){
if (lc->user_certificates_path != NULL) {
ms_free(lc->user_certificates_path);
}
lc->user_certificates_path = path ? ms_strdup(path) : NULL;
}
const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){
return lc->user_certificates_path;
}
LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri) {
MSList *calls;
LinphoneCall *c;
......@@ -6745,6 +6765,8 @@ const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){
switch(menc){
case LinphoneMediaEncryptionSRTP:
return "LinphoneMediaEncryptionSRTP";
case LinphoneMediaEncryptionDTLS:
return "LinphoneMediaEncryptionDTLS";
case LinphoneMediaEncryptionZRTP:
return "LinphoneMediaEncryptionZRTP";
case LinphoneMediaEncryptionNone:
......@@ -6761,6 +6783,8 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone
switch(menc){
case LinphoneMediaEncryptionSRTP:
return media_stream_srtp_supported();
case LinphoneMediaEncryptionDTLS:
return ms_dtls_available();
case LinphoneMediaEncryptionZRTP:
return ms_zrtp_available();
case LinphoneMediaEncryptionNone:
......@@ -6784,7 +6808,14 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption
type="none";
ret=-1;
}else type="zrtp";
}else if (menc == LinphoneMediaEncryptionDTLS){
if (!ms_dtls_available()){
ms_warning("DTLS not supported by library.");
type="none";
ret=-1;
}else type="dtls";
}
lp_config_set_string(lc->config,"sip","media_encryption",type);
return ret;
}
......@@ -6796,6 +6827,8 @@ LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) {
return LinphoneMediaEncryptionNone;
else if (strcmp(menc, "srtp")==0)
return LinphoneMediaEncryptionSRTP;
else if (strcmp(menc, "dtls")==0)
return LinphoneMediaEncryptionDTLS;
else if (strcmp(menc, "zrtp")==0)
return LinphoneMediaEncryptionZRTP;
else
......
......@@ -287,7 +287,8 @@ typedef enum _LinphoneAVPFMode LinphoneAVPFMode;
enum _LinphoneMediaEncryption {
LinphoneMediaEncryptionNone, /**< No media encryption is used */
LinphoneMediaEncryptionSRTP, /**< Use SRTP media encryption */
LinphoneMediaEncryptionZRTP /**< Use ZRTP media encryption */
LinphoneMediaEncryptionZRTP, /**< Use ZRTP media encryption */
LinphoneMediaEncryptionDTLS /**< Use DTLS media encryption */
};
/**
......@@ -2908,6 +2909,22 @@ LINPHONE_PUBLIC void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const
*/
LINPHONE_PUBLIC const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc);
/**
* Set the path to the directory storing the user's x509 certificates (used by dtls)
* @param[in] lc #LinphoneCore object
* @param[in] path The path to the directory to use to store the user's certificates.
* @ingroup initializing
*/
LINPHONE_PUBLIC void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path);
/**
* Get the path to the directory storing the user's certificates.
* @param[in] lc #LinphoneCore object.
* @returns The path to the directory storing the user's certificates.
* @ingroup initializing
*/
LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCore *lc);
/**
* Search from the list of current calls if a remote address match uri
* @ingroup call_control
......
......@@ -315,6 +315,21 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
result->rtcp_xr.enabled = FALSE;
}
// Handle dtls session attribute: if both local and remote have a dtls fingerprint and a dtls setup, get the remote fingerprint into the result
if ((local_offer->dtls_role!=SalDtlsRoleInvalid) && (remote_answer->dtls_role!=SalDtlsRoleInvalid)
&&(strlen(local_offer->dtls_fingerprint)>0) && (strlen(remote_answer->dtls_fingerprint)>0)) {
strcpy(result->dtls_fingerprint, remote_answer->dtls_fingerprint);
if (remote_answer->dtls_role==SalDtlsRoleIsClient) {
result->dtls_role = SalDtlsRoleIsServer;
} else {
result->dtls_role = SalDtlsRoleIsClient;
}
} else {
result->dtls_fingerprint[0] = '\0';
result->dtls_role = SalDtlsRoleInvalid;
}
return 0;
}
......@@ -334,7 +349,9 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) {
if (local == remote) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvp) && ((local == SalProtoUdpTlsRtpSavp) || (local == SalProtoUdpTlsRtpSavpf))) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE;
if ((remote == SalProtoRtpAvpf) && (local == SalProtoUdpTlsRtpSavpf)) return TRUE;
return FALSE;
}
......@@ -368,6 +385,23 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
if (ls){
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
// Handle dtls stream attribute: if both local and remote have a dtls fingerprint and a dtls setup, add the local fingerprint to the answer
// Note: local description usually stores dtls config at session level which means it apply to all streams, check this too
if (((ls->dtls_role!=SalDtlsRoleInvalid) || (local_capabilities->dtls_role!=SalDtlsRoleInvalid)) && (rs->dtls_role!=SalDtlsRoleInvalid)
&& ((strlen(ls->dtls_fingerprint)>0) || (strlen(local_capabilities->dtls_fingerprint)>0)) && (strlen(rs->dtls_fingerprint)>0)) {
if (strlen(ls->dtls_fingerprint)>0) { /* get the fingerprint in stream description */
strcpy(result->streams[i].dtls_fingerprint, ls->dtls_fingerprint);
} else { /* get the fingerprint in session description */
strcpy(result->streams[i].dtls_fingerprint, local_capabilities->dtls_fingerprint);
}
if (rs->dtls_role==SalDtlsRoleUnset) {
result->streams[i].dtls_role = SalDtlsRoleIsClient;
}
} else {
result->streams[i].dtls_fingerprint[0] = '\0';
result->streams[i].dtls_role = SalDtlsRoleInvalid;