mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
Merge remote-tracking branch 'rransom-tor/safecookie-022-v3' into maint-0.2.2
This commit is contained in:
commit
6dcbfec82d
@ -419,6 +419,7 @@ _connection_free(connection_t *conn)
|
|||||||
}
|
}
|
||||||
if (conn->type == CONN_TYPE_CONTROL) {
|
if (conn->type == CONN_TYPE_CONTROL) {
|
||||||
control_connection_t *control_conn = TO_CONTROL_CONN(conn);
|
control_connection_t *control_conn = TO_CONTROL_CONN(conn);
|
||||||
|
tor_free(control_conn->safecookie_client_hash);
|
||||||
tor_free(control_conn->incoming_cmd);
|
tor_free(control_conn->incoming_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
159
src/or/control.c
159
src/or/control.c
@ -101,6 +101,12 @@ static int authentication_cookie_is_set = 0;
|
|||||||
* read it off disk, it has permission to connect.) */
|
* read it off disk, it has permission to connect.) */
|
||||||
static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
|
static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
|
||||||
|
|
||||||
|
#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \
|
||||||
|
"Tor safe cookie authentication server-to-controller hash"
|
||||||
|
#define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \
|
||||||
|
"Tor safe cookie authentication controller-to-server hash"
|
||||||
|
#define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN
|
||||||
|
|
||||||
/** A sufficiently large size to record the last bootstrap phase string. */
|
/** A sufficiently large size to record the last bootstrap phase string. */
|
||||||
#define BOOTSTRAP_MSG_LEN 1024
|
#define BOOTSTRAP_MSG_LEN 1024
|
||||||
|
|
||||||
@ -1078,6 +1084,32 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
|
|||||||
used_quoted_string = 1;
|
used_quoted_string = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conn->safecookie_client_hash != NULL) {
|
||||||
|
/* The controller has chosen safe cookie authentication; the only
|
||||||
|
* acceptable authentication value is the controller-to-server
|
||||||
|
* response. */
|
||||||
|
|
||||||
|
tor_assert(authentication_cookie_is_set);
|
||||||
|
|
||||||
|
if (password_len != DIGEST256_LEN) {
|
||||||
|
log_warn(LD_CONTROL,
|
||||||
|
"Got safe cookie authentication response with wrong length "
|
||||||
|
"(%d)", (int)password_len);
|
||||||
|
errstr = "Wrong length for safe cookie response.";
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) {
|
||||||
|
log_warn(LD_CONTROL,
|
||||||
|
"Got incorrect safe cookie authentication response");
|
||||||
|
errstr = "Safe cookie response did not match expected value.";
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
tor_free(conn->safecookie_client_hash);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
if (!options->CookieAuthentication && !options->HashedControlPassword &&
|
if (!options->CookieAuthentication && !options->HashedControlPassword &&
|
||||||
!options->HashedControlSessionPassword) {
|
!options->HashedControlSessionPassword) {
|
||||||
/* if Tor doesn't demand any stronger authentication, then
|
/* if Tor doesn't demand any stronger authentication, then
|
||||||
@ -2758,8 +2790,10 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len,
|
|||||||
int passwd = (options->HashedControlPassword != NULL ||
|
int passwd = (options->HashedControlPassword != NULL ||
|
||||||
options->HashedControlSessionPassword != NULL);
|
options->HashedControlSessionPassword != NULL);
|
||||||
smartlist_t *mlist = smartlist_create();
|
smartlist_t *mlist = smartlist_create();
|
||||||
if (cookies)
|
if (cookies) {
|
||||||
smartlist_add(mlist, (char*)"COOKIE");
|
smartlist_add(mlist, (char*)"COOKIE");
|
||||||
|
smartlist_add(mlist, (char*)"SAFECOOKIE");
|
||||||
|
}
|
||||||
if (passwd)
|
if (passwd)
|
||||||
smartlist_add(mlist, (char*)"HASHEDPASSWORD");
|
smartlist_add(mlist, (char*)"HASHEDPASSWORD");
|
||||||
if (!cookies && !passwd)
|
if (!cookies && !passwd)
|
||||||
@ -2787,6 +2821,121 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called when we get an AUTHCHALLENGE command. */
|
||||||
|
static int
|
||||||
|
handle_control_authchallenge(control_connection_t *conn, uint32_t len,
|
||||||
|
const char *body)
|
||||||
|
{
|
||||||
|
const char *cp = body;
|
||||||
|
char *client_nonce;
|
||||||
|
size_t client_nonce_len;
|
||||||
|
char server_hash[DIGEST256_LEN];
|
||||||
|
char server_hash_encoded[HEX_DIGEST256_LEN+1];
|
||||||
|
char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN];
|
||||||
|
char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1];
|
||||||
|
|
||||||
|
cp += strspn(cp, " \t\n\r");
|
||||||
|
if (!strcasecmpstart(cp, "SAFECOOKIE")) {
|
||||||
|
cp += strlen("SAFECOOKIE");
|
||||||
|
} else {
|
||||||
|
connection_write_str_to_buf("513 AUTHCHALLENGE only supports SAFECOOKIE "
|
||||||
|
"authentication", conn);
|
||||||
|
connection_mark_for_close(TO_CONN(conn));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authentication_cookie_is_set) {
|
||||||
|
connection_write_str_to_buf("515 Cookie authentication is disabled", conn);
|
||||||
|
connection_mark_for_close(TO_CONN(conn));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp += strspn(cp, " \t\n\r");
|
||||||
|
if (*cp == '"') {
|
||||||
|
const char *newcp =
|
||||||
|
decode_escaped_string(cp, len - (cp - body),
|
||||||
|
&client_nonce, &client_nonce_len);
|
||||||
|
if (newcp == NULL) {
|
||||||
|
connection_write_str_to_buf("513 Invalid quoted client nonce",
|
||||||
|
conn);
|
||||||
|
connection_mark_for_close(TO_CONN(conn));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cp = newcp;
|
||||||
|
} else {
|
||||||
|
size_t client_nonce_encoded_len = strspn(cp, "0123456789ABCDEFabcdef");
|
||||||
|
|
||||||
|
client_nonce_len = client_nonce_encoded_len / 2;
|
||||||
|
client_nonce = tor_malloc_zero(client_nonce_len);
|
||||||
|
|
||||||
|
if (base16_decode(client_nonce, client_nonce_len,
|
||||||
|
cp, client_nonce_encoded_len) < 0) {
|
||||||
|
connection_write_str_to_buf("513 Invalid base16 client nonce",
|
||||||
|
conn);
|
||||||
|
connection_mark_for_close(TO_CONN(conn));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp += client_nonce_encoded_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp += strspn(cp, " \t\n\r");
|
||||||
|
if (*cp != '\0' ||
|
||||||
|
cp != body + len) {
|
||||||
|
connection_write_str_to_buf("513 Junk at end of AUTHCHALLENGE command",
|
||||||
|
conn);
|
||||||
|
connection_mark_for_close(TO_CONN(conn));
|
||||||
|
tor_free(client_nonce);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tor_assert(!crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN));
|
||||||
|
|
||||||
|
/* Now compute and send the server-to-controller response, and the
|
||||||
|
* server's nonce. */
|
||||||
|
tor_assert(authentication_cookie != NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t tmp_len = (AUTHENTICATION_COOKIE_LEN +
|
||||||
|
client_nonce_len +
|
||||||
|
SAFECOOKIE_SERVER_NONCE_LEN);
|
||||||
|
char *tmp = tor_malloc_zero(tmp_len);
|
||||||
|
char *client_hash = tor_malloc_zero(DIGEST256_LEN);
|
||||||
|
memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN);
|
||||||
|
memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len);
|
||||||
|
memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len,
|
||||||
|
server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);
|
||||||
|
|
||||||
|
crypto_hmac_sha256(server_hash,
|
||||||
|
SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT,
|
||||||
|
strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT),
|
||||||
|
tmp,
|
||||||
|
tmp_len);
|
||||||
|
|
||||||
|
crypto_hmac_sha256(client_hash,
|
||||||
|
SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT,
|
||||||
|
strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT),
|
||||||
|
tmp,
|
||||||
|
tmp_len);
|
||||||
|
|
||||||
|
conn->safecookie_client_hash = client_hash;
|
||||||
|
|
||||||
|
tor_free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
|
||||||
|
server_hash, sizeof(server_hash));
|
||||||
|
base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
|
||||||
|
server_nonce, sizeof(server_nonce));
|
||||||
|
|
||||||
|
connection_printf_to_buf(conn,
|
||||||
|
"250 AUTHCHALLENGE SERVERHASH=%s "
|
||||||
|
"SERVERNONCE=%s\r\n",
|
||||||
|
server_hash_encoded,
|
||||||
|
server_nonce_encoded);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Called when we get a USEFEATURE command: parse the feature list, and
|
/** Called when we get a USEFEATURE command: parse the feature list, and
|
||||||
* set up the control_connection's options properly. */
|
* set up the control_connection's options properly. */
|
||||||
static int
|
static int
|
||||||
@ -2888,7 +3037,10 @@ is_valid_initial_command(control_connection_t *conn, const char *cmd)
|
|||||||
if (conn->_base.state == CONTROL_CONN_STATE_OPEN)
|
if (conn->_base.state == CONTROL_CONN_STATE_OPEN)
|
||||||
return 1;
|
return 1;
|
||||||
if (!strcasecmp(cmd, "PROTOCOLINFO"))
|
if (!strcasecmp(cmd, "PROTOCOLINFO"))
|
||||||
return !conn->have_sent_protocolinfo;
|
return (!conn->have_sent_protocolinfo &&
|
||||||
|
conn->safecookie_client_hash == NULL);
|
||||||
|
if (!strcasecmp(cmd, "AUTHCHALLENGE"))
|
||||||
|
return (conn->safecookie_client_hash == NULL);
|
||||||
if (!strcasecmp(cmd, "AUTHENTICATE") ||
|
if (!strcasecmp(cmd, "AUTHENTICATE") ||
|
||||||
!strcasecmp(cmd, "QUIT"))
|
!strcasecmp(cmd, "QUIT"))
|
||||||
return 1;
|
return 1;
|
||||||
@ -3104,6 +3256,9 @@ connection_control_process_inbuf(control_connection_t *conn)
|
|||||||
} else if (!strcasecmp(conn->incoming_cmd, "PROTOCOLINFO")) {
|
} else if (!strcasecmp(conn->incoming_cmd, "PROTOCOLINFO")) {
|
||||||
if (handle_control_protocolinfo(conn, cmd_data_len, args))
|
if (handle_control_protocolinfo(conn, cmd_data_len, args))
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (!strcasecmp(conn->incoming_cmd, "AUTHCHALLENGE")) {
|
||||||
|
if (handle_control_authchallenge(conn, cmd_data_len, args))
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n",
|
connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n",
|
||||||
conn->incoming_cmd);
|
conn->incoming_cmd);
|
||||||
|
@ -1254,6 +1254,12 @@ typedef struct control_connection_t {
|
|||||||
* connection. */
|
* connection. */
|
||||||
unsigned int is_owning_control_connection:1;
|
unsigned int is_owning_control_connection:1;
|
||||||
|
|
||||||
|
/** If we have sent an AUTHCHALLENGE reply on this connection and
|
||||||
|
* have not received a successful AUTHENTICATE command, points to
|
||||||
|
* the value which the client must send to authenticate itself;
|
||||||
|
* otherwise, NULL. */
|
||||||
|
char *safecookie_client_hash;
|
||||||
|
|
||||||
/** Amount of space allocated in incoming_cmd. */
|
/** Amount of space allocated in incoming_cmd. */
|
||||||
uint32_t incoming_cmd_len;
|
uint32_t incoming_cmd_len;
|
||||||
/** Number of bytes currently stored in incoming_cmd. */
|
/** Number of bytes currently stored in incoming_cmd. */
|
||||||
|
Loading…
Reference in New Issue
Block a user