|
@@ -6,7 +6,7 @@
|
|
|
|
|
|
|
|
|
* \file onion.c
|
|
|
- * \brief Functions to queue create cells, wrap the various onionskin types,
|
|
|
+ * \brief Functions to queue create cells,
|
|
|
* and parse and create the CREATE cell and its allies.
|
|
|
*
|
|
|
* This module has a few functions, all related to the CREATE/CREATED
|
|
@@ -14,27 +14,6 @@
|
|
|
* related EXTEND/EXTENDED handshake that we use over circuits in order to
|
|
|
* extend them an additional hop.
|
|
|
*
|
|
|
- * In this module, we provide a set of abstractions to create a uniform
|
|
|
- * interface over the three circuit extension handshakes that Tor has used
|
|
|
- * over the years (TAP, CREATE_FAST, and ntor). These handshakes are
|
|
|
- * implemented in onion_tap.c, onion_fast.c, and onion_ntor.c respectively.
|
|
|
- *
|
|
|
- * All[*] of these handshakes follow a similar pattern: a client, knowing
|
|
|
- * some key from the relay it wants to extend through, generates the
|
|
|
- * first part of a handshake. A relay receives that handshake, and sends
|
|
|
- * a reply. Once the client handles the reply, it knows that it is
|
|
|
- * talking to the right relay, and it shares some freshly negotiated key
|
|
|
- * material with that relay.
|
|
|
- *
|
|
|
- * We sometimes call the client's part of the handshake an "onionskin".
|
|
|
- * We do this because historically, Onion Routing used a multi-layer
|
|
|
- * structure called an "onion" to construct circuits. Each layer of the
|
|
|
- * onion contained key material chosen by the client, the identity of
|
|
|
- * the next relay in the circuit, and a smaller onion, encrypted with
|
|
|
- * the key of the next relay. When we changed Tor to use a telescoping
|
|
|
- * circuit extension design, it corresponded to sending each layer of the
|
|
|
- * onion separately -- as a series of onionskins.
|
|
|
- *
|
|
|
* Clients invoke these functions when creating or extending a circuit,
|
|
|
* from circuitbuild.c.
|
|
|
*
|
|
@@ -57,628 +36,23 @@
|
|
|
* <li>Encoding and decodign EXTEND, EXTENDED, EXTEND2, and EXTENDED2
|
|
|
* relay cells.
|
|
|
* </ul>
|
|
|
- *
|
|
|
- * [*] The CREATE_FAST handshake is weaker than described here; see
|
|
|
- * onion_fast.c for more information.
|
|
|
**/
|
|
|
|
|
|
#include "core/or/or.h"
|
|
|
-#include "core/or/circuitbuild.h"
|
|
|
-#include "core/or/circuitlist.h"
|
|
|
+
|
|
|
#include "app/config/config.h"
|
|
|
-#include "core/mainloop/cpuworker.h"
|
|
|
-#include "lib/crypt_ops/crypto_util.h"
|
|
|
-#include "lib/crypt_ops/crypto_dh.h"
|
|
|
-#include "feature/nodelist/networkstatus.h"
|
|
|
-#include "core/crypto/onion.h"
|
|
|
+#include "core/crypto/onion_crypto.h"
|
|
|
#include "core/crypto/onion_fast.h"
|
|
|
#include "core/crypto/onion_ntor.h"
|
|
|
#include "core/crypto/onion_tap.h"
|
|
|
-#include "core/or/relay.h"
|
|
|
-#include "feature/stats/rephist.h"
|
|
|
-#include "feature/relay/router.h"
|
|
|
+#include "core/or/onion.h"
|
|
|
+#include "feature/nodelist/networkstatus.h"
|
|
|
|
|
|
#include "core/or/cell_st.h"
|
|
|
-#include "core/or/extend_info_st.h"
|
|
|
-#include "core/or/or_circuit_st.h"
|
|
|
|
|
|
|
|
|
#include "trunnel/ed25519_cert.h"
|
|
|
|
|
|
-
|
|
|
- * to process a waiting onion handshake. */
|
|
|
-typedef struct onion_queue_t {
|
|
|
- TOR_TAILQ_ENTRY(onion_queue_t) next;
|
|
|
- or_circuit_t *circ;
|
|
|
- uint16_t handshake_type;
|
|
|
- create_cell_t *onionskin;
|
|
|
- time_t when_added;
|
|
|
-} onion_queue_t;
|
|
|
-
|
|
|
-
|
|
|
-#define ONIONQUEUE_WAIT_CUTOFF 5
|
|
|
-
|
|
|
-
|
|
|
- * if that queue is empty.*/
|
|
|
-static TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t)
|
|
|
- ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
|
|
|
-{ TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]),
|
|
|
- TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]),
|
|
|
- TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]),
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
|
|
|
-
|
|
|
-static int num_ntors_per_tap(void);
|
|
|
-static void onion_queue_entry_remove(onion_queue_t *victim);
|
|
|
-
|
|
|
-
|
|
|
- *
|
|
|
- * (By which I think I meant, "make sure that no
|
|
|
- * X_ONIONSKIN_CHALLENGE/REPLY_LEN is greater than
|
|
|
- * MAX_ONIONSKIN_CHALLENGE/REPLY_LEN." Also, make sure that we can pass
|
|
|
- * over-large values via EXTEND2/EXTENDED2, for future-compatibility.*/
|
|
|
-
|
|
|
-
|
|
|
- * <b>type</b>. */
|
|
|
-static int
|
|
|
-have_room_for_onionskin(uint16_t type)
|
|
|
-{
|
|
|
- const or_options_t *options = get_options();
|
|
|
- int num_cpus;
|
|
|
- uint64_t tap_usec, ntor_usec;
|
|
|
- uint64_t ntor_during_tap_usec, tap_during_ntor_usec;
|
|
|
-
|
|
|
-
|
|
|
- if (ol_entries[type] < 50)
|
|
|
- return 1;
|
|
|
- num_cpus = get_num_cpus(options);
|
|
|
-
|
|
|
- * onionskins in various combinations of the queues. */
|
|
|
-
|
|
|
-
|
|
|
- tap_usec = estimated_usec_for_onionskins(
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_TAP],
|
|
|
- ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
|
|
|
-
|
|
|
-
|
|
|
- ntor_usec = estimated_usec_for_onionskins(
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
|
|
|
- ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
|
|
|
-
|
|
|
-
|
|
|
- * process while draining the ntor queue? */
|
|
|
- tap_during_ntor_usec = estimated_usec_for_onionskins(
|
|
|
- MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()),
|
|
|
- ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
|
|
|
-
|
|
|
-
|
|
|
- * process while draining the tap queue? */
|
|
|
- ntor_during_tap_usec = estimated_usec_for_onionskins(
|
|
|
- MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()),
|
|
|
- ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
|
|
|
-
|
|
|
-
|
|
|
- * this. */
|
|
|
- if (type == ONION_HANDSHAKE_TYPE_NTOR &&
|
|
|
- (ntor_usec + tap_during_ntor_usec) / 1000 >
|
|
|
- (uint64_t)options->MaxOnionQueueDelay)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (type == ONION_HANDSHAKE_TYPE_TAP &&
|
|
|
- (tap_usec + ntor_during_tap_usec) / 1000 >
|
|
|
- (uint64_t)options->MaxOnionQueueDelay)
|
|
|
- return 0;
|
|
|
-
|
|
|
-
|
|
|
- * more than 2/3 of the space on the queue. */
|
|
|
- if (type == ONION_HANDSHAKE_TYPE_TAP &&
|
|
|
- tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3)
|
|
|
- return 0;
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * if ol_list is too long, in which case do nothing and return -1.
|
|
|
- */
|
|
|
-int
|
|
|
-onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
|
|
|
-{
|
|
|
- onion_queue_t *tmp;
|
|
|
- time_t now = time(NULL);
|
|
|
-
|
|
|
- if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
|
|
|
-
|
|
|
- * We should have rejected this far before this point */
|
|
|
- log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
|
|
|
- onionskin->handshake_type);
|
|
|
- return -1;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- tmp = tor_malloc_zero(sizeof(onion_queue_t));
|
|
|
- tmp->circ = circ;
|
|
|
- tmp->handshake_type = onionskin->handshake_type;
|
|
|
- tmp->onionskin = onionskin;
|
|
|
- tmp->when_added = now;
|
|
|
-
|
|
|
- if (!have_room_for_onionskin(onionskin->handshake_type)) {
|
|
|
-#define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60)
|
|
|
- static ratelim_t last_warned =
|
|
|
- RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
|
|
|
- char *m;
|
|
|
- if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR &&
|
|
|
- (m = rate_limit_log(&last_warned, approx_time()))) {
|
|
|
- log_warn(LD_GENERAL,
|
|
|
- "Your computer is too slow to handle this many circuit "
|
|
|
- "creation requests! Please consider using the "
|
|
|
- "MaxAdvertisedBandwidth config option or choosing a more "
|
|
|
- "restricted exit policy.%s",m);
|
|
|
- tor_free(m);
|
|
|
- }
|
|
|
- tor_free(tmp);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ++ol_entries[onionskin->handshake_type];
|
|
|
- log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.",
|
|
|
- onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
|
|
|
-
|
|
|
- circ->onionqueue_entry = tmp;
|
|
|
- TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
|
|
|
-
|
|
|
-
|
|
|
- while (1) {
|
|
|
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
|
|
|
- if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
|
|
|
- break;
|
|
|
-
|
|
|
- circ = head->circ;
|
|
|
- circ->onionqueue_entry = NULL;
|
|
|
- onion_queue_entry_remove(head);
|
|
|
- log_info(LD_CIRC,
|
|
|
- "Circuit create request is too old; canceling due to overload.");
|
|
|
- if (! TO_CIRCUIT(circ)->marked_for_close) {
|
|
|
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
|
|
|
- }
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * handshakes but still slowly drain the TAP queue so we don't starve
|
|
|
- * it entirely. */
|
|
|
-static int
|
|
|
-num_ntors_per_tap(void)
|
|
|
-{
|
|
|
-#define DEFAULT_NUM_NTORS_PER_TAP 10
|
|
|
-#define MIN_NUM_NTORS_PER_TAP 1
|
|
|
-#define MAX_NUM_NTORS_PER_TAP 100000
|
|
|
-
|
|
|
- return networkstatus_get_param(NULL, "NumNTorsPerTAP",
|
|
|
- DEFAULT_NUM_NTORS_PER_TAP,
|
|
|
- MIN_NUM_NTORS_PER_TAP,
|
|
|
- MAX_NUM_NTORS_PER_TAP);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * the other; if they both have elements, load balance across them but
|
|
|
- * favoring NTOR. */
|
|
|
-static uint16_t
|
|
|
-decide_next_handshake_type(void)
|
|
|
-{
|
|
|
-
|
|
|
- static int recently_chosen_ntors = 0;
|
|
|
-
|
|
|
- if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR])
|
|
|
- return ONION_HANDSHAKE_TYPE_TAP;
|
|
|
-
|
|
|
- if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) {
|
|
|
-
|
|
|
-
|
|
|
- * any in the queue and we've processed k ntor cells since the last
|
|
|
- * tap cell. This strategy is maybe a good idea, since it starves tap
|
|
|
- * less in the case where tap is rare, or maybe a poor idea, since it
|
|
|
- * makes the new tap cell unfairly jump in front of ntor cells that
|
|
|
- * got here first. In any case this edge case will only become relevant
|
|
|
- * once tap is rare. We should reevaluate whether we like this decision
|
|
|
- * once tap gets more rare. */
|
|
|
- if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
|
|
|
- recently_chosen_ntors <= num_ntors_per_tap())
|
|
|
- ++recently_chosen_ntors;
|
|
|
-
|
|
|
- return ONION_HANDSHAKE_TYPE_NTOR;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- * too much lately. */
|
|
|
- if (++recently_chosen_ntors <= num_ntors_per_tap()) {
|
|
|
- return ONION_HANDSHAKE_TYPE_NTOR;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- recently_chosen_ntors = 0;
|
|
|
- return ONION_HANDSHAKE_TYPE_TAP;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * return NULL if the lists are empty.
|
|
|
- */
|
|
|
-or_circuit_t *
|
|
|
-onion_next_task(create_cell_t **onionskin_out)
|
|
|
-{
|
|
|
- or_circuit_t *circ;
|
|
|
- uint16_t handshake_to_choose = decide_next_handshake_type();
|
|
|
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[handshake_to_choose]);
|
|
|
-
|
|
|
- if (!head)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- tor_assert(head->circ);
|
|
|
- tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE);
|
|
|
-
|
|
|
-
|
|
|
- * more manageable. That's probably not good long-term. -RD */
|
|
|
- circ = head->circ;
|
|
|
- if (head->onionskin)
|
|
|
- --ol_entries[head->handshake_type];
|
|
|
- log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.",
|
|
|
- head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
|
|
|
- ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
|
|
|
-
|
|
|
- *onionskin_out = head->onionskin;
|
|
|
- head->onionskin = NULL;
|
|
|
- circ->onionqueue_entry = NULL;
|
|
|
- onion_queue_entry_remove(head);
|
|
|
- return circ;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- */
|
|
|
-int
|
|
|
-onion_num_pending(uint16_t handshake_type)
|
|
|
-{
|
|
|
- return ol_entries[handshake_type];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * circ, remove and free that element. Leave circ itself alone.
|
|
|
- */
|
|
|
-void
|
|
|
-onion_pending_remove(or_circuit_t *circ)
|
|
|
-{
|
|
|
- onion_queue_t *victim;
|
|
|
-
|
|
|
- if (!circ)
|
|
|
- return;
|
|
|
-
|
|
|
- victim = circ->onionqueue_entry;
|
|
|
- if (victim)
|
|
|
- onion_queue_entry_remove(victim);
|
|
|
-
|
|
|
- cpuworker_cancel_circ_handshake(circ);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * its circuit and freeing it and any structures it owns.*/
|
|
|
-static void
|
|
|
-onion_queue_entry_remove(onion_queue_t *victim)
|
|
|
-{
|
|
|
- if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
|
|
|
-
|
|
|
- * We should have rejected this far before this point */
|
|
|
- log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
|
|
|
- victim->handshake_type);
|
|
|
-
|
|
|
- return;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
|
|
|
-
|
|
|
- if (victim->circ)
|
|
|
- victim->circ->onionqueue_entry = NULL;
|
|
|
-
|
|
|
- if (victim->onionskin)
|
|
|
- --ol_entries[victim->handshake_type];
|
|
|
-
|
|
|
- tor_free(victim->onionskin);
|
|
|
- tor_free(victim);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-void
|
|
|
-clear_pending_onions(void)
|
|
|
-{
|
|
|
- onion_queue_t *victim, *next;
|
|
|
- int i;
|
|
|
- for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
|
|
|
- for (victim = TOR_TAILQ_FIRST(&ol_list[i]); victim; victim = next) {
|
|
|
- next = TOR_TAILQ_NEXT(victim,next);
|
|
|
- onion_queue_entry_remove(victim);
|
|
|
- }
|
|
|
- tor_assert(TOR_TAILQ_EMPTY(&ol_list[i]));
|
|
|
- }
|
|
|
- memset(ol_entries, 0, sizeof(ol_entries));
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- * and other info we might need to do onion handshakes. (We make a copy of
|
|
|
- * our keys for each cpuworker to avoid race conditions with the main thread,
|
|
|
- * and to avoid locking) */
|
|
|
-server_onion_keys_t *
|
|
|
-server_onion_keys_new(void)
|
|
|
-{
|
|
|
- server_onion_keys_t *keys = tor_malloc_zero(sizeof(server_onion_keys_t));
|
|
|
- memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
|
|
|
- dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
|
|
|
- keys->curve25519_key_map = construct_ntor_key_map();
|
|
|
- keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
|
|
|
- curve25519_keypair_generate(keys->junk_keypair, 0);
|
|
|
- return keys;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-void
|
|
|
-server_onion_keys_free_(server_onion_keys_t *keys)
|
|
|
-{
|
|
|
- if (! keys)
|
|
|
- return;
|
|
|
-
|
|
|
- crypto_pk_free(keys->onion_key);
|
|
|
- crypto_pk_free(keys->last_onion_key);
|
|
|
- ntor_key_map_free(keys->curve25519_key_map);
|
|
|
- tor_free(keys->junk_keypair);
|
|
|
- memwipe(keys, 0, sizeof(server_onion_keys_t));
|
|
|
- tor_free(keys);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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:
|
|
|
-
|
|
|
- * This state should not even exist. */
|
|
|
- log_warn(LD_BUG, "called with unknown handshake state type %d",
|
|
|
- (int)state->tag);
|
|
|
- tor_fragile_assert();
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * (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:
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if (r > 0)
|
|
|
- state_out->tag = (uint16_t) type;
|
|
|
-
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * onion_skin_server_handshake, plus 16. We can make it bigger if needed:
|
|
|
- * It just defines how many bytes to stack-allocate. */
|
|
|
-#define MAX_KEYS_TMP_LEN 128
|
|
|
-
|
|
|
-
|
|
|
- * 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+DH1024_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;
|
|
|
- tor_assert(keys_tmp_len <= MAX_KEYS_TMP_LEN);
|
|
|
- uint8_t keys_tmp[MAX_KEYS_TMP_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) {
|
|
|
-
|
|
|
- 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, sizeof(keys_tmp));
|
|
|
- r = NTOR_REPLY_LEN;
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
-
|
|
|
- * We should have rejected this far before this point */
|
|
|
- log_warn(LD_BUG, "called with unknown handshake state type %d", type);
|
|
|
- tor_fragile_assert();
|
|
|
- return -1;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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 user 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+DH1024_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;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
* <b>unknown_ok</b> is true, allow cells with handshake types we don't
|
|
|
* recognize. */
|