/** Release whatever storage is held in <b>state</b>, depending on its * type, and clear its pointer. */ void onion_handshake_state_release(onion_handshake_state_t *state) { switch (state->tag) { case ONION_HANDSHAKE_TYPE_TAP: crypto_dh_free(state->u.tap); state->u.tap = NULL; break; case ONION_HANDSHAKE_TYPE_FAST: fast_handshake_state_free(state->u.fast); state->u.fast = NULL; break; case ONION_HANDSHAKE_TYPE_NTOR: ntor_handshake_state_free(state->u.ntor); state->u.ntor = NULL; break; default: /* LCOV_EXCL_START * This state should not even exist. */ log_warn(LD_BUG, "called with unknown handshake state type %d", (int)state->tag); tor_fragile_assert(); /* LCOV_EXCL_STOP */ } }
/** Look up the original name that corresponds to 'addr' in req. We use this * to preserve case in order to facilitate people using 0x20-hacks to avoid * DNS poisoning. */ static const char * evdns_get_orig_address(const struct evdns_server_request *req, int rtype, const char *addr) { int i, type; switch (rtype) { case RESOLVED_TYPE_IPV4: type = EVDNS_TYPE_A; break; case RESOLVED_TYPE_HOSTNAME: type = EVDNS_TYPE_PTR; break; case RESOLVED_TYPE_IPV6: type = EVDNS_TYPE_AAAA; break; default: tor_fragile_assert(); return addr; } for (i = 0; i < req->nquestions; ++i) { const struct evdns_server_question *q = req->questions[i]; if (q->type == type && !strcasecmp(q->name, addr)) return q->name; } return addr; }
/** Perform the second (server-side) step of a circuit-creation handshake of * type <b>type</b>, responding to the client request in <b>onion_skin</b> * using the keys in <b>keys</b>. On success, write our response into * <b>reply_out</b>, generate <b>keys_out_len</b> bytes worth of key material * in <b>keys_out_len</b>, a hidden service nonce to <b>rend_nonce_out</b>, * and return the length of the reply. On failure, return -1. */ int onion_skin_server_handshake(int type, const uint8_t *onion_skin, size_t onionskin_len, const server_onion_keys_t *keys, uint8_t *reply_out, uint8_t *keys_out, size_t keys_out_len, uint8_t *rend_nonce_out) { int r = -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN) return -1; if (onion_skin_TAP_server_handshake((const char*)onion_skin, keys->onion_key, keys->last_onion_key, (char*)reply_out, (char*)keys_out, keys_out_len)<0) return -1; r = TAP_ONIONSKIN_REPLY_LEN; memcpy(rend_nonce_out, reply_out+DH_KEY_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_FAST: if (onionskin_len != CREATE_FAST_LEN) return -1; if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0) return -1; r = CREATED_FAST_LEN; memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_NTOR: if (onionskin_len < NTOR_ONIONSKIN_LEN) return -1; { size_t keys_tmp_len = keys_out_len + DIGEST_LEN; uint8_t *keys_tmp = tor_malloc(keys_out_len + DIGEST_LEN); if (onion_skin_ntor_server_handshake( onion_skin, keys->curve25519_key_map, keys->junk_keypair, keys->my_identity, reply_out, keys_tmp, keys_tmp_len)<0) { tor_free(keys_tmp); return -1; } memcpy(keys_out, keys_tmp, keys_out_len); memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN); memwipe(keys_tmp, 0, keys_tmp_len); tor_free(keys_tmp); r = NTOR_REPLY_LEN; } break; default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); return -1; } return r; }
/** * Add a new build time value <b>time</b> to the set of build times. Time * units are milliseconds. * * circuit_build_times <b>cbt</b> is a circular array, so loop around when * array is full. */ int circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) { if (time <= 0 || time > CBT_BUILD_TIME_MAX) { log_warn(LD_BUG, "Circuit build time is too large (%u)." "This is probably a bug.", time); tor_fragile_assert(); return -1; } log_debug(LD_CIRC, "Adding circuit build time %u", time); cbt->circuit_build_times[cbt->build_times_idx] = time; cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) cbt->total_build_times++; if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { /* Save state every n circuit builds */ if (!unit_tests && !get_options()->AvoidDiskWrites) or_state_mark_dirty(get_or_state(), 0); } return 0; }
/** Perform the first step of a circuit-creation handshake of type <b>type</b> * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in * <b>onion_skin_out</b>, and store any state information in <b>state_out</b>. * Return -1 on failure, and the length of the onionskin on acceptance. */ int onion_skin_create(int type, const extend_info_t *node, onion_handshake_state_t *state_out, uint8_t *onion_skin_out) { int r = -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (!node->onion_key) return -1; if (onion_skin_TAP_create(node->onion_key, &state_out->u.tap, (char*)onion_skin_out) < 0) return -1; r = TAP_ONIONSKIN_CHALLENGE_LEN; break; case ONION_HANDSHAKE_TYPE_FAST: if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0) return -1; r = CREATE_FAST_LEN; break; case ONION_HANDSHAKE_TYPE_NTOR: #ifdef CURVE25519_ENABLED if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key, CURVE25519_PUBKEY_LEN)) return -1; if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, &node->curve25519_onion_key, &state_out->u.ntor, onion_skin_out) < 0) return -1; r = NTOR_ONIONSKIN_LEN; #else return -1; #endif break; default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); r = -1; } if (r > 0) state_out->tag = (uint16_t) type; return r; }
/** Return a string specifying the state of the hidden-service circuit * purpose <b>purpose</b>, or NULL if <b>purpose</b> is not a * hidden-service-related circuit purpose. */ const char * circuit_purpose_to_controller_hs_state_string(uint8_t purpose) { switch (purpose) { default: log_fn(LOG_WARN, LD_BUG, "Unrecognized circuit purpose: %d", (int)purpose); tor_fragile_assert(); /* fall through */ case CIRCUIT_PURPOSE_OR: case CIRCUIT_PURPOSE_C_GENERAL: case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: case CIRCUIT_PURPOSE_TESTING: case CIRCUIT_PURPOSE_CONTROLLER: return NULL; case CIRCUIT_PURPOSE_INTRO_POINT: return "OR_HSSI_ESTABLISHED"; case CIRCUIT_PURPOSE_REND_POINT_WAITING: return "OR_HSCR_ESTABLISHED"; case CIRCUIT_PURPOSE_REND_ESTABLISHED: return "OR_HS_R_JOINED"; case CIRCUIT_PURPOSE_C_INTRODUCING: return "HSCI_CONNECTING"; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: return "HSCI_INTRO_SENT"; case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: return "HSCI_DONE"; case CIRCUIT_PURPOSE_C_ESTABLISH_REND: return "HSCR_CONNECTING"; case CIRCUIT_PURPOSE_C_REND_READY: return "HSCR_ESTABLISHED_IDLE"; case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: return "HSCR_ESTABLISHED_WAITING"; case CIRCUIT_PURPOSE_C_REND_JOINED: return "HSCR_JOINED"; case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: return "HSSI_CONNECTING"; case CIRCUIT_PURPOSE_S_INTRO: return "HSSI_ESTABLISHED"; case CIRCUIT_PURPOSE_S_CONNECT_REND: return "HSSR_CONNECTING"; case CIRCUIT_PURPOSE_S_REND_JOINED: return "HSSR_JOINED"; } }
/* Parse the Commit line(s) in the disk state and translate them to the * the memory state. Return 0 on success else -1 on error. */ static int disk_state_parse_commits(sr_state_t *state, const sr_disk_state_t *disk_state) { config_line_t *line; smartlist_t *args = NULL; tor_assert(state); tor_assert(disk_state); for (line = disk_state->Commit; line; line = line->next) { sr_commit_t *commit = NULL; /* Extra safety. */ if (strcasecmp(line->key, dstate_commit_key) || line->value == NULL) { /* Ignore any lines that are not commits. */ tor_fragile_assert(); continue; } args = smartlist_new(); smartlist_split_string(args, line->value, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (smartlist_len(args) < 3) { log_warn(LD_BUG, "SR: Too few arguments in Commit Line: %s", escaped(line->value)); goto error; } commit = sr_parse_commit(args); if (commit == NULL) { /* Ignore badly formed commit. It could also be a authority * fingerprint that we don't know about so it shouldn't be used. */ smartlist_free(args); continue; } /* We consider parseable commit from our disk state to be valid because * they need to be in the first place to get in there. */ commit->valid = 1; /* Add commit to our state pointer. */ commit_add_to_state(commit, state); SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); smartlist_free(args); } return 0; error: SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); smartlist_free(args); return -1; }
/** Perform the first step of a circuit-creation handshake of type <b>type</b> * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in * <b>onion_skin_out</b>, and store any state information in <b>state_out</b>. * Return -1 on failure, and the length of the onionskin on acceptance. */ int onion_skin_create(int type, const extend_info_t *node, onion_handshake_state_t *state_out, uint8_t *onion_skin_out) { int r = -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (!node->onion_key) return -1; if (onion_skin_TAP_create(node->onion_key, &state_out->u.tap, (char*)onion_skin_out) < 0) return -1; r = TAP_ONIONSKIN_CHALLENGE_LEN; break; case ONION_HANDSHAKE_TYPE_FAST: if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0) return -1; r = CREATE_FAST_LEN; break; case ONION_HANDSHAKE_TYPE_NTOR: if (!extend_info_supports_ntor(node)) return -1; if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, &node->curve25519_onion_key, &state_out->u.ntor, onion_skin_out) < 0) return -1; r = NTOR_ONIONSKIN_LEN; break; default: /* LCOV_EXCL_START * We should never try to create an impossible handshake type. */ log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); r = -1; /* LCOV_EXCL_STOP */ } if (r > 0) state_out->tag = (uint16_t) type; return r; }
/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal * statistics about how many of each cell we've processed so far * this second, and the total number of microseconds it took to * process each type of cell. */ void command_process_var_cell(var_cell_t *cell, or_connection_t *conn) { #ifdef KEEP_TIMING_STATS /* how many of each cell have we seen so far this second? needs better * name. */ static int num_versions=0, num_cert=0; time_t now = time(NULL); if (now > current_second) { /* the second has rolled over */ /* print stats */ log_info(LD_OR, "At end of second: %d versions (%d ms), %d cert (%d ms)", num_versions, versions_time/1000, cert, cert_time/1000); num_versions = num_cert = 0; versions_time = cert_time = 0; /* remember which second it is, for next time */ current_second = now; } #endif /* reject all when not handshaking. */ if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING) return; switch (cell->command) { case CELL_VERSIONS: ++stats_n_versions_cells_processed; PROCESS_CELL(versions, cell, conn); break; default: log_warn(LD_BUG, "Variable-length cell of unknown type (%d) received.", cell->command); tor_fragile_assert(); break; } }
/** Release whatever storage is held in <b>state</b>, depending on its * type, and clear its pointer. */ void onion_handshake_state_release(onion_handshake_state_t *state) { switch (state->tag) { case ONION_HANDSHAKE_TYPE_TAP: crypto_dh_free(state->u.tap); state->u.tap = NULL; break; case ONION_HANDSHAKE_TYPE_FAST: fast_handshake_state_free(state->u.fast); state->u.fast = NULL; break; case ONION_HANDSHAKE_TYPE_NTOR: ntor_handshake_state_free(state->u.ntor); state->u.ntor = NULL; break; default: log_warn(LD_BUG, "called with unknown handshake state type %d", (int)state->tag); tor_fragile_assert(); } }
/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal * statistics about how many of each cell we've processed so far * this second, and the total number of microseconds it took to * process each type of cell. */ void command_process_cell(cell_t *cell, or_connection_t *conn) { int handshaking = (conn->_base.state != OR_CONN_STATE_OPEN); #ifdef KEEP_TIMING_STATS /* how many of each cell have we seen so far this second? needs better * name. */ static int num_create=0, num_created=0, num_relay=0, num_destroy=0; /* how long has it taken to process each type of cell? */ static int create_time=0, created_time=0, relay_time=0, destroy_time=0; static time_t current_second = 0; /* from previous calls to time */ time_t now = time(NULL); if (now > current_second) { /* the second has rolled over */ /* print stats */ log_info(LD_OR, "At end of second: %d creates (%d ms), %d createds (%d ms), " "%d relays (%d ms), %d destroys (%d ms)", num_create, create_time/1000, num_created, created_time/1000, num_relay, relay_time/1000, num_destroy, destroy_time/1000); /* zero out stats */ num_create = num_created = num_relay = num_destroy = 0; create_time = created_time = relay_time = destroy_time = 0; /* remember which second it is, for next time */ current_second = now; } #endif #ifdef KEEP_TIMING_STATS #define PROCESS_CELL(tp, cl, cn) STMT_BEGIN { \ ++num ## tp; \ command_time_process_cell(cl, cn, & tp ## time , \ command_process_ ## tp ## _cell); \ } STMT_END #else #define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn) #endif if (conn->_base.marked_for_close) return; /* Reject all but VERSIONS and NETINFO when handshaking. */ /* (VERSIONS should actually be impossible; it's variable-length.) */ if (handshaking && cell->command != CELL_VERSIONS && cell->command != CELL_NETINFO) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received unexpected cell command %d in state %s; ignoring it.", (int)cell->command, conn_state_to_string(CONN_TYPE_OR,conn->_base.state)); return; } if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) or_handshake_state_record_cell(conn->handshake_state, cell, 1); switch (cell->command) { case CELL_PADDING: ++stats_n_padding_cells_processed; /* do nothing */ break; case CELL_CREATE: case CELL_CREATE_FAST: ++stats_n_create_cells_processed; PROCESS_CELL(create, cell, conn); break; case CELL_CREATED: case CELL_CREATED_FAST: ++stats_n_created_cells_processed; PROCESS_CELL(created, cell, conn); break; case CELL_RELAY: case CELL_RELAY_EARLY: ++stats_n_relay_cells_processed; PROCESS_CELL(relay, cell, conn); break; case CELL_DESTROY: ++stats_n_destroy_cells_processed; PROCESS_CELL(destroy, cell, conn); break; case CELL_VERSIONS: tor_fragile_assert(); break; case CELL_NETINFO: ++stats_n_netinfo_cells_processed; PROCESS_CELL(netinfo, cell, conn); break; default: log_fn(LOG_INFO, LD_PROTOCOL, "Cell of unknown type (%d) received. Dropping.", cell->command); break; } }
/** Perform the final (client-side) step of a circuit-creation handshake of * type <b>type</b>, using our state in <b>handshake_state</b> and the * server's response in <b>reply</b>. On success, generate <b>keys_out_len</b> * bytes worth of key material in <b>keys_out_len</b>, set * <b>rend_authenticator_out</b> to the "KH" field that can be used to * establish introduction points at this hop, and return 0. On failure, * return -1, and set *msg_out to an error message if this is worth * complaining to the usre about. */ int onion_skin_client_handshake(int type, const onion_handshake_state_t *handshake_state, const uint8_t *reply, size_t reply_len, uint8_t *keys_out, size_t keys_out_len, uint8_t *rend_authenticator_out, const char **msg_out) { if (handshake_state->tag != type) return -1; switch (type) { case ONION_HANDSHAKE_TYPE_TAP: if (reply_len != TAP_ONIONSKIN_REPLY_LEN) { if (msg_out) *msg_out = "TAP reply was not of the correct length."; return -1; } if (onion_skin_TAP_client_handshake(handshake_state->u.tap, (const char*)reply, (char *)keys_out, keys_out_len, msg_out) < 0) return -1; memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_FAST: if (reply_len != CREATED_FAST_LEN) { if (msg_out) *msg_out = "TAP reply was not of the correct length."; return -1; } if (fast_client_handshake(handshake_state->u.fast, reply, keys_out, keys_out_len, msg_out) < 0) return -1; memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_NTOR: if (reply_len < NTOR_REPLY_LEN) { if (msg_out) *msg_out = "ntor reply was not of the correct length."; return -1; } { size_t keys_tmp_len = keys_out_len + DIGEST_LEN; uint8_t *keys_tmp = tor_malloc(keys_tmp_len); if (onion_skin_ntor_client_handshake(handshake_state->u.ntor, reply, keys_tmp, keys_tmp_len, msg_out) < 0) { tor_free(keys_tmp); return -1; } memcpy(keys_out, keys_tmp, keys_out_len); memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN); memwipe(keys_tmp, 0, keys_tmp_len); tor_free(keys_tmp); } return 0; default: log_warn(LD_BUG, "called with unknown handshake state type %d", type); tor_fragile_assert(); return -1; } }