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_proc.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
36 #include <errno.h>
37 #include <csi_platform.h>
39 #ifdef WIN32
40 #include <winsock2.h>
41 #include <stdlib.h>
42 #include <io.h>
43 #include <time.h>
44 #else /* UNIX */
45 #include <string.h>
46 #endif /* end UNIX */
47 #include <assert.h>
49 #include "stun.h"
50 #include "stun_reg.h"
51 #include "registry.h"
53 static int
54 nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res);
56 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */
57 int
58 nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg)
59 {
60 int _status;
61 nr_stun_message_attribute *attr;
63 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
64 /* if this message was generated by an RFC 3489 impementation,
65 * the call to nr_is_stun_message will fail, so skip that
66 * check and puke elsewhere if the message can't be decoded */
67 if (msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE
68 || msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE2) {
69 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
70 if (!nr_is_stun_message(msg->buffer, msg->length)) {
71 r_log(NR_LOG_STUN, LOG_WARNING, "Not a STUN message");
72 ABORT(R_REJECTED);
73 }
74 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
75 }
76 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
78 if (req == 0) {
79 if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_REQUEST) {
80 r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message type: %03x", msg->header.type);
81 ABORT(R_REJECTED);
82 }
83 }
84 else {
85 if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_RESPONSE
86 && NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_ERROR_RESPONSE) {
87 r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message class: %03x", msg->header.type);
88 ABORT(R_REJECTED);
89 }
91 if (NR_STUN_GET_TYPE_METHOD(req->header.type) != NR_STUN_GET_TYPE_METHOD(msg->header.type)) {
92 r_log(NR_LOG_STUN,LOG_WARNING,"Inconsistent message method: %03x expected %03x", msg->header.type, req->header.type);
93 ABORT(R_REJECTED);
94 }
96 if (nr_stun_different_transaction(msg->buffer, msg->length, req)) {
97 r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized STUN transaction");
98 ABORT(R_REJECTED);
99 }
100 }
102 switch (msg->header.magic_cookie) {
103 case NR_STUN_MAGIC_COOKIE:
104 /* basically draft-ietf-behave-rfc3489bis-10.txt S 6 rules */
106 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &attr)
107 && !attr->u.fingerprint.valid) {
108 r_log(NR_LOG_STUN, LOG_WARNING, "Invalid fingerprint");
109 ABORT(R_REJECTED);
110 }
112 break;
114 #ifdef USE_STUND_0_96
115 case NR_STUN_MAGIC_COOKIE2:
116 /* nothing to check in this case */
117 break;
118 #endif /* USE_STUND_0_96 */
120 default:
121 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
122 /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
123 #else
124 #ifdef NDEBUG
125 /* in deployment builds we should always see a recognized magic cookie */
126 r_log(NR_LOG_STUN, LOG_WARNING, "Missing Magic Cookie");
127 ABORT(R_REJECTED);
128 #else
129 /* ignore this condition because sometimes we like to pretend we're
130 * a server talking to old clients and their messages don't contain
131 * a magic cookie at all but rather the magic cookie field is part
132 * of their ID and therefore random */
133 #endif /* NDEBUG */
134 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
135 break;
136 }
138 _status=0;
139 abort:
140 return _status;
141 }
143 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1 */
144 int
145 nr_stun_process_request(nr_stun_message *req, nr_stun_message *res)
146 {
147 int _status;
148 #ifdef USE_STUN_PEDANTIC
149 int r;
150 nr_stun_attr_unknown_attributes unknown_attributes = { { 0 } };
151 nr_stun_message_attribute *attr;
153 if (req->comprehension_required_unknown_attributes > 0) {
154 nr_stun_form_error_response(req, res, 420, "Unknown Attributes");
156 TAILQ_FOREACH(attr, &req->attributes, entry) {
157 if (attr->name == 0) {
158 /* unrecognized attribute */
160 /* should never happen, but truncate if it ever were to occur */
161 if (unknown_attributes.num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES)
162 break;
164 unknown_attributes.attribute[unknown_attributes.num_attributes++] = attr->type;
165 }
166 }
168 assert(req->comprehension_required_unknown_attributes + req->comprehension_optional_unknown_attributes == unknown_attributes.num_attributes);
170 if ((r=nr_stun_message_add_unknown_attributes_attribute(res, &unknown_attributes)))
171 ABORT(R_ALREADY);
173 ABORT(R_ALREADY);
174 }
175 #endif /* USE_STUN_PEDANTIC */
177 _status=0;
178 #ifdef USE_STUN_PEDANTIC
179 abort:
180 #endif /* USE_STUN_PEDANTIC */
181 return _status;
182 }
184 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.2 */
185 int
186 nr_stun_process_indication(nr_stun_message *ind)
187 {
188 int _status;
189 #ifdef USE_STUN_PEDANTIC
191 if (ind->comprehension_required_unknown_attributes > 0)
192 ABORT(R_REJECTED);
193 #endif /* USE_STUN_PEDANTIC */
195 _status=0;
196 #ifdef USE_STUN_PEDANTIC
197 abort:
198 #endif /* USE_STUN_PEDANTIC */
199 return _status;
200 }
202 /* RFC5389 S 7.3.3, except that we *also* allow a MAPPED_ADDRESS
203 to compensate for a bug in Google's STUN server where it
204 always returns MAPPED_ADDRESS.
206 Mozilla bug: 888274.
207 */
208 int
209 nr_stun_process_success_response(nr_stun_message *res)
210 {
211 int _status;
213 #ifdef USE_STUN_PEDANTIC
214 if (res->comprehension_required_unknown_attributes > 0)
215 ABORT(R_REJECTED);
216 #endif /* USE_STUN_PEDANTIC */
218 if (NR_STUN_GET_TYPE_METHOD(res->header.type) == NR_METHOD_BINDING) {
219 if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0) &&
220 ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
221 r_log(NR_LOG_STUN, LOG_WARNING, "Missing XOR-MAPPED-ADDRESS and MAPPED_ADDRESS");
222 ABORT(R_REJECTED);
223 }
224 }
226 _status=0;
227 abort:
228 return _status;
229 }
231 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.4 */
232 int
233 nr_stun_process_error_response(nr_stun_message *res, UINT2 *error_code)
234 {
235 int _status;
236 nr_stun_message_attribute *attr;
238 if (res->comprehension_required_unknown_attributes > 0) {
239 ABORT(R_REJECTED);
240 }
242 if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, &attr)) {
243 r_log(NR_LOG_STUN, LOG_WARNING, "Missing ERROR-CODE");
244 ABORT(R_REJECTED);
245 }
247 *error_code = attr->u.error_code.number;
249 switch (attr->u.error_code.number / 100) {
250 case 3:
251 /* If the error code is 300 through 399, the client SHOULD consider
252 * the transaction as failed unless the ALTERNATE-SERVER extension is
253 * being used. See Section 11. */
255 if (attr->u.error_code.number == 300) {
256 if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_ALTERNATE_SERVER, 0)) {
257 r_log(NR_LOG_STUN, LOG_WARNING, "Missing ALTERNATE-SERVER");
258 ABORT(R_REJECTED);
259 }
261 /* draft-ietf-behave-rfc3489bis-10.txt S 11 */
262 if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
263 r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
264 ABORT(R_REJECTED);
265 }
267 ABORT(R_RETRY);
268 }
270 ABORT(R_REJECTED);
271 break;
273 case 4:
274 /* If the error code is 400 through 499, the client declares the
275 * transaction failed; in the case of 420 (Unknown Attribute), the
276 * response should contain a UNKNOWN-ATTRIBUTES attribute that gives
277 * additional information. */
278 if (attr->u.error_code.number == 420)
279 ABORT(R_REJECTED);
281 /* it may be possible to restart given the info that was received in
282 * this response, so retry */
283 ABORT(R_RETRY);
284 break;
286 case 5:
287 /* If the error code is 500 through 599, the client MAY resend the
288 * request; clients that do so MUST limit the number of times they do
289 * this. */
290 /* let the retransmit mechanism handle resending the request */
291 break;
293 default:
294 ABORT(R_REJECTED);
295 break;
296 }
298 /* the spec says: "The client then does any processing specified by the authentication
299 * mechanism (see Section 10). This may result in a new transaction
300 * attempt." -- but this is handled already elsewhere, so needn't be repeated
301 * in this function */
303 _status=0;
304 abort:
305 return _status;
306 }
308 /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.2 */
309 int
310 nr_stun_receive_request_or_indication_short_term_auth(nr_stun_message *msg,
311 nr_stun_message *res)
312 {
313 int _status;
314 nr_stun_message_attribute *attr;
316 switch (msg->header.magic_cookie) {
317 default:
318 /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
319 /* drop thru */
320 case NR_STUN_MAGIC_COOKIE:
321 if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
322 nr_stun_form_error_response(msg, res, 400, "Missing MESSAGE-INTEGRITY");
323 ABORT(R_ALREADY);
324 }
326 if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, 0)) {
327 nr_stun_form_error_response(msg, res, 400, "Missing USERNAME");
328 ABORT(R_ALREADY);
329 }
331 if (attr->u.message_integrity.unknown_user) {
332 nr_stun_form_error_response(msg, res, 401, "Unrecognized USERNAME");
333 ABORT(R_ALREADY);
334 }
336 if (!attr->u.message_integrity.valid) {
337 nr_stun_form_error_response(msg, res, 401, "Bad MESSAGE-INTEGRITY");
338 ABORT(R_ALREADY);
339 }
341 break;
343 #ifdef USE_STUND_0_96
344 case NR_STUN_MAGIC_COOKIE2:
345 /* nothing to check in this case */
346 break;
347 #endif /* USE_STUND_0_96 */
348 }
350 _status=0;
351 abort:
352 return _status;
353 }
355 /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.3 */
356 int
357 nr_stun_receive_response_short_term_auth(nr_stun_message *res)
358 {
359 int _status;
360 nr_stun_message_attribute *attr;
362 switch (res->header.magic_cookie) {
363 default:
364 /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
365 /* drop thru */
366 case NR_STUN_MAGIC_COOKIE:
367 if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
368 r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
369 ABORT(R_REJECTED);
370 }
372 if (!attr->u.message_integrity.valid) {
373 r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
374 ABORT(R_REJECTED);
375 }
377 break;
379 #ifdef USE_STUND_0_96
380 case NR_STUN_MAGIC_COOKIE2:
381 /* nothing to check in this case */
382 break;
383 #endif /* USE_STUND_0_96 */
384 }
386 _status=0;
387 abort:
388 return _status;
389 }
391 static int
392 nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res)
393 {
394 int r,_status;
395 char *realm = 0;
396 char *nonce;
397 UINT2 size;
399 if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm)))
400 ABORT(r);
402 if ((r=nr_stun_message_add_realm_attribute(res, realm)))
403 ABORT(r);
405 if (clnt) {
406 if (strlen(clnt->nonce) < 1)
407 new_nonce = 1;
409 if (new_nonce) {
410 if (NR_reg_get_uint2(NR_STUN_REG_PREF_SERVER_NONCE_SIZE, &size))
411 size = 48;
413 if (size > (sizeof(clnt->nonce) - 1))
414 size = sizeof(clnt->nonce) - 1;
416 nr_random_alphanum(clnt->nonce, size);
417 clnt->nonce[size] = '\0';
418 }
420 nonce = clnt->nonce;
421 }
422 else {
423 /* user is not known, so use a bogus nonce since there's no way to
424 * store a good nonce with the client-specific data -- this nonce
425 * will be recognized as stale if the client attempts another
426 * request */
427 nonce = "STALE";
428 }
430 if ((r=nr_stun_message_add_nonce_attribute(res, nonce)))
431 ABORT(r);
433 _status=0;
434 abort:
435 #ifdef USE_TURN
436 assert(_status == 0); /* TODO: !nn! cleanup after I reimplmement TURN */
437 #endif
438 RFREE(realm);
439 return _status;
440 }
442 /* draft-ietf-behave-rfc3489bis-10.txt S 10.2.1 - 10.2.2 */
443 int
444 nr_stun_receive_request_long_term_auth(nr_stun_message *req, nr_stun_server_ctx *ctx, nr_stun_message *res)
445 {
446 int r,_status;
447 nr_stun_message_attribute *mi;
448 nr_stun_message_attribute *n;
449 nr_stun_server_client *clnt = 0;
451 switch (req->header.magic_cookie) {
452 default:
453 /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
454 /* drop thru */
455 case NR_STUN_MAGIC_COOKIE:
456 if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)) {
457 nr_stun_form_error_response(req, res, 400, "Missing USERNAME");
458 nr_stun_add_realm_and_nonce(0, 0, res);
459 ABORT(R_ALREADY);
460 }
462 if ((r=nr_stun_get_message_client(ctx, req, &clnt))) {
463 nr_stun_form_error_response(req, res, 401, "Unrecognized USERNAME");
464 nr_stun_add_realm_and_nonce(0, 0, res);
465 ABORT(R_ALREADY);
466 }
468 if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, &mi)) {
469 nr_stun_form_error_response(req, res, 401, "Missing MESSAGE-INTEGRITY");
470 nr_stun_add_realm_and_nonce(0, clnt, res);
471 ABORT(R_ALREADY);
472 }
474 assert(!mi->u.message_integrity.unknown_user);
476 if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_REALM, 0)) {
477 nr_stun_form_error_response(req, res, 400, "Missing REALM");
478 ABORT(R_ALREADY);
479 }
481 if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_NONCE, &n)) {
482 nr_stun_form_error_response(req, res, 400, "Missing NONCE");
483 ABORT(R_ALREADY);
484 }
486 assert(sizeof(clnt->nonce) == sizeof(n->u.nonce));
487 if (strncmp(clnt->nonce, n->u.nonce, sizeof(n->u.nonce))) {
488 nr_stun_form_error_response(req, res, 438, "Stale NONCE");
489 nr_stun_add_realm_and_nonce(1, clnt, res);
490 ABORT(R_ALREADY);
491 }
493 if (!mi->u.message_integrity.valid) {
494 nr_stun_form_error_response(req, res, 401, "Bad MESSAGE-INTEGRITY");
495 nr_stun_add_realm_and_nonce(0, clnt, res);
496 ABORT(R_ALREADY);
497 }
499 break;
501 #ifdef USE_STUND_0_96
502 case NR_STUN_MAGIC_COOKIE2:
503 /* nothing to do in this case */
504 break;
505 #endif /* USE_STUND_0_96 */
506 }
508 _status=0;
509 abort:
511 return _status;
512 }
514 /* draft-ietf-behave-rfc3489bis-10.txt S 10.2.3 */
515 int
516 nr_stun_receive_response_long_term_auth(nr_stun_message *res, nr_stun_client_ctx *ctx)
517 {
518 int _status;
519 nr_stun_message_attribute *attr;
521 switch (res->header.magic_cookie) {
522 default:
523 /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
524 /* drop thru */
525 case NR_STUN_MAGIC_COOKIE:
526 if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_REALM, &attr)) {
527 RFREE(ctx->realm);
528 ctx->realm = r_strdup(attr->u.realm);
529 if (!ctx->realm)
530 ABORT(R_NO_MEMORY);
531 }
532 else {
533 r_log(NR_LOG_STUN, LOG_WARNING, "Missing REALM");
534 ABORT(R_REJECTED);
535 }
537 if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_NONCE, &attr)) {
538 RFREE(ctx->nonce);
539 ctx->nonce = r_strdup(attr->u.nonce);
540 if (!ctx->nonce)
541 ABORT(R_NO_MEMORY);
542 }
543 else {
544 r_log(NR_LOG_STUN, LOG_WARNING, "Missing NONCE");
545 ABORT(R_REJECTED);
546 }
548 if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
549 if (!attr->u.message_integrity.valid) {
550 r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
551 ABORT(R_REJECTED);
552 }
553 }
555 break;
557 #ifdef USE_STUND_0_96
558 case NR_STUN_MAGIC_COOKIE2:
559 /* nothing to check in this case */
560 break;
561 #endif /* USE_STUND_0_96 */
562 }
564 _status=0;
565 abort:
566 return _status;
567 }