tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

control_auth.c (15478B)


      1 /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      2 * Copyright (c) 2007-2024, The Tor Project, Inc. */
      3 /* See LICENSE for licensing information */
      4 
      5 /**
      6 * \file control_auth.c
      7 * \brief Authentication for Tor's control-socket interface.
      8 **/
      9 
     10 #include "core/or/or.h"
     11 #include "app/config/config.h"
     12 #include "core/mainloop/connection.h"
     13 #include "feature/control/control.h"
     14 #include "feature/control/control_events.h"
     15 #include "feature/control/control_cmd.h"
     16 #include "feature/control/control_auth.h"
     17 #include "feature/control/control_cmd_args_st.h"
     18 #include "feature/control/control_connection_st.h"
     19 #include "feature/control/control_proto.h"
     20 #include "lib/crypt_ops/crypto_rand.h"
     21 #include "lib/crypt_ops/crypto_util.h"
     22 #include "lib/encoding/confline.h"
     23 #include "lib/encoding/kvline.h"
     24 #include "lib/encoding/qstring.h"
     25 
     26 #include "lib/crypt_ops/crypto_s2k.h"
     27 
     28 /* List of authenticated control connections */
     29 static smartlist_t *control_auth_conns = NULL;
     30 
     31 static void
     32 control_add_authenticated_connection(control_connection_t *conn)
     33 {
     34  if (!control_auth_conns)
     35    control_auth_conns = smartlist_new();
     36 
     37  smartlist_add(control_auth_conns, conn);
     38 
     39  if (smartlist_len(control_auth_conns) == 1)
     40    stats_init();
     41 }
     42 
     43 void
     44 control_remove_authenticated_connection(const control_connection_t *conn)
     45 {
     46  if (!control_auth_conns)
     47    return;
     48 
     49  smartlist_remove(control_auth_conns, conn);
     50 
     51  if (smartlist_len(control_auth_conns) == 0) {
     52    smartlist_free(control_auth_conns);
     53    control_auth_conns = NULL;
     54    stats_clear();
     55  }
     56 }
     57 
     58 /** If we're using cookie-type authentication, how long should our cookies be?
     59 */
     60 #define AUTHENTICATION_COOKIE_LEN 32
     61 
     62 /** If true, we've set authentication_cookie to a secret code and
     63 * stored it to disk. */
     64 static int authentication_cookie_is_set = 0;
     65 /** If authentication_cookie_is_set, a secret cookie that we've stored to disk
     66 * and which we're using to authenticate controllers.  (If the controller can
     67 * read it off disk, it has permission to connect.) */
     68 static uint8_t *authentication_cookie = NULL;
     69 
     70 #define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \
     71  "Tor safe cookie authentication server-to-controller hash"
     72 #define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \
     73  "Tor safe cookie authentication controller-to-server hash"
     74 #define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN
     75 
     76 /** Helper: Return a newly allocated string containing a path to the
     77 * file where we store our authentication cookie. */
     78 char *
     79 get_controller_cookie_file_name(void)
     80 {
     81  const or_options_t *options = get_options();
     82  if (options->CookieAuthFile && strlen(options->CookieAuthFile)) {
     83    return tor_strdup(options->CookieAuthFile);
     84  } else {
     85    return get_datadir_fname("control_auth_cookie");
     86  }
     87 }
     88 
     89 /* Initialize the cookie-based authentication system of the
     90 * ControlPort. If <b>enabled</b> is 0, then disable the cookie
     91 * authentication system.  */
     92 int
     93 init_control_cookie_authentication(int enabled)
     94 {
     95  char *fname = NULL;
     96  int retval;
     97 
     98  if (!enabled) {
     99    authentication_cookie_is_set = 0;
    100    return 0;
    101  }
    102 
    103  fname = get_controller_cookie_file_name();
    104  retval = init_cookie_authentication(fname, "", /* no header */
    105                                      AUTHENTICATION_COOKIE_LEN,
    106                                   get_options()->CookieAuthFileGroupReadable,
    107                                      &authentication_cookie,
    108                                      &authentication_cookie_is_set);
    109  tor_free(fname);
    110  return retval;
    111 }
    112 
    113 /** Decode the hashed, base64'd passwords stored in <b>passwords</b>.
    114 * Return a smartlist of acceptable passwords (unterminated strings of
    115 * length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on
    116 * failure.
    117 */
    118 smartlist_t *
    119 decode_hashed_passwords(config_line_t *passwords)
    120 {
    121  char decoded[64];
    122  config_line_t *cl;
    123  smartlist_t *sl = smartlist_new();
    124 
    125  tor_assert(passwords);
    126 
    127  for (cl = passwords; cl; cl = cl->next) {
    128    const char *hashed = cl->value;
    129 
    130    if (!strcmpstart(hashed, "16:")) {
    131      if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))
    132                        != S2K_RFC2440_SPECIFIER_LEN + DIGEST_LEN
    133          || strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) {
    134        goto err;
    135      }
    136    } else {
    137        if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed))
    138            != S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) {
    139          goto err;
    140        }
    141    }
    142    smartlist_add(sl,
    143                  tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN));
    144  }
    145 
    146  return sl;
    147 
    148 err:
    149  SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp));
    150  smartlist_free(sl);
    151  return NULL;
    152 }
    153 
    154 const control_cmd_syntax_t authchallenge_syntax = {
    155   .min_args = 1,
    156   .max_args = 1,
    157   .accept_keywords=true,
    158   .kvline_flags=KV_OMIT_KEYS|KV_QUOTED_QSTRING,
    159   .store_raw_body=true
    160 };
    161 
    162 /** Called when we get an AUTHCHALLENGE command. */
    163 int
    164 handle_control_authchallenge(control_connection_t *conn,
    165                             const control_cmd_args_t *args)
    166 {
    167  char *client_nonce;
    168  size_t client_nonce_len;
    169  char server_hash[DIGEST256_LEN];
    170  char server_hash_encoded[HEX_DIGEST256_LEN+1];
    171  char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN];
    172  char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1];
    173 
    174  if (strcasecmp(smartlist_get(args->args, 0), "SAFECOOKIE")) {
    175    control_write_endreply(conn, 513,
    176                           "AUTHCHALLENGE only supports SAFECOOKIE "
    177                           "authentication");
    178    goto fail;
    179  }
    180  if (!authentication_cookie_is_set) {
    181    control_write_endreply(conn, 515, "Cookie authentication is disabled");
    182    goto fail;
    183  }
    184  if (args->kwargs == NULL || args->kwargs->next != NULL) {
    185    control_write_endreply(conn, 512,
    186                           "Wrong number of arguments for AUTHCHALLENGE");
    187    goto fail;
    188  }
    189  if (strcmp(args->kwargs->key, "")) {
    190    control_write_endreply(conn, 512,
    191                           "AUTHCHALLENGE does not accept keyword "
    192                           "arguments.");
    193    goto fail;
    194  }
    195 
    196  bool contains_quote = strchr(args->raw_body, '\"');
    197  if (contains_quote) {
    198    /* The nonce was quoted */
    199    client_nonce = tor_strdup(args->kwargs->value);
    200    client_nonce_len = strlen(client_nonce);
    201  } else {
    202    /* The nonce was should be in hex. */
    203    const char *hex_nonce = args->kwargs->value;
    204    client_nonce_len = strlen(hex_nonce) / 2;
    205    client_nonce = tor_malloc(client_nonce_len);
    206    if (base16_decode(client_nonce, client_nonce_len, hex_nonce,
    207                      strlen(hex_nonce)) != (int)client_nonce_len) {
    208      control_write_endreply(conn, 513, "Invalid base16 client nonce");
    209      tor_free(client_nonce);
    210      goto fail;
    211    }
    212  }
    213 
    214  crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);
    215 
    216  /* Now compute and send the server-to-controller response, and the
    217   * server's nonce. */
    218  tor_assert(authentication_cookie != NULL);
    219 
    220  {
    221    size_t tmp_len = (AUTHENTICATION_COOKIE_LEN +
    222                      client_nonce_len +
    223                      SAFECOOKIE_SERVER_NONCE_LEN);
    224    char *tmp = tor_malloc_zero(tmp_len);
    225    char *client_hash = tor_malloc_zero(DIGEST256_LEN);
    226    memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN);
    227    memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len);
    228    memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len,
    229           server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);
    230 
    231    crypto_hmac_sha256(server_hash,
    232                       SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT,
    233                       strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT),
    234                       tmp,
    235                       tmp_len);
    236 
    237    crypto_hmac_sha256(client_hash,
    238                       SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT,
    239                       strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT),
    240                       tmp,
    241                       tmp_len);
    242 
    243    conn->safecookie_client_hash = client_hash;
    244 
    245    tor_free(tmp);
    246  }
    247 
    248  base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
    249                server_hash, sizeof(server_hash));
    250  base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
    251                server_nonce, sizeof(server_nonce));
    252 
    253  control_printf_endreply(conn, 250,
    254                          "AUTHCHALLENGE SERVERHASH=%s SERVERNONCE=%s",
    255                          server_hash_encoded,
    256                          server_nonce_encoded);
    257 
    258  tor_free(client_nonce);
    259  return 0;
    260 fail:
    261  connection_mark_for_close(TO_CONN(conn));
    262  return -1;
    263 }
    264 
    265 const control_cmd_syntax_t authenticate_syntax = {
    266   .max_args = 0,
    267   .accept_keywords=true,
    268   .kvline_flags=KV_OMIT_KEYS|KV_QUOTED_QSTRING,
    269   .store_raw_body=true
    270 };
    271 
    272 /** Called when we get an AUTHENTICATE message.  Check whether the
    273 * authentication is valid, and if so, update the connection's state to
    274 * OPEN.  Reply with DONE or ERROR.
    275 */
    276 int
    277 handle_control_authenticate(control_connection_t *conn,
    278                            const control_cmd_args_t *args)
    279 {
    280  bool used_quoted_string = false;
    281  const or_options_t *options = get_options();
    282  const char *errstr = "Unknown error";
    283  char *password;
    284  size_t password_len;
    285  int bad_cookie=0, bad_password=0;
    286  smartlist_t *sl = NULL;
    287 
    288  if (args->kwargs == NULL) {
    289    password = tor_strdup("");
    290    password_len = 0;
    291  } else if (args->kwargs->next) {
    292    control_write_endreply(conn, 512, "Too many arguments to AUTHENTICATE.");
    293    connection_mark_for_close(TO_CONN(conn));
    294    return 0;
    295  } else if (strcmp(args->kwargs->key, "")) {
    296    control_write_endreply(conn, 512,
    297                           "AUTHENTICATE does not accept keyword arguments.");
    298    connection_mark_for_close(TO_CONN(conn));
    299    return 0;
    300  } else if (strchr(args->raw_body, '\"')) {
    301    used_quoted_string = true;
    302    password = tor_strdup(args->kwargs->value);
    303    password_len = strlen(password);
    304  } else {
    305    const char *hex_passwd = args->kwargs->value;
    306    password_len = strlen(hex_passwd) / 2;
    307    password = tor_malloc(password_len+1);
    308    if (base16_decode(password, password_len+1, hex_passwd, strlen(hex_passwd))
    309                      != (int) password_len) {
    310      control_write_endreply(conn, 551,
    311            "Invalid hexadecimal encoding.  Maybe you tried a plain text "
    312            "password?  If so, the standard requires that you put it in "
    313            "double quotes.");
    314      connection_mark_for_close(TO_CONN(conn));
    315      tor_free(password);
    316      return 0;
    317    }
    318  }
    319 
    320  if (conn->safecookie_client_hash != NULL) {
    321    /* The controller has chosen safe cookie authentication; the only
    322     * acceptable authentication value is the controller-to-server
    323     * response. */
    324 
    325    tor_assert(authentication_cookie_is_set);
    326 
    327    if (password_len != DIGEST256_LEN) {
    328      log_warn(LD_CONTROL,
    329               "Got safe cookie authentication response with wrong length "
    330               "(%d)", (int)password_len);
    331      errstr = "Wrong length for safe cookie response.";
    332      goto err;
    333    }
    334 
    335    if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) {
    336      log_warn(LD_CONTROL,
    337               "Got incorrect safe cookie authentication response");
    338      errstr = "Safe cookie response did not match expected value.";
    339      goto err;
    340    }
    341 
    342    tor_free(conn->safecookie_client_hash);
    343    goto ok;
    344  }
    345 
    346  if (!options->CookieAuthentication && !options->HashedControlPassword &&
    347      !options->HashedControlSessionPassword) {
    348    /* if Tor doesn't demand any stronger authentication, then
    349     * the controller can get in with anything. */
    350    goto ok;
    351  }
    352 
    353  if (options->CookieAuthentication) {
    354    int also_password = options->HashedControlPassword != NULL ||
    355      options->HashedControlSessionPassword != NULL;
    356    if (password_len != AUTHENTICATION_COOKIE_LEN) {
    357      if (!also_password) {
    358        log_warn(LD_CONTROL, "Got authentication cookie with wrong length "
    359                 "(%d)", (int)password_len);
    360        errstr = "Wrong length on authentication cookie.";
    361        goto err;
    362      }
    363      bad_cookie = 1;
    364    } else if (tor_memneq(authentication_cookie, password, password_len)) {
    365      if (!also_password) {
    366        log_warn(LD_CONTROL, "Got mismatched authentication cookie");
    367        errstr = "Authentication cookie did not match expected value.";
    368        goto err;
    369      }
    370      bad_cookie = 1;
    371    } else {
    372      goto ok;
    373    }
    374  }
    375 
    376  if (options->HashedControlPassword ||
    377      options->HashedControlSessionPassword) {
    378    int bad = 0;
    379    smartlist_t *sl_tmp;
    380    char received[DIGEST_LEN];
    381    int also_cookie = options->CookieAuthentication;
    382    sl = smartlist_new();
    383    if (options->HashedControlPassword) {
    384      sl_tmp = decode_hashed_passwords(options->HashedControlPassword);
    385      if (!sl_tmp)
    386        bad = 1;
    387      else {
    388        smartlist_add_all(sl, sl_tmp);
    389        smartlist_free(sl_tmp);
    390      }
    391    }
    392    if (options->HashedControlSessionPassword) {
    393      sl_tmp = decode_hashed_passwords(options->HashedControlSessionPassword);
    394      if (!sl_tmp)
    395        bad = 1;
    396      else {
    397        smartlist_add_all(sl, sl_tmp);
    398        smartlist_free(sl_tmp);
    399      }
    400    }
    401    if (bad) {
    402      if (!also_cookie) {
    403        log_warn(LD_BUG,
    404                 "Couldn't decode HashedControlPassword: invalid base16");
    405        errstr="Couldn't decode HashedControlPassword value in configuration.";
    406        goto err;
    407      }
    408      bad_password = 1;
    409      SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
    410      smartlist_free(sl);
    411      sl = NULL;
    412    } else {
    413      SMARTLIST_FOREACH(sl, char *, expected,
    414      {
    415        secret_to_key_rfc2440(received,DIGEST_LEN,
    416                              password,password_len,expected);
    417        if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN,
    418                      received, DIGEST_LEN))
    419          goto ok;
    420      });
    421      SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
    422      smartlist_free(sl);
    423      sl = NULL;
    424 
    425      if (used_quoted_string)
    426        errstr = "Password did not match HashedControlPassword value from "
    427          "configuration";
    428      else
    429        errstr = "Password did not match HashedControlPassword value from "
    430          "configuration. Maybe you tried a plain text password? "
    431          "If so, the standard requires that you put it in double quotes.";
    432      bad_password = 1;
    433      if (!also_cookie)
    434        goto err;
    435    }
    436  }
    437 
    438  /** We only get here if both kinds of authentication failed. */
    439  tor_assert(bad_password && bad_cookie);
    440  log_warn(LD_CONTROL, "Bad password or authentication cookie on controller.");
    441  errstr = "Password did not match HashedControlPassword *or* authentication "
    442    "cookie.";
    443 
    444 err:
    445  tor_free(password);
    446  control_printf_endreply(conn, 515, "Authentication failed: %s", errstr);
    447  connection_mark_for_close(TO_CONN(conn));
    448  if (sl) { /* clean up */
    449    SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
    450    smartlist_free(sl);
    451  }
    452  return 0;
    453 ok:
    454  log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT
    455           ")", conn->base_.s);
    456  send_control_done(conn);
    457  conn->base_.state = CONTROL_CONN_STATE_OPEN;
    458  tor_free(password);
    459  if (sl) { /* clean up */
    460    SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
    461    smartlist_free(sl);
    462  }
    463 
    464  control_add_authenticated_connection(conn);
    465 
    466  return 0;
    467 }
    468 
    469 void
    470 control_auth_free_all(void)
    471 {
    472  if (authentication_cookie) /* Free the auth cookie */
    473    tor_free(authentication_cookie);
    474  authentication_cookie_is_set = 0;
    475 
    476  if (control_auth_conns)
    477    smartlist_free(control_auth_conns);
    478 }