LCOV - code coverage report
Current view: top level - feature/control - control_auth.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 27 204 13.2 %
Date: 2021-11-24 03:28:48 Functions: 3 6 50.0 %

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

Generated by: LCOV version 1.14