diff options
Diffstat (limited to 'src/or/circuitbuild.c')
-rw-r--r-- | src/or/circuitbuild.c | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 32841f8b9c..102230e61c 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -19,7 +19,8 @@ extern circuit_t *global_circuitlist; /********* END VARIABLES ************/ -static int circuit_deliver_create_cell(circuit_t *circ, char *payload); +static int circuit_deliver_create_cell(circuit_t *circ, + uint8_t cell_type, char *payload); static int onion_pick_cpath_exit(circuit_t *circ, routerinfo_t *exit); static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); static int onion_next_router_in_cpath(circuit_t *circ, routerinfo_t **router); @@ -374,7 +375,7 @@ void circuit_n_conn_done(connection_t *or_conn, int status) { } } else { /* pull the create cell out of circ->onionskin, and send it */ - if (circuit_deliver_create_cell(circ, circ->onionskin) < 0) { + if (circuit_deliver_create_cell(circ,CELL_CREATE,circ->onionskin) < 0) { circuit_mark_for_close(circ); continue; } @@ -384,7 +385,7 @@ void circuit_n_conn_done(connection_t *or_conn, int status) { } static int -circuit_deliver_create_cell(circuit_t *circ, char *payload) { +circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload) { cell_t cell; uint16_t id; @@ -392,6 +393,7 @@ circuit_deliver_create_cell(circuit_t *circ, char *payload) { tor_assert(circ->n_conn); tor_assert(circ->n_conn->type == CONN_TYPE_OR); tor_assert(payload); + tor_assert(cell_type == CELL_CREATE || cell_type == CELL_CREATE_FAST); id = get_unique_circ_id_by_conn(circ->n_conn); if (!id) { @@ -402,7 +404,7 @@ circuit_deliver_create_cell(circuit_t *circ, char *payload) { circuit_set_circid_orconn(circ, id, circ->n_conn, N_CONN_CHANGED); memset(&cell, 0, sizeof(cell_t)); - cell.command = CELL_CREATE; + cell.command = cell_type; cell.circ_id = circ->n_circ_id; memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN); @@ -434,6 +436,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) { tor_assert(CIRCUIT_IS_ORIGIN(circ)); if (circ->cpath->state == CPATH_STATE_CLOSED) { + uint8_t cell_type; log_fn(LOG_DEBUG,"First skin; sending create cell."); router = router_get_by_digest(circ->n_conn->identity_digest); @@ -443,14 +446,30 @@ int circuit_send_next_onion_skin(circuit_t *circ) { return -1; } - if (onion_skin_create(router->onion_pkey, - &(circ->cpath->handshake_state), - payload) < 0) { - log_fn(LOG_WARN,"onion_skin_create (first hop) failed."); - return -1; + if (get_options()->ORPort || !router->platform || + !tor_version_as_new_as(router->platform, "0.1.0.6-rc")) { + /* We are an OR, or we are connecting to an old Tor: we should + * send an old slow create cell. + */ + cell_type = CELL_CREATE; + if (onion_skin_create(router->onion_pkey, + &(circ->cpath->dh_handshake_state), + payload) < 0) { + log_fn(LOG_WARN,"onion_skin_create (first hop) failed."); + return -1; + } + } else { + /* We are not an OR, and we building the first hop of a circuit to + * a new OR: we can be speedy. */ + cell_type = CELL_CREATE_FAST; + memset(payload, 0, sizeof(payload)); + crypto_rand(circ->cpath->fast_handshake_state, + sizeof(circ->cpath->fast_handshake_state)); + memcpy(payload, circ->cpath->fast_handshake_state, + sizeof(circ->cpath->fast_handshake_state)); } - if (circuit_deliver_create_cell(circ, payload) < 0) + if (circuit_deliver_create_cell(circ, cell_type, payload) < 0) return -1; circ->cpath->state = CPATH_STATE_AWAITING_KEYS; @@ -491,7 +510,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) { memcpy(payload+2+4+ONIONSKIN_CHALLENGE_LEN, hop->identity_digest, DIGEST_LEN); payload_len = 2+4+ONIONSKIN_CHALLENGE_LEN+DIGEST_LEN; - if (onion_skin_create(router->onion_pkey, &(hop->handshake_state), onionskin) < 0) { + if (onion_skin_create(router->onion_pkey, &(hop->dh_handshake_state), onionskin) < 0) { log_fn(LOG_WARN,"onion_skin_create failed."); return -1; } @@ -589,7 +608,7 @@ int circuit_extend(cell_t *cell, circuit_t *circ) { memcpy(circ->n_conn_id_digest, n_conn->identity_digest, DIGEST_LEN); log_fn(LOG_DEBUG,"n_conn is %s:%u",n_conn->address,n_conn->port); - if (circuit_deliver_create_cell(circ, onionskin) < 0) + if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0) return -1; return 0; } @@ -648,13 +667,14 @@ int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse) /** A created or extended cell came back to us on the circuit, * and it included <b>reply</b> (the second DH key, plus KH). + * DOCDOC reply_type. * * Calculate the appropriate keys and digests, make sure KH is * correct, and initialize this hop of the cpath. * * Return -1 if we want to mark circ for close, else return 0. */ -int circuit_finish_handshake(circuit_t *circ, char *reply) { +int circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply) { unsigned char keys[CPATH_KEY_MATERIAL_LEN]; crypt_path_t *hop; @@ -670,16 +690,31 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) { } tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS); - if (onion_skin_client_handshake(hop->handshake_state, reply, keys, - DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) { - log_fn(LOG_WARN,"onion_skin_client_handshake failed."); + if (reply_type == CELL_CREATED && hop->dh_handshake_state) { + if (onion_skin_client_handshake(hop->dh_handshake_state, reply, keys, + DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) { + log_fn(LOG_WARN,"onion_skin_client_handshake failed."); + return -1; + } + /* Remember hash of g^xy */ + memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN); + } else if (reply_type == CELL_CREATED_FAST && !hop->dh_handshake_state) { + if (fast_client_handshake(hop->fast_handshake_state, reply, keys, + DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) { + log_fn(LOG_WARN,"fast_client_handshake failed."); + return -1; + } + memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN); + } else { + log_fn(LOG_WARN,"CREATED cell type did not match CREATE cell type."); return -1; } - crypto_dh_free(hop->handshake_state); /* don't need it anymore */ - hop->handshake_state = NULL; - /* Remember hash of g^xy */ - memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN); + if (hop->dh_handshake_state) { + crypto_dh_free(hop->dh_handshake_state); /* don't need it anymore */ + hop->dh_handshake_state = NULL; + } + memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state)); if (circuit_init_cpath_crypto(hop, keys, 0)<0) { return -1; @@ -742,7 +777,7 @@ int circuit_truncated(circuit_t *circ, crypt_path_t *layer) { /** Given a response payload and keys, initialize, then send a created * cell back. */ -int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys) { +int onionskin_answer(circuit_t *circ, uint8_t cell_type, unsigned char *payload, unsigned char *keys) { cell_t cell; crypt_path_t *tmp_cpath; @@ -750,14 +785,15 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key tmp_cpath->magic = CRYPT_PATH_MAGIC; memset(&cell, 0, sizeof(cell_t)); - cell.command = CELL_CREATED; + cell.command = cell_type; cell.circ_id = circ->p_circ_id; circ->state = CIRCUIT_STATE_OPEN; log_fn(LOG_DEBUG,"Entering."); - memcpy(cell.payload, payload, ONIONSKIN_REPLY_LEN); + memcpy(cell.payload, payload, + cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2); log_fn(LOG_INFO,"init digest forward 0x%.8x, backward 0x%.8x.", (unsigned int)*(uint32_t*)(keys), (unsigned int)*(uint32_t*)(keys+20)); @@ -773,7 +809,10 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key tmp_cpath->magic = 0; tor_free(tmp_cpath); - memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN); + if (cell_type == CELL_CREATED) + memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN); + else + memcpy(circ->handshake_digest, cell.payload+DIGEST_LEN, DIGEST_LEN); connection_or_write_cell_to_buf(&cell, circ->p_conn); log_fn(LOG_DEBUG,"Finished sending 'created' cell."); @@ -1457,4 +1496,3 @@ onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice) { return 0; } - |