Merge branch 'maint-0.2.2' into release-0.2.2
This commit is contained in:
commit
14e3900393
|
@ -0,0 +1,11 @@
|
|||
o Security fixes:
|
||||
- When using the debuging BridgePassword field, a bridge authority
|
||||
now compares alleged passwords by hashing them, then comparing
|
||||
the result to a digest of the expected authenticator. This avoids
|
||||
a potential side-channel attack in the previous code, which
|
||||
had foolishly used strcmp(). Fortunately, the BridgePassword field
|
||||
*is not in use*, but if it had been, the timing
|
||||
behavior of strcmp() might have allowed an adversary to guess the
|
||||
BridgePassword value, and enumerate the bridges. Bugfix on
|
||||
0.2.0.14-alpha. Fixes bug 5543.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
o Minor bugfixes:
|
||||
- Detect and reject certain misformed escape sequences in configuration
|
||||
values. Previously, these values would cause us to crash if received
|
||||
in a torrc file or over an (authenticated) control port. Bug found by
|
||||
Esteban Manchado Velázquez. Patch by Alexander Schrijver. Fix for
|
||||
bug 5090; bugfix on 0.2.0.16-alpha.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
o Minor bugfixes:
|
||||
- Fix a compile warning when using the --enable-openbsd-malloc configure
|
||||
option. Fixes bug 5340; bugfix on 0.2.0.20-rc.
|
|
@ -0,0 +1,3 @@
|
|||
o Security fixes:
|
||||
- Never use a bridge as an exit, even if it claims to be one. Found by
|
||||
wanoskarnet. Fixes bug 5342. Bugfix on ????.
|
|
@ -0,0 +1,7 @@
|
|||
o Security fixes:
|
||||
- Only build circuits if we have a sufficient threshold of the total
|
||||
descriptors marked in the consensus with the "Exit" flag. This
|
||||
mitigates an attack proposed by wanoskarnet, in which all of a
|
||||
client's bridges collude to restrict the exit nodes that the
|
||||
client knows about. Fixes bug 5343.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
o Minor features:
|
||||
- Update to the March 6 2012 Maxmind GeoLite Country database.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
o Directory authority changes:
|
||||
- Change IP address for ides (v3 directory authority), and rename it to
|
||||
turtles.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
o Security Features:
|
||||
- Provide controllers with a safer way to implement the cookie
|
||||
authentication mechanism. With the old method, if another locally
|
||||
running program could convince a controller that it was the Tor
|
||||
process, then that program could trick the contoller into
|
||||
telling it the contents of an arbitrary 32-byte file. The new
|
||||
"SAFECOOKIE" authentication method uses a challenge-response
|
||||
approach to prevent this. Fixes bug 5185, implements proposal 193.
|
||||
|
|
@ -1297,8 +1297,11 @@ DIRECTORY AUTHORITY SERVER OPTIONS
|
|||
|
||||
**BridgePassword** __Password__::
|
||||
If set, contains an HTTP authenticator that tells a bridge authority to
|
||||
serve all requested bridge information. Used for debugging. (Default:
|
||||
not set.)
|
||||
serve all requested bridge information. Used by the (only partially
|
||||
implemented) "bridge community" design, where a community of bridge
|
||||
relay operators all use an alternate bridge directory authority,
|
||||
and their target user audience can periodically fetch the list of
|
||||
available community bridges to stay up-to-date. (Default: not set.)
|
||||
|
||||
**V3AuthVotingInterval** __N__ **minutes**|**hours**::
|
||||
V3 authoritative directories only. Configures the server's preferred voting
|
||||
|
|
|
@ -285,6 +285,8 @@ static void *imalloc(size_t size);
|
|||
static void ifree(void *ptr);
|
||||
static void *irealloc(void *ptr, size_t size);
|
||||
static void *malloc_bytes(size_t size);
|
||||
void *memalign(size_t boundary, size_t size);
|
||||
size_t malloc_good_size(size_t size);
|
||||
|
||||
/*
|
||||
* Function for page directory lookup.
|
||||
|
@ -1980,10 +1982,11 @@ static int ispowerof2 (size_t a) {
|
|||
int posix_memalign(void **memptr, size_t alignment, size_t size)
|
||||
{
|
||||
void *r;
|
||||
size_t max;
|
||||
if ((alignment < PTR_SIZE) || (alignment%PTR_SIZE != 0)) return EINVAL;
|
||||
if (!ispowerof2(alignment)) return EINVAL;
|
||||
if (alignment < malloc_minsize) alignment = malloc_minsize;
|
||||
size_t max = alignment > size ? alignment : size;
|
||||
max = alignment > size ? alignment : size;
|
||||
if (alignment <= malloc_pagesize)
|
||||
r = malloc(max);
|
||||
else {
|
||||
|
|
|
@ -1714,6 +1714,74 @@ crypto_hmac_sha1(char *hmac_out,
|
|||
(unsigned char*)hmac_out, NULL);
|
||||
}
|
||||
|
||||
/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
|
||||
* the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
|
||||
* in <b>hmac_out</b>.
|
||||
*/
|
||||
void
|
||||
crypto_hmac_sha256(char *hmac_out,
|
||||
const char *key, size_t key_len,
|
||||
const char *msg, size_t msg_len)
|
||||
{
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x00908000l)
|
||||
/* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
|
||||
tor_assert(key_len < INT_MAX);
|
||||
tor_assert(msg_len < INT_MAX);
|
||||
HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
|
||||
(unsigned char*)hmac_out, NULL);
|
||||
#else
|
||||
/* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
|
||||
to do HMAC on our own.
|
||||
|
||||
HMAC isn't so hard: To compute HMAC(key, msg):
|
||||
1. If len(key) > blocksize, key = H(key).
|
||||
2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
|
||||
3. let ipad = key xor 0x363636363636....36
|
||||
let opad = key xor 0x5c5c5c5c5c5c....5c
|
||||
The result is H(opad | H( ipad | msg ) )
|
||||
*/
|
||||
#define BLOCKSIZE 64
|
||||
#define DIGESTSIZE 32
|
||||
uint8_t k[BLOCKSIZE];
|
||||
uint8_t pad[BLOCKSIZE];
|
||||
uint8_t d[DIGESTSIZE];
|
||||
int i;
|
||||
SHA256_CTX st;
|
||||
|
||||
tor_assert(key_len < INT_MAX);
|
||||
tor_assert(msg_len < INT_MAX);
|
||||
|
||||
if (key_len <= BLOCKSIZE) {
|
||||
memset(k, 0, sizeof(k));
|
||||
memcpy(k, key, key_len); /* not time invariant in key_len */
|
||||
} else {
|
||||
SHA256((const uint8_t *)key, key_len, k);
|
||||
memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
|
||||
}
|
||||
for (i = 0; i < BLOCKSIZE; ++i)
|
||||
pad[i] = k[i] ^ 0x36;
|
||||
SHA256_Init(&st);
|
||||
SHA256_Update(&st, pad, BLOCKSIZE);
|
||||
SHA256_Update(&st, (uint8_t*)msg, msg_len);
|
||||
SHA256_Final(d, &st);
|
||||
|
||||
for (i = 0; i < BLOCKSIZE; ++i)
|
||||
pad[i] = k[i] ^ 0x5c;
|
||||
SHA256_Init(&st);
|
||||
SHA256_Update(&st, pad, BLOCKSIZE);
|
||||
SHA256_Update(&st, d, DIGESTSIZE);
|
||||
SHA256_Final((uint8_t*)hmac_out, &st);
|
||||
|
||||
/* Now clear everything. */
|
||||
memset(k, 0, sizeof(k));
|
||||
memset(pad, 0, sizeof(pad));
|
||||
memset(d, 0, sizeof(d));
|
||||
memset(&st, 0, sizeof(st));
|
||||
#undef BLOCKSIZE
|
||||
#undef DIGESTSIZE
|
||||
#endif
|
||||
}
|
||||
|
||||
/* DH */
|
||||
|
||||
/** Shared P parameter for our circuit-crypto DH key exchanges. */
|
||||
|
|
|
@ -195,6 +195,9 @@ void crypto_digest_assign(crypto_digest_env_t *into,
|
|||
void crypto_hmac_sha1(char *hmac_out,
|
||||
const char *key, size_t key_len,
|
||||
const char *msg, size_t msg_len);
|
||||
void crypto_hmac_sha256(char *hmac_out,
|
||||
const char *key, size_t key_len,
|
||||
const char *msg, size_t msg_len);
|
||||
|
||||
/* Key negotiation */
|
||||
#define DH_TYPE_CIRCUIT 1
|
||||
|
|
|
@ -2212,14 +2212,16 @@ unescape_string(const char *s, char **result, size_t *size_out)
|
|||
case '\"':
|
||||
goto end_of_loop;
|
||||
case '\\':
|
||||
if ((cp[1] == 'x' || cp[1] == 'X')
|
||||
&& TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])) {
|
||||
if (cp[1] == 'x' || cp[1] == 'X') {
|
||||
if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])))
|
||||
return NULL;
|
||||
cp += 4;
|
||||
} else if (TOR_ISODIGIT(cp[1])) {
|
||||
cp += 2;
|
||||
if (TOR_ISODIGIT(*cp)) ++cp;
|
||||
if (TOR_ISODIGIT(*cp)) ++cp;
|
||||
} else if (cp[1]) {
|
||||
} else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"'
|
||||
|| cp[1] == '\\' || cp[1] == '\'') {
|
||||
cp += 2;
|
||||
} else {
|
||||
return NULL;
|
||||
|
@ -2251,9 +2253,19 @@ unescape_string(const char *s, char **result, size_t *size_out)
|
|||
case 'r': *out++ = '\r'; cp += 2; break;
|
||||
case 't': *out++ = '\t'; cp += 2; break;
|
||||
case 'x': case 'X':
|
||||
*out++ = ((hex_decode_digit(cp[2])<<4) +
|
||||
hex_decode_digit(cp[3]));
|
||||
cp += 4;
|
||||
{
|
||||
int x1, x2;
|
||||
|
||||
x1 = hex_decode_digit(cp[2]);
|
||||
x2 = hex_decode_digit(cp[3]);
|
||||
if (x1 == -1 || x2 == -1) {
|
||||
tor_free(*result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out++ = ((x1<<4) + x2);
|
||||
cp += 4;
|
||||
}
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7':
|
||||
|
|
26743
src/config/geoip
26743
src/config/geoip
File diff suppressed because it is too large
Load Diff
|
@ -2704,7 +2704,11 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
n_supported[i] = -1;
|
||||
continue; /* skip routers that are known to be down or bad exits */
|
||||
}
|
||||
|
||||
if (router->purpose != ROUTER_PURPOSE_GENERAL) {
|
||||
/* never pick a non-general node as a random exit. */
|
||||
n_supported[i] = -1;
|
||||
continue;
|
||||
}
|
||||
if (options->_ExcludeExitNodesUnion &&
|
||||
routerset_contains_router(options->_ExcludeExitNodesUnion, router)) {
|
||||
n_supported[i] = -1;
|
||||
|
|
|
@ -713,6 +713,7 @@ or_options_free(or_options_t *options)
|
|||
return;
|
||||
|
||||
routerset_free(options->_ExcludeExitNodesUnion);
|
||||
tor_free(options->_BridgePassword_AuthDigest);
|
||||
config_free(&options_format, options);
|
||||
}
|
||||
|
||||
|
@ -808,8 +809,9 @@ add_default_trusted_dir_authorities(authority_type_t type)
|
|||
"194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
|
||||
"Tonga orport=443 bridge no-v2 82.94.251.203:80 "
|
||||
"4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D",
|
||||
"ides orport=9090 no-v2 v3ident=27B6B5996C426270A5C95488AA5BCEB6BCC86956 "
|
||||
"216.224.124.114:9030 F397 038A DC51 3361 35E7 B80B D99C A384 4360 292B",
|
||||
"turtles orport=9090 no-v2 "
|
||||
"v3ident=27B6B5996C426270A5C95488AA5BCEB6BCC86956 "
|
||||
"76.73.17.194:9030 F397 038A DC51 3361 35E7 B80B D99C A384 4360 292B",
|
||||
"gabelmoo orport=443 no-v2 "
|
||||
"v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
|
||||
"212.112.245.170:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
|
||||
|
@ -1298,6 +1300,24 @@ options_act(or_options_t *old_options)
|
|||
/* Change the cell EWMA settings */
|
||||
cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
|
||||
|
||||
/* Update the BridgePassword's hashed version as needed. We store this as a
|
||||
* digest so that we can do side-channel-proof comparisons on it.
|
||||
*/
|
||||
if (options->BridgePassword) {
|
||||
char *http_authenticator;
|
||||
http_authenticator = alloc_http_authenticator(options->BridgePassword);
|
||||
if (!http_authenticator) {
|
||||
log_warn(LD_BUG, "Unable to allocate HTTP authenticator. Not setting "
|
||||
"BridgePassword.");
|
||||
return -1;
|
||||
}
|
||||
options->_BridgePassword_AuthDigest = tor_malloc(DIGEST256_LEN);
|
||||
crypto_digest256(options->_BridgePassword_AuthDigest,
|
||||
http_authenticator, strlen(http_authenticator),
|
||||
DIGEST_SHA256);
|
||||
tor_free(http_authenticator);
|
||||
}
|
||||
|
||||
/* Check for transitions that need action. */
|
||||
if (old_options) {
|
||||
int revise_trackexithosts = 0;
|
||||
|
|
|
@ -419,6 +419,7 @@ _connection_free(connection_t *conn)
|
|||
}
|
||||
if (conn->type == CONN_TYPE_CONTROL) {
|
||||
control_connection_t *control_conn = TO_CONTROL_CONN(conn);
|
||||
tor_free(control_conn->safecookie_client_hash);
|
||||
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.) */
|
||||
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. */
|
||||
#define BOOTSTRAP_MSG_LEN 1024
|
||||
|
||||
|
@ -1078,6 +1084,32 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
|
|||
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 &&
|
||||
!options->HashedControlSessionPassword) {
|
||||
/* 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 ||
|
||||
options->HashedControlSessionPassword != NULL);
|
||||
smartlist_t *mlist = smartlist_create();
|
||||
if (cookies)
|
||||
if (cookies) {
|
||||
smartlist_add(mlist, (char*)"COOKIE");
|
||||
smartlist_add(mlist, (char*)"SAFECOOKIE");
|
||||
}
|
||||
if (passwd)
|
||||
smartlist_add(mlist, (char*)"HASHEDPASSWORD");
|
||||
if (!cookies && !passwd)
|
||||
|
@ -2787,6 +2821,121 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len,
|
|||
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
|
||||
* set up the control_connection's options properly. */
|
||||
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)
|
||||
return 1;
|
||||
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") ||
|
||||
!strcasecmp(cmd, "QUIT"))
|
||||
return 1;
|
||||
|
@ -3104,6 +3256,9 @@ connection_control_process_inbuf(control_connection_t *conn)
|
|||
} else if (!strcasecmp(conn->incoming_cmd, "PROTOCOLINFO")) {
|
||||
if (handle_control_protocolinfo(conn, cmd_data_len, args))
|
||||
return -1;
|
||||
} else if (!strcasecmp(conn->incoming_cmd, "AUTHCHALLENGE")) {
|
||||
if (handle_control_authchallenge(conn, cmd_data_len, args))
|
||||
return -1;
|
||||
} else {
|
||||
connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n",
|
||||
conn->incoming_cmd);
|
||||
|
|
|
@ -3069,22 +3069,24 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
|
|||
}
|
||||
|
||||
if (options->BridgeAuthoritativeDir &&
|
||||
options->BridgePassword &&
|
||||
options->_BridgePassword_AuthDigest &&
|
||||
connection_dir_is_encrypted(conn) &&
|
||||
!strcmp(url,"/tor/networkstatus-bridges")) {
|
||||
char *status;
|
||||
char *secret = alloc_http_authenticator(options->BridgePassword);
|
||||
char digest[DIGEST256_LEN];
|
||||
|
||||
header = http_get_header(headers, "Authorization: Basic ");
|
||||
if (header)
|
||||
crypto_digest256(digest, header, strlen(header), DIGEST_SHA256);
|
||||
|
||||
/* now make sure the password is there and right */
|
||||
if (!header || strcmp(header, secret)) {
|
||||
if (!header ||
|
||||
tor_memneq(digest,
|
||||
options->_BridgePassword_AuthDigest, DIGEST256_LEN)) {
|
||||
write_http_status_line(conn, 404, "Not found");
|
||||
tor_free(secret);
|
||||
tor_free(header);
|
||||
goto done;
|
||||
}
|
||||
tor_free(secret);
|
||||
tor_free(header);
|
||||
|
||||
/* all happy now. send an answer. */
|
||||
|
|
13
src/or/or.h
13
src/or/or.h
|
@ -1254,6 +1254,12 @@ typedef struct control_connection_t {
|
|||
* connection. */
|
||||
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. */
|
||||
uint32_t incoming_cmd_len;
|
||||
/** Number of bytes currently stored in incoming_cmd. */
|
||||
|
@ -2483,10 +2489,11 @@ typedef struct {
|
|||
* that aggregates bridge descriptors? */
|
||||
|
||||
/** If set on a bridge authority, it will answer requests on its dirport
|
||||
* for bridge statuses -- but only if the requests use this password.
|
||||
* If set on a bridge user, request bridge statuses, and use this password
|
||||
* when doing so. */
|
||||
* for bridge statuses -- but only if the requests use this password. */
|
||||
char *BridgePassword;
|
||||
/** If BridgePassword is set, this is a SHA256 digest of the basic http
|
||||
* authenticator for it. Used so we can do a time-independent comparison. */
|
||||
char *_BridgePassword_AuthDigest;
|
||||
|
||||
int UseBridges; /**< Boolean: should we start all circuits with a bridge? */
|
||||
config_line_t *Bridges; /**< List of bootstrap bridge addresses. */
|
||||
|
|
|
@ -4788,18 +4788,21 @@ get_dir_info_status_string(void)
|
|||
* them seem like ones we'd use, and how many of <em>those</em> we have
|
||||
* descriptors for. Store the former in *<b>num_usable</b> and the latter in
|
||||
* *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
|
||||
* routers in <b>in_set</b>.
|
||||
* routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
|
||||
* with the Exit flag.
|
||||
*/
|
||||
static void
|
||||
count_usable_descriptors(int *num_present, int *num_usable,
|
||||
const networkstatus_t *consensus,
|
||||
or_options_t *options, time_t now,
|
||||
routerset_t *in_set)
|
||||
routerset_t *in_set, int exit_only)
|
||||
{
|
||||
*num_present = 0, *num_usable=0;
|
||||
|
||||
SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs,
|
||||
{
|
||||
if (exit_only && ! rs->is_exit)
|
||||
continue;
|
||||
if (in_set && ! routerset_contains_routerstatus(in_set, rs))
|
||||
continue;
|
||||
if (client_would_use_router(rs, now, options)) {
|
||||
|
@ -4830,7 +4833,7 @@ count_loading_descriptors_progress(void)
|
|||
return 0; /* can't count descriptors if we have no list of them */
|
||||
|
||||
count_usable_descriptors(&num_present, &num_usable,
|
||||
consensus, get_options(), now, NULL);
|
||||
consensus, get_options(), now, NULL, 0);
|
||||
|
||||
if (num_usable == 0)
|
||||
return 0; /* don't div by 0 */
|
||||
|
@ -4849,6 +4852,7 @@ static void
|
|||
update_router_have_minimum_dir_info(void)
|
||||
{
|
||||
int num_present = 0, num_usable=0;
|
||||
int num_exit_present = 0, num_exit_usable = 0;
|
||||
time_t now = time(NULL);
|
||||
int res;
|
||||
or_options_t *options = get_options();
|
||||
|
@ -4875,7 +4879,9 @@ update_router_have_minimum_dir_info(void)
|
|||
}
|
||||
|
||||
count_usable_descriptors(&num_present, &num_usable, consensus, options, now,
|
||||
NULL);
|
||||
NULL, 0);
|
||||
count_usable_descriptors(&num_exit_present, &num_exit_usable,
|
||||
consensus, options, now, options->ExitNodes, 1);
|
||||
|
||||
if (num_present < num_usable/4) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
|
@ -4889,12 +4895,19 @@ update_router_have_minimum_dir_info(void)
|
|||
num_present, num_present ? "" : "s");
|
||||
res = 0;
|
||||
goto done;
|
||||
} else if (num_exit_present < num_exit_usable / 3) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
"We have only %d/%d usable exit node descriptors.",
|
||||
num_exit_present, num_exit_usable);
|
||||
res = 0;
|
||||
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check for entry nodes. */
|
||||
if (options->EntryNodes) {
|
||||
count_usable_descriptors(&num_present, &num_usable, consensus, options,
|
||||
now, options->EntryNodes);
|
||||
now, options->EntryNodes, 0);
|
||||
|
||||
if (!num_usable || !num_present) {
|
||||
tor_snprintf(dir_info_status, sizeof(dir_info_status),
|
||||
|
|
|
@ -231,7 +231,7 @@ test_crypto_sha(void)
|
|||
{
|
||||
crypto_digest_env_t *d1 = NULL, *d2 = NULL;
|
||||
int i;
|
||||
char key[80];
|
||||
char key[160];
|
||||
char digest[32];
|
||||
char data[50];
|
||||
char d_out1[DIGEST_LEN], d_out2[DIGEST256_LEN];
|
||||
|
@ -276,6 +276,75 @@ test_crypto_sha(void)
|
|||
test_streq(hex_str(digest, 20),
|
||||
"AA4AE5E15272D00E95705637CE8A3B55ED402112");
|
||||
|
||||
/* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */
|
||||
|
||||
/* Case empty (wikipedia) */
|
||||
crypto_hmac_sha256(digest, "", 0, "", 0);
|
||||
test_streq(hex_str(digest, 32),
|
||||
"B613679A0814D9EC772F95D778C35FC5FF1697C493715653C6C712144292C5AD");
|
||||
|
||||
/* Case quick-brown (wikipedia) */
|
||||
crypto_hmac_sha256(digest, "key", 3,
|
||||
"The quick brown fox jumps over the lazy dog", 43);
|
||||
test_streq(hex_str(digest, 32),
|
||||
"F7BC83F430538424B13298E6AA6FB143EF4D59A14946175997479DBC2D1A3CD8");
|
||||
|
||||
/* "Test Case 1" from RFC 4231 */
|
||||
memset(key, 0x0b, 20);
|
||||
crypto_hmac_sha256(digest, key, 20, "Hi There", 8);
|
||||
test_memeq_hex(digest,
|
||||
"b0344c61d8db38535ca8afceaf0bf12b"
|
||||
"881dc200c9833da726e9376c2e32cff7");
|
||||
|
||||
/* "Test Case 2" from RFC 4231 */
|
||||
memset(key, 0x0b, 20);
|
||||
crypto_hmac_sha256(digest, "Jefe", 4, "what do ya want for nothing?", 28);
|
||||
test_memeq_hex(digest,
|
||||
"5bdcc146bf60754e6a042426089575c7"
|
||||
"5a003f089d2739839dec58b964ec3843");
|
||||
|
||||
/* "Test case 3" from RFC 4231 */
|
||||
memset(key, 0xaa, 20);
|
||||
memset(data, 0xdd, 50);
|
||||
crypto_hmac_sha256(digest, key, 20, data, 50);
|
||||
test_memeq_hex(digest,
|
||||
"773ea91e36800e46854db8ebd09181a7"
|
||||
"2959098b3ef8c122d9635514ced565fe");
|
||||
|
||||
/* "Test case 4" from RFC 4231 */
|
||||
base16_decode(key, 25,
|
||||
"0102030405060708090a0b0c0d0e0f10111213141516171819", 50);
|
||||
memset(data, 0xcd, 50);
|
||||
crypto_hmac_sha256(digest, key, 25, data, 50);
|
||||
test_memeq_hex(digest,
|
||||
"82558a389a443c0ea4cc819899f2083a"
|
||||
"85f0faa3e578f8077a2e3ff46729665b");
|
||||
|
||||
/* "Test case 5" from RFC 4231 */
|
||||
memset(key, 0x0c, 20);
|
||||
crypto_hmac_sha256(digest, key, 20, "Test With Truncation", 20);
|
||||
test_memeq_hex(digest,
|
||||
"a3b6167473100ee06e0c796c2955552b");
|
||||
|
||||
/* "Test case 6" from RFC 4231 */
|
||||
memset(key, 0xaa, 131);
|
||||
crypto_hmac_sha256(digest, key, 131,
|
||||
"Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
54);
|
||||
test_memeq_hex(digest,
|
||||
"60e431591ee0b67f0d8a26aacbf5b77f"
|
||||
"8e0bc6213728c5140546040f0ee37f54");
|
||||
|
||||
/* "Test case 7" from RFC 4231 */
|
||||
memset(key, 0xaa, 131);
|
||||
crypto_hmac_sha256(digest, key, 131,
|
||||
"This is a test using a larger than block-size key and a "
|
||||
"larger than block-size data. The key needs to be hashed "
|
||||
"before being used by the HMAC algorithm.", 152);
|
||||
test_memeq_hex(digest,
|
||||
"9b09ffa71b942fcb27635fbcd5b0e944"
|
||||
"bfdc63644f0713938a7f51535c3a35e2");
|
||||
|
||||
/* Incremental digest code. */
|
||||
d1 = crypto_new_digest_env();
|
||||
test_assert(d1);
|
||||
|
|
Loading…
Reference in New Issue