mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 13:53:31 +01:00
Track routers by hash of identity key; use hex hash of identity key in place of nickname; accept (and use) hash of identity key in EXTEND cells.
svn:r1994
This commit is contained in:
parent
f42f04c859
commit
541add90a1
@ -837,8 +837,8 @@ int crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out)
|
||||
* space).
|
||||
*
|
||||
* Fingerprints are computed as the SHA1 digest of the ASN.1 encoding
|
||||
* of the public key, converted to hexadecimal, with a space after every
|
||||
* four digits.
|
||||
* of the public key, converted to hexadecimal, in upper case, with a
|
||||
* space after every four digits.
|
||||
*/
|
||||
int
|
||||
crypto_pk_get_fingerprint(crypto_pk_env_t *pk, char *fp_out)
|
||||
@ -1433,6 +1433,62 @@ base32_encode(char *dest, int destlen, const char *src, int srclen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int base16_encode(char *dest, int destlen, const char *src, int srclen)
|
||||
{
|
||||
const char *end;
|
||||
char *cp;
|
||||
|
||||
if (destlen < srclen*2+1)
|
||||
return -1;
|
||||
|
||||
cp = dest;
|
||||
end = src+srclen;
|
||||
while (src<end) {
|
||||
sprintf(cp,"%02X",*(const uint8_t*)src);
|
||||
++src;
|
||||
cp += 2;
|
||||
}
|
||||
*dest = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char HEX_DIGITS[] = "0123456789ABCDEFabcdef";
|
||||
|
||||
static INLINE int hex_decode_digit(char c)
|
||||
{
|
||||
const char *cp;
|
||||
int n;
|
||||
cp = strchr(HEX_DIGITS, c);
|
||||
if (!cp)
|
||||
return -1;
|
||||
n = cp-HEX_DIGITS;
|
||||
if (n<=15)
|
||||
return n; /* digit or uppercase */
|
||||
else
|
||||
return n-6; /* lowercase */
|
||||
}
|
||||
|
||||
int base16_decode(char *dest, int destlen, const char *src, int srclen)
|
||||
{
|
||||
const char *end;
|
||||
int v1,v2;
|
||||
if ((srclen % 2) != 0)
|
||||
return -1;
|
||||
if (destlen < srclen/2)
|
||||
return -1;
|
||||
end = src+srclen;
|
||||
while (src<end) {
|
||||
v1 = hex_decode_digit(*src);
|
||||
v2 = hex_decode_digit(*(src+1));
|
||||
if(v1<0||v2<0)
|
||||
return -1;
|
||||
*(uint8_t*)dest = (v1<<4)|v2;
|
||||
++dest;
|
||||
}
|
||||
*dest = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
|
@ -37,6 +37,8 @@
|
||||
/** Length of encoded public key fingerprints, including space; but not
|
||||
* including terminating NUL. */
|
||||
#define FINGERPRINT_LEN 49
|
||||
/** Length of hex encoding of SHA1 digest, not including final NUL. */
|
||||
#define HEX_DIGEST_LEN 40
|
||||
|
||||
typedef struct crypto_pk_env_t crypto_pk_env_t;
|
||||
typedef struct crypto_cipher_env_t crypto_cipher_env_t;
|
||||
@ -91,6 +93,8 @@ int base64_encode(char *dest, int destlen, const char *src, int srclen);
|
||||
int base64_decode(char *dest, int destlen, const char *src, int srclen);
|
||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||
int base32_encode(char *dest, int destlen, const char *src, int srclen);
|
||||
int base16_encode(char *dest, int destlen, const char *src, int srclen);
|
||||
int base16_decode(char *dest, int destlen, const char *src, int srclen);
|
||||
|
||||
/* Key negotiation */
|
||||
crypto_dh_env_t *crypto_dh_new();
|
||||
|
@ -292,7 +292,9 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
routerinfo_t *router;
|
||||
int r;
|
||||
int circ_id_type;
|
||||
char payload[2+4+ONIONSKIN_CHALLENGE_LEN];
|
||||
char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN];
|
||||
char *onionskin;
|
||||
int payload_len;
|
||||
|
||||
tor_assert(circ && CIRCUIT_IS_ORIGIN(circ));
|
||||
|
||||
@ -352,7 +354,17 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
|
||||
*(uint32_t*)payload = htonl(hop->addr);
|
||||
*(uint16_t*)(payload+4) = htons(hop->port);
|
||||
if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), payload+6) < 0) {
|
||||
if (strncmp(router->platform, "Tor 0.0.7", 9)) {
|
||||
/* Before 0.0.8, we didn't support the long payload format. */
|
||||
memcpy(payload+2+4, hop->identity_digest, DIGEST_LEN);
|
||||
onionskin = payload+2+4+DIGEST_LEN;
|
||||
payload_len = 2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN;
|
||||
} else {
|
||||
onionskin = payload+2+4;
|
||||
payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN;
|
||||
}
|
||||
|
||||
if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), onionskin) < 0) {
|
||||
log_fn(LOG_WARN,"onion_skin_create failed.");
|
||||
return -1;
|
||||
}
|
||||
@ -361,7 +373,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
/* send it to hop->prev, because it will transfer
|
||||
* it to a create cell and then send to hop */
|
||||
if(connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTEND,
|
||||
payload, sizeof(payload), hop->prev) < 0)
|
||||
payload, payload_len, hop->prev) < 0)
|
||||
return 0; /* circuit is closed */
|
||||
|
||||
hop->state = CPATH_STATE_AWAITING_KEYS;
|
||||
@ -377,16 +389,42 @@ int circuit_extend(cell_t *cell, circuit_t *circ) {
|
||||
connection_t *n_conn;
|
||||
int circ_id_type;
|
||||
cell_t newcell;
|
||||
relay_header_t rh;
|
||||
int old_format;
|
||||
char *onionskin;
|
||||
|
||||
if(circ->n_conn) {
|
||||
log_fn(LOG_WARN,"n_conn already set. Bug/attack. Closing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
relay_header_unpack(&rh, cell->payload);
|
||||
|
||||
if (rh.length == 4+2+ONIONSKIN_CHALLENGE_LEN) {
|
||||
old_format = 1;
|
||||
} else if (rh.length == 4+2+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN) {
|
||||
old_format = 0;
|
||||
} else {
|
||||
log_fn(LOG_WARN, "Wrong length on extend cell. Closing circuit.");
|
||||
circuit_mark_for_close(circ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
circ->n_addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
|
||||
circ->n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
|
||||
|
||||
n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
|
||||
if (old_format) {
|
||||
n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
|
||||
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2;
|
||||
} else {
|
||||
/* XXXX Roger: in this case, we should create the connnection if
|
||||
* n_conn is null. */
|
||||
n_conn = connection_get_by_identity_digest(
|
||||
cell->payload+RELAY_HEADER_SIZE+4+2,
|
||||
CONN_TYPE_OR);
|
||||
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2+DIGEST_LEN;
|
||||
}
|
||||
|
||||
if(!n_conn || n_conn->type != CONN_TYPE_OR) {
|
||||
/* I've disabled making connections through OPs, but it's definitely
|
||||
* possible here. I'm not sure if it would be a bug or a feature.
|
||||
@ -426,8 +464,7 @@ int circuit_extend(cell_t *cell, circuit_t *circ) {
|
||||
newcell.command = CELL_CREATE;
|
||||
newcell.circ_id = circ->n_circ_id;
|
||||
|
||||
memcpy(newcell.payload, cell->payload+RELAY_HEADER_SIZE+2+4,
|
||||
ONIONSKIN_CHALLENGE_LEN);
|
||||
memcpy(newcell.payload, onionskin, ONIONSKIN_CHALLENGE_LEN);
|
||||
|
||||
connection_or_write_cell_to_buf(&newcell, circ->n_conn);
|
||||
return 0;
|
||||
@ -1079,6 +1116,7 @@ onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t
|
||||
|
||||
hop->port = choice->or_port;
|
||||
hop->addr = choice->addr;
|
||||
memcpy(hop->identity_digest, choice->identity_digest, DIGEST_LEN);
|
||||
|
||||
hop->package_window = CIRCWINDOW_START;
|
||||
hop->deliver_window = CIRCWINDOW_START;
|
||||
|
@ -979,6 +979,25 @@ connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connection_t *connection_get_by_identity_digest(const char *digest, int type)
|
||||
{
|
||||
int i, n;
|
||||
connection_t *conn, *best=NULL;
|
||||
connection_t **carray;
|
||||
|
||||
get_connection_array(&carray,&n);
|
||||
for(i=0;i<n;i++) {
|
||||
conn = carray[i];
|
||||
if (conn->type != type)
|
||||
continue;
|
||||
if (!memcmp(conn->identity_digest, digest, DIGEST_LEN)
|
||||
&& !conn->marked_for_close
|
||||
&& (!best || best->timestamp_created < conn->timestamp_created))
|
||||
best = conn;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/** Return a connection of type <b>type</b> that is not marked for
|
||||
* close.
|
||||
*/
|
||||
|
@ -107,11 +107,34 @@ connection_or_init_conn_from_router(connection_t *conn, routerinfo_t *router) {
|
||||
conn->port = router->or_port;
|
||||
conn->receiver_bucket = conn->bandwidth = router->bandwidthburst;
|
||||
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
||||
crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest);
|
||||
conn->nickname = tor_strdup(router->nickname);
|
||||
tor_free(conn->address);
|
||||
conn->address = tor_strdup(router->address);
|
||||
}
|
||||
|
||||
static void
|
||||
connection_or_init_conn_from_address(connection_t *conn,
|
||||
uint32_t addr, uint16_t port,
|
||||
const char *id_digest)
|
||||
{
|
||||
routerinfo_t *r;
|
||||
r = router_get_by_digest(id_digest);
|
||||
if (r) {
|
||||
connection_or_init_conn_from_router(conn,r);
|
||||
return;
|
||||
}
|
||||
conn->addr = addr;
|
||||
conn->port = port;
|
||||
/* This next part isn't really right, but it's good enough for now. */
|
||||
conn->receiver_bucket = conn->bandwidth = options.BandwidthBurst;
|
||||
memcpy(conn->identity_digest, id_digest, DIGEST_LEN);
|
||||
conn->nickname = tor_malloc(HEX_DIGEST_LEN+1);
|
||||
base16_encode(conn->nickname, HEX_DIGEST_LEN+1,
|
||||
conn->identity_digest, DIGEST_LEN);
|
||||
/* Do something about address? Or is it already set? XXXX NMNM */
|
||||
}
|
||||
|
||||
/** Launch a new OR connection to <b>router</b>.
|
||||
*
|
||||
* If <b>router</b> is me, do nothing. If we're already connected to <b>router</b>,
|
||||
|
@ -137,6 +137,7 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
|
||||
conn->nickname = tor_strdup(router->nickname);
|
||||
tor_assert(router->identity_pkey);
|
||||
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
|
||||
crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest);
|
||||
|
||||
conn->purpose = purpose;
|
||||
|
||||
|
12
src/or/or.h
12
src/or/or.h
@ -493,8 +493,9 @@ struct connection_t {
|
||||
char *address; /**< FQDN (or IP) of the guy on the other end.
|
||||
* strdup into this, because free_connection frees it.
|
||||
*/
|
||||
crypto_pk_env_t *identity_pkey; /**> Public RSA key for the other side's
|
||||
crypto_pk_env_t *identity_pkey; /**< Public RSA key for the other side's
|
||||
* signing key. */
|
||||
char identity_digest[DIGEST_LEN]; /**< Hash of identity_pkey */
|
||||
char *nickname; /**< Nickname of OR on other side (if any). */
|
||||
|
||||
/* Used only by OR connections: */
|
||||
@ -569,7 +570,7 @@ typedef struct {
|
||||
|
||||
crypto_pk_env_t *onion_pkey; /**< Public RSA key for onions. */
|
||||
crypto_pk_env_t *identity_pkey; /**< Public RSA key for signing. */
|
||||
|
||||
char identity_digest[DIGEST_LEN]; /** Digest of identity key */
|
||||
|
||||
char *platform; /**< What software/operating system is this OR using? */
|
||||
|
||||
@ -633,6 +634,8 @@ struct crypt_path_t {
|
||||
uint32_t addr;
|
||||
/** Port of the OR at this step. */
|
||||
uint16_t port;
|
||||
/** Identity key digest of the OR at this step. */
|
||||
char identity_digest[DIGEST_LEN];
|
||||
|
||||
/** Is the circuit built to this step? Must be one of:
|
||||
* - CPATH_STATE_CLOSED (The circuit has not been extended to this step)
|
||||
@ -1044,6 +1047,7 @@ void connection_write_to_buf(const char *string, int len, connection_t *conn);
|
||||
|
||||
connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
connection_t *connection_get_by_identity_digest(const char *digest, int type);
|
||||
|
||||
connection_t *connection_get_by_type(int type);
|
||||
connection_t *connection_get_by_type_state(int type, int state);
|
||||
@ -1341,7 +1345,9 @@ void router_add_running_routers_to_smartlist(struct smartlist_t *sl);
|
||||
routerinfo_t *router_choose_random_node(char *preferred, char *excluded,
|
||||
struct smartlist_t *excludedsmartlist);
|
||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
routerinfo_t *router_get_by_nickname(char *nickname);
|
||||
routerinfo_t *router_get_by_nickname(const char *nickname);
|
||||
routerinfo_t *router_get_by_hexdigest(const char *hexdigest);
|
||||
routerinfo_t *router_get_by_digest(const char *digest);
|
||||
void router_get_routerlist(routerlist_t **prouterlist);
|
||||
void routerlist_free(routerlist_t *routerlist);
|
||||
void routerlist_clear_trusted_directories(void);
|
||||
|
@ -444,6 +444,10 @@ int router_rebuild_descriptor(void) {
|
||||
ri->published_on = time(NULL);
|
||||
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from main thread */
|
||||
ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
|
||||
if (crypto_pk_get_digest(ri->identity_pkey, ri->identity_digest)<0) {
|
||||
routerinfo_free(ri);
|
||||
return -1;
|
||||
}
|
||||
get_platform_str(platform, sizeof(platform));
|
||||
ri->platform = tor_strdup(platform);
|
||||
ri->bandwidthrate = options.BandwidthRate;
|
||||
|
@ -206,21 +206,59 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return the router in our routerlist whose nickname is <b>nickname</b>
|
||||
* (case insensitive). Return NULL if no such router is known.
|
||||
/** Return the router in our routerlist whose (case-insensitive)
|
||||
* nickname or (case-sensitive) hexadecimal key digest is
|
||||
* <b>nickname</b>. Return NULL if no such router is known.
|
||||
*/
|
||||
routerinfo_t *router_get_by_nickname(char *nickname)
|
||||
routerinfo_t *router_get_by_nickname(const char *nickname)
|
||||
{
|
||||
int i;
|
||||
int i, maybedigest;
|
||||
routerinfo_t *router;
|
||||
char digest[DIGEST_LEN];
|
||||
|
||||
tor_assert(nickname);
|
||||
if (!routerlist)
|
||||
return NULL;
|
||||
maybedigest = (strlen(nickname) == HEX_DIGEST_LEN) &&
|
||||
(base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
|
||||
|
||||
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
||||
router = smartlist_get(routerlist->routers, i);
|
||||
if (0 == strcasecmp(router->nickname, nickname))
|
||||
if (0 == strcasecmp(router->nickname, nickname) ||
|
||||
(maybedigest && 0 == memcmp(digest, router->identity_digest,
|
||||
DIGEST_LEN)))
|
||||
return router;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return the router in our routerlist whose hexadecimal key digest
|
||||
* is <b>hexdigest</b>. Return NULL if no such router is known. */
|
||||
routerinfo_t *router_get_by_hexdigest(const char *hexdigest) {
|
||||
char digest[DIGEST_LEN];
|
||||
|
||||
tor_assert(hexdigest);
|
||||
if (!routerlist)
|
||||
return NULL;
|
||||
if (strlen(hexdigest) != HEX_DIGEST_LEN ||
|
||||
base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
return router_get_by_digest(digest);
|
||||
}
|
||||
|
||||
/** Return the router in our routerlist whose 20-byte key digest
|
||||
* is <b>hexdigest</b>. Return NULL if no such router is known. */
|
||||
routerinfo_t *router_get_by_digest(const char *digest) {
|
||||
int i;
|
||||
routerinfo_t *router;
|
||||
|
||||
tor_assert(digest);
|
||||
|
||||
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
||||
router = smartlist_get(routerlist->routers, i);
|
||||
if (0 == memcmp(router->identity_digest, digest, DIGEST_LEN))
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -733,11 +733,14 @@ routerinfo_t *router_parse_entry_from_string(const char *s,
|
||||
}
|
||||
|
||||
if (!(tok = find_first_by_keyword(tokens, K_SIGNING_KEY))) {
|
||||
log_fn(LOG_WARN, "Missing onion key"); goto err;
|
||||
log_fn(LOG_WARN, "Missing identity key"); goto err;
|
||||
}
|
||||
/* XXX Check key length */
|
||||
router->identity_pkey = tok->key;
|
||||
tok->key = NULL; /* Prevent free */
|
||||
if (crypto_pk_get_digest(router->identity_pkey,router->identity_digest)){
|
||||
log_fn(LOG_WARN, "Couldn't calculate key digest"); goto err;
|
||||
}
|
||||
|
||||
if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) {
|
||||
router->platform = tor_strdup(tok->args[0]);
|
||||
|
Loading…
Reference in New Issue
Block a user