blob: 86ac5d8ab576a6e6bb4cefe4f20f3426d5d35ab3 [file] [log] [blame]
Benny Prijonoa5d214f2008-03-19 23:00:30 +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 */
19#include "test.h"
20
21#define THIS_FILE "sess_auth.c"
22
23#define REALM "STUN session test"
24#define USERNAME "theusername"
25#define PASSWORD "thepassword"
26#define NONCE "thenonce"
27
28
29/* STUN config */
30static pj_stun_config stun_cfg;
31
32
33//////////////////////////////////////////////////////////////////////////////////////////
34//
35// SERVER PART
36//
37
38
39/* Server instance */
40static struct server
41{
42 pj_pool_t *pool;
43 pj_sockaddr addr;
44 pj_stun_session *sess;
45
46 pj_bool_t responding;
47 unsigned recv_count;
48 pj_stun_auth_type auth_type;
49
50 pj_sock_t sock;
51
52 pj_bool_t quit;
53 pj_thread_t *thread;
54} *server;
55
56
57static pj_status_t server_send_msg(pj_stun_session *sess,
58 const void *pkt,
59 pj_size_t pkt_size,
60 const pj_sockaddr_t *dst_addr,
61 unsigned addr_len)
62{
63 pj_ssize_t len = pkt_size;
64
65 PJ_UNUSED_ARG(sess);
66
67 return pj_sock_sendto(server->sock, pkt, &len, 0, dst_addr, addr_len);
68}
69
70static pj_status_t server_on_rx_request(pj_stun_session *sess,
71 const pj_uint8_t *pkt,
72 unsigned pkt_len,
73 const pj_stun_rx_data *rdata,
74 const pj_sockaddr_t *src_addr,
75 unsigned src_addr_len)
76{
77 PJ_UNUSED_ARG(pkt);
78 PJ_UNUSED_ARG(pkt_len);
79
80 return pj_stun_session_respond(sess, rdata, 0, NULL, PJ_TRUE,
81 src_addr, src_addr_len);
82}
83
84
85static pj_status_t server_get_auth(void *user_data,
86 pj_pool_t *pool,
87 pj_str_t *realm,
88 pj_str_t *nonce)
89{
90 PJ_UNUSED_ARG(user_data);
91 PJ_UNUSED_ARG(pool);
92
93 if (server->auth_type == PJ_STUN_AUTH_SHORT_TERM) {
94 realm->slen = nonce->slen = 0;
95 } else {
96 *realm = pj_str(REALM);
97 *nonce = pj_str(NONCE);
98 }
99
100 return PJ_SUCCESS;
101}
102
103
104static pj_status_t server_get_password( const pj_stun_msg *msg,
105 void *user_data,
106 const pj_str_t *realm,
107 const pj_str_t *username,
108 pj_pool_t *pool,
109 pj_stun_passwd_type *data_type,
110 pj_str_t *data)
111{
112 PJ_UNUSED_ARG(msg);
113 PJ_UNUSED_ARG(user_data);
114 PJ_UNUSED_ARG(pool);
115
116 if (server->auth_type == PJ_STUN_AUTH_SHORT_TERM) {
117 if (realm && realm->slen) {
118 PJ_LOG(4,(THIS_FILE, " server expecting short term"));
119 return -1;
120 }
121 } else {
122 if (realm==NULL || realm->slen==0) {
123 PJ_LOG(4,(THIS_FILE, " realm not present"));
124 return -1;
125 }
126 }
127
128 if (pj_strcmp2(username, USERNAME) != 0) {
129 PJ_LOG(4,(THIS_FILE, " wrong username"));
130 return -1;
131 }
132
133 *data_type = PJ_STUN_PASSWD_PLAIN;
134 *data = pj_str(PASSWORD);
135
136 return PJ_SUCCESS;
137}
138
139
140static pj_bool_t server_verify_nonce(const pj_stun_msg *msg,
141 void *user_data,
142 const pj_str_t *realm,
143 const pj_str_t *username,
144 const pj_str_t *nonce)
145{
146 PJ_UNUSED_ARG(msg);
147 PJ_UNUSED_ARG(user_data);
148 PJ_UNUSED_ARG(realm);
149 PJ_UNUSED_ARG(username);
150
151 if (pj_strcmp2(nonce, NONCE) != 0)
152 return PJ_FALSE;
153
154 return PJ_TRUE;
155}
156
157
158static int server_thread(void *unused)
159{
160 PJ_UNUSED_ARG(unused);
161
162 while (!server->quit) {
163 pj_fd_set_t readset;
164 pj_time_val delay = {0, 10};
165
166 PJ_FD_ZERO(&readset);
167 PJ_FD_SET(server->sock, &readset);
168
169 if (pj_sock_select(server->sock, &readset, NULL, NULL, &delay)==1 &&
170 PJ_FD_ISSET(server->sock, &readset))
171 {
172 char pkt[1000];
173 pj_ssize_t len;
174 pj_status_t status;
175 pj_sockaddr src_addr;
176 int src_addr_len;
177
178 len = sizeof(pkt);
179 src_addr_len = sizeof(src_addr);
180
181 status = pj_sock_recvfrom(server->sock, pkt, &len, 0, &src_addr, &src_addr_len);
182 if (status != PJ_SUCCESS)
183 continue;
184
185 /* Increment server's receive count */
186 server->recv_count++;
187
188 /* Only pass to server if we allow to respond */
189 if (!server->responding)
190 continue;
191
192 pj_stun_session_on_rx_pkt(server->sess, pkt, len,
193 PJ_STUN_CHECK_PACKET | PJ_STUN_IS_DATAGRAM,
194 NULL, &src_addr, src_addr_len);
195 }
196 }
197
198 return 0;
199}
200
201
202/* Destroy server */
203static void destroy_server(void)
204{
205 if (server->thread) {
206 server->quit = PJ_TRUE;
207 pj_thread_join(server->thread);
208 pj_thread_destroy(server->thread);
209 }
210
211 if (server->sock) {
212 pj_sock_close(server->sock);
213 }
214
215 if (server->sess) {
216 pj_stun_session_destroy(server->sess);
217 }
218
219 pj_pool_release(server->pool);
220 server = NULL;
221}
222
223/* Instantiate standard server */
224static int create_std_server(pj_stun_auth_type auth_type,
225 pj_bool_t responding)
226{
227 pj_pool_t *pool;
228 pj_stun_session_cb sess_cb;
229 pj_stun_auth_cred cred;
230 pj_status_t status;
231
232 /* Create server */
233 pool = pj_pool_create(mem, "server", 1000, 1000, NULL);
234 server = PJ_POOL_ZALLOC_T(pool, struct server);
235 server->pool = pool;
236 server->auth_type = auth_type;
237 server->responding = responding;
238
239 /* Create STUN session */
240 pj_bzero(&sess_cb, sizeof(sess_cb));
241 sess_cb.on_rx_request = &server_on_rx_request;
242 sess_cb.on_send_msg = &server_send_msg;
243 status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, &server->sess);
244 if (status != PJ_SUCCESS) {
245 destroy_server();
246 return -10;
247 }
248
249 /* Configure credential */
250 pj_bzero(&cred, sizeof(cred));
251 cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
252 cred.data.dyn_cred.get_auth = &server_get_auth;
253 cred.data.dyn_cred.get_password = &server_get_password;
254 cred.data.dyn_cred.verify_nonce = &server_verify_nonce;
255 status = pj_stun_session_set_credential(server->sess, auth_type, &cred);
256 if (status != PJ_SUCCESS) {
257 destroy_server();
258 return -20;
259 }
260
261 /* Create socket */
262 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &server->sock);
263 if (status != PJ_SUCCESS) {
264 destroy_server();
265 return -30;
266 }
267
268 /* Bind */
269 pj_sockaddr_in_init(&server->addr.ipv4, NULL, 0);
270 status = pj_sock_bind(server->sock, &server->addr, pj_sockaddr_get_len(&server->addr));
271 if (status != PJ_SUCCESS) {
272 destroy_server();
273 return -40;
274 } else {
275 /* Get the bound IP address */
276 int namelen = sizeof(server->addr);
277 pj_sockaddr addr;
278
279 status = pj_sock_getsockname(server->sock, &server->addr, &namelen);
280 if (status != PJ_SUCCESS) {
281 destroy_server();
282 return -43;
283 }
284
285 status = pj_gethostip(pj_AF_INET(), &addr);
286 if (status != PJ_SUCCESS) {
287 destroy_server();
288 return -45;
289 }
290
291 pj_sockaddr_copy_addr(&server->addr, &addr);
292 }
293
294
295 /* Create worker thread */
296 status = pj_thread_create(pool, "server", &server_thread, 0, 0, 0, &server->thread);
297 if (status != PJ_SUCCESS) {
298 destroy_server();
299 return -30;
300 }
301
302 return 0;
303}
304
305
306//////////////////////////////////////////////////////////////////////////////////////////
307//
308// CLIENT PART
309//
310
311static struct client
312{
313 pj_pool_t *pool;
314 pj_stun_session *sess;
315 pj_sem_t *test_complete;
316 pj_sock_t sock;
317
318 pj_bool_t responding;
319 unsigned recv_count;
320
321 pj_status_t response_status;
322 pj_stun_msg *response;
323
324 pj_bool_t quit;
325 pj_thread_t *thread;
326} *client;
327
328
329static pj_status_t client_send_msg(pj_stun_session *sess,
330 const void *pkt,
331 pj_size_t pkt_size,
332 const pj_sockaddr_t *dst_addr,
333 unsigned addr_len)
334{
335 pj_ssize_t len = pkt_size;
336
337 PJ_UNUSED_ARG(sess);
338
339 return pj_sock_sendto(client->sock, pkt, &len, 0, dst_addr, addr_len);
340}
341
342
343static void client_on_request_complete( pj_stun_session *sess,
344 pj_status_t status,
345 pj_stun_tx_data *tdata,
346 const pj_stun_msg *response,
347 const pj_sockaddr_t *src_addr,
348 unsigned src_addr_len)
349{
350 PJ_UNUSED_ARG(sess);
351 PJ_UNUSED_ARG(tdata);
352 PJ_UNUSED_ARG(src_addr);
353 PJ_UNUSED_ARG(src_addr_len);
354
355 client->response_status = status;
356 if (response)
357 client->response = pj_stun_msg_clone(client->pool, response);
358
359 pj_sem_post(client->test_complete);
360}
361
362
363static int client_thread(void *unused)
364{
365 PJ_UNUSED_ARG(unused);
366
367 while (!client->quit) {
368 pj_fd_set_t readset;
369 pj_time_val delay = {0, 10};
370
371 /* Also poll the timer heap */
372 pj_timer_heap_poll(stun_cfg.timer_heap, NULL);
373
374 /* Poll client socket */
375 PJ_FD_ZERO(&readset);
376 PJ_FD_SET(client->sock, &readset);
377
378 if (pj_sock_select(client->sock, &readset, NULL, NULL, &delay)==1 &&
379 PJ_FD_ISSET(client->sock, &readset))
380 {
381 char pkt[1000];
382 pj_ssize_t len;
383 pj_status_t status;
384 pj_sockaddr src_addr;
385 int src_addr_len;
386
387 len = sizeof(pkt);
388 src_addr_len = sizeof(src_addr);
389
390 status = pj_sock_recvfrom(client->sock, pkt, &len, 0, &src_addr, &src_addr_len);
391 if (status != PJ_SUCCESS)
392 continue;
393
394 /* Increment client's receive count */
395 client->recv_count++;
396
397 /* Only pass to client if we allow to respond */
398 if (!client->responding)
399 continue;
400
401 pj_stun_session_on_rx_pkt(client->sess, pkt, len,
402 PJ_STUN_CHECK_PACKET | PJ_STUN_IS_DATAGRAM,
403 NULL, &src_addr, src_addr_len);
404 }
405
406 }
407
408 return 0;
409}
410
411
412static void destroy_client_server(void)
413{
414 if (client->thread) {
415 client->quit = 1;
416 pj_thread_join(client->thread);
417 pj_thread_destroy(client->thread);
418 }
419
420 if (client->sess)
421 pj_stun_session_destroy(client->sess);
422
423 if (client->sock)
424 pj_sock_close(client->sock);
425
426 if (client->test_complete)
427 pj_sem_destroy(client->test_complete);
428
429 if (server)
430 destroy_server();
431}
432
433static int run_client_test(const char *title,
434
435 pj_bool_t server_responding,
436 pj_stun_auth_type server_auth_type,
437
438 pj_stun_auth_type client_auth_type,
439 const char *realm,
440 const char *username,
441 const char *nonce,
442 const char *password,
443 pj_bool_t dummy_mi,
444
445 pj_stun_status expected_error,
446 pj_stun_status expected_code,
447 const char *expected_realm,
448 const char *expected_nonce,
449
450 int (*more_check)(void))
451{
452 pj_pool_t *pool;
453 pj_stun_session_cb sess_cb;
454 pj_stun_auth_cred cred;
455 pj_stun_tx_data *tdata;
456 pj_status_t status;
457 int rc = 0;
458
459 PJ_LOG(3,(THIS_FILE, " %s test", title));
460
461 /* Create client */
462 pool = pj_pool_create(mem, "client", 1000, 1000, NULL);
463 client = PJ_POOL_ZALLOC_T(pool, struct client);
464 client->pool = pool;
465 client->responding = PJ_TRUE;
466
467 /* Create STUN session */
468 pj_bzero(&sess_cb, sizeof(sess_cb));
469 sess_cb.on_request_complete = &client_on_request_complete;
470 sess_cb.on_send_msg = &client_send_msg;
471 status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, &client->sess);
472 if (status != PJ_SUCCESS) {
473 destroy_client_server();
474 return -200;
475 }
476
477 /* Create semaphore */
478 status = pj_sem_create(pool, "client", 0, 1, &client->test_complete);
479 if (status != PJ_SUCCESS) {
480 destroy_client_server();
481 return -205;
482 }
483
484 /* Create client socket */
485 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &client->sock);
486 if (status != PJ_SUCCESS) {
487 destroy_client_server();
488 return -210;
489 }
490
491 /* Bind client socket */
492 status = pj_sock_bind_in(client->sock, 0, 0);
493 if (status != PJ_SUCCESS) {
494 destroy_client_server();
495 return -220;
496 }
497
498 /* Create client thread */
499 status = pj_thread_create(pool, "client", &client_thread, NULL, 0, 0, &client->thread);
500 if (status != PJ_SUCCESS) {
501 destroy_client_server();
502 return -230;
503 }
504
505 /* Initialize credential */
506 pj_bzero(&cred, sizeof(cred));
507 cred.type = PJ_STUN_AUTH_CRED_STATIC;
508 if (realm) cred.data.static_cred.realm = pj_str((char*)realm);
509 if (username) cred.data.static_cred.username = pj_str((char*)username);
510 if (nonce) cred.data.static_cred.nonce = pj_str((char*)nonce);
511 if (password) cred.data.static_cred.data = pj_str((char*)password);
512 cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
513 status = pj_stun_session_set_credential(client->sess, client_auth_type, &cred);
514 if (status != PJ_SUCCESS) {
515 destroy_client_server();
516 return -240;
517 }
518
519 /* Create the server */
520 status = create_std_server(server_auth_type, server_responding);
521 if (status != 0) {
522 destroy_client_server();
523 return status;
524 }
525
526 /* Create request */
527 status = pj_stun_session_create_req(client->sess, PJ_STUN_BINDING_REQUEST,
528 PJ_STUN_MAGIC, NULL, &tdata);
529 if (status != PJ_SUCCESS) {
530 destroy_client_server();
531 return -250;
532 }
533
534 /* Add our own attributes if client authentication is set to none */
535 if (client_auth_type == PJ_STUN_AUTH_NONE) {
536 pj_str_t tmp;
537 if (realm)
538 pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_REALM, pj_cstr(&tmp, realm));
539 if (username)
540 pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_USERNAME, pj_cstr(&tmp, username));
541 if (nonce)
542 pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, nonce));
543 if (password) {
544 // ignored
545 }
546 if (dummy_mi) {
547 pj_stun_msgint_attr *mi;
548
549 pj_stun_msgint_attr_create(tdata->pool, &mi);
550 pj_stun_msg_add_attr(tdata->msg, &mi->hdr);
551 }
552
553 }
554
555 /* Send the request */
556 status = pj_stun_session_send_msg(client->sess, PJ_FALSE, &server->addr,
557 pj_sockaddr_get_len(&server->addr), tdata);
558 if (status != PJ_SUCCESS) {
559 destroy_client_server();
560 return -270;
561 }
562
563 /* Wait until test complete */
564 pj_sem_wait(client->test_complete);
565
566
567 /* Verify response */
568 if (expected_error) {
569 if (expected_code != client->response_status) {
570 char e1[PJ_ERR_MSG_SIZE], e2[PJ_ERR_MSG_SIZE];
571
572 pj_strerror(expected_code, e1, sizeof(e1));
573 pj_strerror(client->response_status, e2, sizeof(e2));
574
575 PJ_LOG(3,(THIS_FILE, " err: expecting %d (%s) but got %d (%s) response",
576 expected_code, e1, client->response_status, e2));
577 rc = -500;
578 }
579
580 } else {
581 int res_code = 0;
582 pj_stun_realm_attr *arealm;
583 pj_stun_nonce_attr *anonce;
584
585 if (client->response_status != 0) {
586 PJ_LOG(3,(THIS_FILE, " err: expecting successful operation but got error %d",
587 client->response_status));
588 rc = -600;
589 goto done;
590 }
591
592 if (PJ_STUN_IS_ERROR_RESPONSE(client->response->hdr.type)) {
593 pj_stun_errcode_attr *aerr = NULL;
594
595 aerr = (pj_stun_errcode_attr*)
596 pj_stun_msg_find_attr(client->response,
597 PJ_STUN_ATTR_ERROR_CODE, 0);
598 if (aerr == NULL) {
599 PJ_LOG(3,(THIS_FILE, " err: received error response without ERROR-CODE"));
600 rc = -610;
601 goto done;
602 }
603
604 res_code = aerr->err_code;
605 } else {
606 res_code = 0;
607 }
608
609 /* Check that code matches */
610 if (expected_code != res_code) {
611 PJ_LOG(3,(THIS_FILE, " err: expecting response code %d but got %d",
612 expected_code, res_code));
613 rc = -620;
614 goto done;
615 }
616
617 /* Find REALM and NONCE attributes */
618 arealm = (pj_stun_realm_attr*)
619 pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_REALM, 0);
620 anonce = (pj_stun_nonce_attr*)
621 pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_NONCE, 0);
622
623 if (expected_realm) {
624 if (arealm == NULL) {
625 PJ_LOG(3,(THIS_FILE, " err: expecting REALM in esponse"));
626 rc = -630;
627 goto done;
628 }
629 if (pj_strcmp2(&arealm->value, expected_realm)!=0) {
630 PJ_LOG(3,(THIS_FILE, " err: REALM mismatch in response"));
631 rc = -640;
632 goto done;
633 }
634 } else {
635 if (arealm != NULL) {
636 PJ_LOG(3,(THIS_FILE, " err: non expecting REALM in response"));
637 rc = -650;
638 goto done;
639 }
640 }
641
642 if (expected_nonce) {
643 if (anonce == NULL) {
644 PJ_LOG(3,(THIS_FILE, " err: expecting NONCE in esponse"));
645 rc = -660;
646 goto done;
647 }
648 if (pj_strcmp2(&anonce->value, expected_nonce)!=0) {
649 PJ_LOG(3,(THIS_FILE, " err: NONCE mismatch in response"));
650 rc = -670;
651 goto done;
652 }
653 } else {
654 if (anonce != NULL) {
655 PJ_LOG(3,(THIS_FILE, " err: non expecting NONCE in response"));
656 rc = -680;
657 goto done;
658 }
659 }
660 }
661
662 /* Our tests are okay so far. Let caller do some more tests if
663 * it wants to.
664 */
665 if (rc==0 && more_check) {
666 rc = (*more_check)();
667 }
668
669
670done:
671 destroy_client_server();
672 return rc;
673}
674
675
676//////////////////////////////////////////////////////////////////////////////////////////
677//
678// More verification
679//
680
681/* Retransmission test */
682static int retransmit_check(void)
683{
684 if (server->recv_count != PJ_STUN_MAX_TRANSMIT_COUNT)
685 return -700;
686 if (client->recv_count != 0)
687 return -710;
688
689 return 0;
690}
691
692static int long_term_check1(void)
693{
694 /* SHOULD NOT contain USERNAME or MESSAGE-INTEGRITY */
695 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_USERNAME, 0))
696 return -800;
697 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0))
698 return -800;
699
700 return 0;
701}
702
703static int long_term_check2(void)
704{
705 /* response SHOULD NOT include a USERNAME, NONCE, REALM or
706 * MESSAGE-INTEGRITY attribute.
707 */
708 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_USERNAME, 0))
709 return -900;
710 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_NONCE, 0))
711 return -910;
712 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_REALM, 0))
713 return -920;
714 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0))
715 return -930;
716
717 return 0;
718}
719
720static int long_term_check3(void)
721{
722 /* response SHOULD NOT include a USERNAME, NONCE, and REALM */
723 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_USERNAME, 0))
724 return -1000;
725 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_NONCE, 0))
726 return -1010;
727 if (pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_REALM, 0))
728 return -1020;
729
730 return 0;
731}
732
733//////////////////////////////////////////////////////////////////////////////////////////
734//
735// TEST MAIN
736//
737
738
739int sess_auth_test(void)
740{
741 pj_pool_t *pool;
742 int rc;
743
744 PJ_LOG(3,(THIS_FILE, " STUN session authentication test"));
745
746 /* Init STUN config */
747 pj_stun_config_init(&stun_cfg, mem, 0, NULL, NULL);
748
749 /* Create pool and timer heap */
750 pool = pj_pool_create(mem, "authtest", 200, 200, NULL);
751 if (pj_timer_heap_create(pool, 20, &stun_cfg.timer_heap)) {
752 pj_pool_release(pool);
753 return -5;
754 }
755
756 /* Basic retransmission test */
757 rc = run_client_test("Retransmission", // title
758 PJ_FALSE, // server responding
759 PJ_STUN_AUTH_NONE, // server auth
760 PJ_STUN_AUTH_NONE, // client auth
761 NULL, // realm
762 NULL, // username
763 NULL, // nonce
764 NULL, // password
765 PJ_FALSE, // dummy MI
766 PJ_TRUE, // expected error
767 PJNATH_ESTUNTIMEDOUT,// expected code
768 NULL, // expected realm
769 NULL, // expected nonce
770 &retransmit_check // more check
771 );
772 if (rc != 0) {
773 goto done;
774 }
775
776 /*
777 * Short term credential.
778 * draft-ietf-behave-rfc3489bis-15#section-10.1.2
779 */
780
781 /*
782 * If the message does not contain both a MESSAGE-INTEGRITY and a
783 * USERNAME attribute, If the message is a request, the server MUST
784 * reject the request with an error response. This response MUST
785 * use an error code of 400 (Bad Request).
786 */
787 rc = run_client_test("Missing MESSAGE-INTEGRITY (short term)", // title
788 PJ_TRUE, // server responding
789 PJ_STUN_AUTH_SHORT_TERM, // server auth
790 PJ_STUN_AUTH_NONE, // client auth
791 NULL, // realm
792 NULL, // username
793 NULL, // nonce
794 NULL, // password
795 PJ_FALSE, // dummy MI
796 PJ_TRUE, // expected error
797 PJ_STATUS_FROM_STUN_CODE(400),// expected code
798 NULL, // expected realm
799 NULL, // expected nonce
800 NULL // more check
801 );
802 if (rc != 0) {
803 goto done;
804 }
805
806 /* If the USERNAME does not contain a username value currently valid
807 * within the server: If the message is a request, the server MUST
808 * reject the request with an error response. This response MUST use
809 * an error code of 401 (Unauthorized).
810 */
811 rc = run_client_test("USERNAME mismatch (short term)", // title
812 PJ_TRUE, // server responding
813 PJ_STUN_AUTH_SHORT_TERM, // server auth
814 PJ_STUN_AUTH_SHORT_TERM, // client auth
815 NULL, // realm
816 "anotheruser", // username
817 NULL, // nonce
818 "anotherpass", // password
819 PJ_FALSE, // dummy MI
820 PJ_TRUE, // expected error
821 PJ_STATUS_FROM_STUN_CODE(401),// expected code
822 NULL, // expected realm
823 NULL, // expected nonce
824 NULL // more check
825 );
826 if (rc != 0) {
827 goto done;
828 }
829
830 /* Using the password associated with the username, compute the value
831 * for the message-integrity as described in Section 15.4. If the
832 * resulting value does not match the contents of the MESSAGE-
833 * INTEGRITY attribute:
834 *
835 * - If the message is a request, the server MUST reject the request
836 * with an error response. This response MUST use an error code
837 * of 401 (Unauthorized).
838 */
839 rc = run_client_test("MESSAGE-INTEGRITY mismatch (short term)", // title
840 PJ_TRUE, // server responding
841 PJ_STUN_AUTH_SHORT_TERM, // server auth
842 PJ_STUN_AUTH_SHORT_TERM, // client auth
843 NULL, // realm
844 USERNAME, // username
845 NULL, // nonce
846 "anotherpass", // password
847 PJ_FALSE, // dummy MI
848 PJ_TRUE, // expected error
849 PJ_STATUS_FROM_STUN_CODE(401),// expected code
850 NULL, // expected realm
851 NULL, // expected nonce
852 NULL // more check
853 );
854 if (rc != 0) {
855 goto done;
856 }
857
858 /* USERNAME is not present, server must respond with 400 (Bad
859 * Request).
860 */
861 rc = run_client_test("Missing USERNAME (short term)",// title
862 PJ_TRUE, // server responding
863 PJ_STUN_AUTH_SHORT_TERM, // server auth
864 PJ_STUN_AUTH_NONE, // client auth
865 NULL, // realm
866 NULL, // username
867 NULL, // nonce
868 NULL, // password
869 PJ_TRUE, // dummy MI
870 PJ_TRUE, // expected error
871 PJ_STATUS_FROM_STUN_CODE(400), // expected code
872 NULL, // expected realm
873 NULL, // expected nonce
874 NULL // more check
875 );
876 if (rc != 0) {
877 goto done;
878 }
879
880 /* Successful short term authentication */
881 rc = run_client_test("Successful scenario (short term)", // title
882 PJ_TRUE, // server responding
883 PJ_STUN_AUTH_SHORT_TERM, // server auth
884 PJ_STUN_AUTH_SHORT_TERM, // client auth
885 NULL, // realm
886 USERNAME, // username
887 NULL, // nonce
888 PASSWORD, // password
889 PJ_FALSE, // dummy MI
890 PJ_FALSE, // expected error
891 PJ_SUCCESS, // expected code
892 NULL, // expected realm
893 NULL, // expected nonce
894 NULL // more check
895 );
896 if (rc != 0) {
897 goto done;
898 }
899
900 /*
901 * (our own) Extended tests for long term credential
902 */
903
904 /* When server wants to use short term credential, but request has
905 * REALM, reject with .... 401 ???
906 */
907 rc = run_client_test("Unwanted REALM (short term)", // title
908 PJ_TRUE, // server responding
909 PJ_STUN_AUTH_SHORT_TERM, // server auth
910 PJ_STUN_AUTH_NONE, // client auth
911 REALM, // realm
912 USERNAME, // username
913 NULL, // nonce
914 PASSWORD, // password
915 PJ_TRUE, // dummy MI
916 PJ_TRUE, // expected error
917 PJ_STATUS_FROM_STUN_CODE(401), // expected code
918 NULL, // expected realm
919 NULL, // expected nonce
920 &long_term_check2 // more check
921 );
922 if (rc != 0) {
923 goto done;
924 }
925
926
927 /*
928 * Long term credential.
929 * draft-ietf-behave-rfc3489bis-15#section-10.2.2
930 */
931
932 /* If the message does not contain a MESSAGE-INTEGRITY attribute, the
933 * server MUST generate an error response with an error code of 401
934 * (Unauthorized). This response MUST include a REALM value. It is
935 * RECOMMENDED that the REALM value be the domain name of the
936 * provider of the STUN server. The response MUST include a NONCE,
937 * selected by the server. The response SHOULD NOT contain a
938 * USERNAME or MESSAGE-INTEGRITY attribute.
939 */
940 rc = run_client_test("Missing M-I (long term)", // title
941 PJ_TRUE, // server responding
942 PJ_STUN_AUTH_LONG_TERM, // server auth
943 PJ_STUN_AUTH_NONE, // client auth
944 NULL, // client realm
945 NULL, // client username
946 NULL, // client nonce
947 NULL, // client password
948 PJ_FALSE, // client dummy MI
949 PJ_TRUE, // expected error
950 PJ_STATUS_FROM_STUN_CODE(401), // expected code
951 REALM, // expected realm
952 NONCE, // expected nonce
953 &long_term_check1 // more check
954 );
955 if (rc != 0) {
956 goto done;
957 }
958
959 /* If the message contains a MESSAGE-INTEGRITY attribute, but is
960 * missing the USERNAME, REALM or NONCE attributes, the server MUST
961 * generate an error response with an error code of 400 (Bad
962 * Request). This response SHOULD NOT include a USERNAME, NONCE,
963 * REALM or MESSAGE-INTEGRITY attribute.
964 */
965 /* Missing USERNAME */
966 rc = run_client_test("Missing USERNAME (long term)", // title
967 PJ_TRUE, // server responding
968 PJ_STUN_AUTH_LONG_TERM, // server auth
969 PJ_STUN_AUTH_NONE, // client auth
970 REALM, // client realm
971 NULL, // client username
972 NONCE, // client nonce
973 PASSWORD, // client password
974 PJ_TRUE, // client dummy MI
975 PJ_TRUE, // expected error
976 PJ_STATUS_FROM_STUN_CODE(400), // expected code
977 NULL, // expected realm
978 NULL, // expected nonce
979 &long_term_check2 // more check
980 );
981 if (rc != 0) {
982 goto done;
983 }
984
985 /* Missing REALM */
986 rc = run_client_test("Missing REALM (long term)", // title
987 PJ_TRUE, // server responding
988 PJ_STUN_AUTH_LONG_TERM, // server auth
989 PJ_STUN_AUTH_NONE, // client auth
990 NULL, // client realm
991 USERNAME, // client username
992 NONCE, // client nonce
993 PASSWORD, // client password
994 PJ_TRUE, // client dummy MI
995 PJ_TRUE, // expected error
996 PJ_STATUS_FROM_STUN_CODE(400), // expected code
997 NULL, // expected realm
998 NULL, // expected nonce
999 &long_term_check2 // more check
1000 );
1001 if (rc != 0) {
1002 goto done;
1003 }
1004
1005 /* Missing NONCE */
1006 rc = run_client_test("Missing NONCE (long term)", // title
1007 PJ_TRUE, // server responding
1008 PJ_STUN_AUTH_LONG_TERM, // server auth
1009 PJ_STUN_AUTH_NONE, // client auth
1010 REALM, // client realm
1011 USERNAME, // client username
1012 NULL, // client nonce
1013 PASSWORD, // client password
1014 PJ_TRUE, // client dummy MI
1015 PJ_TRUE, // expected error
1016 PJ_STATUS_FROM_STUN_CODE(400), // expected code
1017 NULL, // expected realm
1018 NULL, // expected nonce
1019 &long_term_check2 // more check
1020 );
1021 if (rc != 0) {
1022 goto done;
1023 }
1024
1025 /* If the NONCE is no longer valid, the server MUST generate an error
1026 * response with an error code of 438 (Stale Nonce). This response
1027 * MUST include a NONCE and REALM attribute and SHOULD NOT incude the
1028 * USERNAME or MESSAGE-INTEGRITY attribute. Servers can invalidate
1029 * nonces in order to provide additional security. See Section 4.3
1030 * of [RFC2617] for guidelines.
1031 */
1032 // how??
1033
1034 /* If the username in the USERNAME attribute is not valid, the server
1035 * MUST generate an error response with an error code of 401
1036 * (Unauthorized). This response MUST include a REALM value. It is
1037 * RECOMMENDED that the REALM value be the domain name of the
1038 * provider of the STUN server. The response MUST include a NONCE,
1039 * selected by the server. The response SHOULD NOT contain a
1040 * USERNAME or MESSAGE-INTEGRITY attribute.
1041 */
1042 rc = run_client_test("Invalid username (long term)", // title
1043 PJ_TRUE, // server responding
1044 PJ_STUN_AUTH_LONG_TERM, // server auth
1045 PJ_STUN_AUTH_LONG_TERM, // client auth
1046 REALM, // client realm
1047 "anotheruser", // client username
1048 "a nonce", // client nonce
1049 "somepassword", // client password
1050 PJ_FALSE, // client dummy MI
1051 PJ_TRUE, // expected error
1052 PJ_STATUS_FROM_STUN_CODE(401), // expected code
1053 REALM, // expected realm
1054 NONCE, // expected nonce
1055 &long_term_check1 // more check
1056 );
1057 if (rc != 0) {
1058 goto done;
1059 }
1060
1061 /* Successful long term authentication */
1062 rc = run_client_test("Successful scenario (long term)", // title
1063 PJ_TRUE, // server responding
1064 PJ_STUN_AUTH_LONG_TERM, // server auth
1065 PJ_STUN_AUTH_LONG_TERM, // client auth
1066 REALM, // client realm
1067 USERNAME, // client username
1068 "anothernonce", // client nonce
1069 PASSWORD, // client password
1070 PJ_FALSE, // client dummy MI
1071 PJ_FALSE, // expected error
1072 0, // expected code
1073 NULL, // expected realm
1074 NULL, // expected nonce
1075 &long_term_check3 // more check
1076 );
1077 if (rc != 0) {
1078 goto done;
1079 }
1080
1081 /*
1082 * (our own) Extended tests for long term credential
1083 */
1084
1085 /* If REALM doesn't match, server must respond with 401
1086 */
1087 rc = run_client_test("Invalid REALM (long term)", // title
1088 PJ_TRUE, // server responding
1089 PJ_STUN_AUTH_LONG_TERM, // server auth
1090 PJ_STUN_AUTH_LONG_TERM, // client auth
1091 "anotherrealm", // client realm
1092 USERNAME, // client username
1093 NONCE, // client nonce
1094 PASSWORD, // client password
1095 PJ_FALSE, // client dummy MI
1096 PJ_TRUE, // expected error
1097 PJ_STATUS_FROM_STUN_CODE(401), // expected code
1098 REALM, // expected realm
1099 NONCE, // expected nonce
1100 &long_term_check1 // more check
1101 );
1102 if (rc != 0) {
1103 goto done;
1104 }
1105
1106 /* Invalid HMAC */
1107
1108 /* Valid static short term, without NONCE */
1109
1110 /* Valid static short term, WITH NONCE */
1111
1112 /* Valid static long term (with NONCE */
1113
1114 /* Valid dynamic short term (without NONCE) */
1115
1116 /* Valid dynamic short term (with NONCE) */
1117
1118 /* Valid dynamic long term (with NONCE) */
1119
1120
1121done:
1122 pj_timer_heap_destroy(stun_cfg.timer_heap);
1123 pj_pool_release(pool);
1124 return rc;
1125}