summaryrefslogtreecommitdiff
path: root/src/or/circuitbuild.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/circuitbuild.c')
-rw-r--r--src/or/circuitbuild.c88
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;
}
-