blob: 3070d17363fcfe50bc199b1832b53d73eb801d27 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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 */
20#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"
167 "\x80\xff\x00\x03\x00\x00\x00\x00",
168 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};
230
231static int decode_test(void)
232{
233 unsigned i;
234 pj_pool_t *pool;
235 int rc = 0;
236
237 pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL);
238
239 PJ_LOG(3,(THIS_FILE, " STUN decode test"));
240
241 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;
246 pj_size_t len;
247 pj_status_t status;
248
249 PJ_LOG(3,(THIS_FILE, " %s", t->title));
250
251 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);
255
256 /* 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 }
263
264 } else {
265 msg = t->create(pool);
266 status = PJ_SUCCESS;
267 }
268
269 if (status != PJ_SUCCESS)
270 continue;
271
272 /* Try to encode message */
273 pj_stun_create_key(pool, &key, NULL, &USERNAME, PJ_STUN_PASSWD_PLAIN, &PASSWORD);
274 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 }
280
281 /* 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 }
290
291 /* Verify */
292 if (t->verify) {
293 rc = t->verify(msg);
294 if (rc != 0) {
295 goto on_return;
296 }
297 }
298 }
299
300on_return:
301 pj_pool_release(pool);
302 if (rc == 0)
303 PJ_LOG(3,(THIS_FILE, "...success!"));
304 return rc;
305}
306
307/* 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;
316
317 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);
322
323 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 }
366
367 return 0;
368}
369
370/* Attribute count should be zero since unknown attribute is not parsed */
371static int verify2(pj_stun_msg *msg)
372{
373 pj_stun_binary_attr *bin_attr;
374
375 if (msg->attr_count != 1) {
376 PJ_LOG(1,(THIS_FILE, " expecting one attribute count"));
377 return -200;
378 }
379
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
398 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
427static int decode_verify(void)
428{
429 /* Decode all attribute types */
430 return 0;
431}
432
433/*
434 * Test vectors, from:
435 * http://tools.ietf.org/html/draft-denis-behave-rfc3489bis-test-vectors-02
436 */
437typedef struct test_vector test_vector;
438
439static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
440static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
441static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v);
442
443enum
444{
445 USE_MESSAGE_INTEGRITY = 1,
446 USE_FINGERPRINT = 2
447};
448
449static struct test_vector
450{
451 unsigned msg_type;
452 char *tsx_id;
453 char *pdu;
454 unsigned pdu_len;
455 unsigned options;
456 char *username;
457 char *password;
458 char *realm;
459 char *nonce;
460 pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
461} test_vectors[] =
462{
463 {
464 PJ_STUN_BINDING_REQUEST,
465 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
466 "\x00\x01\x00\x44\x21\x12\xa4\x42\xb7\xe7"
467 "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
468 "\x00\x24\x00\x04\x6e\x00\x01\xff\x80\x29"
469 "\x00\x08\x93\x2f\xf9\xb1\x51\x26\x3b\x36"
470 "\x00\x06\x00\x09\x65\x76\x74\x6a\x3a\x68"
471 "\x36\x76\x59\x20\x20\x20\x00\x08\x00\x14"
472 "\x62\x4e\xeb\xdc\x3c\xc9\x2d\xd8\x4b\x74"
473 "\xbf\x85\xd1\xc0\xf5\xde\x36\x87\xbd\x33"
474 "\x80\x28\x00\x04\xad\x8a\x85\xff",
475 88,
476 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
477 "evtj:h6vY",
478 "VOkJxbRl1RmTxUk/WvJxBt",
479 "",
480 "",
481 &create_msgint1
482 }
483 /* disabled: see http://trac.pjsip.org/repos/ticket/960
484 ,
485 {
486 PJ_STUN_BINDING_RESPONSE,
487 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
488 "\x01\x01\x00\x3c"
489 "\x21\x12\xa4\x42"
490 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
491 "\x80\x22\x00\x0b"
492 "\x74\x65\x73\x74\x20\x76\x65\x63\x74\x6f\x72\x20"
493 "\x00\x20\x00\x08"
494 "\x00\x01\xa1\x47\xe1\x12\xa6\x43"
495 "\x00\x08\x00\x14"
496 "\x2b\x91\xf5\x99\xfd\x9e\x90\xc3\x8c\x74\x89\xf9"
497 "\x2a\xf9\xba\x53\xf0\x6b\xe7\xd7"
498 "\x80\x28\x00\x04"
499 "\xc0\x7d\x4c\x96",
500 80,
501 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
502 "evtj:h6vY",
503 "VOkJxbRl1RmTxUk/WvJxBt",
504 "",
505 "",
506 &create_msgint2
507 }
508 */
509
510 /* disabled: see http://trac.pjsip.org/repos/ticket/960
511#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
512 ,
513 {
514 PJ_STUN_BINDING_RESPONSE,
515 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
516 "\x01\x01\x00\x48" // Response type and message length
517 "\x21\x12\xa4\x42" // Message cookie
518 "\xb7\xe7\xa7\x01" // }
519 "\xbc\x34\xd6\x86" // } Transaction ID
520 "\xfa\x87\xdf\xae" // }
521
522 "\x80\x22\x00\x0b" // SOFTWARE, length=11
523 "\x74\x65\x73\x74"
524 "\x20\x76\x65\x63"
525 "\x74\x6f\x72\x20"
526 "\x00\x20\x00\x14" // XOR-MAPPED-ADDRESS
527 "\x00\x02\xa1\x47"
528 "\x01\x13\xa9\xfa"
529 "\xa5\xd3\xf1\x79"
530 "\xbc\x25\xf4\xb5"
531 "\xbe\xd2\xb9\xd9"
532 "\x00\x08\x00\x14" // MESSAGE-INTEGRITY attribute header
533 "\xa3\x82\x95\x4e" // }
534 "\x4b\xe6\x7b\xf1" // }
535 "\x17\x84\xc9\x7c" // } HMAC-SHA1 fingerprint
536 "\x82\x92\xc2\x75" // }
537 "\xbf\xe3\xed\x41" // }
538 "\x80\x28\x00\x04" // FINGERPRINT attribute header
539 "\xc8\xfb\x0b\x4c" // CRC32 fingerprint
540 ,
541 92,
542 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
543 "evtj:h6vY",
544 "VOkJxbRl1RmTxUk/WvJxBt",
545 "",
546 "",
547 &create_msgint3
548 }
549#endif
550 */
551};
552
553
554static char* print_binary(const pj_uint8_t *data, unsigned data_len)
555{
556 static char buf[1500];
557 unsigned length = sizeof(buf);
558 char *p = buf;
559 unsigned i;
560
561 for (i=0; i<data_len;) {
562 unsigned j;
563
564 pj_ansi_snprintf(p, 1500-(p-buf),
565 "%04d-%04d ",
566 i, (i+20 < data_len) ? i+20 : data_len);
567 p += 12;
568
569 for (j=0; j<20 && i<data_len && p<(buf+length-10); ++j, ++i) {
570 pj_ansi_sprintf(p, "%02x ", (*data) & 0xFF);
571 p += 3;
572 data++;
573 }
574
575 pj_ansi_sprintf(p, "\n");
576 p++;
577 }
578
579 return buf;
580}
581
582static int cmp_buf(const pj_uint8_t *s1, const pj_uint8_t *s2, unsigned len)
583{
584 unsigned i;
585 for (i=0; i<len; ++i) {
586 if (s1[i] != s2[i])
587 return i;
588 }
589
590 return -1;
591}
592
593static int fingerprint_test_vector()
594{
595 pj_pool_t *pool;
596 pj_status_t status;
597 unsigned i;
598 int rc = 0;
599
600 /* To avoid function not referenced warnings */
601 (void)create_msgint2;
602 (void)create_msgint3;
603
604 PJ_LOG(3,(THIS_FILE, " draft-denis-behave-rfc3489bis-test-vectors-02"));
605
606 pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
607
608 for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) {
609 struct test_vector *v;
610 pj_stun_msg *ref_msg, *msg;
611 pj_size_t parsed_len;
612 pj_size_t len;
613 unsigned pos;
614 pj_uint8_t buf[1500];
615 char print[1500];
616 pj_str_t key;
617
618 PJ_LOG(3,(THIS_FILE, " Running test %d/%d", i,
619 PJ_ARRAY_SIZE(test_vectors)));
620
621 v = &test_vectors[i];
622
623 /* Print reference message */
624 PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
625 print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));
626
627 /* Try to parse the reference message first */
628 status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
629 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
630 &ref_msg, &parsed_len, NULL);
631 if (status != PJ_SUCCESS) {
632 PJ_LOG(1,(THIS_FILE, " Error decoding reference message"));
633 rc = -1010;
634 goto on_return;
635 }
636
637 if (parsed_len != v->pdu_len) {
638 PJ_LOG(1,(THIS_FILE, " Parsed len error"));
639 rc = -1020;
640 goto on_return;
641 }
642
643 /* Print the reference message */
644 pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
645 PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));
646
647 /* Create our message */
648 msg = v->create(pool, v);
649 if (msg == NULL) {
650 PJ_LOG(1,(THIS_FILE, " Error creating stun message"));
651 rc = -1030;
652 goto on_return;
653 }
654
655 /* Encode message */
656 if (v->options & USE_MESSAGE_INTEGRITY) {
657 pj_str_t s1, s2, r;
658
659 pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm),
660 pj_cstr(&s1, v->username),
661 PJ_STUN_PASSWD_PLAIN,
662 pj_cstr(&s2, v->password));
663 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
664
665 } else {
666 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
667 }
668
669 /* Print our raw message */
670 PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
671 print_binary((pj_uint8_t*)buf, (unsigned)len)));
672
673 /* Print our message */
674 pj_stun_msg_dump(msg, print, sizeof(print), NULL);
675 PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));
676
677 /* Compare message length */
678 if (len != v->pdu_len) {
679 PJ_LOG(1,(THIS_FILE, " Message length mismatch"));
680 rc = -1050;
681 goto on_return;
682 }
683
684 pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, (unsigned)len);
685 if (pos != (unsigned)-1) {
686 PJ_LOG(1,(THIS_FILE, " Message mismatch at byte %d", pos));
687 rc = -1060;
688 goto on_return;
689 }
690
691 /* Authenticate the request/response */
692 if (v->options & USE_MESSAGE_INTEGRITY) {
693 if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
694 pj_stun_auth_cred cred;
695 pj_status_t status;
696
697 pj_bzero(&cred, sizeof(cred));
698 cred.type = PJ_STUN_AUTH_CRED_STATIC;
699 cred.data.static_cred.realm = pj_str(v->realm);
700 cred.data.static_cred.username = pj_str(v->username);
701 cred.data.static_cred.data = pj_str(v->password);
702 cred.data.static_cred.nonce = pj_str(v->nonce);
703
704 status = pj_stun_authenticate_request(buf, (unsigned)len, msg,
705 &cred, pool, NULL, NULL);
706 if (status != PJ_SUCCESS) {
707 char errmsg[PJ_ERR_MSG_SIZE];
708 pj_strerror(status, errmsg, sizeof(errmsg));
709 PJ_LOG(1,(THIS_FILE,
710 " Request authentication failed: %s",
711 errmsg));
712 rc = -1070;
713 goto on_return;
714 }
715
716 } else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
717 pj_status_t status;
718 status = pj_stun_authenticate_response(buf, (unsigned)len,
719 msg, &key);
720 if (status != PJ_SUCCESS) {
721 char errmsg[PJ_ERR_MSG_SIZE];
722 pj_strerror(status, errmsg, sizeof(errmsg));
723 PJ_LOG(1,(THIS_FILE,
724 " Response authentication failed: %s",
725 errmsg));
726 rc = -1080;
727 goto on_return;
728 }
729 }
730 }
731 }
732
733
734on_return:
735 pj_pool_release(pool);
736 return rc;
737}
738
739static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v)
740{
741 pj_stun_msg *msg;
742 pj_timestamp u64;
743 pj_str_t s1;
744 pj_status_t status;
745
746 status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
747 (pj_uint8_t*)v->tsx_id, &msg);
748 if (status != PJ_SUCCESS)
749 goto on_error;
750
751 status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY,
752 0x6e0001ff);
753 if (status != PJ_SUCCESS)
754 goto on_error;
755
756 u64.u32.hi = 0x932ff9b1;
757 u64.u32.lo = 0x51263b36;
758 status = pj_stun_msg_add_uint64_attr(pool, msg,
759 PJ_STUN_ATTR_ICE_CONTROLLED, &u64);
760 if (status != PJ_SUCCESS)
761 goto on_error;
762
763 status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME,
764 pj_cstr(&s1, v->username));
765 if (status != PJ_SUCCESS)
766 goto on_error;
767
768 status = pj_stun_msg_add_msgint_attr(pool, msg);
769 if (status != PJ_SUCCESS)
770 goto on_error;
771
772 status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
773 if (status != PJ_SUCCESS)
774 goto on_error;
775
776 return msg;
777
778on_error:
779 app_perror(" error: create_msgint1()", status);
780 return NULL;
781}
782
783static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
784{
785 pj_stun_msg *msg;
786 pj_sockaddr_in mapped_addr;
787 pj_str_t s1;
788 pj_status_t status;
789
790 status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
791 (pj_uint8_t*)v->tsx_id, &msg);
792 if (status != PJ_SUCCESS)
793 goto on_error;
794
795 status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
796 pj_cstr(&s1, "test vector"));
797 if (status != PJ_SUCCESS)
798 goto on_error;
799
800 status = pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "192.0.2.1"),
801 32853);
802 if (status != PJ_SUCCESS)
803 goto on_error;
804
805 status = pj_stun_msg_add_sockaddr_attr(pool, msg,
806 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
807 PJ_TRUE, &mapped_addr,
808 sizeof(pj_sockaddr_in));
809 if (status != PJ_SUCCESS)
810 goto on_error;
811
812 status = pj_stun_msg_add_msgint_attr(pool, msg);
813 if (status != PJ_SUCCESS)
814 goto on_error;
815
816 status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
817 if (status != PJ_SUCCESS)
818 goto on_error;
819
820 return msg;
821
822on_error:
823 app_perror(" error: create_msgint2()", status);
824 return NULL;
825}
826
827
828static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
829{
830 pj_stun_msg *msg;
831 pj_sockaddr mapped_addr;
832 pj_str_t s1;
833 pj_status_t status;
834
835 status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
836 (pj_uint8_t*)v->tsx_id, &msg);
837 if (status != PJ_SUCCESS)
838 goto on_error;
839
840 status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
841 pj_cstr(&s1, "test vector"));
842 if (status != PJ_SUCCESS)
843 goto on_error;
844
845 status = pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
846 pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
847 32853);
848 if (status != PJ_SUCCESS)
849 goto on_error;
850
851 status = pj_stun_msg_add_sockaddr_attr(pool, msg,
852 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
853 PJ_TRUE, &mapped_addr,
854 sizeof(pj_sockaddr));
855 if (status != PJ_SUCCESS)
856 goto on_error;
857
858 status = pj_stun_msg_add_msgint_attr(pool, msg);
859 if (status != PJ_SUCCESS)
860 goto on_error;
861
862 status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
863 if (status != PJ_SUCCESS)
864 goto on_error;
865
866 return msg;
867
868on_error:
869 app_perror(" error: create_msgint3()", status);
870 return NULL;
871}
872
873
874/* Compare two messages */
875static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
876{
877 unsigned i;
878
879 if (msg1->hdr.type != msg2->hdr.type)
880 return -10;
881 if (msg1->hdr.length != msg2->hdr.length)
882 return -20;
883 if (msg1->hdr.magic != msg2->hdr.magic)
884 return -30;
885 if (pj_memcmp(msg1->hdr.tsx_id, msg2->hdr.tsx_id, sizeof(msg1->hdr.tsx_id)))
886 return -40;
887 if (msg1->attr_count != msg2->attr_count)
888 return -50;
889
890 for (i=0; i<msg1->attr_count; ++i) {
891 const pj_stun_attr_hdr *a1 = msg1->attr[i];
892 const pj_stun_attr_hdr *a2 = msg2->attr[i];
893
894 if (a1->type != a2->type)
895 return -60;
896 if (a1->length != a2->length)
897 return -70;
898 }
899
900 return 0;
901}
902
903/* Decode and authenticate message with unknown non-mandatory attribute */
904static int handle_unknown_non_mandatory(void)
905{
906 pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL);
907 pj_stun_msg *msg0, *msg1, *msg2;
908 pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6};
909 pj_uint8_t packet[500];
910 pj_stun_auth_cred cred;
911 pj_size_t len;
912 pj_status_t rc;
913
914 PJ_LOG(3,(THIS_FILE, " handling unknown non-mandatory attr"));
915
916 PJ_LOG(3,(THIS_FILE, " encoding"));
917 rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0);
918 rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME);
919 rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data));
920 rc += pj_stun_msg_add_msgint_attr(pool, msg0);
921 rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len);
922
923#if 0
924 if (1) {
925 unsigned i;
926 puts("");
927 printf("{ ");
928 for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]);
929 puts(" }");
930 }
931#endif
932
933 PJ_LOG(3,(THIS_FILE, " decoding"));
934 rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
935 &msg1, NULL, NULL);
936
937 rc += cmp_msg(msg0, msg1);
938
939 pj_bzero(&cred, sizeof(cred));
940 cred.type = PJ_STUN_AUTH_CRED_STATIC;
941 cred.data.static_cred.username = USERNAME;
942 cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
943 cred.data.static_cred.data = PASSWORD;
944
945 PJ_LOG(3,(THIS_FILE, " authenticating"));
946 rc += pj_stun_authenticate_request(packet, (unsigned)len, msg1, &cred, pool,
947 NULL, NULL);
948
949 PJ_LOG(3,(THIS_FILE, " clone"));
950 msg2 = pj_stun_msg_clone(pool, msg1);
951 rc += cmp_msg(msg0, msg2);
952
953 pj_pool_release(pool);
954
955 return rc==0 ? 0 : -4410;
956}
957
958
959int stun_test(void)
960{
961 int pad, rc;
962
963 pad = pj_stun_set_padding_char(32);
964
965 rc = decode_test();
966 if (rc != 0)
967 goto on_return;
968
969 rc = decode_verify();
970 if (rc != 0)
971 goto on_return;
972
973 rc = fingerprint_test_vector();
974 if (rc != 0)
975 goto on_return;
976
977 rc = handle_unknown_non_mandatory();
978 if (rc != 0)
979 goto on_return;
980
981on_return:
982 pj_stun_set_padding_char(pad);
983 return rc;
984}
985