diff --git a/apps/conference/Conference.cpp b/apps/conference/Conference.cpp
index 23d19e0a..9a90c261 100644
--- a/apps/conference/Conference.cpp
+++ b/apps/conference/Conference.cpp
@@ -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);
diff --git a/apps/dsm/DSMCall.cpp b/apps/dsm/DSMCall.cpp
index 589d93ae..d02f6ff0 100644
--- a/apps/dsm/DSMCall.cpp
+++ b/apps/dsm/DSMCall.cpp
@@ -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 params;
+ params["event"] = zrtp_protocol_event_desc(event);
+ params["event_id"] = int2str(event);
+ engine.runEvent(this, this, DSMCondition::ZRTPProtocolEvent, ¶ms);
+ }
+
+}
+
+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 params;
+ params["event"] = zrtp_security_event_desc(event);
+ params["event_id"] = int2str(event);
+ engine.runEvent(this, this, DSMCondition::ZRTPSecurityEvent, ¶ms);
+ }
+
+}
+#endif
+
void DSMCall::process(AmEvent* event)
{
diff --git a/apps/dsm/DSMCall.h b/apps/dsm/DSMCall.h
index 0aafbf8c..70b36de1 100644
--- a/apps/dsm/DSMCall.h
+++ b/apps/dsm/DSMCall.h
@@ -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();
diff --git a/apps/dsm/DSMSession.h b/apps/dsm/DSMSession.h
index c33fa62f..4fd007bc 100644
--- a/apps/dsm/DSMSession.h
+++ b/apps/dsm/DSMSession.h
@@ -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"
diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h
index 36a5b9de..6c0b9f1c 100644
--- a/apps/dsm/DSMStateEngine.h
+++ b/apps/dsm/DSMStateEngine.h
@@ -121,6 +121,11 @@ class DSMCondition
RelayOnSipReply,
RelayOnB2BRequest,
RelayOnB2BReply
+
+#ifdef WITH_ZRTP
+ , ZRTPProtocolEvent,
+ ZRTPSecurityEvent
+#endif
};
bool invert;
diff --git a/apps/dsm/mods/Makefile b/apps/dsm/mods/Makefile
index a89f9e3f..cc3cdf78 100644
--- a/apps/dsm/mods/Makefile
+++ b/apps/dsm/mods/Makefile
@@ -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, \
diff --git a/apps/dsm/mods/mod_zrtp/Makefile b/apps/dsm/mods/mod_zrtp/Makefile
new file mode 100644
index 00000000..b28285ba
--- /dev/null
+++ b/apps/dsm/mods/mod_zrtp/Makefile
@@ -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
diff --git a/apps/dsm/mods/mod_zrtp/ModZrtp.cpp b/apps/dsm/mods/mod_zrtp/ModZrtp.cpp
new file mode 100644
index 00000000..d09026f5
--- /dev/null
+++ b/apps/dsm/mods/mod_zrtp/ModZrtp.cpp
@@ -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;ivar[varname+".zid"]+=char2hex(zrtp_session_info.zid.buffer[i], true);
+
+ sc_sess->var[varname+".peer_zid"] = "";
+ for (size_t i=0;ivar[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;iSET_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
diff --git a/apps/dsm/mods/mod_zrtp/ModZrtp.h b/apps/dsm/mods/mod_zrtp/ModZrtp.h
new file mode 100644
index 00000000..d858772f
--- /dev/null
+++ b/apps/dsm/mods/mod_zrtp/ModZrtp.h
@@ -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
diff --git a/apps/sbc/SBCCallLeg.cpp b/apps/sbc/SBCCallLeg.cpp
index eabf22d2..f099ebd0 100644
--- a/apps/sbc/SBCCallLeg.cpp
+++ b/apps/sbc/SBCCallLeg.cpp
@@ -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));
diff --git a/apps/sbc/SBCCallProfile.cpp b/apps/sbc/SBCCallProfile.cpp
index a6eb06bf..da70eaee 100644
--- a/apps/sbc/SBCCallProfile.cpp
+++ b/apps/sbc/SBCCallProfile.cpp
@@ -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;
diff --git a/core/AmB2BMedia.cpp b/core/AmB2BMedia.cpp
index b83d5aa4..5c76def2 100644
--- a/core/AmB2BMedia.cpp
+++ b/core/AmB2BMedia.cpp
@@ -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
diff --git a/core/AmConfig.cpp b/core/AmConfig.cpp
index 5cd84551..fc56ded7 100644
--- a/core/AmConfig.cpp
+++ b/core/AmConfig.cpp
@@ -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 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());
}
diff --git a/core/AmConfig.h b/core/AmConfig.h
index 818a859a..f1b75089 100644
--- a/core/AmConfig.h
+++ b/core/AmConfig.h
@@ -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;
diff --git a/core/AmPlugIn.cpp b/core/AmPlugIn.cpp
index ac909c70..f210406c 100644
--- a/core/AmPlugIn.cpp
+++ b/core/AmPlugIn.cpp
@@ -422,7 +422,8 @@ void AmPlugIn::getPayloads(vector& pl_vec) const
for (std::map::const_iterator it = payload_order.begin(); it != payload_order.end(); ++it) {
std::map::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);
}
diff --git a/core/AmRtpStream.cpp b/core/AmRtpStream.cpp
index 4e51c5a3..7db47c9a 100644
--- a/core/AmRtpStream.cpp
+++ b/core/AmRtpStream.cpp
@@ -57,7 +57,7 @@
#include
#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);
diff --git a/core/AmSdp.cpp b/core/AmSdp.cpp
index 5689a34d..dd2ff5ff 100644
--- a/core/AmSdp.cpp
+++ b/core/AmSdp.cpp
@@ -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 "";
}
@@ -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::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
diff --git a/core/AmSdp.h b/core/AmSdp.h
index 1e20e129..23302fc1 100644
--- a/core/AmSdp.h
+++ b/core/AmSdp.h
@@ -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
diff --git a/core/AmSession.cpp b/core/AmSession.cpp
index 8e2e90d7..2f6c5f58 100644
--- a/core/AmSession.cpp
+++ b/core/AmSession.cpp
@@ -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(ev);
- if(zrtp_ev){
- onZRTPEvent((zrtp_event_t)zrtp_ev->event_id, zrtp_ev->stream_ctx);
+ AmZRTPProtocolEvent* zrtp_p_ev = dynamic_cast(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(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
diff --git a/core/AmSession.h b/core/AmSession.h
index 1e9f7be2..4d1f1a46 100644
--- a/core/AmSession.h
+++ b/core/AmSession.h
@@ -41,9 +41,7 @@
#include "AmSessionEventHandler.h"
#include "AmMediaProcessor.h"
-#ifdef WITH_ZRTP
-#include "zrtp/zrtp.h"
-#endif
+#include "AmZRTP.h"
#include
#include
@@ -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 */
diff --git a/core/AmZRTP.cpp b/core/AmZRTP.cpp
index ecc3c906..7c4e0298 100644
--- a/core/AmZRTP.cpp
+++ b/core/AmZRTP.cpp
@@ -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(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(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(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(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(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(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
diff --git a/core/AmZRTP.h b/core/AmZRTP.h
index 60eccf8b..3de8e63e 100644
--- a/core/AmZRTP.h
+++ b/core/AmZRTP.h
@@ -30,33 +30,63 @@
#ifdef WITH_ZRTP
-#include "zrtp/zrtp.h"
+#include "libzrtp/zrtp.h"
#include "AmThread.h"
#include "AmEvent.h"
#include
-#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
diff --git a/core/etc/sems.conf.sample b/core/etc/sems.conf.sample
index 397f57bc..bb15cb15 100644
--- a/core/etc/sems.conf.sample
+++ b/core/etc/sems.conf.sample
@@ -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=
# 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
diff --git a/core/etc/zrtp.conf b/core/etc/zrtp.conf
index 6d2bd5cf..0b8a71f0 100644
--- a/core/etc/zrtp.conf
+++ b/core/etc/zrtp.conf
@@ -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
diff --git a/core/plug-in/opus/opus.c b/core/plug-in/opus/opus.c
index edba1d1e..8cb6f391 100644
--- a/core/plug-in/opus/opus.c
+++ b/core/plug-in/opus/opus.c
@@ -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
diff --git a/core/sip/trans_layer.cpp b/core/sip/trans_layer.cpp
index 024d13ec..b602b254 100644
--- a/core/sip/trans_layer.cpp
+++ b/core/sip/trans_layer.cpp
@@ -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 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 contact_buf(msg->contacts.size());
- vector::iterator contact_buf_it = contact_buf.begin();
+ contact_buf.resize(msg->contacts.size());
+ vector::iterator contact_buf_it = contact_buf.begin();
- for(list::iterator contact_it = msg->contacts.begin();
- contact_it != msg->contacts.end(); contact_it++, contact_buf_it++) {
+ for(list::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;
diff --git a/core/sip/transport.h b/core/sip/transport.h
index e2789e96..e12ed907 100644
--- a/core/sip/transport.h
+++ b/core/sip/transport.h
@@ -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;
diff --git a/doc/ZRTP.txt b/doc/ZRTP.txt
index 94c87ce3..4f0f94ec 100644
--- a/doc/ZRTP.txt
+++ b/doc/ZRTP.txt
@@ -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
diff --git a/doc/dsm/mods/Readme.mod_zrtp.txt b/doc/dsm/mods/Readme.mod_zrtp.txt
new file mode 100644
index 00000000..5d207c41
--- /dev/null
+++ b/doc/dsm/mods/Readme.mod_zrtp.txt
@@ -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
+
diff --git a/doc/src/doc_applications.h b/doc/src/doc_applications.h
index 53e28a7b..929e2e82 100644
--- a/doc/src/doc_applications.h
+++ b/doc/src/doc_applications.h
@@ -443,6 +443,12 @@
\verbinclude Readme.mod_xml.txt
+
+ \subsection dsm_mod_zrtp mod_zrtp - ZRTP support functions
+
+ \verbinclude Readme.mod_zrtp.txt
+
+
*
* \section Links
* Back to \ref AppDoc, to \ref AppDocExample.
diff --git a/doc/src/doc_zrtp.h b/doc/src/doc_zrtp.h
index ce684bc6..0c0eef21 100644
--- a/doc/src/doc_zrtp.h
+++ b/doc/src/doc_zrtp.h
@@ -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
*
* ZRTP is a key agreement protocol to negotiate the keys for encryption of RTP in phone calls.
- * It is a proposed public standard:
- * ZRTP: Media Path Key Agreement for Secure RTP.
+ * It is an 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
* SRTP.
- * For more information about ZRTP, see the
+ *
+ *
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 Jitsi,
+ baresip, CSipSimple, Twinkle, Linphone.
+ *
+ * For more information about ZRTP, see the
* Zfone project, the
- * draft and the
+ * RFC and the
* wikipedia article.
*
* \section zinsems ZRTP in SEMS
@@ -25,25 +29,35 @@
* Since the version 1.0 SEMS supports ZRTP with the use of the
* Zfone SDK.
*
+ * Currrently, the newest version of the ZRTP SDK, and the one that works with SEMS, is available at
+ * 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
*
*
+ ZRTP can be enabled in sems.conf by the enable_zrtp config parameter, e.g. enable_zrtp=yes.
+
+ ZRTP debug logging (lots of info in the log) can be disabled in sems.conf by setting enable_zrtp_debuglog=no
+
+ 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.
+
+
+ There is support for some utility functions in a DSM module (see \ref dsm_mod_zrtp).
+
+
* 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 flite text-to-speech synthesizer version 1.2 or 1.3 is needed.
*
- * \section onlinedemo Online demo
- *
- * Call
sip:secureconference@iptel.org
or sip: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.
- *
* \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
* void AmSession::onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx)
* 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 @@
*
* - Zfone turns every softphone into a secure phone
* by tapping into the RTP sent and received
+ * - Jitsi
* - Twinkle is a very good free softphone for Linux.
* It can speak ZRTP with the use of GNU
* libzrtpcpp.