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 : }
|