Browse code

dsm:mod_zrtp:more ZRTP API functions (allowclear, autosecure, SAS etc)

Stefan Sayer authored on 04/11/2014 14:56:36
Showing 6 changed files
... ...
@@ -1,6 +1,8 @@
1 1
 /*
2 2
  * Copyright (C) 2014 Stefan Sayer
3 3
  *
4
+ * Parts of the development of this module was kindly sponsored by AMTEL Inc.
5
+ *
4 6
  * This file is part of SEMS, a free SIP media server.
5 7
  *
6 8
  * SEMS is free software; you can redistribute it and/or modify
... ...
@@ -38,6 +40,15 @@ MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
38 38
 
39 39
 #ifdef WITH_ZRTP
40 40
   DEF_CMD("zrtp.setEnabled", ZRTPSetEnabledAction);
41
+  DEF_CMD("zrtp.setAllowclear", ZRTPSetAllowclearAction);
42
+  DEF_CMD("zrtp.setAutosecure", ZRTPSetAutosecureAction);
43
+  DEF_CMD("zrtp.setDisclosebit", ZRTPSetDisclosebitAction);
44
+  DEF_CMD("zrtp.getSAS", ZRTPGetSASAction);
45
+  DEF_CMD("zrtp.getSessionInfo", ZRTPGetSessionInfoAction);
46
+  DEF_CMD("zrtp.setVerified", ZRTPSetVerifiedAction);
47
+  DEF_CMD("zrtp.setUnverified", ZRTPSetUnverifiedAction);
48
+  DEF_CMD("zrtp.setSignalingHash", ZRTPSetSignalingHash);
49
+  DEF_CMD("zrtp.getSignalingHash", ZRTPGetSignalingHash);
41 50
 #endif
42 51
 
43 52
 } MOD_ACTIONEXPORT_END;
... ...
@@ -62,18 +73,222 @@ EXEC_ACTION_START(ZRTPSetEnabledAction) {
62 62
   sess->enable_zrtp = b;
63 63
 } EXEC_ACTION_END;
64 64
 
65
+EXEC_ACTION_START(ZRTPSetAllowclearAction) {
66
+  bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
67
+  DBG("setting ZRTP allowclear %sabled\n", b?"en":"dis");
68
+  sess->zrtp_session_state.zrtp_profile.allowclear = b;
69
+} EXEC_ACTION_END;
65 70
 
66
-#endif
67 71
 
68
-// CONST_ACTION_2P(DLGReplyAction, ',', true);
69
-// EXEC_ACTION_START(DLGReplyAction) {
72
+EXEC_ACTION_START(ZRTPSetAutosecureAction) {
73
+  bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
74
+  DBG("setting ZRTP autosecure %sabled\n", b?"en":"dis");
75
+  sess->zrtp_session_state.zrtp_profile.autosecure = b;
76
+} EXEC_ACTION_END;
77
+
78
+
79
+EXEC_ACTION_START(ZRTPSetDisclosebitAction) {
80
+  bool b = resolveVars(arg, sess, sc_sess, event_params) == DSM_TRUE;
81
+  DBG("setting ZRTP disclose_bit %sabled\n", b?"en":"dis");
82
+  sess->zrtp_session_state.zrtp_profile.disclose_bit = b;
83
+} EXEC_ACTION_END;
84
+
85
+CONST_ACTION_2P(ZRTPGetSASAction, ',', true);
86
+EXEC_ACTION_START(ZRTPGetSASAction) {
87
+  string varname = par1;
88
+  if (varname.size() && varname[0]=='$') varname = varname.substr(1);
89
+
90
+  string sas2 = par2;
91
+  if (sas2.size() && sas2[0]=='$') sas2 = sas2.substr(1);
92
+
93
+  if (varname.empty()) {
94
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
95
+    sc_sess->SET_STRERROR("need variable name for zrtp.getSAS");
96
+    EXEC_ACTION_STOP;
97
+  }
98
+
99
+  if (NULL == sess->zrtp_session_state.zrtp_session) {
100
+    WARN("ZRTP not active on that session\n");
101
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
102
+    sc_sess->SET_STRERROR("ZRTP not active on that session");
103
+    EXEC_ACTION_STOP;
104
+  }
105
+
106
+   zrtp_session_info_t zrtp_session_info;
107
+   zrtp_session_get(sess->zrtp_session_state.zrtp_session, &zrtp_session_info);
108
+
109
+   if (!zrtp_session_info.sas_is_ready) {
110
+     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
111
+     sc_sess->SET_STRERROR("ZRTP SAS not ready on that session");
112
+     EXEC_ACTION_STOP;
113
+   }
114
+
115
+   sc_sess->var[varname] = string(zrtp_session_info.sas1.buffer, zrtp_session_info.sas1.length);
116
+   if (!sas2.empty())
117
+     sc_sess->var[sas2] = string(zrtp_session_info.sas2.buffer, zrtp_session_info.sas2.length);
118
+
119
+   DBG("got SAS1 and SAS2: <%.*s> <%.*s>\n", zrtp_session_info.sas1.length, zrtp_session_info.sas1.buffer,
120
+       zrtp_session_info.sas2.length, zrtp_session_info.sas1.buffer);
121
+} EXEC_ACTION_END;
122
+
123
+EXEC_ACTION_START(ZRTPGetSessionInfoAction) {
124
+  string varname = arg;
125
+  if (varname.size() && varname[0]=='$') varname = varname.substr(1);
126
+
127
+  if (varname.empty()) {
128
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
129
+    sc_sess->SET_STRERROR("need variable name for zrtp.getSessionInfo");
130
+    EXEC_ACTION_STOP;
131
+  }
132
+
133
+  if (NULL == sess->zrtp_session_state.zrtp_session) {
134
+    WARN("ZRTP not active on that session\n");
135
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
136
+    sc_sess->SET_STRERROR("ZRTP not active on that session");
137
+    EXEC_ACTION_STOP;
138
+  }
139
+
140
+   zrtp_session_info_t zrtp_session_info;
141
+   zrtp_session_get(sess->zrtp_session_state.zrtp_session, &zrtp_session_info);
142
+
143
+   sc_sess->var[varname+".sas_is_ready"] = zrtp_session_info.sas_is_ready ? "true":"false";
144
+
145
+   if (zrtp_session_info.sas_is_ready) {
146
+     sc_sess->var[varname+".sas1"] = string(zrtp_session_info.sas1.buffer, zrtp_session_info.sas1.length);
147
+     sc_sess->var[varname+".sas2"] = string(zrtp_session_info.sas2.buffer, zrtp_session_info.sas2.length);
148
+   } else {
149
+     sc_sess->var[varname+".sas1"] = sc_sess->var[varname+".sas2"] = string();
150
+   }
151
+
152
+   sc_sess->var[varname+".id"] = int2str(zrtp_session_info.id);
153
+   string zid_hex;
154
+
155
+   sc_sess->var[varname+".zid"] = "";
156
+   for (size_t i=0;i<zrtp_session_info.zid.length;i++)
157
+     sc_sess->var[varname+".zid"]+=char2hex(zrtp_session_info.zid.buffer[i], true);
70 158
 
71
-//   if (!sc_sess->last_req.get()) {
72
-//     ERROR("no last request to reply\n");
73
-//     sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
74
-//     sc_sess->SET_STRERROR("no last request to reply");
75
-//     return false;
76
-//   }
159
+   sc_sess->var[varname+".peer_zid"] = "";
160
+   for (size_t i=0;i<zrtp_session_info.peer_zid.length;i++)
161
+     sc_sess->var[varname+".peer_zid"]+=char2hex(zrtp_session_info.peer_zid.buffer[i], true);
77 162
 
78
-//   replyRequest(sc_sess, sess, event_params, par1, par2, *sc_sess->last_req.get());
79
-// } EXEC_ACTION_END;
163
+   sc_sess->var[varname+".peer_clientid"] = string(zrtp_session_info.peer_clientid.buffer, zrtp_session_info.peer_clientid.length);
164
+   sc_sess->var[varname+".peer_version"] = string(zrtp_session_info.peer_version.buffer, zrtp_session_info.peer_version.length);
165
+
166
+   sc_sess->var[varname+".sas_is_verified"] = zrtp_session_info.sas_is_verified ? "true":"false";
167
+   // todo: cached_flags, matches_flags, wrongs_flags
168
+
169
+} EXEC_ACTION_END;
170
+
171
+bool hex2zid(const string& zid1, char* buffer) {
172
+  for (size_t i=0;i<zid1.length()/2;i++) {
173
+    unsigned int h;
174
+    if (reverse_hex2int(zid1.substr(i*2, 2), h)) {
175
+      ERROR("in zid: '%s' is no hex number\n", zid1.substr(i*2, 2).c_str());
176
+      return false;
177
+    }
178
+    buffer[i]=h % 0xff;
179
+  }
180
+  return true;
181
+}
182
+
183
+CONST_ACTION_2P(ZRTPSetVerifiedAction, ',', false);
184
+EXEC_ACTION_START(ZRTPSetVerifiedAction) {
185
+  string zid1 = resolveVars(par1, sess, sc_sess, event_params);
186
+  string zid2 = resolveVars(par2, sess, sc_sess, event_params);
187
+  if (zid1.empty() || zid2.empty()) {
188
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
189
+    sc_sess->SET_STRERROR("zid1 and zid2 must be there for setVerified");
190
+    EXEC_ACTION_STOP;
191
+  }
192
+
193
+  DBG("setting as verified zids <%s> and <%s>\n", zid1.c_str(), zid2.c_str());
194
+
195
+  zrtp_string16_t _zid1, _zid2;
196
+
197
+  if (!hex2zid(zid1, _zid1.buffer)) {
198
+      EXEC_ACTION_STOP;
199
+  }
200
+
201
+  if (!hex2zid(zid2, _zid2.buffer)) {
202
+      EXEC_ACTION_STOP;
203
+  }
204
+
205
+  if (zrtp_status_ok != zrtp_verified_set(AmZRTP::zrtp_global, &_zid1, &_zid2, 1)) {
206
+    DBG("zrtp_verified_set failed\n");
207
+    sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
208
+    sc_sess->SET_STRERROR("zrtp_verified_set failed");
209
+  }
210
+} EXEC_ACTION_END;
211
+
212
+CONST_ACTION_2P(ZRTPSetUnverifiedAction, ',', false);
213
+EXEC_ACTION_START(ZRTPSetUnverifiedAction) {
214
+  string zid1 = resolveVars(par1, sess, sc_sess, event_params);
215
+  string zid2 = resolveVars(par2, sess, sc_sess, event_params);
216
+  if (zid1.empty() || zid2.empty()) {
217
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
218
+    sc_sess->SET_STRERROR("zid1 and zid2 must be there for setUnverified");
219
+    EXEC_ACTION_STOP;
220
+  }
221
+
222
+  DBG("setting as unverified zids <%s> and <%s>\n", zid1.c_str(), zid2.c_str());
223
+
224
+  zrtp_string16_t _zid1, _zid2;
225
+
226
+  if (!hex2zid(zid1, _zid1.buffer)) {
227
+      EXEC_ACTION_STOP;
228
+  }
229
+
230
+  if (!hex2zid(zid2, _zid2.buffer)) {
231
+      EXEC_ACTION_STOP;
232
+  }
233
+
234
+  if (zrtp_status_ok != zrtp_verified_set(AmZRTP::zrtp_global, &_zid1, &_zid2, 0)) {
235
+    DBG("zrtp_verified_set failed\n");
236
+    sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
237
+    sc_sess->SET_STRERROR("zrtp_verified_set failed");
238
+  }
239
+} EXEC_ACTION_END;
240
+
241
+EXEC_ACTION_START(ZRTPSetSignalingHash) {
242
+  string h = resolveVars(arg, sess, sc_sess, event_params);
243
+  DBG("setting signaling hash to '%s'\n", h.c_str());
244
+
245
+  if (NULL == sess->zrtp_session_state.zrtp_audio) {
246
+    WARN("ZRTP not active on that stream\n");
247
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
248
+    sc_sess->SET_STRERROR("ZRTP not active on that stream");
249
+    EXEC_ACTION_STOP;
250
+  }
251
+  
252
+  if (zrtp_status_ok != zrtp_signaling_hash_set(sess->zrtp_session_state.zrtp_audio,
253
+						h.c_str(), h.length())) {
254
+    DBG("zrtp_signaling_hash_set failed\n");
255
+    sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
256
+    sc_sess->SET_STRERROR("zrtp_signaling_hash_set failed");
257
+  }
258
+} EXEC_ACTION_END;
259
+
260
+EXEC_ACTION_START(ZRTPGetSignalingHash) {
261
+  string varname = arg;
262
+  if (varname.size() && varname[0]=='$') varname = varname.substr(1);
263
+
264
+  if (NULL == sess->zrtp_session_state.zrtp_audio) {
265
+    WARN("ZRTP not active on that stream\n");
266
+    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
267
+    sc_sess->SET_STRERROR("ZRTP not active on that stream");
268
+    EXEC_ACTION_STOP;
269
+  }
270
+
271
+  char b[ZRTP_SIGN_ZRTP_HASH_LENGTH];
272
+  memset(b, 0, sizeof(b));
273
+  if (zrtp_status_ok != zrtp_signaling_hash_get(sess->zrtp_session_state.zrtp_audio,
274
+						b, ZRTP_SIGN_ZRTP_HASH_LENGTH)) {
275
+    DBG("zrtp_signaling_hash_get failed\n");
276
+    sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
277
+    sc_sess->SET_STRERROR("zrtp_signaling_hash_get failed");
278
+  }
279
+  sc_sess->var[varname] = string(b);
280
+  DBG("got signaling hash '%s'\n", b);
281
+} EXEC_ACTION_END;
282
+
283
+#endif
... ...
@@ -1,6 +1,8 @@
1 1
 /*
2 2
  * Copyright (C) 2014 Stefan Sayer
3 3
  *
4
+ * Parts of the development of this module was kindly sponsored by AMTEL Inc.
5
+ *
4 6
  * This file is part of SEMS, a free SIP media server.
5 7
  *
6 8
  * SEMS is free software; you can redistribute it and/or modify
... ...
@@ -35,6 +37,15 @@ DECLARE_MODULE_END;
35 35
 
36 36
 #ifdef WITH_ZRTP
37 37
 DEF_ACTION_1P(ZRTPSetEnabledAction);
38
+DEF_ACTION_1P(ZRTPSetAllowclearAction);
39
+DEF_ACTION_1P(ZRTPSetAutosecureAction);
40
+DEF_ACTION_1P(ZRTPSetDisclosebitAction);
41
+DEF_ACTION_2P(ZRTPGetSASAction);
42
+DEF_ACTION_1P(ZRTPGetSessionInfoAction);
43
+DEF_ACTION_2P(ZRTPSetVerifiedAction);
44
+DEF_ACTION_2P(ZRTPSetUnverifiedAction);
45
+DEF_ACTION_1P(ZRTPSetSignalingHash);
46
+DEF_ACTION_1P(ZRTPGetSignalingHash);
38 47
 #endif // WITH_ZRTP
39 48
 
40 49
 #endif
... ...
@@ -45,7 +45,7 @@ AmMutex AmZRTP::zrtp_cache_mut;
45 45
 
46 46
 zrtp_global_t* AmZRTP::zrtp_global;      // persistent storage for libzrtp data
47 47
 zrtp_config_t AmZRTP::zrtp_config;
48
-zrtp_zid_t AmZRTP::zrtp_instance_zid = {"defaultsems"}; // todo: generate one?
48
+zrtp_zid_t AmZRTP::zrtp_instance_zid = {"defaultsems"};
49 49
 
50 50
 void zrtp_log(int level, char *data, int len, int offset) {
51 51
   int sems_lvl = L_DBG;
... ...
@@ -38,9 +38,6 @@
38 38
 
39 39
 class AmSession;
40 40
 
41
-extern zrtp_global_t zrtp_global;      // persistent storage for libzrtp data
42
-extern zrtp_zid_t zrtp_instance_zid;
43
-
44 41
 struct AmZRTPSecurityEvent : public AmEvent {
45 42
   zrtp_stream_t* stream_ctx;
46 43
  AmZRTPSecurityEvent(int event_id, zrtp_stream_t* stream_ctx)
... ...
@@ -90,7 +87,6 @@ struct AmZRTPSessionState {
90 90
 const char* zrtp_protocol_event_desc(zrtp_protocol_event_t e);
91 91
 const char* zrtp_security_event_desc(zrtp_security_event_t e);
92 92
 
93
- 
94 93
 #if defined(__cplusplus)
95 94
 extern "C" {
96 95
 #endif
97 96
new file mode 100644
... ...
@@ -0,0 +1,82 @@
0
+
1
+ZRTP support module
2
+
3
+(C) 2014 Stefan Sayer.  Parts of the development of this module was kindly sponsored by AMTEL Inc.
4
+
5
+If SEMS is built with ZRTP support, a module mod_zrtp is created.
6
+
7
+ZRTP may be individually enabled or disabled and configured in the DSM script by using
8
+zrtp.setEnabled in the start event, for example
9
+   import(mod_zrtp);
10
+   initial state START;
11
+   transition "start" START - start / {
12
+    zrtp.setEnabled(false);
13
+-- or, e.g.: zrtp.setAllowclear(false);
14
+   } -> sess_started;
15
+   state sess_started;
16
+
17
+This overrides the sems.conf enable_zrtp setting. 
18
+
19
+NOTE: The setEnabled/setAllowclear/... actions have only effect in the start event!
20
+
21
+ZRTP specific events can be used in DSM if $enable_zrtp_events is set to true:
22
+  set($enable_zrtp_events=true); 
23
+Then the zrtp.protocolEvent and zrtp.securityEvent can be handled specifically.
24
+
25
+Actions
26
+-------
27
+zrtp.setEnabled(bool enabled)
28
+  e.g. zrtp.setEnabled(true) or zrtp.setEnabled(false)
29
+
30
+zrtp.setAllowclear(bool enabled)  - set ZRTP allowclear option, see ZRTP documentation
31
+zrtp.setAutosecure(bool enabled)  - set ZRTP autosecure option, see ZRTP documentation
32
+zrtp.setDisclosebit(bool enabled) - set ZRTP disclose_bit option, see ZRTP documentation
33
+
34
+zrtp.getSAS(sas1_var,sas2_var) - get SAS strings
35
+ to be used after the stream has gone secure, e.g. 
36
+  transition "ZRTP event IS_SECURE" sess_started - zrtp.protocolEvent(#event==ZRTP_EVENT_IS_SECURE) / {
37
+     zrtp.getSAS($sas1,$sas2);
38
+     log(3, $sas1);
39
+     log(3, $sas2);
40
+   } -> sess_started;
41
+
42
+zrtp.getSessionInfo(varname) - get info about the session
43
+  varname.sas_is_ready, varname.sas1, varname.sas2, varname.zid, varname.peer_zid, ...
44
+
45
+
46
+zrtp.setVerified(string zid1, string zid2)   - set as verified
47
+zrtp.setUnverified(string zid1, string zid2) - set as unverified
48
+
49
+ e.g.  zrtp.getSessionInfo(zrtp);
50
+       zrtp.setVerified($zrtp.zid,$zrtp.peer_zid);
51
+
52
+Events
53
+------
54
+
55
+zrtp.protocolEvent - protocol event happened, only if enable_zrtp_events==true
56
+ e.g. 
57
+  zrtp.protocolEvent(#event==ZRTP_EVENT_IS_SECURE)
58
+
59
+  #event    - event type
60
+  #event_id - numeric event type (should not be used)
61
+ 
62
+ see the libzrtp documentation, or /usr/include/libzrtp/zrtp_iface.h for
63
+ event types. Important ones are
64
+   ZRTP_EVENT_IS_SECURE, ZRTP_EVENT_NO_ZRTP, ZRTP_EVENT_IS_SECURE_DONE,
65
+   ZRTP_EVENT_IS_CLEAR, ZRTP_EVENT_IS_PENDINGSECURE, 
66
+
67
+  e.g. 
68
+    transition "ZRTP event" sess_started - zrtp.protocolEvent / {
69
+      logParams(3);
70
+    } -> sess_started;
71
+
72
+zrtp.securityEvent - security event happened, only if enable_zrtp_events==true
73
+ e.g. 
74
+  zrtp.securityEvent(#event==ZRTP_EVENT_PROTOCOL_ERROR)
75
+
76
+  #event    - event type
77
+  #event_id - numeric event type (should not be used)
78
+
79
+  ZRTP_EVENT_PROTOCOL_ERROR, ZRTP_EVENT_WRONG_SIGNALING_HASH, ZRTP_EVENT_WRONG_MESSAGE_HMAC,
80
+  ZRTP_EVENT_MITM_WARNING
81
+       
... ...
@@ -16,7 +16,8 @@
16 16
  *  <a href="http://www.ietf.org/rfc/rfc3711.txt">SRTP</a>.
17 17
  *
18 18
  *  <p>ZRTP is one of the most widely (if not the most widely) supported end-to-end encryption methods for VoIP. 
19
- *  Popular SIP clients that support ZRTP are <a href="http://www.jitsi.org">Jitsi</a>, CSipSimple, Twinkle, Linphone.</p>
19
+ *  Popular SIP clients that support ZRTP are <a href="http://www.jitsi.org">Jitsi</a>, 
20
+   <a href="http://www.creytiv.com/baresip.html">baresip</a>, CSipSimple, Twinkle, Linphone.</p>
20 21
  * 
21 22
  *  <p>For more information about ZRTP, see the 
22 23
  *  <a href="http://zfoneproject.com/">Zfone project</a>, the 
... ...
@@ -46,7 +47,8 @@
46 46
     which can be found in doc/dsm/examples/b2b_connect_audio.
47 47
   </p>
48 48
 
49
-  <p> There is support for some utility functions in a DSM module (see \ref dsm_mod_zrtp). </p>
49
+  <p> There is support for some utility functions in a DSM module (see \ref dsm_mod_zrtp). 
50
+  </p>
50 51
 
51 52
  *  <p>The <em>conference</em> application is enabled to tell the caller the SAS phrase
52 53
  *  if it is compiled with WITH_SAS_TTS option, set in apps/conference/Makefile. For this to work,
... ...
@@ -54,7 +56,8 @@
54 54
  *  
55 55
  *  \section zinyourapp How to use ZRTP in your application 
56 56
  *
57
- *  Have a look at the dsm or the conference application on how to add ZRTP support in your application. There is a 
57
+ *  Have a look at the dsm module mod_zrtp for examples   
58
+or the conference application on how to add ZRTP support in your application. There is a 
58 59
  *  <code>void AmSession::onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx)</code> 
59 60
  *  event that is called with the appropriate ZRTP event type and the zrtp stream context, if the state
60 61
  *  of the ZRTP encryption changes. The zrtp_event are defined in the Zfone SDK, e.g. ZRTP_EVENT_IS_SECURE.