blob: 7369aeb60ae0f76a7b6bc25970efa342707b9790 [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;
Nanang Izzuddin838cb322008-12-18 17:52:57 +0000245 pj_size_t len;
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000246 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;
Nanang Izzuddin838cb322008-12-18 17:52:57 +0000546 pj_size_t parsed_len;
547 pj_size_t len;
548 unsigned pos;
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000549 pj_uint8_t buf[1500];
550 char print[1500];
551 pj_str_t key;
552
553 PJ_LOG(3,(THIS_FILE, " Running test %d/%d", i,
554 PJ_ARRAY_SIZE(test_vectors)));
555
556 v = &test_vectors[i];
557
558 /* Print reference message */
559 PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
560 print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));
561
562 /* Try to parse the reference message first */
563 status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
564 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
565 &ref_msg, &parsed_len, NULL);
566 if (status != PJ_SUCCESS) {
567 PJ_LOG(1,(THIS_FILE, " Error decoding reference message"));
568 rc = -1010;
569 goto on_return;
570 }
571
572 if (parsed_len != v->pdu_len) {
573 PJ_LOG(1,(THIS_FILE, " Parsed len error"));
574 rc = -1020;
575 goto on_return;
576 }
577
578 /* Print the reference message */
579 pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
580 PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));
581
582 /* Create our message */
583 msg = v->create(pool, v);
584
585 /* Encode message */
586 if (v->options & USE_MESSAGE_INTEGRITY) {
587 pj_str_t s1, s2;
588
589 pj_stun_create_key(pool, &key, NULL, pj_cstr(&s1, v->username),
Benny Prijonoa5d214f2008-03-19 23:00:30 +0000590 PJ_STUN_PASSWD_PLAIN, pj_cstr(&s2, v->password));
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000591 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
592
593 } else {
594 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
595 }
596
597 /* Print our raw message */
598 PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
599 print_binary((pj_uint8_t*)buf, len)));
600
601 /* Print our message */
602 pj_stun_msg_dump(msg, print, sizeof(print), NULL);
603 PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));
604
605 /* Compare message length */
606 if (len != v->pdu_len) {
607 PJ_LOG(1,(THIS_FILE, " Message length mismatch"));
608 rc = -1050;
609 goto on_return;
610 }
611
612 pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, len);
Benny Prijono91a5a3a2007-09-24 21:16:48 +0000613 if (pos != (unsigned)-1) {
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000614 PJ_LOG(1,(THIS_FILE, " Message mismatch at byte %d", pos));
615 rc = -1060;
616 goto on_return;
617 }
618
619 /* Authenticate the request/response */
620 if (v->options & USE_MESSAGE_INTEGRITY) {
621 if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
622 pj_stun_auth_cred cred;
623 pj_status_t status;
624
625 pj_bzero(&cred, sizeof(cred));
626 cred.type = PJ_STUN_AUTH_CRED_STATIC;
627 cred.data.static_cred.username = pj_str(v->username);
628 cred.data.static_cred.data = pj_str(v->password);
629
630 status = pj_stun_authenticate_request(buf, len, msg,
Benny Prijono17d10b52008-03-14 17:56:11 +0000631 &cred, pool, NULL, NULL);
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000632 if (status != PJ_SUCCESS) {
633 char errmsg[PJ_ERR_MSG_SIZE];
634 pj_strerror(status, errmsg, sizeof(errmsg));
635 PJ_LOG(1,(THIS_FILE,
636 " Request authentication failed: %s",
637 errmsg));
638 rc = -1070;
639 goto on_return;
640 }
641
642 } else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
643 pj_status_t status;
644 status = pj_stun_authenticate_response(buf, len, msg, &key);
645 if (status != PJ_SUCCESS) {
646 char errmsg[PJ_ERR_MSG_SIZE];
647 pj_strerror(status, errmsg, sizeof(errmsg));
648 PJ_LOG(1,(THIS_FILE,
649 " Response authentication failed: %s",
650 errmsg));
651 rc = -1080;
652 goto on_return;
653 }
654 }
655 }
656 }
657
658
659on_return:
660 pj_pool_release(pool);
661 return rc;
662}
663
664static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v)
665{
666 pj_stun_msg *msg;
667 pj_timestamp u64;
668 pj_str_t s1;
669
670 pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
671 (pj_uint8_t*)v->tsx_id, &msg);
672
673 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY, 0x6e0001ff);
674 u64.u32.hi = 0x932ff9b1;
675 u64.u32.lo = 0x51263b36;
676 pj_stun_msg_add_uint64_attr(pool, msg, PJ_STUN_ATTR_ICE_CONTROLLED,
677 &u64);
678
679 pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME,
680 pj_cstr(&s1, v->username));
681
682 pj_stun_msg_add_msgint_attr(pool, msg);
683
684 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
685
686 return msg;
687}
688
689static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
690{
691 pj_stun_msg *msg;
692 pj_sockaddr_in mapped_addr;
693 pj_str_t s1;
694
695 pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
696 (pj_uint8_t*)v->tsx_id, &msg);
697
Benny Prijonoefa014b2008-08-22 17:46:33 +0000698 pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000699 pj_cstr(&s1, "test vector"));
700
701 pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853);
702 pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
703 PJ_TRUE, &mapped_addr,
704 sizeof(pj_sockaddr_in));
705
706 pj_stun_msg_add_msgint_attr(pool, msg);
707 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
708
709 return msg;
710}
711
Benny Prijonofb9d9872007-03-21 22:05:58 +0000712
Benny Prijono7ce74132008-06-21 12:36:56 +0000713/* Compare two messages */
714static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
715{
716 unsigned i;
717
718 if (msg1->hdr.type != msg2->hdr.type)
719 return -10;
720 if (msg1->hdr.length != msg2->hdr.length)
721 return -20;
722 if (msg1->hdr.magic != msg2->hdr.magic)
723 return -30;
724 if (pj_memcmp(msg1->hdr.tsx_id, msg2->hdr.tsx_id, sizeof(msg1->hdr.tsx_id)))
725 return -40;
726 if (msg1->attr_count != msg2->attr_count)
727 return -50;
728
729 for (i=0; i<msg1->attr_count; ++i) {
730 const pj_stun_attr_hdr *a1 = msg1->attr[i];
731 const pj_stun_attr_hdr *a2 = msg2->attr[i];
732
733 if (a1->type != a2->type)
734 return -60;
735 if (a1->length != a2->length)
736 return -70;
737 }
738
739 return 0;
740}
741
742/* Decode and authenticate message with unknown non-mandatory attribute */
743static int handle_unknown_non_mandatory(void)
744{
745 pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL);
746 pj_stun_msg *msg0, *msg1, *msg2;
747 pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6};
748 pj_uint8_t packet[500];
749 pj_stun_auth_cred cred;
Nanang Izzuddin838cb322008-12-18 17:52:57 +0000750 pj_size_t len;
Benny Prijono7ce74132008-06-21 12:36:56 +0000751 pj_status_t rc;
752
753 PJ_LOG(3,(THIS_FILE, " handling unknown non-mandatory attr"));
754
755 PJ_LOG(3,(THIS_FILE, " encoding"));
756 rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0);
757 rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME);
758 rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data));
759 rc += pj_stun_msg_add_msgint_attr(pool, msg0);
760 rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len);
761
762#if 0
763 if (1) {
764 unsigned i;
765 puts("");
766 printf("{ ");
767 for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]);
768 puts(" }");
769 }
770#endif
771
772 PJ_LOG(3,(THIS_FILE, " decoding"));
773 rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
774 &msg1, NULL, NULL);
775
776 rc += cmp_msg(msg0, msg1);
777
778 pj_bzero(&cred, sizeof(cred));
779 cred.type = PJ_STUN_AUTH_CRED_STATIC;
780 cred.data.static_cred.username = USERNAME;
781 cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
782 cred.data.static_cred.data = PASSWORD;
783
784 PJ_LOG(3,(THIS_FILE, " authenticating"));
785 rc += pj_stun_authenticate_request(packet, len, msg1, &cred, pool, NULL, NULL);
786
787 PJ_LOG(3,(THIS_FILE, " clone"));
788 msg2 = pj_stun_msg_clone(pool, msg1);
789 rc += cmp_msg(msg0, msg2);
790
791 pj_pool_release(pool);
792
793 return rc==0 ? 0 : -4410;
794}
795
796
Benny Prijonofb9d9872007-03-21 22:05:58 +0000797int stun_test(void)
798{
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000799 int pad, rc;
800
801 pad = pj_stun_set_padding_char(32);
802
803 rc = decode_test();
804 if (rc != 0)
805 goto on_return;
806
807 rc = decode_verify();
808 if (rc != 0)
809 goto on_return;
810
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000811 rc = fingerprint_test_vector();
812 if (rc != 0)
813 goto on_return;
814
Benny Prijono7ce74132008-06-21 12:36:56 +0000815 rc = handle_unknown_non_mandatory();
816 if (rc != 0)
817 goto on_return;
818
Benny Prijonoe2d0acb2007-09-18 19:33:33 +0000819on_return:
820 pj_stun_set_padding_char(pad);
821 return rc;
Benny Prijonofb9d9872007-03-21 22:05:58 +0000822}
823