blob: 34065c44b8f5e1ee4b1327ad83e2eb3fc4ee324c [file] [log] [blame]
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -05001/*
2 * Test program for tivi interface
3 */
4#include <stdio.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <errno.h>
8#include <string.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11
12#include <CtZrtpSession.h>
13#include <CtZrtpCallback.h>
14#include <libzrtpcpp/ZrtpSdesStream.h>
15
16
17static void hexdump(const char* title, const unsigned char *s, int l)
18{
19 int n=0;
20
21 if (s == NULL) return;
22
23 fprintf(stderr, "%s",title);
24 for( ; n < l ; ++n) {
25 if((n%16) == 0)
26 fprintf(stderr, "\n%04x",n);
27 fprintf(stderr, " %02x",s[n]);
28 }
29 fprintf(stderr, "\n");
30}
31
32static bool verbose = false;
33// static bool verbose = true;
34
35// This is the callback that we use for audio stream
36class TestCallbackAudio: public CtZrtpCb {
37 void onNewZrtpStatus(CtZrtpSession *session, char *p, CtZrtpSession::streamName streamNm) {
38 if (!verbose)
39 return;
40
41 fprintf(stderr, "new status: %s\n", p == NULL ? "NULL" : p);
42 if (session->isSecure(streamNm)) {
43 uint8_t buffer[20];
44
45 session->getInfo("rs1", buffer, 9);
46 printf("RS1: %s ", buffer);
47
48 session->getInfo("rs2", buffer, 9);
49 printf("RS2: %s ", buffer);
50
51 session->getInfo("pbx", buffer, 9);
52 printf("PBX: %s ", buffer);
53
54 session->getInfo("aux", buffer, 9);
55 printf("AUX: %s\n", buffer);
56
57 session->getInfo("lbClient", buffer, 19);
58 printf("Client: %s ", buffer);
59
60 session->getInfo("lbVersion", buffer, 19);
61 printf("Version: %s ", buffer);
62
63 session->getInfo("lbChiper", buffer, 19);
64 printf("cipher: %s ", buffer);
65
66 session->getInfo("lbHash", buffer, 19);
67 printf("hash: %s ", buffer);
68
69 session->getInfo("lbAuthTag", buffer, 19);
70 printf("auth: %s ", buffer);
71
72 session->getInfo("lbKeyExchange", buffer, 19);
73 printf("KeyEx: %s\n", buffer);
74 }
75 }
76
77 void onNeedEnroll(CtZrtpSession *session, CtZrtpSession::streamName streamNm, int32_t info) {
78 fprintf(stderr, "Need enroll\n");
79 }
80
81 void onPeer(CtZrtpSession *session, char *name, int iIsVerified, CtZrtpSession::streamName streamNm) {
82 fprintf(stderr, "onPeer: %s\n", name == NULL ? "NULL" : name);
83 }
84
85 void onZrtpWarning(CtZrtpSession *session, char *p, CtZrtpSession::streamName streamNm) {
86 fprintf(stderr, "Warning: %s\n", p == NULL ? "NULL" : p);
87 }
88
89};
90
91class TestSendCallbackAudio: public CtZrtpSendCb {
92 void sendRtp(CtZrtpSession const *session, uint8_t* packet, size_t length, CtZrtpSession::streamName streamNm) {
93 if (!verbose)
94 return;
95// hexdump("ZRTP packet", packet, length);
96 fprintf(stderr, "ZRTP send packet, length: %lu\n", length);
97 }
98};
99
100// V2 | PT | seqnum | timestamp | SSRC |
101uint8_t inviterPacket[] = {
102 0x80, 0x03, 0x47, 0x11, 0x01, 0x01, 0x01, 0x01, 0xfe, 0xed, 0xba, 0xac, // Header
103 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20};
104
105uint8_t answererPacket[] = {
106 0x80, 0x03, 0x08, 0x11, 0x02, 0x02, 0x02, 0x02, 0xba, 0xac, 0xed, 0xfe, // Header
107 0x20, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11};
108
109uint8_t inviterPacket_fixed[] = {
110 0x80, 0x03, 0x47, 0x11, 0x01, 0x01, 0x01, 0x01, 0xfe, 0xed, 0xba, 0xac, // Header
111 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20};
112
113uint8_t answererPacket_fixed[] = {
114 0x80, 0x03, 0x08, 0x11, 0x02, 0x02, 0x02, 0x02, 0xba, 0xac, 0xed, 0xfe, // Header
115 0x20, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11};
116
117
118static bool testBasicMix()
119{
120 char buffer[200];
121
122 ZrtpSdesStream sdes;
123
124 int rc = sdes.getCryptoMixAttribute(buffer, sizeof(buffer));
125 if (rc == 0) {
126 fprintf(stderr, "testBasicMix: Get mix is zero\n");
127 return false;
128 }
129 if (verbose)
130 fprintf(stderr, "testBasicMix: algorithms on first get: %s\n", buffer);
131
132 if (sdes.setCryptoMixAttribute("")) {
133 fprintf(stderr, "testBasicMix: Testing empty mix returned true, expecting false\n");
134 return false;
135 }
136 if (!sdes.setCryptoMixAttribute("HMAC-SHA-384")) {
137 fprintf(stderr, "testBasicMix: Testing one valid algo returned false, expecting true\n");
138 return false;
139 }
140 if (!sdes.setCryptoMixAttribute("BABAB HMAC-SHA-384 XYZABC")) {
141 fprintf(stderr, "testBasicMix: Testing invalid/valid returned false, expecting true\n");
142 return false;
143 }
144 if (sdes.setCryptoMixAttribute("BABAB XYZABC")) {
145 fprintf(stderr, "testBasicMix: Testing invalid returned true, expecting false\n");
146 return false;
147 }
148 // set a valid algorithms that we can check on the next get
149 sdes.setCryptoMixAttribute("BABAB HMAC-SHA-384 XYZABC");
150
151 rc = sdes.getCryptoMixAttribute(buffer, sizeof(buffer));
152 int len = strlen("HMAC-SHA-384");
153 if (rc != len) {
154 fprintf(stderr, "testBasicMix: get final mix algo returned wrong length, expected: %d, got: %d\n", len, rc);
155 return false;
156 }
157 if (strcmp(buffer, "HMAC-SHA-384") != 0) {
158 fprintf(stderr, "testBasicMix: get final mix algo returned wrong algorithm, expected:\n'HMAC-SHA-384', got: '%s'\n", buffer);
159 return false;
160 }
161 printf("PASSED - basic mix test\n");
162 return true;
163}
164
165static bool testNormalSdes()
166{
167 size_t invLength, answLength;
168 char invBuffer[200];
169 char answBuffer[200];
170
171 TestCallbackAudio *callback = new TestCallbackAudio();
172 TestSendCallbackAudio *sendCallback = new TestSendCallbackAudio();
173
174 // The Inviter session (offerer)
175 CtZrtpSession *inviter = new CtZrtpSession();
176 inviter->init(true, true); // audio and video
177 inviter->setUserCallback(callback, CtZrtpSession::AudioStream);
178 inviter->setSendCallback(sendCallback, CtZrtpSession::AudioStream);
179
180 // The answerer session
181 CtZrtpSession *answerer = new CtZrtpSession();
182 answerer->init(true, true); // audio and video
183 answerer->setSendCallback(sendCallback, CtZrtpSession::AudioStream);
184
185 // Inviter first step: create a SDES crypto string
186 invLength = sizeof(invBuffer);
187 inviter->createSdes(invBuffer, &invLength, CtZrtpSession::AudioStream);
188 if (invLength != 73) {
189 fprintf(stderr, "testNormalSdes: Inviter: SDES crypto string wrong size: got: %d, expected: 73\n%s\n", (int)invLength, invBuffer);
190 return false;
191 }
192
193 // ****
194 // Now send the Inviter SDES crypto string to the answerer via SIP INVITE ........
195 // ****
196
197
198 // answerer first step: parse the SDES crypto string and the answerer SDES creates onw crypto string
199 answLength = sizeof(answBuffer);
200 answerer->parseSdes(invBuffer, invLength, NULL, NULL, false, CtZrtpSession::AudioStream);
201
202 // answerer second step: get the generated SDES crypto string
203 answerer->getSavedSdes(answBuffer, &answLength, CtZrtpSession::AudioStream);
204 if (answLength != 73) {
205 fprintf(stderr, "testNormalSdes: Answerer: SDES crypto string wrong size: got: %d, expected: 73\n%s\n", (int)answLength, answBuffer);
206 return false;
207 }
208
209 // Send the answerer SDES crypto string and crypto mixer algorithms back to Inviter, via 200 OK probably
210
211 // Inviter second step: parses answerer's string, sets the "sipInvite" parameter to true
212 inviter->parseSdes(answBuffer, answLength, NULL, NULL, true, CtZrtpSession::AudioStream);
213 inviter->start(0xfeedbac, CtZrtpSession::AudioStream); // start this stream to get a send callback
214
215
216 invLength = 0;
217 inviter->processOutoingRtp(inviterPacket, sizeof(inviterPacket), &invLength, CtZrtpSession::AudioStream);
218// hexdump("Inviter packet protected", inviterPacket, invLength);
219
220 answLength = 0;
221 answerer->processIncomingRtp(inviterPacket, invLength, &answLength, CtZrtpSession::AudioStream);
222 if (memcmp(inviterPacket, inviterPacket_fixed, answLength) != 0) {
223 hexdump("testNormalSdes: Inviter packet unprotected by answerer does not match original data", inviterPacket, answLength);
224 return false;
225 }
226
227 answLength = 0;
228 answerer->processOutoingRtp(answererPacket, sizeof(answererPacket), &answLength, CtZrtpSession::AudioStream);
229// hexdump("Answerer packet protected", answererPacket, answLength);
230
231 invLength = 0;
232 inviter->processIncomingRtp(answererPacket, answLength, &invLength, CtZrtpSession::AudioStream);
233 if (memcmp(answererPacket, answererPacket_fixed, invLength) != 0) {
234 hexdump("testNormalSdes: Answerer packet unprotected by inviter does not match original data", answererPacket, invLength);
235 return false;
236 }
237 delete inviter;
238 delete answerer;
239 delete callback;
240 delete sendCallback;
241
242 printf("PASSED - normal SDES\n");
243 return true;
244
245}
246
247static bool testWithMix()
248{
249 size_t invLength, answLength;
250 char invBuffer[200];
251 char answBuffer[200];
252
253 char invMixBuffer[200];
254 char answMixBuffer[200];
255
256 TestCallbackAudio *callback = new TestCallbackAudio();
257 TestSendCallbackAudio *sendCallback = new TestSendCallbackAudio();
258
259 // The Inviter session (offerer)
260 CtZrtpSession *inviter = new CtZrtpSession();
261 inviter->init(true, true); // audio and video
262 inviter->setUserCallback(callback, CtZrtpSession::AudioStream);
263 inviter->setSendCallback(sendCallback, CtZrtpSession::AudioStream);
264
265 // The answerer session
266 CtZrtpSession *answerer = new CtZrtpSession();
267 answerer->init(true, true); // audio and video
268 answerer->setSendCallback(sendCallback, CtZrtpSession::AudioStream);
269
270 // Inviter first step: create a SDES crypto string
271 invLength = sizeof(invBuffer);
272 inviter->createSdes(invBuffer, &invLength, CtZrtpSession::AudioStream);
273 if (invLength != 73) {
274 fprintf(stderr, "testWithMix: Inviter: SDES crypto string wrong size: got: %d, expected: 73\n%s\n", (int)invLength, invBuffer);
275 return false;
276 }
277 // Inviter second step: Get all available SDES crypto mix algorithms as nul terminated string
278 int invMixLength = sizeof(invMixBuffer);
279 invMixLength = inviter->getCryptoMixAttribute(invMixBuffer, invMixLength, CtZrtpSession::AudioStream);
280 if (invMixLength == 0) {
281 fprintf(stderr, "testWithMix: Inviter: SDES crypto mixer algorithm returned zero\n");
282 return false;
283 }
284
285 // ****
286 // Now send the Inviter SDES crypto string and the mixer algo string to the answerer via SIP INVITE ........
287 // ****
288
289 // answerer first step: set the crypto mix algorithms, the answerer selects one of it
290 answerer->setCryptoMixAttribute(invMixBuffer, CtZrtpSession::AudioStream);
291
292 // answerer second step: get the seleted crypto mixer algorithm
293 int answMixLength = sizeof(answMixBuffer);
294 answMixLength = answerer->getCryptoMixAttribute(answMixBuffer, answMixLength, CtZrtpSession::AudioStream);
295 if (answMixLength == 0) {
296 fprintf(stderr, "testWithMix: Answerer: SDES crypto mixer algorithm returned zero\n");
297 return false;
298 }
299
300 // answerer third step: parse the SDES crypto string and the answere SDES creates onw crypto string
301 answLength = sizeof(answBuffer);
302 answerer->parseSdes(invBuffer, invLength, NULL, NULL, false, CtZrtpSession::AudioStream);
303
304 // answerer fourth step: get the generated SDES crypto string
305 answerer->getSavedSdes(answBuffer, &answLength, CtZrtpSession::AudioStream);
306 if (answLength != 73) {
307 fprintf(stderr, "testWithMix: Answerer: SDES crypto string wrong size: got: %d, expected: 73\n%s\n", (int)answLength, answBuffer);
308 return false;
309 }
310 // additional test: get the seleted crypto mixer algorithm again after parse and check.
311 answMixLength = sizeof(answMixBuffer);
312 answMixLength = answerer->getCryptoMixAttribute(answMixBuffer, answMixLength, CtZrtpSession::AudioStream);
313 if (answMixLength == 0) {
314 fprintf(stderr, "testWithMix: Answerer: SDES crypto mixer algorithm returned zero at second call\n");
315 return false;
316 }
317
318 // Send the answerer SDES crypto string and crypto mixer algorithms back to Inviter, via 200 OK probably
319
320 // Inviter third step: set the received (it's one only) crypto mix algorithm
321 inviter->setCryptoMixAttribute(answMixBuffer, CtZrtpSession::AudioStream);
322
323 // Inviter fourth step: parses answerer's string, sets the "sipInvite" parameter to true
324 inviter->parseSdes(answBuffer, answLength, NULL, NULL, true, CtZrtpSession::AudioStream);
325 inviter->start(0xfeedbac, CtZrtpSession::AudioStream); // start this stream to get a send callback
326
327
328 invLength = 0;
329 inviter->processOutoingRtp(inviterPacket, sizeof(inviterPacket), &invLength, CtZrtpSession::AudioStream);
330// hexdump("Inviter packet protected", inviterPacket, invLength);
331
332 answLength = 0;
333 answerer->processIncomingRtp(inviterPacket, invLength, &answLength, CtZrtpSession::AudioStream);
334 if (memcmp(inviterPacket, inviterPacket_fixed, answLength) != 0) {
335 hexdump("testWithMix: Inviter packet unprotected by answerer does not match original data", inviterPacket, answLength);
336 return false;
337 }
338
339 answLength = 0;
340 answerer->processOutoingRtp(answererPacket, sizeof(answererPacket), &answLength, CtZrtpSession::AudioStream);
341// hexdump("Answerer packet protected", answererPacket, answLength);
342
343 invLength = 0;
344 inviter->processIncomingRtp(answererPacket, answLength, &invLength, CtZrtpSession::AudioStream);
345 if (memcmp(answererPacket, answererPacket_fixed, invLength) != 0) {
346 hexdump("testWithMix: Answerer packet unprotected by inviter does not match original data", answererPacket, invLength);
347 return false;
348 }
349 delete inviter;
350 delete answerer;
351 delete callback;
352 delete sendCallback;
353
354 printf("PASSED - with SDES Mix\n");
355 return true;
356
357}
358
359int main(int argc,char **argv)
360{
361 CtZrtpSession::initCache("testzidSdes.dat"); // initialize global cache file
362
363 if (!testNormalSdes()) {
364 fprintf(stderr, "SDES crypto test failed\n");
365 return 1;
366 }
367 if (!testBasicMix()) {
368 fprintf(stderr, "Basic crypto mixing test failed\n");
369 return 1;
370 }
371 if (!testWithMix()) {
372 fprintf(stderr, "SDES crypto mixing test failed\n");
373 return 1;
374 }
375 return 0;
376}
377
378
379
380
381
382
383
384
385
386
387
388
389