blob: 71775f6b04bf9d38ae95a7d47c3a5e99a74bee37 [file] [log] [blame]
Benny Prijonofb9d9872007-03-21 22:05:58 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
Benny Prijonoe2d0acb2007-09-18 19:33:33 +000019#include "test.h"
20
21#define THIS_FILE "stun.c"
22
23static pj_stun_msg* create1(pj_pool_t*);
24static int verify1(pj_stun_msg*);
25static int verify2(pj_stun_msg*);
26static int verify5(pj_stun_msg*);
27
28static struct test
29{
30 const char *title;
31 char *pdu;
32 unsigned pdu_len;
33 pj_stun_msg* (*create)(pj_pool_t*);
34 pj_status_t expected_status;
35 int (*verify)(pj_stun_msg*);
36} tests[] =
37{
38 {
39 "Invalid message type",
40 "\x11\x01\x00\x00\x21\x12\xa4\x42"
41 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
42 20,
43 NULL,
44 PJNATH_EINSTUNMSGTYPE,
45 NULL
46 },
47 {
48 "Short message (1) (partial header)",
49 "\x00\x01",
50 2,
51 NULL,
52 PJNATH_EINSTUNMSGLEN,
53 NULL
54 },
55 {
56 "Short message (2) (partial header)",
57 "\x00\x01\x00\x00\x21\x12\xa4\x42"
58 "\x00\x00\x00\x00\x00\x00\x00\x00",
59 16,
60 NULL,
61 PJNATH_EINSTUNMSGLEN,
62 NULL
63 },
64 {
65 "Short message (3), (missing attribute)",
66 "\x00\x01\x00\x08\x21\x12\xa4\x42"
67 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
68 20,
69 NULL,
70 PJNATH_EINSTUNMSGLEN,
71 NULL
72 },
73 {
74 "Short message (4), (partial attribute header)",
75 "\x00\x01\x00\x08\x21\x12\xa4\x42"
76 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
77 "\x80\x28",
78 22,
79 NULL,
80 PJNATH_EINSTUNMSGLEN,
81 NULL
82 },
83 {
84 "Short message (5), (partial attribute header)",
85 "\x00\x01\x00\x08\x21\x12\xa4\x42"
86 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
87 "\x80\x28\x00",
88 23,
89 NULL,
90 PJNATH_EINSTUNMSGLEN,
91 NULL
92 },
93 {
94 "Short message (6), (partial attribute header)",
95 "\x00\x01\x00\x08\x21\x12\xa4\x42"
96 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
97 "\x80\x28\x00\x04",
98 24,
99 NULL,
100 PJNATH_EINSTUNMSGLEN,
101 NULL
102 },
103 {
104 "Short message (7), (partial attribute body)",
105 "\x00\x01\x00\x08\x21\x12\xa4\x42"
106 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
107 "\x80\x28\x00\x04\x00\x00\x00",
108 27,
109 NULL,
110 PJNATH_EINSTUNMSGLEN,
111 NULL
112 },
113 {
114 "Message length in header is too long",
115 "\x00\x01\xff\xff\x21\x12\xa4\x42"
116 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
117 "\x80\x28\x00\x04\x00\x00\x00",
118 27,
119 NULL,
120 PJNATH_EINSTUNMSGLEN,
121 NULL
122 },
123 {
124 "Message length in header is shorter",
125 "\x00\x01\x00\x04\x21\x12\xa4\x42"
126 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
127 "\x80\x28\x00\x04\x00\x00\x00\x00",
128 28,
129 NULL,
130 PJNATH_EINSTUNMSGLEN,
131 NULL
132 },
133 {
134 "Invalid magic",
135 "\x00\x01\x00\x08\x00\x12\xa4\x42"
136 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
137 "\x80\x28\x00\x04\x00\x00\x00\x00",
138 28,
139 NULL,
140 PJ_SUCCESS,
141 NULL
142 },
143 {
144 "Character beyond message",
145 "\x00\x01\x00\x08\x21\x12\xa4\x42"
146 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
147 "\x80\x28\x00\x04\x00\x00\x00\x00\x0a",
148 29,
149 NULL,
150 PJNATH_EINSTUNMSGLEN,
151 NULL
152 },
153 {
154 "Respond unknown mandatory attribute with 420 and "
155 "UNKNOWN-ATTRIBUTES attribute",
156 NULL,
157 0,
158 &create1,
159 0,
160 &verify1
161 },
162 {
163 "Unknown but non-mandatory should be okay",
164 "\x00\x01\x00\x08\x21\x12\xa4\x42"
165 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
Benny Prijono7ce74132008-06-21 12:36:56 +0000166 "\x80\xff\x00\x03\x00\x00\x00\x00",
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000167 28,
168 NULL,
169 PJ_SUCCESS,
170 &verify2
171 },
172 {
173 "String attr length larger than message",
174 "\x00\x01\x00\x08\x00\x12\xa4\x42"
175 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
176 "\x00\x06\x00\xff\x00\x00\x00\x00",
177 28,
178 NULL,
179 PJNATH_ESTUNINATTRLEN,
180 NULL
181 },
182 {
183 "Attribute other than FINGERPRINT after MESSAGE-INTEGRITY is allowed",
184 "\x00\x01\x00\x20\x21\x12\xa4\x42"
185 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
186 "\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
187 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
188 "\x80\x24\x00\x04\x00\x00\x00\x00", // REFRESH-INTERVAL
189 52,
190 NULL,
191 PJ_SUCCESS,
192 NULL
193 },
194 {
195 "Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed",
196 "\x00\x01\x00\x28\x21\x12\xa4\x42"
197 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
198 "\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
199 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
200 "\x80\x24\x00\x04\x00\x00\x00\x00" // REFRESH-INTERVAL
201 "\x80\x28\x00\x04\xc7\xde\xdd\x65", // FINGERPRINT
202 60,
203 NULL,
204 PJ_SUCCESS,
205 &verify5
206 },
207 {
208 "Attribute past FINGERPRINT is not allowed",
209 "\x00\x01\x00\x10\x21\x12\xa4\x42"
210 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
211 "\x80\x28\x00\x04\x00\x00\x00\x00"
212 "\x80\x24\x00\x04\x00\x00\x00\x00",
213 36,
214 NULL,
215 PJNATH_ESTUNFINGERPOS,
216 NULL
217 }
218};
219
220static const char *err(pj_status_t status)
221{
222 static char errmsg[PJ_ERR_MSG_SIZE];
223 pj_strerror(status, errmsg, sizeof(errmsg));
224 return errmsg;
225}
226
227static const pj_str_t USERNAME = {"user", 4};
228static const pj_str_t PASSWORD = {"password", 8};
Benny Prijonofb9d9872007-03-21 22:05:58 +0000229
230static int decode_test(void)
231{
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000232 unsigned i;
233 pj_pool_t *pool;
234 int rc = 0;
235
236 pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL);
Benny Prijonofb9d9872007-03-21 22:05:58 +0000237
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000238 PJ_LOG(3,(THIS_FILE, " STUN decode test"));
Benny Prijonofb9d9872007-03-21 22:05:58 +0000239
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000240 for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
241 struct test *t = &tests[i];
242 pj_stun_msg *msg, *msg2;
243 pj_uint8_t buf[1500];
244 pj_str_t key;
245 unsigned len;
246 pj_status_t status;
Benny Prijonofb9d9872007-03-21 22:05:58 +0000247
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000248 PJ_LOG(3,(THIS_FILE, " %s", t->title));
Benny Prijonofb9d9872007-03-21 22:05:58 +0000249
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000250 if (t->pdu) {
251 status = pj_stun_msg_decode(pool, (pj_uint8_t*)t->pdu, t->pdu_len,
252 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
253 &msg, NULL, NULL);
Benny Prijonofb9d9872007-03-21 22:05:58 +0000254
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000255 /* Check expected decode result */
256 if (t->expected_status != status) {
257 PJ_LOG(1,(THIS_FILE, " expecting status %d, got %d",
258 t->expected_status, status));
259 rc = -10;
260 goto on_return;
261 }
Benny Prijonofb9d9872007-03-21 22:05:58 +0000262
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000263 } else {
264 msg = t->create(pool);
265 status = PJ_SUCCESS;
266 }
Benny Prijonofb9d9872007-03-21 22:05:58 +0000267
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000268 if (status != PJ_SUCCESS)
269 continue;
Benny Prijonofb9d9872007-03-21 22:05:58 +0000270
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000271 /* Try to encode message */
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000272 pj_stun_create_key(pool, &key, NULL, &USERNAME, PJ_STUN_PASSWD_PLAIN, &PASSWORD);
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000273 status = pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
274 if (status != PJ_SUCCESS) {
275 PJ_LOG(1,(THIS_FILE, " encode error: %s", err(status)));
276 rc = -40;
277 goto on_return;
278 }
Benny Prijonofb9d9872007-03-21 22:05:58 +0000279
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000280 /* Try to decode it once more */
281 status = pj_stun_msg_decode(pool, buf, len,
282 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
283 &msg2, NULL, NULL);
284 if (status != PJ_SUCCESS) {
285 PJ_LOG(1,(THIS_FILE, " subsequent decoding failed: %s", err(status)));
286 rc = -50;
287 goto on_return;
288 }
Benny Prijonofb9d9872007-03-21 22:05:58 +0000289
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000290 /* Verify */
291 if (t->verify) {
292 rc = t->verify(msg);
293 if (rc != 0) {
294 goto on_return;
295 }
296 }
297 }
Benny Prijonofb9d9872007-03-21 22:05:58 +0000298
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000299on_return:
300 pj_pool_release(pool);
301 if (rc == 0)
302 PJ_LOG(3,(THIS_FILE, "...success!"));
303 return rc;
304}
Benny Prijonofb9d9872007-03-21 22:05:58 +0000305
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000306/* Create 420 response */
307static pj_stun_msg* create1(pj_pool_t *pool)
308{
309 char *pdu = "\x00\x01\x00\x08\x21\x12\xa4\x42"
310 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
311 "\x00\xff\x00\x04\x00\x00\x00\x00";
312 unsigned pdu_len = 28;
313 pj_stun_msg *msg, *res;
314 pj_status_t status;
Benny Prijonofb9d9872007-03-21 22:05:58 +0000315
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000316 status = pj_stun_msg_decode(pool, (pj_uint8_t*)pdu, pdu_len,
317 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
318 &msg, NULL, &res);
319 pj_assert(status != PJ_SUCCESS);
320 pj_assert(res != NULL);
Benny Prijonofb9d9872007-03-21 22:05:58 +0000321
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000322 return res;
323}
324
325/* Error response MUST have ERROR-CODE attribute */
326/* 420 response MUST contain UNKNOWN-ATTRIBUTES */
327static int verify1(pj_stun_msg *msg)
328{
329 pj_stun_errcode_attr *aerr;
330 pj_stun_unknown_attr *aunk;
331
332 if (!PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) {
333 PJ_LOG(1,(THIS_FILE, " expecting error message"));
334 return -100;
335 }
336
337 aerr = (pj_stun_errcode_attr*)
338 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
339 if (aerr == NULL) {
340 PJ_LOG(1,(THIS_FILE, " missing ERROR-CODE attribute"));
341 return -110;
342 }
343
344 if (aerr->err_code != 420) {
345 PJ_LOG(1,(THIS_FILE, " expecting 420 error"));
346 return -120;
347 }
348
349 aunk = (pj_stun_unknown_attr*)
350 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
351 if (aunk == NULL) {
352 PJ_LOG(1,(THIS_FILE, " missing UNKNOWN-ATTRIBUTE attribute"));
353 return -130;
354 }
355
356 if (aunk->attr_count != 1) {
357 PJ_LOG(1,(THIS_FILE, " expecting one unknown attribute"));
358 return -140;
359 }
360
361 if (aunk->attrs[0] != 0xff) {
362 PJ_LOG(1,(THIS_FILE, " expecting 0xff as unknown attribute"));
363 return -150;
364 }
Benny Prijonofb9d9872007-03-21 22:05:58 +0000365
366 return 0;
367}
368
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000369/* Attribute count should be zero since unknown attribute is not parsed */
370static int verify2(pj_stun_msg *msg)
371{
Benny Prijono7ce74132008-06-21 12:36:56 +0000372 pj_stun_binary_attr *bin_attr;
373
374 if (msg->attr_count != 1) {
375 PJ_LOG(1,(THIS_FILE, " expecting one attribute count"));
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000376 return -200;
377 }
Benny Prijono7ce74132008-06-21 12:36:56 +0000378
379 bin_attr = (pj_stun_binary_attr*)msg->attr[0];
380 if (bin_attr->hdr.type != 0x80ff) {
381 PJ_LOG(1,(THIS_FILE, " expecting attribute type 0x80ff"));
382 return -210;
383 }
384 if (bin_attr->hdr.length != 3) {
385 PJ_LOG(1,(THIS_FILE, " expecting attribute length = 4"));
386 return -220;
387 }
388 if (bin_attr->magic != PJ_STUN_MAGIC) {
389 PJ_LOG(1,(THIS_FILE, " expecting PJ_STUN_MAGIC for unknown attr"));
390 return -230;
391 }
392 if (bin_attr->length != 3) {
393 PJ_LOG(1,(THIS_FILE, " expecting data length 4"));
394 return -240;
395 }
396
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000397 return 0;
398}
399
400
401/* Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed */
402static int verify5(pj_stun_msg *msg)
403{
404 if (msg->attr_count != 3) {
405 PJ_LOG(1,(THIS_FILE, " expecting 3 attribute count"));
406 return -500;
407 }
408
409 if (msg->attr[0]->type != PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
410 PJ_LOG(1,(THIS_FILE, " expecting MESSAGE-INTEGRITY"));
411 return -510;
412 }
413 if (msg->attr[1]->type != PJ_STUN_ATTR_REFRESH_INTERVAL) {
414 PJ_LOG(1,(THIS_FILE, " expecting REFRESH-INTERVAL"));
415 return -520;
416 }
417 if (msg->attr[2]->type != PJ_STUN_ATTR_FINGERPRINT) {
418 PJ_LOG(1,(THIS_FILE, " expecting FINGERPRINT"));
419 return -530;
420 }
421
422 return 0;
423}
424
425
Benny Prijonofb9d9872007-03-21 22:05:58 +0000426static int decode_verify(void)
427{
428 /* Decode all attribute types */
429 return 0;
430}
431
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000432typedef struct test_vector test_vector;
433
434static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
435static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
436
437enum
438{
439 USE_MESSAGE_INTEGRITY = 1,
440 USE_FINGERPRINT = 2
441};
442
443struct test_vector
444{
445 unsigned msg_type;
446 char *tsx_id;
447 char *pdu;
448 unsigned pdu_len;
449 unsigned options;
450 char *username;
451 char *password;
452 pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
453} test_vectors[] =
454{
455 {
456 PJ_STUN_BINDING_REQUEST,
457 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
458 "\x00\x01\x00\x44\x21\x12\xa4\x42\xb7\xe7"
459 "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
460 "\x00\x24\x00\x04\x6e\x00\x01\xff\x80\x29"
461 "\x00\x08\x93\x2f\xf9\xb1\x51\x26\x3b\x36"
462 "\x00\x06\x00\x09\x65\x76\x74\x6a\x3a\x68"
463 "\x36\x76\x59\x20\x20\x20\x00\x08\x00\x14"
464 "\x62\x4e\xeb\xdc\x3c\xc9\x2d\xd8\x4b\x74"
465 "\xbf\x85\xd1\xc0\xf5\xde\x36\x87\xbd\x33"
466 "\x80\x28\x00\x04\xad\x8a\x85\xff",
467 88,
468 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
469 "evtj:h6vY",
470 "VOkJxbRl1RmTxUk/WvJxBt",
471 &create_msgint1
472 },
473 {
474 PJ_STUN_BINDING_RESPONSE,
475 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
476 "\x01\x01\x00\x3c\x21\x12\xa4\x42\xb7\xe7"
477 "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
478 "\x80\x22\x00\x0b\x74\x65\x73\x74\x20\x76"
479 "\x65\x63\x74\x6f\x72\x20\x00\x20\x00\x08"
480 "\x00\x01\xa1\x47\x5e\x12\xa4\x43\x00\x08"
481 "\x00\x14\xab\x4e\x53\x29\x61\x00\x08\x4c"
482 "\x89\xf2\x7c\x69\x30\x33\x5c\xa3\x58\x14"
483 "\xea\x90\x80\x28\x00\x04\xae\x25\x8d\xf2",
484 80,
485 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
486 "evtj:h6vY",
487 "VOkJxbRl1RmTxUk/WvJxBt",
488 &create_msgint2
489 }
490};
491
492
493static char* print_binary(const pj_uint8_t *data, unsigned data_len)
494{
495 static char buf[1500];
496 unsigned length = sizeof(buf);
497 char *p = buf;
498 unsigned i;
499
500 for (i=0; i<data_len;) {
501 unsigned j;
502
503 pj_ansi_snprintf(p, 1500-(p-buf),
504 "%04d-%04d ",
505 i, (i+20 < data_len) ? i+20 : data_len);
506 p += 12;
507
508 for (j=0; j<20 && i<data_len && p<(buf+length-10); ++j, ++i) {
509 pj_ansi_sprintf(p, "%02x ", (*data) & 0xFF);
510 p += 3;
511 data++;
512 }
513
514 pj_ansi_sprintf(p, "\n");
515 p++;
516 }
517
518 return buf;
519}
520
521static int cmp_buf(const pj_uint8_t *s1, const pj_uint8_t *s2, unsigned len)
522{
523 unsigned i;
524 for (i=0; i<len; ++i) {
525 if (s1[i] != s2[i])
526 return i;
527 }
528
529 return -1;
530}
531
532static int fingerprint_test_vector()
533{
534 pj_pool_t *pool;
535 pj_status_t status;
536 unsigned i;
537 int rc = 0;
538
539 PJ_LOG(3,(THIS_FILE, " STUN message test vectors"));
540
541 pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
542
543 for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) {
544 struct test_vector *v;
545 pj_stun_msg *ref_msg, *msg;
546 unsigned parsed_len;
547 unsigned len, pos;
548 pj_uint8_t buf[1500];
549 char print[1500];
550 pj_str_t key;
551
552 PJ_LOG(3,(THIS_FILE, " Running test %d/%d", i,
553 PJ_ARRAY_SIZE(test_vectors)));
554
555 v = &test_vectors[i];
556
557 /* Print reference message */
558 PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
559 print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));
560
561 /* Try to parse the reference message first */
562 status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
563 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
564 &ref_msg, &parsed_len, NULL);
565 if (status != PJ_SUCCESS) {
566 PJ_LOG(1,(THIS_FILE, " Error decoding reference message"));
567 rc = -1010;
568 goto on_return;
569 }
570
571 if (parsed_len != v->pdu_len) {
572 PJ_LOG(1,(THIS_FILE, " Parsed len error"));
573 rc = -1020;
574 goto on_return;
575 }
576
577 /* Print the reference message */
578 pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
579 PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));
580
581 /* Create our message */
582 msg = v->create(pool, v);
583
584 /* Encode message */
585 if (v->options & USE_MESSAGE_INTEGRITY) {
586 pj_str_t s1, s2;
587
588 pj_stun_create_key(pool, &key, NULL, pj_cstr(&s1, v->username),
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000589 PJ_STUN_PASSWD_PLAIN, pj_cstr(&s2, v->password));
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000590 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
591
592 } else {
593 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
594 }
595
596 /* Print our raw message */
597 PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
598 print_binary((pj_uint8_t*)buf, len)));
599
600 /* Print our message */
601 pj_stun_msg_dump(msg, print, sizeof(print), NULL);
602 PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));
603
604 /* Compare message length */
605 if (len != v->pdu_len) {
606 PJ_LOG(1,(THIS_FILE, " Message length mismatch"));
607 rc = -1050;
608 goto on_return;
609 }
610
611 pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, len);
Benny Prijono91a5a3a2007-09-24 21:16:48 +0000612 if (pos != (unsigned)-1) {
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000613 PJ_LOG(1,(THIS_FILE, " Message mismatch at byte %d", pos));
614 rc = -1060;
615 goto on_return;
616 }
617
618 /* Authenticate the request/response */
619 if (v->options & USE_MESSAGE_INTEGRITY) {
620 if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
621 pj_stun_auth_cred cred;
622 pj_status_t status;
623
624 pj_bzero(&cred, sizeof(cred));
625 cred.type = PJ_STUN_AUTH_CRED_STATIC;
626 cred.data.static_cred.username = pj_str(v->username);
627 cred.data.static_cred.data = pj_str(v->password);
628
629 status = pj_stun_authenticate_request(buf, len, msg,
Benny Prijono17d10b52008-03-14 17:56:11 +0000630 &cred, pool, NULL, NULL);
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000631 if (status != PJ_SUCCESS) {
632 char errmsg[PJ_ERR_MSG_SIZE];
633 pj_strerror(status, errmsg, sizeof(errmsg));
634 PJ_LOG(1,(THIS_FILE,
635 " Request authentication failed: %s",
636 errmsg));
637 rc = -1070;
638 goto on_return;
639 }
640
641 } else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
642 pj_status_t status;
643 status = pj_stun_authenticate_response(buf, len, msg, &key);
644 if (status != PJ_SUCCESS) {
645 char errmsg[PJ_ERR_MSG_SIZE];
646 pj_strerror(status, errmsg, sizeof(errmsg));
647 PJ_LOG(1,(THIS_FILE,
648 " Response authentication failed: %s",
649 errmsg));
650 rc = -1080;
651 goto on_return;
652 }
653 }
654 }
655 }
656
657
658on_return:
659 pj_pool_release(pool);
660 return rc;
661}
662
663static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v)
664{
665 pj_stun_msg *msg;
666 pj_timestamp u64;
667 pj_str_t s1;
668
669 pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
670 (pj_uint8_t*)v->tsx_id, &msg);
671
672 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY, 0x6e0001ff);
673 u64.u32.hi = 0x932ff9b1;
674 u64.u32.lo = 0x51263b36;
675 pj_stun_msg_add_uint64_attr(pool, msg, PJ_STUN_ATTR_ICE_CONTROLLED,
676 &u64);
677
678 pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME,
679 pj_cstr(&s1, v->username));
680
681 pj_stun_msg_add_msgint_attr(pool, msg);
682
683 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
684
685 return msg;
686}
687
688static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
689{
690 pj_stun_msg *msg;
691 pj_sockaddr_in mapped_addr;
692 pj_str_t s1;
693
694 pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
695 (pj_uint8_t*)v->tsx_id, &msg);
696
697 pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER,
698 pj_cstr(&s1, "test vector"));
699
700 pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853);
701 pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
702 PJ_TRUE, &mapped_addr,
703 sizeof(pj_sockaddr_in));
704
705 pj_stun_msg_add_msgint_attr(pool, msg);
706 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
707
708 return msg;
709}
710
Benny Prijonofb9d9872007-03-21 22:05:58 +0000711
Benny Prijono7ce74132008-06-21 12:36:56 +0000712/* Compare two messages */
713static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
714{
715 unsigned i;
716
717 if (msg1->hdr.type != msg2->hdr.type)
718 return -10;
719 if (msg1->hdr.length != msg2->hdr.length)
720 return -20;
721 if (msg1->hdr.magic != msg2->hdr.magic)
722 return -30;
723 if (pj_memcmp(msg1->hdr.tsx_id, msg2->hdr.tsx_id, sizeof(msg1->hdr.tsx_id)))
724 return -40;
725 if (msg1->attr_count != msg2->attr_count)
726 return -50;
727
728 for (i=0; i<msg1->attr_count; ++i) {
729 const pj_stun_attr_hdr *a1 = msg1->attr[i];
730 const pj_stun_attr_hdr *a2 = msg2->attr[i];
731
732 if (a1->type != a2->type)
733 return -60;
734 if (a1->length != a2->length)
735 return -70;
736 }
737
738 return 0;
739}
740
741/* Decode and authenticate message with unknown non-mandatory attribute */
742static int handle_unknown_non_mandatory(void)
743{
744 pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL);
745 pj_stun_msg *msg0, *msg1, *msg2;
746 pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6};
747 pj_uint8_t packet[500];
748 pj_stun_auth_cred cred;
749 unsigned len;
750 pj_status_t rc;
751
752 PJ_LOG(3,(THIS_FILE, " handling unknown non-mandatory attr"));
753
754 PJ_LOG(3,(THIS_FILE, " encoding"));
755 rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0);
756 rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME);
757 rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data));
758 rc += pj_stun_msg_add_msgint_attr(pool, msg0);
759 rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len);
760
761#if 0
762 if (1) {
763 unsigned i;
764 puts("");
765 printf("{ ");
766 for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]);
767 puts(" }");
768 }
769#endif
770
771 PJ_LOG(3,(THIS_FILE, " decoding"));
772 rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
773 &msg1, NULL, NULL);
774
775 rc += cmp_msg(msg0, msg1);
776
777 pj_bzero(&cred, sizeof(cred));
778 cred.type = PJ_STUN_AUTH_CRED_STATIC;
779 cred.data.static_cred.username = USERNAME;
780 cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
781 cred.data.static_cred.data = PASSWORD;
782
783 PJ_LOG(3,(THIS_FILE, " authenticating"));
784 rc += pj_stun_authenticate_request(packet, len, msg1, &cred, pool, NULL, NULL);
785
786 PJ_LOG(3,(THIS_FILE, " clone"));
787 msg2 = pj_stun_msg_clone(pool, msg1);
788 rc += cmp_msg(msg0, msg2);
789
790 pj_pool_release(pool);
791
792 return rc==0 ? 0 : -4410;
793}
794
795
Benny Prijonofb9d9872007-03-21 22:05:58 +0000796int stun_test(void)
797{
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000798 int pad, rc;
799
800 pad = pj_stun_set_padding_char(32);
801
802 rc = decode_test();
803 if (rc != 0)
804 goto on_return;
805
806 rc = decode_verify();
807 if (rc != 0)
808 goto on_return;
809
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000810 rc = fingerprint_test_vector();
811 if (rc != 0)
812 goto on_return;
813
Benny Prijono7ce74132008-06-21 12:36:56 +0000814 rc = handle_unknown_non_mandatory();
815 if (rc != 0)
816 goto on_return;
817
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000818on_return:
819 pj_stun_set_padding_char(pad);
820 return rc;
Benny Prijonofb9d9872007-03-21 22:05:58 +0000821}
822