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

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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, &params->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, &params->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, &params->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, &params->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, &params->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 }

mercurial