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