mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Implement two flavors of authentication for control connections: one for trusted FS, one for untrusted FS.
svn:r2664
This commit is contained in:
parent
871bf904ae
commit
cea9125d71
@ -1575,6 +1575,47 @@ base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
|||||||
dest[i] = '\0';
|
dest[i] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Implement RFC2440-style iterated-salted S2K conversion: convert the
|
||||||
|
* <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
|
||||||
|
* <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
|
||||||
|
* are a salt; the 9th byte describes how much iteration to do.
|
||||||
|
* Does not support <b>key_out_len</b> > DIGEST_LEN.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
secret_to_key(char *key_out, size_t key_out_len, const char *secret,
|
||||||
|
size_t secret_len, const char *s2k_specifier)
|
||||||
|
{
|
||||||
|
crypto_digest_env_t *d;
|
||||||
|
uint8_t c;
|
||||||
|
size_t count;
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
#define EXPBIAS 6
|
||||||
|
c = s2k_specifier[8];
|
||||||
|
count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
|
||||||
|
#undef EXPBIAS
|
||||||
|
|
||||||
|
tor_assert(key_out_len <= DIGEST_LEN);
|
||||||
|
|
||||||
|
d = crypto_new_digest_env();
|
||||||
|
tmp = tor_malloc(8+secret_len);
|
||||||
|
memcpy(tmp,s2k_specifier,8);
|
||||||
|
memcpy(tmp+8,secret,secret_len);
|
||||||
|
secret_len += 8;
|
||||||
|
while (count) {
|
||||||
|
if (count >= secret_len) {
|
||||||
|
crypto_digest_add_bytes(d, tmp, secret_len);
|
||||||
|
count -= secret_len;
|
||||||
|
} else {
|
||||||
|
crypto_digest_add_bytes(d, tmp, count);
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crypto_digest_get_digest(d, key_out, key_out_len);
|
||||||
|
tor_free(tmp);
|
||||||
|
crypto_free_digest_env(d);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local Variables:
|
Local Variables:
|
||||||
mode:c
|
mode:c
|
||||||
|
@ -153,6 +153,10 @@ int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
|||||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||||
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||||
|
|
||||||
|
#define S2K_SPECIFIER_LEN 9
|
||||||
|
void secret_to_key(char *key_out, size_t key_out_len, const char *secret,
|
||||||
|
size_t secret_len, const char *s2k_specifier);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -101,6 +101,7 @@ static config_var_t config_vars[] = {
|
|||||||
VAR("MyFamily", STRING, MyFamily, NULL),
|
VAR("MyFamily", STRING, MyFamily, NULL),
|
||||||
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
|
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
|
||||||
VAR("Group", STRING, Group, NULL),
|
VAR("Group", STRING, Group, NULL),
|
||||||
|
VAR("HashedControlPassword",STRING, HashedControlPassword, NULL),
|
||||||
VAR("HttpProxy", STRING, HttpProxy, NULL),
|
VAR("HttpProxy", STRING, HttpProxy, NULL),
|
||||||
VAR("HiddenServiceDir", LINELIST, RendConfigLines, NULL),
|
VAR("HiddenServiceDir", LINELIST, RendConfigLines, NULL),
|
||||||
VAR("HiddenServicePort", LINELIST, RendConfigLines, NULL),
|
VAR("HiddenServicePort", LINELIST, RendConfigLines, NULL),
|
||||||
@ -183,12 +184,13 @@ config_get_commandlines(int argc, char **argv)
|
|||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
while (i < argc-1) {
|
while (i < argc-1) {
|
||||||
if (!strcmp(argv[i],"-f")) {
|
if (!strcmp(argv[i],"-f") ||
|
||||||
// log(LOG_DEBUG,"Commandline: skipping over -f.");
|
!strcmp(argv[i],"--hash-password")) {
|
||||||
i += 2; /* this is the config file option. ignore it. */
|
i += 2; /* command-line option with argument. ignore them. */
|
||||||
continue;
|
continue;
|
||||||
} else if (!strcmp(argv[i],"--list-fingerprint")) {
|
} else if (!strcmp(argv[i],"--list-fingerprint")) {
|
||||||
i += 1; /* command-line option. ignore it. */
|
i += 1; /* command-line option. ignore it. */
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = tor_malloc(sizeof(struct config_line_t));
|
new = tor_malloc(sizeof(struct config_line_t));
|
||||||
@ -803,7 +805,12 @@ getconfig(int argc, char **argv, or_options_t *options)
|
|||||||
++i;
|
++i;
|
||||||
} else if (!strcmp(argv[i],"--list-fingerprint")) {
|
} else if (!strcmp(argv[i],"--list-fingerprint")) {
|
||||||
options->command = CMD_LIST_FINGERPRINT;
|
options->command = CMD_LIST_FINGERPRINT;
|
||||||
|
} else if (!strcmp(argv[i],"--hash-password")) {
|
||||||
|
options->command = CMD_HASH_PASSWORD;
|
||||||
|
options->command_arg = tor_strdup(argv[i+1]);
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (using_default_torrc) {
|
if (using_default_torrc) {
|
||||||
|
@ -47,6 +47,10 @@ extern or_options_t options;
|
|||||||
|
|
||||||
static uint32_t global_event_mask = 0;
|
static uint32_t global_event_mask = 0;
|
||||||
|
|
||||||
|
#define AUTHENTICATION_COOKIE_LEN 32
|
||||||
|
static int authentication_cookie_is_set = 0;
|
||||||
|
static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
|
||||||
|
|
||||||
static void update_global_event_mask(void);
|
static void update_global_event_mask(void);
|
||||||
static void send_control_message(connection_t *conn, uint16_t type,
|
static void send_control_message(connection_t *conn, uint16_t type,
|
||||||
uint16_t len, const char *body);
|
uint16_t len, const char *body);
|
||||||
@ -216,13 +220,34 @@ static int handle_control_setevents(connection_t *conn, uint16_t len,
|
|||||||
static int handle_control_authenticate(connection_t *conn, uint16_t len,
|
static int handle_control_authenticate(connection_t *conn, uint16_t len,
|
||||||
const char *body)
|
const char *body)
|
||||||
{
|
{
|
||||||
if (0/* XXXX009 NM */) {
|
if (len == AUTHENTICATION_COOKIE_LEN &&
|
||||||
send_control_done(conn);
|
authentication_cookie_is_set &&
|
||||||
conn->state = CONTROL_CONN_STATE_OPEN;
|
!memcmp(authentication_cookie, body, len)) {
|
||||||
} else {
|
goto ok;
|
||||||
send_control_error(conn, ERR_FAILED_AUTHENTICATION,"Authentication failed");
|
} else if (options.HashedControlPassword) {
|
||||||
|
char expected[S2K_SPECIFIER_LEN+DIGEST_LEN];
|
||||||
|
char received[DIGEST_LEN];
|
||||||
|
if (base64_decode(expected,sizeof(expected),
|
||||||
|
options.HashedControlPassword,
|
||||||
|
strlen(options.HashedControlPassword))<0) {
|
||||||
|
/* XXXX009 NM we should warn sooner. */
|
||||||
|
log_fn(LOG_WARN,"Couldn't decode HashedControlPassword: invalid base64");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
secret_to_key(received,DIGEST_LEN,body,len,expected);
|
||||||
|
if (!memcmp(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN))
|
||||||
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
send_control_error(conn, ERR_FAILED_AUTHENTICATION,"Authentication failed");
|
||||||
return 0;
|
return 0;
|
||||||
|
ok:
|
||||||
|
log_fn(LOG_INFO, "Authenticated control connection (%d)", conn->s);
|
||||||
|
send_control_done(conn);
|
||||||
|
conn->state = CONTROL_CONN_STATE_OPEN;
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int connection_control_finished_flushing(connection_t *conn) {
|
int connection_control_finished_flushing(connection_t *conn) {
|
||||||
@ -391,6 +416,25 @@ void control_event_logmsg(int severity, const char *msg)
|
|||||||
send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg);
|
send_control_event(EVENT_WARNING, (uint16_t)(len+1), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int init_cookie_authentication(void)
|
||||||
|
{
|
||||||
|
char fname[512];
|
||||||
|
|
||||||
|
/* XXXX009 NM add config option to disable this. */
|
||||||
|
|
||||||
|
tor_snprintf(fname, sizeof(fname), "%s/control_auth_cookie",
|
||||||
|
get_data_directory(&options));
|
||||||
|
crypto_rand(authentication_cookie, AUTHENTICATION_COOKIE_LEN);
|
||||||
|
authentication_cookie_is_set = 1;
|
||||||
|
if (write_bytes_to_file(fname, authentication_cookie,
|
||||||
|
AUTHENTICATION_COOKIE_LEN, 1)) {
|
||||||
|
log_fn(LOG_WARN,"Error writing authentication cookie.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local Variabls:
|
Local Variabls:
|
||||||
mode:c
|
mode:c
|
||||||
|
@ -1373,6 +1373,25 @@ static void do_list_fingerprint(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DOCDOC **/
|
||||||
|
static void do_hash_password(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
char output[256];
|
||||||
|
char key[S2K_SPECIFIER_LEN+DIGEST_LEN];
|
||||||
|
|
||||||
|
crypto_rand(key, S2K_SPECIFIER_LEN-1);
|
||||||
|
key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
|
||||||
|
secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN,
|
||||||
|
options.command_arg, strlen(options.command_arg),
|
||||||
|
key);
|
||||||
|
if (base64_encode(output, sizeof(output), key, sizeof(key))<0) {
|
||||||
|
log_fn(LOG_ERR, "Unable to compute base64");
|
||||||
|
} else {
|
||||||
|
printf("%s",output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef MS_WINDOWS_SERVICE
|
#ifdef MS_WINDOWS_SERVICE
|
||||||
void nt_service_control(DWORD request)
|
void nt_service_control(DWORD request)
|
||||||
{
|
{
|
||||||
@ -1449,6 +1468,9 @@ int tor_main(int argc, char *argv[]) {
|
|||||||
case CMD_LIST_FINGERPRINT:
|
case CMD_LIST_FINGERPRINT:
|
||||||
do_list_fingerprint();
|
do_list_fingerprint();
|
||||||
break;
|
break;
|
||||||
|
case CMD_HASH_PASSWORD:
|
||||||
|
do_hash_password();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_fn(LOG_ERR, "Illegal command number %d: internal error.",
|
log_fn(LOG_ERR, "Illegal command number %d: internal error.",
|
||||||
options.command);
|
options.command);
|
||||||
|
@ -852,8 +852,10 @@ typedef struct exit_redirect_t {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
/** What should the tor process actually do? */
|
/** What should the tor process actually do? */
|
||||||
enum {
|
enum {
|
||||||
CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT
|
CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD,
|
||||||
} command;
|
} command;
|
||||||
|
const char *command_arg; /**< Argument for command-line option. */
|
||||||
|
|
||||||
struct config_line_t *LogOptions; /**< List of configuration lines
|
struct config_line_t *LogOptions; /**< List of configuration lines
|
||||||
* for logfiles */
|
* for logfiles */
|
||||||
|
|
||||||
@ -949,6 +951,8 @@ typedef struct {
|
|||||||
int AccountingMaxKB; /**< How many KB do we allow per accounting
|
int AccountingMaxKB; /**< How many KB do we allow per accounting
|
||||||
* interval before hibernation? 0 for "never
|
* interval before hibernation? 0 for "never
|
||||||
* hibernate." */
|
* hibernate." */
|
||||||
|
char *HashedControlPassword; /**< Base64-encoded hash of a password for
|
||||||
|
* the control system. */
|
||||||
} or_options_t;
|
} or_options_t;
|
||||||
|
|
||||||
/* XXX are these good enough defaults? */
|
/* XXX are these good enough defaults? */
|
||||||
@ -1241,6 +1245,8 @@ int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
|
|||||||
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
|
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
|
||||||
void control_event_logmsg(int severity, const char *msg);
|
void control_event_logmsg(int severity, const char *msg);
|
||||||
|
|
||||||
|
int init_cookie_authentication(void);
|
||||||
|
|
||||||
/********************************* cpuworker.c *****************************/
|
/********************************* cpuworker.c *****************************/
|
||||||
|
|
||||||
void cpu_init(void);
|
void cpu_init(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user