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