Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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 */
34 static char *RCSSTRING __UNUSED__="$Id: stun_build.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
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>
43 #include "nr_api.h"
44 #include "stun.h"
45 #include "registry.h"
46 #include "stun_reg.h"
47 #include "nr_crypto.h"
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;
64 assert(NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_REQUEST
65 || NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_INDICATION);
67 *msg = 0;
69 if ((r=nr_stun_message_create(&req)))
70 ABORT(r);
72 req->header.type = msg_type;
74 nr_crypto_random_bytes((UCHAR*)&req->header.id,sizeof(req->header.id));
76 switch (mode) {
77 default:
78 req->header.magic_cookie = NR_STUN_MAGIC_COOKIE;
80 if ((r=nr_stun_message_add_fingerprint_attribute(req)))
81 ABORT(r);
83 break;
85 #ifdef USE_STUND_0_96
86 case NR_STUN_MODE_STUND_0_96:
87 req->header.magic_cookie = NR_STUN_MAGIC_COOKIE2;
89 /* actually, stund 0.96 just ignores the fingerprint
90 * attribute, but don't bother to send it */
92 break;
93 #endif /* USE_STUND_0_96 */
95 }
97 *msg = req;
99 _status=0;
100 abort:
101 if (_status) RFREE(req);
102 return _status;
103 }
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;
111 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
112 ABORT(r);
114 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
115 ABORT(r);
117 if (params->realm && params->nonce) {
118 if ((r=nr_stun_message_add_realm_attribute(req, params->realm)))
119 ABORT(r);
121 if ((r=nr_stun_message_add_nonce_attribute(req, params->nonce)))
122 ABORT(r);
124 if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
125 ABORT(r);
126 }
128 *msg = req;
130 _status=0;
131 abort:
132 if (_status) nr_stun_message_destroy(&req);
133 return _status;
134 }
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;
142 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
143 ABORT(r);
145 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
146 ABORT(r);
148 if (params->password) {
149 if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
150 ABORT(r);
151 }
153 *msg = req;
155 _status=0;
156 abort:
157 if (_status) nr_stun_message_destroy(&req);
158 return _status;
159 }
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;
167 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
168 ABORT(r);
170 *msg = req;
172 _status=0;
173 abort:
174 if (_status) nr_stun_message_destroy(&req);
175 return _status;
176 }
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;
184 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_INDICATION, &ind)))
185 ABORT(r);
187 *msg = ind;
189 _status=0;
190 abort:
191 if (_status) nr_stun_message_destroy(&ind);
192 return _status;
193 }
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;
202 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUND_0_96, NR_STUN_MSG_BINDING_REQUEST, &req)))
203 ABORT(r);
205 if ((r=nr_stun_message_add_change_request_attribute(req, 0)))
206 ABORT(r);
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));
211 *msg = req;
213 _status=0;
214 abort:
215 if (_status) nr_stun_message_destroy(&req);
216 return _status;
217 }
218 #endif /* USE_STUND_0_96 */
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;
227 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
228 ABORT(r);
230 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
231 ABORT(r);
233 if ((r=nr_stun_message_add_message_integrity_attribute(req, ¶ms->password)))
234 ABORT(r);
236 if ((r=nr_stun_message_add_use_candidate_attribute(req)))
237 ABORT(r);
239 if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
240 ABORT(r);
242 if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker)))
243 ABORT(r);
245 *msg = req;
247 _status=0;
248 abort:
249 if (_status) nr_stun_message_destroy(&req);
250 return _status;
251 }
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;
259 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
260 ABORT(r);
262 if ((r=nr_stun_message_add_username_attribute(req, params->username)))
263 ABORT(r);
265 if ((r=nr_stun_message_add_message_integrity_attribute(req, ¶ms->password)))
266 ABORT(r);
268 if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
269 ABORT(r);
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 }
285 *msg = req;
287 _status=0;
288 abort:
289 if (_status) nr_stun_message_destroy(&req);
290 return _status;
291 }
292 #endif /* USE_ICE */
294 #ifdef USE_TURN
296 #ifndef __isascii
297 #define __isascii(c) (((c) & ~0x7F) == 0)
298 #endif
300 /* Long-term passwords are computed over the key:
302 key = MD5(username ":" realm ":" SASLprep(password))
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;
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 }
324 if (hmac_key->len < 16)
325 ABORT(R_BAD_ARGS);
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);
331 len = strlen(digest_input);
332 memcpy(digest_input + len, password->data, password->len);
335 if (r=nr_crypto_md5((UCHAR *)digest_input, len + password->len, hmac_key->data))
336 ABORT(r);
337 hmac_key->len=16;
339 _status=0;
340 abort:
341 return(_status);
342 }
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;
351 ATTACH_DATA(hmac_key, hmac_key_d);
353 if (!auth->authenticate)
354 goto done;
356 assert(auth->username);
357 assert(auth->password.len);
358 assert(auth->realm);
359 assert(auth->nonce);
361 if (r=nr_stun_compute_lt_message_integrity_password(auth->username,
362 auth->realm,
363 &auth->password,
364 &hmac_key))
365 ABORT(r);
367 if (!auth->username) {
368 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no username provided");
369 ABORT(R_INTERNAL);
370 }
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 }
377 if (!auth->realm) {
378 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no realm provided");
379 ABORT(R_INTERNAL);
380 }
382 if (!auth->nonce) {
383 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no nonce provided");
384 ABORT(R_INTERNAL);
385 }
387 if ((r=nr_stun_message_add_username_attribute(req, auth->username)))
388 ABORT(r);
390 if ((r=nr_stun_message_add_realm_attribute(req, auth->realm)))
391 ABORT(r);
393 if ((r=nr_stun_message_add_nonce_attribute(req, auth->nonce)))
394 ABORT(r);
396 if ((r=nr_stun_message_add_message_integrity_attribute(req, &hmac_key)))
397 ABORT(r);
399 done:
400 _status=0;
401 abort:
402 return(_status);
403 }
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;
411 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_ALLOCATE_REQUEST, &req)))
412 ABORT(r);
414 if ((r=nr_stun_message_add_requested_transport_attribute(req, NR_STUN_ATTR_REQUESTED_TRANSPORT_UDP)))
415 ABORT(r);
417 if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
418 ABORT(r);
420 /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */
422 if ((r=nr_stun_build_auth_params(auth, req)))
423 ABORT(r);
425 *msg = req;
427 _status=0;
428 abort:
429 if (_status) nr_stun_message_destroy(&req);
430 return _status;
431 }
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;
439 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_REFRESH_REQUEST, &req)))
440 ABORT(r);
442 if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
443 ABORT(r);
446 /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */
448 if ((r=nr_stun_build_auth_params(auth, req)))
449 ABORT(r);
451 *msg = req;
453 _status=0;
454 abort:
455 if (_status) nr_stun_message_destroy(&req);
456 return _status;
457 }
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;
465 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_PERMISSION_REQUEST, &req)))
466 ABORT(r);
468 if ((r=nr_stun_message_add_xor_peer_address_attribute(req, ¶ms->remote_addr)))
469 ABORT(r);
471 if ((r=nr_stun_build_auth_params(auth, req)))
472 ABORT(r);
474 *msg = req;
476 _status=0;
477 abort:
478 if (_status) nr_stun_message_destroy(&req);
479 return _status;
480 }
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;
488 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_SEND_INDICATION, &ind)))
489 ABORT(r);
491 if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, ¶ms->remote_addr)))
492 ABORT(r);
494 if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len)))
495 ABORT(r);
497 *msg = ind;
499 _status=0;
500 abort:
501 if (_status) nr_stun_message_destroy(&ind);
502 return _status;
503 }
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;
511 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_DATA_INDICATION, &ind)))
512 ABORT(r);
514 if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, ¶ms->remote_addr)))
515 ABORT(r);
517 if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len)))
518 ABORT(r);
520 *msg = ind;
522 _status=0;
523 abort:
524 if (_status) nr_stun_message_destroy(&ind);
525 return _status;
526 }
528 #endif /* USE_TURN */
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 */
538 /* set up information for default response */
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));
545 r_log(NR_LOG_STUN, LOG_DEBUG, "Mapped Address = %s", from->as_string);
547 if ((r=nr_stun_message_add_xor_mapped_address_attribute(res, from)))
548 ABORT(r);
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 }
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 }
561 if ((r=nr_stun_message_add_fingerprint_attribute(res)))
562 ABORT(r);
563 }
565 _status=0;
566 abort:
567 return _status;
568 }
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 */
578 if (number < 300 || number > 699)
579 number = 500;
581 r_log(NR_LOG_STUN, LOG_INFO, "Responding with error %d: %s", number, msg);
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));
588 /* during development we should never see 500s (hopefully not in deployment either) */
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 }
606 if (nr_stun_message_add_error_code_attribute(res, number, str)) {
607 assert(0); /* should never happen */
608 }
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 }