media/mtransport/third_party/nICEr/src/stun/stun_build.c

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:7458b8f2b6b7
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34 static char *RCSSTRING __UNUSED__="$Id: stun_build.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
35
36 #include <csi_platform.h>
37 #include <assert.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <ctype.h>
42
43 #include "nr_api.h"
44 #include "stun.h"
45 #include "registry.h"
46 #include "stun_reg.h"
47 #include "nr_crypto.h"
48
49
50 /* draft-ietf-behave-rfc3489bis-10.txt S 7.1 */
51 /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.1 */
52 /* note that S 10.1.1 states the message MUST include MESSAGE-INTEGRITY
53 * and USERNAME, but that's not correct -- for instance ICE keepalive
54 * messages don't include these (See draft-ietf-mmusic-ice-18.txt S 10:
55 * "If STUN is being used for keepalives, a STUN Binding Indication is
56 * used. The Indication MUST NOT utilize any authentication mechanism")
57 */
58 int
59 nr_stun_form_request_or_indication(int mode, int msg_type, nr_stun_message **msg)
60 {
61 int r,_status;
62 nr_stun_message *req = 0;
63
64 assert(NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_REQUEST
65 || NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_INDICATION);
66
67 *msg = 0;
68
69 if ((r=nr_stun_message_create(&req)))
70 ABORT(r);
71
72 req->header.type = msg_type;
73
74 nr_crypto_random_bytes((UCHAR*)&req->header.id,sizeof(req->header.id));
75
76 switch (mode) {
77 default:
78 req->header.magic_cookie = NR_STUN_MAGIC_COOKIE;
79
80 if ((r=nr_stun_message_add_fingerprint_attribute(req)))
81 ABORT(r);
82
83 break;
84
85 #ifdef USE_STUND_0_96
86 case NR_STUN_MODE_STUND_0_96:
87 req->header.magic_cookie = NR_STUN_MAGIC_COOKIE2;
88
89 /* actually, stund 0.96 just ignores the fingerprint
90 * attribute, but don't bother to send it */
91
92 break;
93 #endif /* USE_STUND_0_96 */
94
95 }
96
97 *msg = req;
98
99 _status=0;
100 abort:
101 if (_status) RFREE(req);
102 return _status;
103 }
104
105 int
106 nr_stun_build_req_lt_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg)
107 {
108 int r,_status;
109 nr_stun_message *req = 0;
110
111 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
112 ABORT(r);
113
114 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
115 ABORT(r);
116
117 if (params->realm && params->nonce) {
118 if ((r=nr_stun_message_add_realm_attribute(req, params->realm)))
119 ABORT(r);
120
121 if ((r=nr_stun_message_add_nonce_attribute(req, params->nonce)))
122 ABORT(r);
123
124 if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
125 ABORT(r);
126 }
127
128 *msg = req;
129
130 _status=0;
131 abort:
132 if (_status) nr_stun_message_destroy(&req);
133 return _status;
134 }
135
136 int
137 nr_stun_build_req_st_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg)
138 {
139 int r,_status;
140 nr_stun_message *req = 0;
141
142 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
143 ABORT(r);
144
145 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
146 ABORT(r);
147
148 if (params->password) {
149 if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
150 ABORT(r);
151 }
152
153 *msg = req;
154
155 _status=0;
156 abort:
157 if (_status) nr_stun_message_destroy(&req);
158 return _status;
159 }
160
161 int
162 nr_stun_build_req_no_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg)
163 {
164 int r,_status;
165 nr_stun_message *req = 0;
166
167 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
168 ABORT(r);
169
170 *msg = req;
171
172 _status=0;
173 abort:
174 if (_status) nr_stun_message_destroy(&req);
175 return _status;
176 }
177
178 int
179 nr_stun_build_keepalive(nr_stun_client_stun_keepalive_params *params, nr_stun_message **msg)
180 {
181 int r,_status;
182 nr_stun_message *ind = 0;
183
184 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_INDICATION, &ind)))
185 ABORT(r);
186
187 *msg = ind;
188
189 _status=0;
190 abort:
191 if (_status) nr_stun_message_destroy(&ind);
192 return _status;
193 }
194
195 #ifdef USE_STUND_0_96
196 int
197 nr_stun_build_req_stund_0_96(nr_stun_client_stun_binding_request_stund_0_96_params *params, nr_stun_message **msg)
198 {
199 int r,_status;
200 nr_stun_message *req = 0;
201
202 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUND_0_96, NR_STUN_MSG_BINDING_REQUEST, &req)))
203 ABORT(r);
204
205 if ((r=nr_stun_message_add_change_request_attribute(req, 0)))
206 ABORT(r);
207
208 assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0));
209 assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0));
210
211 *msg = req;
212
213 _status=0;
214 abort:
215 if (_status) nr_stun_message_destroy(&req);
216 return _status;
217 }
218 #endif /* USE_STUND_0_96 */
219
220 #ifdef USE_ICE
221 int
222 nr_stun_build_use_candidate(nr_stun_client_ice_use_candidate_params *params, nr_stun_message **msg)
223 {
224 int r,_status;
225 nr_stun_message *req = 0;
226
227 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
228 ABORT(r);
229
230 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
231 ABORT(r);
232
233 if ((r=nr_stun_message_add_message_integrity_attribute(req, &params->password)))
234 ABORT(r);
235
236 if ((r=nr_stun_message_add_use_candidate_attribute(req)))
237 ABORT(r);
238
239 if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
240 ABORT(r);
241
242 if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker)))
243 ABORT(r);
244
245 *msg = req;
246
247 _status=0;
248 abort:
249 if (_status) nr_stun_message_destroy(&req);
250 return _status;
251 }
252
253 int
254 nr_stun_build_req_ice(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg)
255 {
256 int r,_status;
257 nr_stun_message *req = 0;
258
259 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
260 ABORT(r);
261
262 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
263 ABORT(r);
264
265 if ((r=nr_stun_message_add_message_integrity_attribute(req, &params->password)))
266 ABORT(r);
267
268 if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
269 ABORT(r);
270
271 switch (params->control) {
272 case NR_ICE_CONTROLLING:
273 if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker)))
274 ABORT(r);
275 break;
276 case NR_ICE_CONTROLLED:
277 if ((r=nr_stun_message_add_ice_controlled_attribute(req, params->tiebreaker)))
278 ABORT(r);
279 break;
280 default:
281 assert(0);
282 ABORT(R_INTERNAL);
283 }
284
285 *msg = req;
286
287 _status=0;
288 abort:
289 if (_status) nr_stun_message_destroy(&req);
290 return _status;
291 }
292 #endif /* USE_ICE */
293
294 #ifdef USE_TURN
295
296 #ifndef __isascii
297 #define __isascii(c) (((c) & ~0x7F) == 0)
298 #endif
299
300 /* Long-term passwords are computed over the key:
301
302 key = MD5(username ":" realm ":" SASLprep(password))
303
304 Per RFC 5389 S 15.4
305 */
306 int
307 nr_stun_compute_lt_message_integrity_password(const char *username, const char *realm,
308 Data *password, Data *hmac_key)
309 {
310 char digest_input[1000];
311 int i;
312 int r, _status;
313 size_t len;
314
315 /* First check that the password is ASCII. We are supposed to
316 SASLprep but we don't support this yet
317 TODO(ekr@rtfm.com): Add SASLprep for password.
318 */
319 for (i=0; i<password->len; i++) {
320 if (!__isascii(password->data[i]))
321 ABORT(R_BAD_DATA);
322 }
323
324 if (hmac_key->len < 16)
325 ABORT(R_BAD_ARGS);
326
327 snprintf(digest_input, sizeof(digest_input), "%s:%s:", username, realm);
328 if ((sizeof(digest_input) - strlen(digest_input)) < password->len)
329 ABORT(R_BAD_DATA);
330
331 len = strlen(digest_input);
332 memcpy(digest_input + len, password->data, password->len);
333
334
335 if (r=nr_crypto_md5((UCHAR *)digest_input, len + password->len, hmac_key->data))
336 ABORT(r);
337 hmac_key->len=16;
338
339 _status=0;
340 abort:
341 return(_status);
342 }
343
344 static int
345 nr_stun_build_auth_params(nr_stun_client_auth_params *auth, nr_stun_message *req)
346 {
347 int r, _status;
348 UCHAR hmac_key_d[16];
349 Data hmac_key;
350
351 ATTACH_DATA(hmac_key, hmac_key_d);
352
353 if (!auth->authenticate)
354 goto done;
355
356 assert(auth->username);
357 assert(auth->password.len);
358 assert(auth->realm);
359 assert(auth->nonce);
360
361 if (r=nr_stun_compute_lt_message_integrity_password(auth->username,
362 auth->realm,
363 &auth->password,
364 &hmac_key))
365 ABORT(r);
366
367 if (!auth->username) {
368 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no username provided");
369 ABORT(R_INTERNAL);
370 }
371
372 if (!auth->password.len) {
373 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no password provided");
374 ABORT(R_INTERNAL);
375 }
376
377 if (!auth->realm) {
378 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no realm provided");
379 ABORT(R_INTERNAL);
380 }
381
382 if (!auth->nonce) {
383 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no nonce provided");
384 ABORT(R_INTERNAL);
385 }
386
387 if ((r=nr_stun_message_add_username_attribute(req, auth->username)))
388 ABORT(r);
389
390 if ((r=nr_stun_message_add_realm_attribute(req, auth->realm)))
391 ABORT(r);
392
393 if ((r=nr_stun_message_add_nonce_attribute(req, auth->nonce)))
394 ABORT(r);
395
396 if ((r=nr_stun_message_add_message_integrity_attribute(req, &hmac_key)))
397 ABORT(r);
398
399 done:
400 _status=0;
401 abort:
402 return(_status);
403 }
404
405 int
406 nr_stun_build_allocate_request(nr_stun_client_auth_params *auth, nr_stun_client_allocate_request_params *params, nr_stun_message **msg)
407 {
408 int r,_status;
409 nr_stun_message *req = 0;
410
411 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_ALLOCATE_REQUEST, &req)))
412 ABORT(r);
413
414 if ((r=nr_stun_message_add_requested_transport_attribute(req, NR_STUN_ATTR_REQUESTED_TRANSPORT_UDP)))
415 ABORT(r);
416
417 if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
418 ABORT(r);
419
420 /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */
421
422 if ((r=nr_stun_build_auth_params(auth, req)))
423 ABORT(r);
424
425 *msg = req;
426
427 _status=0;
428 abort:
429 if (_status) nr_stun_message_destroy(&req);
430 return _status;
431 }
432
433
434 int nr_stun_build_refresh_request(nr_stun_client_auth_params *auth, nr_stun_client_refresh_request_params *params, nr_stun_message **msg)
435 {
436 int r,_status;
437 nr_stun_message *req = 0;
438
439 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_REFRESH_REQUEST, &req)))
440 ABORT(r);
441
442 if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
443 ABORT(r);
444
445
446 /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */
447
448 if ((r=nr_stun_build_auth_params(auth, req)))
449 ABORT(r);
450
451 *msg = req;
452
453 _status=0;
454 abort:
455 if (_status) nr_stun_message_destroy(&req);
456 return _status;
457 }
458
459
460 int nr_stun_build_permission_request(nr_stun_client_auth_params *auth, nr_stun_client_permission_request_params *params, nr_stun_message **msg)
461 {
462 int r,_status;
463 nr_stun_message *req = 0;
464
465 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_PERMISSION_REQUEST, &req)))
466 ABORT(r);
467
468 if ((r=nr_stun_message_add_xor_peer_address_attribute(req, &params->remote_addr)))
469 ABORT(r);
470
471 if ((r=nr_stun_build_auth_params(auth, req)))
472 ABORT(r);
473
474 *msg = req;
475
476 _status=0;
477 abort:
478 if (_status) nr_stun_message_destroy(&req);
479 return _status;
480 }
481
482 int
483 nr_stun_build_send_indication(nr_stun_client_send_indication_params *params, nr_stun_message **msg)
484 {
485 int r,_status;
486 nr_stun_message *ind = 0;
487
488 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_SEND_INDICATION, &ind)))
489 ABORT(r);
490
491 if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, &params->remote_addr)))
492 ABORT(r);
493
494 if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len)))
495 ABORT(r);
496
497 *msg = ind;
498
499 _status=0;
500 abort:
501 if (_status) nr_stun_message_destroy(&ind);
502 return _status;
503 }
504
505 int
506 nr_stun_build_data_indication(nr_stun_client_data_indication_params *params, nr_stun_message **msg)
507 {
508 int r,_status;
509 nr_stun_message *ind = 0;
510
511 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_DATA_INDICATION, &ind)))
512 ABORT(r);
513
514 if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, &params->remote_addr)))
515 ABORT(r);
516
517 if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len)))
518 ABORT(r);
519
520 *msg = ind;
521
522 _status=0;
523 abort:
524 if (_status) nr_stun_message_destroy(&ind);
525 return _status;
526 }
527
528 #endif /* USE_TURN */
529
530 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */
531 int
532 nr_stun_form_success_response(nr_stun_message *req, nr_transport_addr *from, Data *password, nr_stun_message *res)
533 {
534 int r,_status;
535 int request_method;
536 char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */
537
538 /* set up information for default response */
539
540 request_method = NR_STUN_GET_TYPE_METHOD(req->header.type);
541 res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_RESPONSE);
542 res->header.magic_cookie = req->header.magic_cookie;
543 memcpy(&res->header.id, &req->header.id, sizeof(res->header.id));
544
545 r_log(NR_LOG_STUN, LOG_DEBUG, "Mapped Address = %s", from->as_string);
546
547 if ((r=nr_stun_message_add_xor_mapped_address_attribute(res, from)))
548 ABORT(r);
549
550 if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) {
551 if ((r=nr_stun_message_add_server_attribute(res, server_name)))
552 ABORT(r);
553 }
554
555 if (res->header.magic_cookie == NR_STUN_MAGIC_COOKIE) {
556 if (password != 0) {
557 if ((r=nr_stun_message_add_message_integrity_attribute(res, password)))
558 ABORT(r);
559 }
560
561 if ((r=nr_stun_message_add_fingerprint_attribute(res)))
562 ABORT(r);
563 }
564
565 _status=0;
566 abort:
567 return _status;
568 }
569
570 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */
571 void
572 nr_stun_form_error_response(nr_stun_message *req, nr_stun_message* res, int number, char* msg)
573 {
574 char *str;
575 int request_method;
576 char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */
577
578 if (number < 300 || number > 699)
579 number = 500;
580
581 r_log(NR_LOG_STUN, LOG_INFO, "Responding with error %d: %s", number, msg);
582
583 request_method = NR_STUN_GET_TYPE_METHOD(req->header.type);
584 res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_ERROR_RESPONSE);
585 res->header.magic_cookie = req->header.magic_cookie;
586 memcpy(&res->header.id, &req->header.id, sizeof(res->header.id));
587
588 /* during development we should never see 500s (hopefully not in deployment either) */
589
590 str = 0;
591 switch (number) {
592 case 300: str = "Try Alternate"; break;
593 case 400: str = "Bad Request"; break;
594 case 401: str = "Unauthorized"; break;
595 case 420: str = "Unknown Attribute"; break;
596 case 438: str = "Stale Nonce"; break;
597 #ifdef USE_ICE
598 case 487: str = "Role Conflict"; break;
599 #endif
600 case 500: str = "Server Error"; break;
601 }
602 if (str == 0) {
603 str = "Unknown";
604 }
605
606 if (nr_stun_message_add_error_code_attribute(res, number, str)) {
607 assert(0); /* should never happen */
608 }
609
610 if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) {
611 nr_stun_message_add_server_attribute(res, server_name);
612 }
613 }
614

mercurial