Imported Upstream version 1.6.0~20150519~ae8a42

upstream upstream/1.6.0_20150519_ae8a42
Victor Seva 10 years ago
parent be6b7d527c
commit 6a96ffdbbc

@ -155,8 +155,11 @@ int get_audio_file(const string& message, const string& domain, const string& la
int ConferenceFactory::onLoad()
{
if(cfg.loadFile(AmConfig::ModConfigPath + string(APP_NAME)+ ".conf"))
if(cfg.loadFile(AmConfig::ModConfigPath + string(APP_NAME)+ ".conf")) {
ERROR("Configuration file '%s' missing.\n",
(AmConfig::ModConfigPath + string(APP_NAME)+ ".conf").c_str());
return -1;
}
// get application specific global parameters
configureModule(cfg);

@ -449,6 +449,32 @@ void DSMCall::onBeforeDestroy() {
engine.onBeforeDestroy(this, this);
}
#ifdef WITH_ZRTP
void DSMCall::onZRTPProtocolEvent(zrtp_protocol_event_t event, zrtp_stream_t *stream_ctx) {
DBG("DSMCall::onZRTPProtocolEvent: %s\n", zrtp_protocol_event_desc(event));
if (checkVar(DSM_ENABLE_ZRTP_EVENTS, DSM_TRUE)) {
map<string, string> params;
params["event"] = zrtp_protocol_event_desc(event);
params["event_id"] = int2str(event);
engine.runEvent(this, this, DSMCondition::ZRTPProtocolEvent, &params);
}
}
void DSMCall::onZRTPSecurityEvent(zrtp_security_event_t event, zrtp_stream_t *stream_ctx) {
DBG("DSMCall::onZRTPSecurityEvent: %s\n", zrtp_security_event_desc(event));
if (checkVar(DSM_ENABLE_ZRTP_EVENTS, DSM_TRUE)) {
map<string, string> params;
params["event"] = zrtp_security_event_desc(event);
params["event_id"] = int2str(event);
engine.runEvent(this, this, DSMCondition::ZRTPSecurityEvent, &params);
}
}
#endif
void DSMCall::process(AmEvent* event)
{

@ -98,10 +98,15 @@ public:
bool getSdpOffer(AmSdp& offer);
bool getSdpAnswer(const AmSdp& offer, AmSdp& answer);
virtual void onNoAck(unsigned int cseq);
void onNoAck(unsigned int cseq);
void onSystemEvent(AmSystemEvent* ev);
#ifdef WITH_ZRTP
void onZRTPProtocolEvent(zrtp_protocol_event_t event, zrtp_stream_t *stream_ctx);
void onZRTPSecurityEvent(zrtp_security_event_t event, zrtp_stream_t *stream_ctx);
#endif
void process(AmEvent* event);
UACAuthCred* getCredentials();

@ -58,6 +58,8 @@ using std::map;
#define DSM_ENABLE_REQUEST_EVENTS "enable_request_events"
#define DSM_ENABLE_REPLY_EVENTS "enable_reply_events"
#define DSM_ENABLE_ZRTP_EVENTS "enable_zrtp_events"
#define DSM_B2B_RELAYED_INVITE "b2b_relayed_invite"
#define DSM_B2B_LOCAL_PARTY "b2b_local_party" // From in outgoing call
#define DSM_B2B_LOCAL_URI "b2b_local_uri"

@ -121,6 +121,11 @@ class DSMCondition
RelayOnSipReply,
RelayOnB2BRequest,
RelayOnB2BReply
#ifdef WITH_ZRTP
, ZRTPProtocolEvent,
ZRTPSecurityEvent
#endif
};
bool invert;

@ -10,6 +10,10 @@ ifneq ($(USE_MONITORING), yes)
exclude_dsm_modules += mod_monitoring
endif
ifneq ($(WITH_ZRTP), yes)
exclude_dsm_modules += mod_zrtp
endif
$(info exclude_dsm_modules: $(exclude_dsm_modules))
dsm_modules = $(filter-out $(subst ;, ,$(exclude_dsm_modules))\
$(wildcard Makefile*) lib CMakeLists.txt, \

@ -0,0 +1,10 @@
plug_in_name = mod_zrtp
DSMPATH ?= ../..
module_ldflags =
module_cflags = -DMOD_NAME=\"$(plug_in_name)\" -I$(DSMPATH)
COREPATH ?=$(DSMPATH)/../../core
lib_full_name = $(DSMPATH)/mods/lib/$(lib_name)
include $(DSMPATH)/mods/Makefile.dsm_module

@ -0,0 +1,294 @@
/*
* Copyright (C) 2014 Stefan Sayer
*
* Parts of the development of this module was kindly sponsored by AMTEL Inc.
*
* This file is part of SEMS, a free SIP media server.
*
* SEMS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* SEMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ModZrtp.h"
#include "log.h"
#include "AmUtils.h"
#include "DSMSession.h"
#include "DSMCoreModule.h"
SC_EXPORT(MOD_CLS_NAME);
MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
#ifdef WITH_ZRTP
DEF_CMD("zrtp.setEnabled", ZRTPSetEnabledAction);
DEF_CMD("zrtp.setAllowclear", ZRTPSetAllowclearAction);
DEF_CMD("zrtp.setAutosecure", ZRTPSetAutosecureAction);
DEF_CMD("zrtp.setDisclosebit", ZRTPSetDisclosebitAction);
DEF_CMD("zrtp.getSAS", ZRTPGetSASAction);
DEF_CMD("zrtp.getSessionInfo", ZRTPGetSessionInfoAction);
DEF_CMD("zrtp.setVerified", ZRTPSetVerifiedAction);
DEF_CMD("zrtp.setUnverified", ZRTPSetUnverifiedAction);
DEF_CMD("zrtp.setSignalingHash", ZRTPSetSignalingHash);
DEF_CMD("zrtp.getSignalingHash", ZRTPGetSignalingHash);
#endif
} MOD_ACTIONEXPORT_END;
MOD_CONDITIONEXPORT_BEGIN(MOD_CLS_NAME) {
#ifdef WITH_ZRTP
if (cmd == "zrtp.protocolEvent")
return new TestDSMCondition(params, DSMCondition::ZRTPProtocolEvent);
if (cmd == "zrtp.securityEvent")
return new TestDSMCondition(params, DSMCondition::ZRTPSecurityEvent);
#endif
} MOD_CONDITIONEXPORT_END;
#ifdef WITH_ZRTP
EXEC_ACTION_START(ZRTPSetEnabledAction) {
bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
DBG("setting ZRTP to %sabled\n", b?"en":"dis");
sess->enable_zrtp = b;
} EXEC_ACTION_END;
EXEC_ACTION_START(ZRTPSetAllowclearAction) {
bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
DBG("setting ZRTP allowclear %sabled\n", b?"en":"dis");
sess->zrtp_session_state.zrtp_profile.allowclear = b;
} EXEC_ACTION_END;
EXEC_ACTION_START(ZRTPSetAutosecureAction) {
bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
DBG("setting ZRTP autosecure %sabled\n", b?"en":"dis");
sess->zrtp_session_state.zrtp_profile.autosecure = b;
} EXEC_ACTION_END;
EXEC_ACTION_START(ZRTPSetDisclosebitAction) {
bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
DBG("setting ZRTP disclose_bit %sabled\n", b?"en":"dis");
sess->zrtp_session_state.zrtp_profile.disclose_bit = b;
} EXEC_ACTION_END;
CONST_ACTION_2P(ZRTPGetSASAction, ',', true);
EXEC_ACTION_START(ZRTPGetSASAction) {
string varname = par1;
if (varname.size() && varname[0]=='$') varname = varname.substr(1);
string sas2 = par2;
if (sas2.size() && sas2[0]=='$') sas2 = sas2.substr(1);
if (varname.empty()) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("need variable name for zrtp.getSAS");
EXEC_ACTION_STOP;
}
if (NULL == sess->zrtp_session_state.zrtp_session) {
WARN("ZRTP not active on that session\n");
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("ZRTP not active on that session");
EXEC_ACTION_STOP;
}
zrtp_session_info_t zrtp_session_info;
zrtp_session_get(sess->zrtp_session_state.zrtp_session, &zrtp_session_info);
if (!zrtp_session_info.sas_is_ready) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("ZRTP SAS not ready on that session");
EXEC_ACTION_STOP;
}
sc_sess->var[varname] = string(zrtp_session_info.sas1.buffer, zrtp_session_info.sas1.length);
if (!sas2.empty())
sc_sess->var[sas2] = string(zrtp_session_info.sas2.buffer, zrtp_session_info.sas2.length);
DBG("got SAS1 and SAS2: <%.*s> <%.*s>\n", zrtp_session_info.sas1.length, zrtp_session_info.sas1.buffer,
zrtp_session_info.sas2.length, zrtp_session_info.sas1.buffer);
} EXEC_ACTION_END;
EXEC_ACTION_START(ZRTPGetSessionInfoAction) {
string varname = arg;
if (varname.size() && varname[0]=='$') varname = varname.substr(1);
if (varname.empty()) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("need variable name for zrtp.getSessionInfo");
EXEC_ACTION_STOP;
}
if (NULL == sess->zrtp_session_state.zrtp_session) {
WARN("ZRTP not active on that session\n");
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("ZRTP not active on that session");
EXEC_ACTION_STOP;
}
zrtp_session_info_t zrtp_session_info;
zrtp_session_get(sess->zrtp_session_state.zrtp_session, &zrtp_session_info);
sc_sess->var[varname+".sas_is_ready"] = zrtp_session_info.sas_is_ready ? "true":"false";
if (zrtp_session_info.sas_is_ready) {
sc_sess->var[varname+".sas1"] = string(zrtp_session_info.sas1.buffer, zrtp_session_info.sas1.length);
sc_sess->var[varname+".sas2"] = string(zrtp_session_info.sas2.buffer, zrtp_session_info.sas2.length);
} else {
sc_sess->var[varname+".sas1"] = sc_sess->var[varname+".sas2"] = string();
}
sc_sess->var[varname+".id"] = int2str(zrtp_session_info.id);
string zid_hex;
sc_sess->var[varname+".zid"] = "";
for (size_t i=0;i<zrtp_session_info.zid.length;i++)
sc_sess->var[varname+".zid"]+=char2hex(zrtp_session_info.zid.buffer[i], true);
sc_sess->var[varname+".peer_zid"] = "";
for (size_t i=0;i<zrtp_session_info.peer_zid.length;i++)
sc_sess->var[varname+".peer_zid"]+=char2hex(zrtp_session_info.peer_zid.buffer[i], true);
sc_sess->var[varname+".peer_clientid"] = string(zrtp_session_info.peer_clientid.buffer, zrtp_session_info.peer_clientid.length);
sc_sess->var[varname+".peer_version"] = string(zrtp_session_info.peer_version.buffer, zrtp_session_info.peer_version.length);
sc_sess->var[varname+".sas_is_verified"] = zrtp_session_info.sas_is_verified ? "true":"false";
// todo: cached_flags, matches_flags, wrongs_flags
} EXEC_ACTION_END;
bool hex2zid(const string& zid1, char* buffer) {
for (size_t i=0;i<zid1.length()/2;i++) {
unsigned int h;
if (reverse_hex2int(zid1.substr(i*2, 2), h)) {
ERROR("in zid: '%s' is no hex number\n", zid1.substr(i*2, 2).c_str());
return false;
}
buffer[i]=h % 0xff;
}
return true;
}
CONST_ACTION_2P(ZRTPSetVerifiedAction, ',', false);
EXEC_ACTION_START(ZRTPSetVerifiedAction) {
string zid1 = resolveVars(par1, sess, sc_sess, event_params);
string zid2 = resolveVars(par2, sess, sc_sess, event_params);
if (zid1.empty() || zid2.empty()) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("zid1 and zid2 must be there for setVerified");
EXEC_ACTION_STOP;
}
DBG("setting as verified zids <%s> and <%s>\n", zid1.c_str(), zid2.c_str());
zrtp_string16_t _zid1, _zid2;
if (!hex2zid(zid1, _zid1.buffer)) {
EXEC_ACTION_STOP;
}
if (!hex2zid(zid2, _zid2.buffer)) {
EXEC_ACTION_STOP;
}
if (zrtp_status_ok != zrtp_verified_set(AmZRTP::zrtp_global, &_zid1, &_zid2, 1)) {
DBG("zrtp_verified_set failed\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("zrtp_verified_set failed");
}
} EXEC_ACTION_END;
CONST_ACTION_2P(ZRTPSetUnverifiedAction, ',', false);
EXEC_ACTION_START(ZRTPSetUnverifiedAction) {
string zid1 = resolveVars(par1, sess, sc_sess, event_params);
string zid2 = resolveVars(par2, sess, sc_sess, event_params);
if (zid1.empty() || zid2.empty()) {
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("zid1 and zid2 must be there for setUnverified");
EXEC_ACTION_STOP;
}
DBG("setting as unverified zids <%s> and <%s>\n", zid1.c_str(), zid2.c_str());
zrtp_string16_t _zid1, _zid2;
if (!hex2zid(zid1, _zid1.buffer)) {
EXEC_ACTION_STOP;
}
if (!hex2zid(zid2, _zid2.buffer)) {
EXEC_ACTION_STOP;
}
if (zrtp_status_ok != zrtp_verified_set(AmZRTP::zrtp_global, &_zid1, &_zid2, 0)) {
DBG("zrtp_verified_set failed\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("zrtp_verified_set failed");
}
} EXEC_ACTION_END;
EXEC_ACTION_START(ZRTPSetSignalingHash) {
string h = resolveVars(arg, sess, sc_sess, event_params);
DBG("setting signaling hash to '%s'\n", h.c_str());
if (NULL == sess->zrtp_session_state.zrtp_audio) {
WARN("ZRTP not active on that stream\n");
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("ZRTP not active on that stream");
EXEC_ACTION_STOP;
}
if (zrtp_status_ok != zrtp_signaling_hash_set(sess->zrtp_session_state.zrtp_audio,
h.c_str(), h.length())) {
DBG("zrtp_signaling_hash_set failed\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("zrtp_signaling_hash_set failed");
}
} EXEC_ACTION_END;
EXEC_ACTION_START(ZRTPGetSignalingHash) {
string varname = arg;
if (varname.size() && varname[0]=='$') varname = varname.substr(1);
if (NULL == sess->zrtp_session_state.zrtp_audio) {
WARN("ZRTP not active on that stream\n");
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
sc_sess->SET_STRERROR("ZRTP not active on that stream");
EXEC_ACTION_STOP;
}
char b[ZRTP_SIGN_ZRTP_HASH_LENGTH];
memset(b, 0, sizeof(b));
if (zrtp_status_ok != zrtp_signaling_hash_get(sess->zrtp_session_state.zrtp_audio,
b, ZRTP_SIGN_ZRTP_HASH_LENGTH)) {
DBG("zrtp_signaling_hash_get failed\n");
sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
sc_sess->SET_STRERROR("zrtp_signaling_hash_get failed");
}
sc_sess->var[varname] = string(b);
DBG("got signaling hash '%s'\n", b);
} EXEC_ACTION_END;
#endif

@ -0,0 +1,51 @@
/*
* Copyright (C) 2014 Stefan Sayer
*
* Parts of the development of this module was kindly sponsored by AMTEL Inc.
*
* This file is part of SEMS, a free SIP media server.
*
* SEMS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. This program is released under
* the GPL with the additional exemption that compiling, linking,
* and/or using OpenSSL is allowed.
*
* For a license to use the SEMS software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* SEMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _MOD_ZRTP_H
#define _MOD_ZRTP_H
#include "DSMModule.h"
#define MOD_CLS_NAME ZRTPModule
DECLARE_MODULE_BEGIN(MOD_CLS_NAME);
DECLARE_MODULE_END;
#ifdef WITH_ZRTP
DEF_ACTION_1P(ZRTPSetEnabledAction);
DEF_ACTION_1P(ZRTPSetAllowclearAction);
DEF_ACTION_1P(ZRTPSetAutosecureAction);
DEF_ACTION_1P(ZRTPSetDisclosebitAction);
DEF_ACTION_2P(ZRTPGetSASAction);
DEF_ACTION_1P(ZRTPGetSessionInfoAction);
DEF_ACTION_2P(ZRTPSetVerifiedAction);
DEF_ACTION_2P(ZRTPSetUnverifiedAction);
DEF_ACTION_1P(ZRTPSetSignalingHash);
DEF_ACTION_1P(ZRTPGetSignalingHash);
#endif // WITH_ZRTP
#endif

@ -128,6 +128,9 @@ SBCCallLeg::SBCCallLeg(const SBCCallProfile& call_profile, AmSipDialog* p_dlg,
cc_started(false),
logger(NULL)
{
#ifdef WITH_ZRTP
enable_zrtp = false;
#endif
set_sip_relay_only(false);
dlg->setRel100State(Am100rel::REL100_IGNORED);
@ -155,6 +158,10 @@ SBCCallLeg::SBCCallLeg(SBCCallLeg* caller, AmSipDialog* p_dlg,
cc_started(false),
logger(NULL)
{
#ifdef WITH_ZRTP
enable_zrtp = false;
#endif
// FIXME: do we want to inherit cc_vars from caller?
// Can be pretty dangerous when caller stored pointer to object - we should
// not probably operate on it! But on other hand it could be handy for
@ -202,6 +209,10 @@ SBCCallLeg::SBCCallLeg(AmSipDialog* p_dlg, AmSipSubscription* p_subs)
cc_started(false),
logger(NULL)
{
#ifdef WITH_ZRTP
enable_zrtp = false;
#endif
memset(&call_start_ts, 0, sizeof(struct timeval));
memset(&call_connect_ts, 0, sizeof(struct timeval));
memset(&call_end_ts, 0, sizeof(struct timeval));

@ -106,7 +106,7 @@ static string payload2str(const SdpPayload &p);
iface = name_it->second; \
else { \
ERROR("selected " #what " '%s' does not exist as a media interface. " \
"Please check the 'additional_interfaces' " \
"Please check the 'interfaces' " \
"parameter in the main configuration file.", \
what.c_str()); \
return false; \
@ -128,7 +128,7 @@ static string payload2str(const SdpPayload &p);
else { \
ERROR("selected " #what " '%s' does not exist as a signaling" \
" interface. " \
"Please check the 'additional_interfaces' " \
"Please check the 'interfaces' " \
"parameter in the main configuration file.", \
what.c_str()); \
return false; \
@ -859,7 +859,7 @@ bool SBCCallProfile::evaluateOutboundInterface() {
} else {
ERROR("selected outbound_interface '%s' does not exist as a signaling"
" interface. "
"Please check the 'additional_interfaces' "
"Please check the 'interfaces' "
"parameter in the main configuration file.",
outbound_interface.c_str());
return false;
@ -890,7 +890,7 @@ static int apply_outbound_interface(const string& oi, AmBasicSipDialog& dlg)
} else {
ERROR("selected [aleg_]outbound_interface '%s' "
"does not exist as an interface. "
"Please check the 'additional_interfaces' "
"Please check the 'interfaces' "
"parameter in the main configuration file.",
oi.c_str());
@ -1290,6 +1290,7 @@ string SBCCallProfile::retarget(const string& alias, AmBasicSipDialog& dlg) cons
// REG-Cache lookup
AliasEntry alias_entry;
if(!RegisterCache::instance()->findAliasEntry(alias, alias_entry)) {
DBG("No alias entry found for alias '%s', replying with 404\n", alias.c_str());
throw AmSession::Exception(404,"User not found");
}
string new_r_uri = alias_entry.contact_uri;

@ -495,7 +495,10 @@ void AudioStreamData::setReceiving(bool r) {
AmB2BMedia::RelayStreamPair::RelayStreamPair(AmB2BSession *_a, AmB2BSession *_b)
: a(_a, _a ? _a->getRtpInterface() : -1),
b(_b, _b ? _b->getRtpInterface() : -1)
{ }
{
a.enableRawRelay();
b.enableRawRelay();
}
AmB2BMedia::AmB2BMedia(AmB2BSession *_a, AmB2BSession *_b):
ref_cnt(0), // everybody who wants to use must add one reference itselves

@ -104,6 +104,11 @@ bool AmConfig::LogSessions = false;
bool AmConfig::LogEvents = false;
int AmConfig::UnhandledReplyLoglevel = 0;
#ifdef WITH_ZRTP
bool AmConfig::enable_zrtp = true;
bool AmConfig::enable_zrtp_debuglog = true;
#endif
unsigned int AmConfig::SessionLimit = 0;
unsigned int AmConfig::SessionLimitErrCode = 503;
string AmConfig::SessionLimitErrReason = "Server overload";
@ -588,6 +593,14 @@ int AmConfig::readConfiguration()
}
}
#ifdef WITH_ZRTP
enable_zrtp = cfg.getParameter("enable_zrtp", "yes") == "yes";
INFO("ZRTP %sabled\n", enable_zrtp ? "en":"dis");
enable_zrtp_debuglog = cfg.getParameter("enable_zrtp_debuglog", "yes") == "yes";
INFO("ZRTP debug log %sabled\n", enable_zrtp_debuglog ? "en":"dis");
#endif
if(cfg.hasParameter("session_limit")){
vector<string> limit = explode(cfg.getParameter("session_limit"), ";");
if (limit.size() != 3) {
@ -761,8 +774,9 @@ static int readSIPInterface(AmConfigReader& cfg, const string& i_name)
it_opt != opt_strs.end(); ++it_opt) {
if(*it_opt == "force_via_address") {
opts |= trsp_socket::force_via_address;
}
else {
} else if(*it_opt == "no_transport_in_contact") {
opts |= trsp_socket::no_transport_in_contact;
} else {
WARN("unknown signaling socket option '%s' set on interface '%s'\n",
it_opt->c_str(),i_name.c_str());
}

@ -220,6 +220,11 @@ struct AmConfig
/* this is regex->application mapping is used if App_MAPPING */
static RegexMappingVector AppMapping;
#ifdef WITH_ZRTP
static bool enable_zrtp;
static bool enable_zrtp_debuglog;
#endif
static unsigned int SessionLimit;
static unsigned int SessionLimitErrCode;
static string SessionLimitErrReason;

@ -422,7 +422,8 @@ void AmPlugIn::getPayloads(vector<SdpPayload>& pl_vec) const
for (std::map<int,int>::const_iterator it = payload_order.begin(); it != payload_order.end(); ++it) {
std::map<int,amci_payload_t*>::const_iterator pl_it = payloads.find(it->second);
if(pl_it != payloads.end()){
pl_vec.push_back(SdpPayload(pl_it->first, pl_it->second->name, pl_it->second->advertised_sample_rate, 0));
// if channels==2 use that value; otherwise don't add channels param
pl_vec.push_back(SdpPayload(pl_it->first, pl_it->second->name, pl_it->second->advertised_sample_rate, pl_it->second->channels==2?2:0));
} else {
ERROR("Payload %d (from the payload_order map) was not found in payloads map!\n", it->second);
}

@ -57,7 +57,7 @@
#include <netinet/in.h>
#ifdef WITH_ZRTP
#include "zrtp/zrtp.h"
#include "libzrtp/zrtp.h"
#endif
#include "rtp/rtp.h"
@ -260,10 +260,15 @@ int AmRtpStream::compile_and_send(const int payload, bool marker, unsigned int t
rp.setAddr(&r_saddr);
#ifdef WITH_ZRTP
if (session && session->zrtp_audio) {
zrtp_status_t status = zrtp_status_fail;
if (session && session->enable_zrtp){
if (NULL == session->zrtp_session_state.zrtp_audio) {
ERROR("ZRTP enabled on session, but no audio stream created\n");
return -1;
}
unsigned int size = rp.getBufferSize();
status = zrtp_process_rtp(session->zrtp_audio, (char*)rp.getBuffer(), &size);
zrtp_status_t status = zrtp_process_rtp(session->zrtp_session_state.zrtp_audio,
(char*)rp.getBuffer(), &size);
switch (status) {
case zrtp_status_drop: {
DBG("ZRTP says: drop packet! %u - %u\n", size, rp.getBufferSize());
@ -748,13 +753,6 @@ int AmRtpStream::init(const AmSdp& local,
DBG("default payload selected = %i\n",payload);
last_payload = payload;
#ifdef WITH_ZRTP
if( session->zrtp_audio ) {
DBG("now starting zrtp stream...\n");
zrtp_start_stream( session->zrtp_audio );
}
#endif
active = false; // mark as nothing received yet
return 0;
}
@ -768,6 +766,13 @@ void AmRtpStream::pause()
{
DBG("RTP Stream instance [%p] pausing (receiving=false)\n", this);
receiving = false;
#ifdef WITH_ZRTP
if (session && session->enable_zrtp) {
session->zrtp_session_state.stopStreams();
}
#endif
}
void AmRtpStream::resume()
@ -777,8 +782,16 @@ void AmRtpStream::resume()
receive_mut.lock();
mem.clear();
receive_buf.clear();
while (!rtp_ev_qu.empty())
rtp_ev_qu.pop();
receive_mut.unlock();
receiving = true;
#ifdef WITH_ZRTP
if (session && session->enable_zrtp) {
session->zrtp_session_state.startStreams(get_ssrc());
}
#endif
}
void AmRtpStream::setOnHold(bool on_hold) {
@ -818,7 +831,7 @@ void AmRtpStream::bufferPacket(AmRtpPacket* p)
return;
}
if (relay_enabled) {
if (relay_enabled) { // todo: ZRTP
if (force_receive_dtmf) {
recvDtmfPacket(p);
}
@ -858,35 +871,37 @@ void AmRtpStream::bufferPacket(AmRtpPacket* p)
#endif
receive_mut.lock();
// NOTE: useless, as DTMF events are pushed into 'rtp_ev_qu'
// free packet on double packet for TS received
// if(p->payload == getLocalTelephoneEventPT()) {
// if (receive_buf.find(p->timestamp) != receive_buf.end()) {
// mem.freePacket(receive_buf[p->timestamp]);
// }
// }
#ifdef WITH_ZRTP
if (session->zrtp_audio) {
if (session && session->enable_zrtp) {
zrtp_status_t status = zrtp_status_fail;
unsigned int size = p->getBufferSize();
status = zrtp_process_srtp(session->zrtp_audio, (char*)p->getBuffer(), &size);
if (NULL == session->zrtp_session_state.zrtp_audio) {
WARN("dropping received packet, as there's no ZRTP stream initialized\n");
receive_mut.unlock();
mem.freePacket(p);
return;
}
unsigned int size = p->getBufferSize();
zrtp_status_t status = zrtp_process_srtp(session->zrtp_session_state.zrtp_audio, (char*)p->getBuffer(), &size);
switch (status)
{
case zrtp_status_forward:
case zrtp_status_ok: {
p->setBufferSize(size);
if (p->parse() < 0) {
ERROR("parsing decoded packet!\n");
mem.freePacket(p);
} else {
if(p->payload == getLocalTelephoneEventPT()) {
rtp_ev_qu.push(p);
} else {
receive_buf[p->timestamp] = p;
if(!receive_buf.insert(ReceiveBuffer::value_type(p->timestamp,p)).second) {
// insert failed
mem.freePacket(p);
}
}
}
} break;
@ -1033,9 +1048,14 @@ void AmRtpStream::recvPacket(int fd)
gettimeofday(&p->recv_time,NULL);
if(!relay_raw)
if(!relay_raw
#ifdef WITH_ZRTP
&& !(session && session->enable_zrtp)
#endif
) {
parse_res = p->parse();
}
if (parse_res == -1) {
DBG("error while parsing RTP packet.\n");
clearRTPTimeout(&p->recv_time);

@ -103,6 +103,8 @@ inline string transport_p_2_str(int tp)
case TP_UDP: return "udp";
case TP_RTPSAVP: return "RTP/SAVP";
case TP_RTPSAVPF: return "RTP/SAVPF";
case TP_UDPTLSRTPSAVP: return "UDP/TLS/RTP/SAVP";
case TP_UDPTLSRTPSAVPF: return "UDP/TLS/RTP/SAVPF";
case TP_UDPTL: return "udptl";
default: return "<unknown media type>";
}
@ -358,7 +360,7 @@ void AmSdp::print(string& body) const
string options;
if (media_it->transport == TP_RTPAVP || media_it->transport == TP_RTPSAVP || media_it->transport == TP_RTPSAVPF) {
if (media_it->transport == TP_RTPAVP || media_it->transport == TP_RTPSAVP || media_it->transport == TP_RTPSAVPF || media_it->transport == TP_UDPTLSRTPSAVP || media_it->transport == TP_UDPTLSRTPSAVPF) {
for(std::vector<SdpPayload>::const_iterator pl_it = media_it->payloads.begin();
pl_it != media_it->payloads.end(); pl_it++) {
@ -889,7 +891,7 @@ static void parse_sdp_media(AmSdp* sdp_msg, char* s)
}
case FMT:
{
if (m.transport == TP_RTPAVP || m.transport == TP_RTPSAVP || m.transport == TP_RTPSAVPF) {
if (m.transport == TP_RTPAVP || m.transport == TP_RTPSAVP || m.transport == TP_RTPSAVPF || m.transport == TP_UDPTLSRTPSAVP || m.transport == TP_UDPTLSRTPSAVPF) {
if (contains(media_line, line_end, ' ')) {
next = parse_until(media_line, ' ');
string value;
@ -1471,6 +1473,10 @@ static TransProt transport_type(string transport)
return TP_RTPSAVP;
else if(transport_uc == "RTP/SAVPF")
return TP_RTPSAVPF;
else if(transport_uc == "UDP/TLS/RTP/SAVP")
return TP_UDPTLSRTPSAVP;
else if(transport_uc == "UDP/TLS/RTP/SAVPF")
return TP_UDPTLSRTPSAVPF;
else if(transport_uc == "UDPTL")
return TP_UDPTL;
else

@ -55,7 +55,7 @@ enum AddressType { AT_NONE=0, AT_V4, AT_V6 };
/** media type */
enum MediaType { MT_NONE=0, MT_AUDIO, MT_VIDEO, MT_APPLICATION, MT_TEXT, MT_MESSAGE, MT_IMAGE };
/** transport protocol */
enum TransProt { TP_NONE=0, TP_RTPAVP, TP_UDP, TP_RTPSAVP, TP_UDPTL, TP_RTPSAVPF };
enum TransProt { TP_NONE=0, TP_RTPAVP, TP_UDP, TP_RTPSAVP, TP_UDPTL, TP_RTPSAVPF, TP_UDPTLSRTPSAVP, TP_UDPTLSRTPSAVPF };
/** \brief c=... line in SDP*/
struct SdpConnection

@ -76,7 +76,7 @@ AmSession::AmSession(AmSipDialog* p_dlg)
refresh_method(REFRESH_UPDATE_FB_REINV),
processing_status(SESSION_PROCESSING_EVENTS)
#ifdef WITH_ZRTP
, zrtp_session(NULL), zrtp_audio(NULL), enable_zrtp(true)
, enable_zrtp(AmConfig::enable_zrtp)
#endif
#ifdef SESSION_THREADPOOL
@ -97,10 +97,6 @@ AmSession::~AmSession()
delete *evh;
}
#ifdef WITH_ZRTP
AmZRTP::freeSession(zrtp_session);
#endif
delete dlg;
DBG("AmSession destructor finished\n");
@ -278,39 +274,6 @@ void AmSession::run() {
#endif
bool AmSession::startup() {
#ifdef WITH_ZRTP
if (enable_zrtp) {
zrtp_session = (zrtp_conn_ctx_t*)malloc(sizeof(zrtp_conn_ctx_t));
if (NULL == zrtp_session) {
ERROR("allocating ZRTP session context mem.\n");
} else {
zrtp_profile_t profile;
zrtp_profile_autoload(&profile, &AmZRTP::zrtp_global);
profile.active = false;
profile.allowclear = true;
profile.autosecure = true; // automatically go into secure mode at the beginning
if (zrtp_status_ok != zrtp_init_session_ctx( zrtp_session,
&AmZRTP::zrtp_global,
&profile,
AmZRTP::zrtp_instance_zid) ) {
ERROR("initializing ZRTP session context\n");
return false;
}
zrtp_audio = zrtp_attach_stream(zrtp_session, RTPStream()->get_ssrc());
zrtp_audio->stream_usr_data = this;
if (NULL == zrtp_audio) {
ERROR("attaching zrtp stream.\n");
return false;
}
DBG("initialized ZRTP session context OK\n");
}
}
#endif
session_started();
try {
@ -318,6 +281,16 @@ bool AmSession::startup() {
onStart();
#ifdef WITH_ZRTP
if (enable_zrtp) {
if (zrtp_session_state.initSession(this)) {
ERROR("initializing ZRTP session\n");
throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
}
DBG("initialized ZRTP session context OK\n");
}
#endif
}
catch(const AmSession::Exception& e){ throw e; }
catch(const string& str){
@ -456,6 +429,12 @@ void AmSession::finalize()
DBG("running finalize sequence...\n");
dlg->finalize();
#ifdef WITH_ZRTP
if (enable_zrtp) {
zrtp_session_state.freeSession();
}
#endif
onBeforeDestroy();
destroy();
@ -694,9 +673,15 @@ void AmSession::process(AmEvent* ev)
}
#ifdef WITH_ZRTP
AmZRTPEvent* zrtp_ev = dynamic_cast<AmZRTPEvent*>(ev);
if(zrtp_ev){
onZRTPEvent((zrtp_event_t)zrtp_ev->event_id, zrtp_ev->stream_ctx);
AmZRTPProtocolEvent* zrtp_p_ev = dynamic_cast<AmZRTPProtocolEvent*>(ev);
if(zrtp_p_ev){
onZRTPProtocolEvent((zrtp_protocol_event_t)zrtp_p_ev->event_id, zrtp_p_ev->stream_ctx);
return;
}
AmZRTPSecurityEvent* zrtp_s_ev = dynamic_cast<AmZRTPSecurityEvent*>(ev);
if(zrtp_s_ev){
onZRTPSecurityEvent((zrtp_security_event_t)zrtp_s_ev->event_id, zrtp_s_ev->stream_ctx);
return;
}
#endif
@ -1261,89 +1246,35 @@ bool AmSession::removeTimers() {
#ifdef WITH_ZRTP
void AmSession::onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx) {
DBG("AmSession::onZRTPEvent \n");
switch (event)
{
case ZRTP_EVENT_IS_SECURE: {
void AmSession::onZRTPProtocolEvent(zrtp_protocol_event_t event, zrtp_stream_t *stream_ctx) {
DBG("AmSession::onZRTPProtocolEvent: %s\n", zrtp_protocol_event_desc(event));
if (event==ZRTP_EVENT_IS_SECURE) {
INFO("ZRTP_EVENT_IS_SECURE \n");
// info->is_verified = ctx->_session_ctx->secrets.verifieds & ZRTP_BIT_RS0;
zrtp_conn_ctx_t *session = stream_ctx->_session_ctx;
if (ZRTP_SAS_BASE32 == session->sas_values.rendering) {
DBG("Got SAS value <<<%.4s>>>\n", session->sas_values.str1.buffer);
} else {
DBG("Got SAS values SAS1 '%s' and SAS2 '%s'\n",
session->sas_values.str1.buffer,
session->sas_values.str2.buffer);
}
} break;
case ZRTP_EVENT_IS_PENDINGCLEAR:
INFO("ZRTP_EVENT_IS_PENDINGCLEAR\n");
INFO("other side requested goClear. Going clear.\n\n");
zrtp_clear_stream(zrtp_audio);
break;
case ZRTP_EVENT_IS_CLEAR:
INFO("ZRTP_EVENT_IS_CLEAR\n");
break;
case ZRTP_EVENT_UNSUPPORTED:
INFO("ZRTP_EVENT_UNSUPPORTED\n");
break;
case ZRTP_EVENT_IS_INITIATINGSECURE:
INFO("ZRTP_EVENT_IS_INITIATINGSECURE\n");
break;
case ZRTP_EVENT_IS_PENDINGSECURE:
INFO("ZRTP_EVENT_PENDINGSECURE\n");
break;
case ZRTP_EVENT_IS_SECURE_DONE:
INFO("ZRTP_EVENT_IS_SECURE_DONE\n");
break;
case ZRTP_EVENT_ERROR:
INFO("ZRTP_EVENT_ERROR\n");
break;
case ZRTP_EVENT_NO_ZRTP:
INFO("ZRTP_EVENT_NO_ZRTP\n");
break;
case ZRTP_EVENT_NO_ZRTP_QUICK:
INFO("ZRTP_EVENT_NO_ZRTP_QUICK\n");
break;
// zrtp_session_t *session = stream_ctx->_session_ctx;
// pbx functions
case ZRTP_EVENT_IS_CLIENT_ENROLLMENT:
INFO("ZRTP_EVENT_IS_CLIENT_ENROLLMENT\n");
break;
case ZRTP_EVENT_NEW_USER_ENROLLED:
INFO("ZRTP_EVENT_NEW_USER_ENROLLED\n");
break;
case ZRTP_EVENT_USER_ALREADY_ENROLLED:
INFO("ZRTP_EVENT_USER_ALREADY_ENROLLED\n");
break;
case ZRTP_EVENT_USER_UNENROLLED:
INFO("ZRTP_EVENT_USER_UNENROLLED\n");
break;
case ZRTP_EVENT_LOCAL_SAS_UPDATED:
INFO("ZRTP_EVENT_LOCAL_SAS_UPDATED\n");
break;
case ZRTP_EVENT_REMOTE_SAS_UPDATED:
INFO("ZRTP_EVENT_REMOTE_SAS_UPDATED\n");
break;
// if (ZRTP_SAS_BASE32 == session->sas_values.rendering) {
// DBG("Got SAS value <<<%.4s>>>\n", session->sas_values.str1.buffer);
// } else {
// DBG("Got SAS values SAS1 '%s' and SAS2 '%s'\n",
// session->sas_values.str1.buffer,
// session->sas_values.str2.buffer);
// }
}
// errors
case ZRTP_EVENT_WRONG_SIGNALING_HASH:
INFO("ZRTP_EVENT_WRONG_SIGNALING_HASH\n");
break;
case ZRTP_EVENT_WRONG_MESSAGE_HMAC:
INFO("ZRTP_EVENT_WRONG_MESSAGE_HMAC\n");
break;
default:
INFO("unknown ZRTP_EVENT\n");
break;
} // end events case
// case ZRTP_EVENT_IS_PENDINGCLEAR:
// INFO("ZRTP_EVENT_IS_PENDINGCLEAR\n");
// INFO("other side requested goClear. Going clear.\n\n");
// // zrtp_clear_stream(zrtp_audio);
// break;
}
void AmSession::onZRTPSecurityEvent(zrtp_security_event_t event, zrtp_stream_t *stream_ctx) {
DBG("AmSession::onZRTPSecurityEvent: %s\n", zrtp_security_event_desc(event));
}
#endif

@ -41,9 +41,7 @@
#include "AmSessionEventHandler.h"
#include "AmMediaProcessor.h"
#ifdef WITH_ZRTP
#include "zrtp/zrtp.h"
#endif
#include "AmZRTP.h"
#include <string>
#include <vector>
@ -187,11 +185,11 @@ public:
bool hasRtpStream() { return _rtp_str.get() != NULL; }
#ifdef WITH_ZRTP
zrtp_conn_ctx_t* zrtp_session; // ZRTP session
zrtp_stream_ctx_t* zrtp_audio; // ZRTP stream for audio
AmZRTPSessionState zrtp_session_state;
/** must be set before session is started! i.e. in constructor */
bool enable_zrtp;
#endif
AmSipDialog* dlg;
@ -541,7 +539,8 @@ public:
/**
* ZRTP events @see ZRTP
*/
virtual void onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx);
virtual void onZRTPProtocolEvent(zrtp_protocol_event_t event, zrtp_stream_t *stream_ctx);
virtual void onZRTPSecurityEvent(zrtp_security_event_t event, zrtp_stream_t *stream_ctx);
#endif
/** This callback is called if RTP timeout encountered */

@ -38,126 +38,306 @@
#define ZRTP_CACHE_SAVE_INTERVAL 1
string AmZRTP::cache_path = "zrtp_cache.dat";
#define SEMS_CLIENT_ID "SEMS"
int AmZRTP::zrtp_cache_save_cntr = 0;
AmMutex AmZRTP::zrtp_cache_mut;
zrtp_global_ctx_t AmZRTP::zrtp_global; // persistent storage for libzrtp data
zrtp_zid_t AmZRTP::zrtp_instance_zid = {"defaultsems"}; // todo: generate one
zrtp_global_t* AmZRTP::zrtp_global; // persistent storage for libzrtp data
zrtp_config_t AmZRTP::zrtp_config;
zrtp_zid_t AmZRTP::zrtp_instance_zid = {"defaultsems"};
void zrtp_log(int level, char *data, int len, int offset) {
int sems_lvl = L_DBG;
if (level==2)
sems_lvl = L_WARN; // ??
else if (level==1)
sems_lvl = L_INFO; // ??
if (sems_lvl==L_DBG && !AmConfig::enable_zrtp_debuglog)
return;
_LOG(sems_lvl, "%.*s", len, data);
}
int AmZRTP::init() {
zrtp_log_set_log_engine(zrtp_log);
AmConfigReader cfg;
string cfgname=add2path(AmConfig::ModConfigPath, 1, "zrtp.conf");
if(cfg.loadFile(cfgname)) {
ERROR("No %s config file present.\n",
cfgname.c_str());
ERROR("No %s config file present.\n", cfgname.c_str());
return -1;
}
cache_path = cfg.getParameter("cache_path");
string zid = cfg.getParameter("zid");
if (zid.length() != sizeof(zrtp_zid_t)) {
ERROR("ZID of this instance MUST be set for ZRTP.\n");
ERROR("ZID needs to be %u characters long.\n",
sizeof(zrtp_zid_t));
return -1;
if (cfg.hasParameter("zid_hex")) {
string zid_hex = cfg.getParameter("zid_hex");
if (zid_hex.size() != 2*sizeof(zrtp_instance_zid)) {
ERROR("zid_hex config parameter in zrtp.conf must be %lu characters long.\n",
sizeof(zrtp_zid_t)*2);
return -1;
}
for (size_t i=0;i<sizeof(zrtp_instance_zid);i++) {
unsigned int h;
if (reverse_hex2int(zid_hex.substr(i*2, 2), h)) {
ERROR("in zid_hex in zrtp.conf: '%s' is no hex number\n", zid_hex.substr(i*2, 2).c_str());
return -1;
}
zrtp_instance_zid[i]=h % 0xff;
}
} else if (cfg.hasParameter("zid")) {
string zid = cfg.getParameter("zid");
WARN("zid parameter in zrtp.conf is only supported for backwards compatibility. Please use zid_hex\n");
if (zid.length() != sizeof(zrtp_zid_t)) {
ERROR("zid config parameter in zrtp.conf must be %lu characters long.\n",
sizeof(zrtp_zid_t));
return -1;
}
for (size_t i=0;i<zid.length();i++)
zrtp_instance_zid[i]=zid[i];
} else {
// generate one
string zid_hex;
for (size_t i=0;i<sizeof(zrtp_instance_zid);i++) {
zrtp_instance_zid[i]=get_random() % 0xff;
zid_hex+=char2hex(zrtp_instance_zid[i], true);
}
WARN("Generated random ZID. To support key continuity through key cache "
"on the peers, add this to zrtp.conf: 'zid_hex=\"%s\"'", zid_hex.c_str());
}
for (int i=0;i<12;i++)
zrtp_instance_zid[i]=zid[i];
DBG("initializing ZRTP library with ZID '%s', cache path '%s'.\n",
zid.c_str(), cache_path.c_str());
if ( zrtp_status_ok != zrtp_init(&zrtp_global, "zrtp_sems") ) {
ERROR("Some error during zrtp initialization\n");
DBG("initializing ZRTP library with cache path '%s'.\n", cache_path.c_str());
zrtp_config_defaults(&zrtp_config);
strcpy(zrtp_config.client_id, SEMS_CLIENT_ID);
memcpy((char*)zrtp_config.zid, (char*)zrtp_instance_zid, sizeof(zrtp_zid_t));
zrtp_config.lic_mode = ZRTP_LICENSE_MODE_UNLIMITED;
strncpy(zrtp_config.cache_file_cfg.cache_path, cache_path.c_str(), 256);
zrtp_config.cb.misc_cb.on_send_packet = AmZRTP::on_send_packet;
zrtp_config.cb.event_cb.on_zrtp_secure = AmZRTP::on_zrtp_secure;
zrtp_config.cb.event_cb.on_zrtp_security_event = AmZRTP::on_zrtp_security_event;
zrtp_config.cb.event_cb.on_zrtp_protocol_event = AmZRTP::on_zrtp_protocol_event;
if ( zrtp_status_ok != zrtp_init(&zrtp_config, &zrtp_global) ) {
ERROR("Error during ZRTP initialization\n");
return -1;
}
zrtp_add_entropy(&zrtp_global, NULL, 0);
size_t rand_bytes = cfg.getParameterInt("random_entropy_bytes", 172);
if (rand_bytes) {
INFO("adding %zd bytes entropy from /dev/random to ZRTP entropy pool\n", rand_bytes);
FILE* fd = fopen("/dev/random", "r");
if (!fd) {
ERROR("opening /dev/random for adding entropy to the pool\n");
return -1;
}
void* p = malloc(rand_bytes);
if (p==NULL)
return -1;
size_t read_bytes = fread(p, 1, rand_bytes, fd);
if (read_bytes != rand_bytes) {
ERROR("reading %zd bytes from /dev/random\n", rand_bytes);
return -1;
}
zrtp_entropy_add(zrtp_global, (const unsigned char*)p, read_bytes);
free(p);
}
// zrtp_add_entropy(zrtp_global, NULL, 0); // fixme
DBG("ZRTP initialized ok.\n");
return 0;
}
void AmZRTP::freeSession(zrtp_conn_ctx_t* zrtp_session) {
zrtp_done_session_ctx(zrtp_session);
free(zrtp_session);
// save zrtp cache
zrtp_cache_mut.lock();
if (!((++zrtp_cache_save_cntr) % ZRTP_CACHE_SAVE_INTERVAL)) {
if (zrtp_cache_user_down() != zrtp_status_ok) {
ERROR("while writing ZRTP cache.\n");
}
}
zrtp_cache_mut.unlock();
AmZRTPSessionState::AmZRTPSessionState()
: zrtp_session(NULL), zrtp_audio(NULL)
{
// copy default profile
zrtp_profile_defaults(&zrtp_profile, AmZRTP::zrtp_global);
}
void zrtp_get_cache_path(char *path, uint32_t length) {
snprintf(path, length, "%s", AmZRTP::cache_path.c_str());
int AmZRTPSessionState::initSession(AmSession* session) {
DBG("Initializing ZRTP stream...\n");
// Allocate zrtp session
zrtp_status_t status =
zrtp_session_init( AmZRTP::zrtp_global,
&zrtp_profile,
ZRTP_SIGNALING_ROLE_UNKNOWN, // fixme
&zrtp_session);
if (zrtp_status_ok != status) {
// Check error code and debug logs
return status;
}
// Set call-back pointer to our parent structure
zrtp_session_set_userdata(zrtp_session, session);
// Attach audio stream
status = zrtp_stream_attach(zrtp_session, &zrtp_audio);
if (zrtp_status_ok != status) {
// Check error code and debug logs
return status;
}
zrtp_stream_set_userdata(zrtp_audio, session);
return 0;
}
int AmZRTPSessionState::startStreams(uint32_t ssrc){
if (NULL == zrtp_audio)
return -1;
// void zrtp_get_cache_path(char *path, uint32_t length) {
// }
zrtp_status_t status = zrtp_stream_start(zrtp_audio, ssrc);
if (zrtp_status_ok != status) {
ERROR("starting ZRTP stream\n");
return -1;
}
return 0;
}
int AmZRTPSessionState::stopStreams(){
if (NULL == zrtp_audio)
return -1;
void zrtp_event_callback(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx)
{
if (NULL==stream_ctx) {
ERROR("event received without stream context.\n");
return;
zrtp_status_t status = zrtp_stream_stop(zrtp_audio);
if (zrtp_status_ok != status) {
ERROR("stopping ZRTP stream\n");
return -1;
}
return 0;
}
AmSession* sess = reinterpret_cast<AmSession*>(stream_ctx->stream_usr_data);
if (NULL==sess) {
ERROR("event received without session set up.\n");
void AmZRTPSessionState::freeSession() {
if (NULL == zrtp_session)
return;
}
sess->postEvent(new AmZRTPEvent(event, stream_ctx));
zrtp_session_down(zrtp_session);
// // save zrtp cache
// zrtp_cache_mut.lock();
// if (!((++zrtp_cache_save_cntr) % ZRTP_CACHE_SAVE_INTERVAL)) {
// if (zrtp_cache_user_down() != zrtp_status_ok) {
// ERROR("while writing ZRTP cache.\n");
// }
// }
// zrtp_cache_mut.unlock();
}
void zrtp_play_alert(zrtp_stream_ctx_t* ctx) {
INFO("zrtp_play_alert: ALERT!\n");
ctx->need_play_alert = zrtp_play_no;
AmZRTPSessionState::~AmZRTPSessionState() {
}
int zrtp_send_rtp( const zrtp_stream_ctx_t* stream_ctx,
char* packet, unsigned int length) {
if (NULL==stream_ctx) {
ERROR("trying to send packet without stream context.\n");
// void zrtp_get_cache_path(char *path, uint32_t length) {
// }
int AmZRTP::on_send_packet(const zrtp_stream_t *stream, char *packet, unsigned int length) {
DBG("on_send_packet(stream [%p], len=%u)\n", stream, length);
if (NULL==stream) {
ERROR("on_send_packet without stream context.\n");
return -1;
}
AmSession* sess = reinterpret_cast<AmSession*>(stream_ctx->stream_usr_data);
if (NULL==sess) {
ERROR("trying to send packet without session set up.\n");
void* udata = zrtp_stream_get_userdata(stream);
if (NULL == udata) {
ERROR("ZRTP on_send_packet without session context.\n");
return -1;
}
AmSession* sess = reinterpret_cast<AmSession*>(udata);
return sess->rtp_str.send_raw(packet, length);
return sess->RTPStream()->send_raw(packet, length);
}
void AmZRTP::on_zrtp_secure(zrtp_stream_t *stream) {
DBG("on_zrtp_secure(stream [%p])\n", stream);
#define BUFFER_LOG_SIZE 256
void zrtp_print_log(log_level_t level, const char* format, ...)
{
char buffer[BUFFER_LOG_SIZE];
va_list arg;
va_start(arg, format);
vsnprintf(buffer, BUFFER_LOG_SIZE, format, arg);
va_end( arg );
int sems_lvl = L_ERR;
switch(level) {
case ZRTP_LOG_DEBUG: sems_lvl = L_DBG; break;
case ZRTP_LOG_INFO: sems_lvl = L_INFO; break;
case ZRTP_LOG_WARNING: sems_lvl = L_WARN; break;
case ZRTP_LOG_ERROR: sems_lvl = L_ERR; break;
case ZRTP_LOG_FATAL: sems_lvl = L_ERR; break;
case ZRTP_LOG_ALL: sems_lvl = L_ERR; break;
}
_LOG(sems_lvl, "*** %s", buffer);
// if (NULL==stream) {
// ERROR("event received without stream context.\n");
// return;
// }
// void* udata = zrtp_stream_get_userdata(stream);
// if (NULL == udata) {
// ERROR("ZRTP on_send_packet without session set context.\n");
// return;
// }
// AmSession* sess = reinterpret_cast<AmSession*>(udata);
// sess->onZrtpSecure();
}
void AmZRTP::on_zrtp_security_event(zrtp_stream_t *stream, zrtp_security_event_t event) {
DBG("on_zrtp_security_event(stream [%p])\n", stream);
if (NULL==stream) {
ERROR("event received without stream context.\n");
return;
}
void* udata = zrtp_stream_get_userdata(stream);
if (NULL == udata) {
ERROR("ZRTP on_send_packet without session set context.\n");
return;
}
AmSession* sess = reinterpret_cast<AmSession*>(udata);
sess->postEvent(new AmZRTPSecurityEvent(event, stream));
}
#endif
void AmZRTP::on_zrtp_protocol_event(zrtp_stream_t *stream, zrtp_protocol_event_t event) {
DBG("on_zrtp_protocol_event(stream [%p])\n", stream);
if (NULL==stream) {
ERROR("event received without stream context.\n");
return;
}
void* udata = zrtp_stream_get_userdata(stream);
if (NULL == udata) {
ERROR("ZRTP on_send_packet without session set context.\n");
return;
}
AmSession* sess = reinterpret_cast<AmSession*>(udata);
sess->postEvent(new AmZRTPProtocolEvent(event, stream));
}
const char* zrtp_protocol_event_desc(zrtp_protocol_event_t e) {
switch (e) {
case ZRTP_EVENT_UNSUPPORTED: return "ZRTP_EVENT_UNSUPPORTED";
case ZRTP_EVENT_IS_CLEAR: return "ZRTP_EVENT_IS_CLEAR";
case ZRTP_EVENT_IS_INITIATINGSECURE: return "ZRTP_EVENT_IS_INITIATINGSECURE";
case ZRTP_EVENT_IS_PENDINGSECURE: return "ZRTP_EVENT_IS_PENDINGSECURE";
case ZRTP_EVENT_IS_PENDINGCLEAR: return "ZRTP_EVENT_IS_PENDINGCLEAR";
case ZRTP_EVENT_NO_ZRTP: return "ZRTP_EVENT_NO_ZRTP";
case ZRTP_EVENT_NO_ZRTP_QUICK: return "ZRTP_EVENT_NO_ZRTP_QUICK";
case ZRTP_EVENT_IS_CLIENT_ENROLLMENT: return "ZRTP_EVENT_IS_CLIENT_ENROLLMENT";
case ZRTP_EVENT_NEW_USER_ENROLLED: return "ZRTP_EVENT_NEW_USER_ENROLLED";
case ZRTP_EVENT_USER_ALREADY_ENROLLED: return "ZRTP_EVENT_USER_ALREADY_ENROLLED";
case ZRTP_EVENT_USER_UNENROLLED: return "ZRTP_EVENT_USER_UNENROLLED";
case ZRTP_EVENT_LOCAL_SAS_UPDATED: return "ZRTP_EVENT_LOCAL_SAS_UPDATED";
case ZRTP_EVENT_REMOTE_SAS_UPDATED: return "ZRTP_EVENT_REMOTE_SAS_UPDATED";
case ZRTP_EVENT_IS_SECURE: return "ZRTP_EVENT_IS_SECURE";
case ZRTP_EVENT_IS_SECURE_DONE: return "ZRTP_EVENT_IS_SECURE_DONE";
case ZRTP_EVENT_IS_PASSIVE_RESTRICTION: return "ZRTP_EVENT_IS_PASSIVE_RESTRICTION";
case ZRTP_EVENT_COUNT: return "ZRTP_EVENT_COUNT"; // ?
default: return "UNKNOWN_ZRTP_PROTOCOL_EVENT";
}
};
const char* zrtp_security_event_desc(zrtp_security_event_t e) {
switch (e) {
case ZRTP_EVENT_PROTOCOL_ERROR: return "ZRTP_EVENT_PROTOCOL_ERROR";
case ZRTP_EVENT_WRONG_SIGNALING_HASH: return "ZRTP_EVENT_WRONG_SIGNALING_HASH";
case ZRTP_EVENT_WRONG_MESSAGE_HMAC: return "ZRTP_EVENT_WRONG_MESSAGE_HMAC";
case ZRTP_EVENT_MITM_WARNING: return "ZRTP_EVENT_MITM_WARNING";
default: return "UNKNOWN_ZRTP_SECURITY_EVENT";
}
}
#endif

@ -30,33 +30,63 @@
#ifdef WITH_ZRTP
#include "zrtp/zrtp.h"
#include "libzrtp/zrtp.h"
#include "AmThread.h"
#include "AmEvent.h"
#include <string>
#include "zrtp/zrtp.h"
extern zrtp_global_ctx_t zrtp_global; // persistent storage for libzrtp data
extern zrtp_zid_t zrtp_instance_zid;
class AmSession;
struct AmZRTPEvent : public AmEvent {
zrtp_stream_ctx_t* stream_ctx;
AmZRTPEvent(int event_id, zrtp_stream_ctx_t* stream_ctx)
struct AmZRTPSecurityEvent : public AmEvent {
zrtp_stream_t* stream_ctx;
AmZRTPSecurityEvent(int event_id, zrtp_stream_t* stream_ctx)
: AmEvent(event_id), stream_ctx(stream_ctx) { }
~AmZRTPEvent() { }
~AmZRTPSecurityEvent() { }
};
struct AmZRTPProtocolEvent : public AmEvent {
zrtp_stream_t* stream_ctx;
AmZRTPProtocolEvent(int event_id, zrtp_stream_t* stream_ctx)
: AmEvent(event_id), stream_ctx(stream_ctx) { }
~AmZRTPProtocolEvent() { }
};
struct AmZRTP {
static int zrtp_cache_save_cntr;
static std::string cache_path;
static AmMutex zrtp_cache_mut;
static int init();
static zrtp_global_ctx_t zrtp_global;
static zrtp_zid_t zrtp_instance_zid;
static void freeSession(zrtp_conn_ctx_t* zrtp_session);
static int zrtp_cache_save_cntr;
static std::string cache_path;
static AmMutex zrtp_cache_mut;
static int init();
static zrtp_global_t* zrtp_global;
static zrtp_config_t zrtp_config;
static zrtp_zid_t zrtp_instance_zid;
static int on_send_packet(const zrtp_stream_t *stream, char *packet, unsigned int length);
static void on_zrtp_secure(zrtp_stream_t *stream);
static void on_zrtp_security_event(zrtp_stream_t *stream, zrtp_security_event_t event);
static void on_zrtp_protocol_event(zrtp_stream_t *stream, zrtp_protocol_event_t event);
};
struct AmZRTPSessionState {
AmZRTPSessionState();
~AmZRTPSessionState();
int initSession(AmSession* s);
void freeSession();
int startStreams(uint32_t ssrc);
int stopStreams();
zrtp_profile_t zrtp_profile;
zrtp_session_t* zrtp_session; // ZRTP session
zrtp_stream_t* zrtp_audio; // ZRTP stream for audio
};
const char* zrtp_protocol_event_desc(zrtp_protocol_event_t e);
const char* zrtp_security_event_desc(zrtp_security_event_t e);
#if defined(__cplusplus)
extern "C" {
#endif

@ -87,9 +87,11 @@ rtp_high_port=60000
# optional parameter: sig_sock_opts=option,option,option,...
#
# - signaling socket options
# o force_via_address - force sending replies to 1st Via
# o force_via_address - force sending replies to 1st Via
# o no_transport_in_contact - do not add transport to contact in replies
#
# Example:
# sig_sock_opts=force_via_address
# sig_sock_opts=force_via_address,no_transport_in_contact
# optional parameter: tcp_connect_timeout=<timeout in millisec>
# Default: 2000 (2 sec)
@ -373,6 +375,15 @@ loglevel=2
# Example:
# cps_limit="100;503;Server overload"
###########################################################
# if build with ZRTP support (see Makefile.defs)
# enable ZRTP support in endpoint calls:
#enable_zrtp=yes (default: yes)
#
# enable ZRTP debug log? (prints lots of info)
#enable_zrtp_debuglog=no (default: yes)
############################################################
# tuning

@ -4,6 +4,18 @@
cache_path=zrtp_cache.dat
#
# ZID - must be set to a unique identifier on installation.
# ZID - must be set to a unique random identifier on installation.
# if none is provided, a random one will be generated - this should be
# then taken into zrtp.conf to support key continuity.
#
#zid=012345678901
#zid_hex="d4d8bb2d7d3536244cb67598"
# random_entropy_bytes - bytes to read from /dev/random to zrtp entropy pool
# Warning: can stall the startup process if there's many bytes read.
# If there's too little, packets might get dropped.
#
# default: 172
#
#random_entropy_bytes=512
#
#random_entropy_bytes=0 # disable

@ -109,7 +109,7 @@ BEGIN_EXPORTS( "opus" , AMCI_NO_MODULEINIT, AMCI_NO_MODULEDESTROY )
END_CODECS
BEGIN_PAYLOADS
PAYLOAD( -1, "opus", _OPUS_RATE, 48000, 1, CODEC_OPUS, AMCI_PT_AUDIO_FRAME )
PAYLOAD( -1, "opus", _OPUS_RATE, 48000, 2, CODEC_OPUS, AMCI_PT_AUDIO_FRAME )
END_PAYLOADS
BEGIN_FILE_FORMATS

@ -267,17 +267,20 @@ int _trans_layer::send_reply(sip_msg* msg, const trans_ticket* tt,
sip_msg* req = t->msg;
assert(req);
// patch Contact-HF
vector<string> contact_buf;
trsp_socket* local_socket = req->local_socket;
cstring trsp(local_socket->get_transport());
if(!local_socket->is_opt_set(trsp_socket::no_transport_in_contact)) {
cstring trsp(local_socket->get_transport());
// patch Contact-HF
vector<string> contact_buf(msg->contacts.size());
vector<string>::iterator contact_buf_it = contact_buf.begin();
contact_buf.resize(msg->contacts.size());
vector<string>::iterator contact_buf_it = contact_buf.begin();
for(list<sip_header*>::iterator contact_it = msg->contacts.begin();
contact_it != msg->contacts.end(); contact_it++, contact_buf_it++) {
for(list<sip_header*>::iterator contact_it = msg->contacts.begin();
contact_it != msg->contacts.end(); contact_it++, contact_buf_it++) {
patch_contact_transport(*contact_it,trsp,*contact_buf_it);
patch_contact_transport(*contact_it,trsp,*contact_buf_it);
}
}
bool have_to_tag = false;

@ -44,9 +44,10 @@ class trsp_socket
{
public:
enum socket_options {
force_via_address = (1 << 0),
force_outbound_if = (1 << 1),
use_raw_sockets = (1 << 2)
force_via_address = (1 << 0),
force_outbound_if = (1 << 1),
use_raw_sockets = (1 << 2),
no_transport_in_contact = (1 << 3)
};
static int log_level_raw_msgs;

@ -1,3 +1,4 @@
SEMS
* [1]Main Page
* [2]Related Pages
* [3]Namespaces
@ -6,50 +7,45 @@
* [6]Directories
* [7]Examples
ZRTP encryption
ZRTP encryption
Introduction
ZRTP is a key agreement protocol to negotiate the keys for encryption
of RTP in phone calls. It is a proposed public standard: [8]ZRTP: Media
Path Key Agreement for Secure RTP.
of RTP in phone calls. It is an [8]informational RFC - RFC6189 ZRTP:
Media Path Key Agreement for Unicast Secure RTP.
Even though it uses public key encryption, a PKI is not needed. Since
the keys are negotiated in the media path, support for it in signaling
is not necessary. ZRTP also offers opportunistic encryption, which
means that calls between UAs that support it are encrypted, but calls
to UAs not supporting it are still possible, but unencrypted. The
actual RTP encryption is done with [9]SRTP. For more information about
ZRTP, see the [10]Zfone project, the [11]draft and the [12]wikipedia
article.
actual RTP encryption is done with [9]SRTP.
ZRTP is one of the widest (if not the widest) supported end-to-end
encryption methods for VoIP. Popular SIP clients that support ZRTP are
[10]Jitsi, CSipSimple, Twinkle, Linphone.
For more information about ZRTP, see the [11]Zfone project, the [12]RFC
and the [13]wikipedia article.
ZRTP in SEMS
Since the version 1.0 SEMS supports ZRTP with the use of the [13]Zfone
Since the version 1.0 SEMS supports ZRTP with the use of the [14]Zfone
SDK.
Currrently, the newest version of the ZRTP SDK, and the one that works
with SEMS, is available at [15]https://github.com/traviscross/libzrtp.
To build SEMS with ZRTP support, install the SDK and set WITH_ZRTP=yes
in Makefile.defs, or build with
$ make WITH_ZRTP=yes
The conference application is enabled to tell the caller the SAS phrase
if it is compiled with WITH_SAS_TTS option, set in
apps/conference/Makefile. For this to work, the [14]flite
apps/conference/Makefile. For this to work, the [16]flite
text-to-speech synthesizer version 1.2 or 1.3 is needed.
Online demo
Call
sip:[15]secureconference@iptel.org
or
sip:[16]zrtp@iptel.org
for a test drive of ZRTP conferencing. If you call that number with a
ZRTP enabled phone, you should be told the SAS string that is also
displayed in your phone. Press two times the hash (##) while in the
call to read out the SAS string again.
How to use ZRTP in your application
Have a look at the conference application on how to add ZRTP support in
@ -76,32 +72,34 @@ Phones with ZRTP
* [17]Zfone turns every softphone into a secure phone by tapping into
the RTP sent and received
* [18]Twinkle is a very good free softphone for Linux. It can speak
ZRTP with the use of GNU [19]libzrtpcpp.
* [18]Jitsi
* [19]Twinkle is a very good free softphone for Linux. It can speak
ZRTP with the use of GNU [20]libzrtpcpp.
__________________________________________________________________
Generated on Thu Feb 3 02:29:25 2011 for SEMS by [20]doxygen 1.6.1
Generated by [21] doxygen 1.7.6.1
References
1. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/index.html
2. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/pages.html
3. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/namespaces.html
4. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/annotated.html
5. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/files.html
6. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/dirs.html
7. file://localhost/home/stefan/devel/sems/sems/doc/doxygen_doc/html/examples.html
8. http://tools.ietf.org/html/draft-zimmermann-avt-zrtp
1. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/index.html
2. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/pages.html
3. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/namespaces.html
4. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/annotated.html
5. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/files.html
6. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/dirs.html
7. file://localhost/home/stefan_plain/devel/sems/zrtp/sems/doc/doxygen_doc/html/examples.html
8. http://tools.ietf.org/html/rfc6189
9. http://www.ietf.org/rfc/rfc3711.txt
10. http://zfoneproject.com/
11. http://tools.ietf.org/html/draft-zimmermann-avt-zrtp
12. http://en.wikipedia.org/wiki/ZRTP
13. http://zfoneproject.com/prod_sdk.html
14. http://cmuflite.org/
15. mailto:secureconference@iptel.org
16. mailto:zrtp@iptel.org
10. http://www.jitsi.org/
11. http://zfoneproject.com/
12. http://tools.ietf.org/html/rfc6189
13. http://en.wikipedia.org/wiki/ZRTP
14. http://zfoneproject.com/prod_sdk.html
15. https://github.com/traviscross/libzrtp
16. http://cmuflite.org/
17. http://zfoneproject.com/
18. http://twinklephone.com/
19. http://www.gnutelephony.org/index.php/GNU_ZRTP
20. http://www.doxygen.org/index.html
18. http://www.jitsi.org/
19. http://twinklephone.com/
20. http://www.gnutelephony.org/index.php/GNU_ZRTP
21. http://www.doxygen.org/index.html

@ -0,0 +1,82 @@
ZRTP support module
(C) 2014 Stefan Sayer. Parts of the development of this module was kindly sponsored by AMTEL Inc.
If SEMS is built with ZRTP support, a module mod_zrtp is created.
ZRTP may be individually enabled or disabled and configured in the DSM script by using
zrtp.setEnabled in the start event, for example
import(mod_zrtp);
initial state START;
transition "start" START - start / {
zrtp.setEnabled(false);
-- or, e.g.: zrtp.setAllowclear(false);
} -> sess_started;
state sess_started;
This overrides the sems.conf enable_zrtp setting.
NOTE: The setEnabled/setAllowclear/... actions have only effect in the start event!
ZRTP specific events can be used in DSM if $enable_zrtp_events is set to true:
set($enable_zrtp_events=true);
Then the zrtp.protocolEvent and zrtp.securityEvent can be handled specifically.
Actions
-------
zrtp.setEnabled(bool enabled)
e.g. zrtp.setEnabled(true) or zrtp.setEnabled(false)
zrtp.setAllowclear(bool enabled) - set ZRTP allowclear option, see ZRTP documentation
zrtp.setAutosecure(bool enabled) - set ZRTP autosecure option, see ZRTP documentation
zrtp.setDisclosebit(bool enabled) - set ZRTP disclose_bit option, see ZRTP documentation
zrtp.getSAS(sas1_var,sas2_var) - get SAS strings
to be used after the stream has gone secure, e.g.
transition "ZRTP event IS_SECURE" sess_started - zrtp.protocolEvent(#event==ZRTP_EVENT_IS_SECURE) / {
zrtp.getSAS($sas1,$sas2);
log(3, $sas1);
log(3, $sas2);
} -> sess_started;
zrtp.getSessionInfo(varname) - get info about the session
varname.sas_is_ready, varname.sas1, varname.sas2, varname.zid, varname.peer_zid, ...
zrtp.setVerified(string zid1, string zid2) - set as verified
zrtp.setUnverified(string zid1, string zid2) - set as unverified
e.g. zrtp.getSessionInfo(zrtp);
zrtp.setVerified($zrtp.zid,$zrtp.peer_zid);
Events
------
zrtp.protocolEvent - protocol event happened, only if enable_zrtp_events==true
e.g.
zrtp.protocolEvent(#event==ZRTP_EVENT_IS_SECURE)
#event - event type
#event_id - numeric event type (should not be used)
see the libzrtp documentation, or /usr/include/libzrtp/zrtp_iface.h for
event types. Important ones are
ZRTP_EVENT_IS_SECURE, ZRTP_EVENT_NO_ZRTP, ZRTP_EVENT_IS_SECURE_DONE,
ZRTP_EVENT_IS_CLEAR, ZRTP_EVENT_IS_PENDINGSECURE,
e.g.
transition "ZRTP event" sess_started - zrtp.protocolEvent / {
logParams(3);
} -> sess_started;
zrtp.securityEvent - security event happened, only if enable_zrtp_events==true
e.g.
zrtp.securityEvent(#event==ZRTP_EVENT_PROTOCOL_ERROR)
#event - event type
#event_id - numeric event type (should not be used)
ZRTP_EVENT_PROTOCOL_ERROR, ZRTP_EVENT_WRONG_SIGNALING_HASH, ZRTP_EVENT_WRONG_MESSAGE_HMAC,
ZRTP_EVENT_MITM_WARNING

@ -443,6 +443,12 @@
\verbinclude Readme.mod_xml.txt
</p>
\subsection dsm_mod_zrtp mod_zrtp - ZRTP support functions
<p>
\verbinclude Readme.mod_zrtp.txt
</p>
*
* \section Links
* Back to \ref AppDoc, to \ref AppDocExample.

@ -1,4 +1,4 @@
/* \file info about ZRTP usage in SEMS
/* \file info about using ZRTP with SEMS
*/
/*!
@ -8,16 +8,20 @@
* \section intro Introduction
*
* <p>ZRTP is a key agreement protocol to negotiate the keys for encryption of RTP in phone calls.
* It is a proposed public standard: <a href="http://tools.ietf.org/html/draft-zimmermann-avt-zrtp">
* ZRTP: Media Path Key Agreement for Secure RTP</a>.</p>
* It is an <a href="http://tools.ietf.org/html/rfc6189">informational RFC - RFC6189 ZRTP: Media Path Key Agreement for Unicast Secure RTP</a>.</p>
* <p>Even though it uses public key encryption, a PKI is not needed. Since the keys are negotiated
* in the media path, support for it in signaling is not necessary. ZRTP also offers opportunistic
* encryption, which means that calls between UAs that support it are encrypted, but calls to UAs
* not supporting it are still possible, but unencrypted. The actual RTP encryption is done with
* <a href="http://www.ietf.org/rfc/rfc3711.txt">SRTP</a>.
* For more information about ZRTP, see the
*
* <p>ZRTP is one of the most widely (if not the most widely) supported end-to-end encryption methods for VoIP.
* Popular SIP clients that support ZRTP are <a href="http://www.jitsi.org">Jitsi</a>,
<a href="http://www.creytiv.com/baresip.html">baresip</a>, CSipSimple, Twinkle, Linphone.</p>
*
* <p>For more information about ZRTP, see the
* <a href="http://zfoneproject.com/">Zfone project</a>, the
* <a href="http://tools.ietf.org/html/draft-zimmermann-avt-zrtp">draft</a> and the
* <a href="http://tools.ietf.org/html/rfc6189">RFC</a> and the
* <a href="http://en.wikipedia.org/wiki/ZRTP">wikipedia article</a>.</p>
*
* \section zinsems ZRTP in SEMS
@ -25,25 +29,35 @@
* <p>Since the version 1.0 SEMS supports ZRTP with the use of the
* <a href="http://zfoneproject.com/prod_sdk.html"> Zfone SDK</a>.</p>
*
* <p>Currrently, the newest version of the ZRTP SDK, and the one that works with SEMS, is available at
* <a href="https://github.com/traviscross/libzrtp">https://github.com/traviscross/libzrtp</a>.
*
* <p>To build SEMS with ZRTP support, install the SDK and set WITH_ZRTP=yes in Makefile.defs,
* or build with <br>
* <pre> $ make WITH_ZRTP=yes</pre>
* </p>
*
<p>ZRTP can be enabled in sems.conf by the enable_zrtp config parameter, e.g. enable_zrtp=yes.</p>
<p>ZRTP debug logging (lots of info in the log) can be disabled in sems.conf by setting enable_zrtp_debuglog=no</p>
<p>ZRTP is NOT supported by the sbc application. I.e. if you want to transcrypt cleartext calls into ZRTP encrypted calls,
you need to use an endpoint application like the webconference module, the conference module, or better yet a
DSM application. If you want to make a plain-RTP to ZRTP gateway, have a look at the b2b_connect_audio DSM example,
which can be found in doc/dsm/examples/b2b_connect_audio.
</p>
<p> There is support for some utility functions in a DSM module (see \ref dsm_mod_zrtp).
</p>
* <p>The <em>conference</em> application is enabled to tell the caller the SAS phrase
* if it is compiled with WITH_SAS_TTS option, set in apps/conference/Makefile. For this to work,
* the <a href="http://cmuflite.org">flite text-to-speech synthesizer</a> version 1.2 or 1.3 is needed.</p>
*
* \section onlinedemo Online demo
*
* <p>Call <pre>sip:secureconference@iptel.org</pre> or <pre>sip:zrtp@iptel.org</pre> for a test drive
* of ZRTP conferencing. If you call that number with a ZRTP enabled phone, you should be told the SAS string
* that is also displayed in your phone. Press two times the hash (##) while in the call to read out the
* SAS string again.</p>
*
* \section zinyourapp How to use ZRTP in your application
*
* Have a look at the conference application on how to add ZRTP support in your application. There is a
* Have a look at the dsm module mod_zrtp for examples
or the conference application on how to add ZRTP support in your application. There is a
* <code>void AmSession::onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx)</code>
* event that is called with the appropriate ZRTP event type and the zrtp stream context, if the state
* of the ZRTP encryption changes. The zrtp_event are defined in the Zfone SDK, e.g. ZRTP_EVENT_IS_SECURE.
@ -63,6 +77,7 @@
*
* - <a href="http://zfoneproject.com/">Zfone</a> turns every softphone into a secure phone
* by tapping into the RTP sent and received</li></ul>
* - <a href="http://www.jitsi.org">Jitsi</a>
* - <a href="http://twinklephone.com/">Twinkle</a> is a very good free softphone for Linux.
* It can speak ZRTP with the use of GNU
* <a href="http://www.gnutelephony.org/index.php/GNU_ZRTP">libzrtpcpp</a>.

Loading…
Cancel
Save