/** Write the persistent state to disk. Return 0 for success, <0 on failure. */ int or_state_save(time_t now) { char *state, *contents; char tbuf[ISO_TIME_LEN+1]; char *fname; tor_assert(global_state); if (global_state->next_write > now) return 0; /* Call everything else that might dirty the state even more, in order * to avoid redundant writes. */ entry_guards_update_state(global_state); rep_hist_update_state(global_state); circuit_build_times_update_state(&circ_times, global_state); if (accounting_is_enabled(get_options())) accounting_run_housekeeping(now); global_state->LastWritten = now; tor_free(global_state->TorVersion); tor_asprintf(&global_state->TorVersion, "Tor %s", get_version()); state = config_dump(&state_format, NULL, global_state, 1, 0); format_local_iso_time(tbuf, now); tor_asprintf(&contents, "# Tor state file last generated on %s local time\n" "# Other times below are in GMT\n" "# You *do not* need to edit this file.\n\n%s", tbuf, state); tor_free(state); fname = get_datadir_fname("state"); if (write_str_to_file(fname, contents, 0)<0) { log_warn(LD_FS, "Unable to write state to file \"%s\"; " "will try again later", fname); last_state_file_write_failed = 1; tor_free(fname); tor_free(contents); /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state * changes sooner). */ global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL; return -1; } last_state_file_write_failed = 0; log_info(LD_GENERAL, "Saved state to \"%s\"", fname); tor_free(fname); tor_free(contents); if (server_mode(get_options())) global_state->next_write = now + STATE_RELAY_CHECKPOINT_INTERVAL; else global_state->next_write = TIME_MAX; return 0; }
int main(int argc, char *argv[]) { parse_arguments(argc, argv); if (mode == SERVER) { server_mode(); } else if (mode == CLIENT){ client_mode(); } exit(1); }
/** Return 1 if we want to fetch and serve descriptors, networkstatuses, etc * Else return 0. * Check options->DirPort_set and directory_permits_begindir_requests() * to see if we are willing to serve these directory documents to others via * the DirPort and begindir-over-ORPort, respectively. * * To check if we should fetch documents, use we_want_to_fetch_flavor and * we_want_to_fetch_unknown_auth_certs instead of this function. */ int directory_caches_dir_info(const or_options_t *options) { if (options->BridgeRelay || dir_server_mode(options)) return 1; if (!server_mode(options) || !advertised_server_mode()) return 0; /* We need an up-to-date view of network info if we're going to try to * block exit attempts from unknown relays. */ return ! router_my_exit_policy_is_reject_star() && should_refuse_unknown_exits(options); }
/** Called when the onion key has changed and we need to spawn new * cpuworkers. Close all currently idle cpuworkers, and mark the last * rotation time as now. */ void cpuworkers_rotate(void) { connection_t *cpuworker; while ((cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, CPUWORKER_STATE_IDLE))) { connection_mark_for_close(cpuworker); --num_cpuworkers; } last_rotation_time = time(NULL); if (server_mode(get_options())) spawn_enough_cpuworkers(); }
/** Return 1 if we fetch our directory material directly from the * authorities, rather than from a mirror. */ int directory_fetches_from_authorities(const or_options_t *options) { const routerinfo_t *me; uint32_t addr; int refuseunknown; if (options->FetchDirInfoEarly) return 1; if (options->BridgeRelay == 1) return 0; if (server_mode(options) && router_pick_published_address(options, &addr, 1) < 0) return 1; /* we don't know our IP address; ask an authority. */ refuseunknown = ! router_my_exit_policy_is_reject_star() && should_refuse_unknown_exits(options); if (!dir_server_mode(options) && !refuseunknown) return 0; if (!server_mode(options) || !advertised_server_mode()) return 0; me = router_get_my_routerinfo(); if (!me || (!me->supports_tunnelled_dir_requests && !refuseunknown)) return 0; /* if we don't service directory requests, return 0 too */ return 1; }
/** Return 1 if we have no need for circuits currently, else return 0. */ int rep_hist_circbuilding_dormant(time_t now) { const or_options_t *options = get_options(); if (any_predicted_circuits(now)) return 0; /* see if we'll still need to build testing circuits */ if (server_mode(options) && (!check_whether_orport_reachable(options) || !circuit_enough_testing_circs())) return 0; if (!check_whether_dirport_reachable(options)) return 0; return 1; }
/** * Retrieve our currently-in-use Ed25519 link certificate and id certificate, * and, if they would expire soon (based on the time <b>now</b>, generate new * certificates (without embedding the public part of the signing key inside). * If <b>force</b> is true, always generate a new certificate. * * The signed_key from the current id->signing certificate will be used to * sign the new key within newly generated X509 certificate. * * Returns -1 upon error. Otherwise, returns 0 upon success (either when the * current certificate is still valid, or when a new certificate was * successfully generated, or no certificate was needed). */ int generate_ed_link_cert(const or_options_t *options, time_t now, int force) { const tor_x509_cert_t *link_ = NULL, *id = NULL; tor_cert_t *link_cert = NULL; if (tor_tls_get_my_certs(1, &link_, &id) < 0 || link_ == NULL) { if (!server_mode(options)) { /* No need to make an Ed25519->Link cert: we are a client */ return 0; } log_warn(LD_OR, "Can't get my x509 link cert."); return -1; } const common_digests_t *digests = tor_x509_cert_get_cert_digests(link_); if (force == 0 && link_cert_cert && ! EXPIRES_SOON(link_cert_cert, options->TestingLinkKeySlop) && fast_memeq(digests->d[DIGEST_SHA256], link_cert_cert->signed_key.pubkey, DIGEST256_LEN)) { return 0; } ed25519_public_key_t dummy_key; memcpy(dummy_key.pubkey, digests->d[DIGEST_SHA256], DIGEST256_LEN); link_cert = tor_cert_create(get_master_signing_keypair(), CERT_TYPE_SIGNING_LINK, &dummy_key, now, options->TestingLinkCertLifetime, 0); if (link_cert) { SET_CERT(link_cert_cert, link_cert); } return 0; }
/** * Running as a server: load, reload, or refresh our ed25519 keys and * certificates, creating and saving new ones as needed. */ int load_ed_keys(const or_options_t *options, time_t now) { ed25519_keypair_t *id = NULL; ed25519_keypair_t *sign = NULL; ed25519_keypair_t *auth = NULL; const ed25519_keypair_t *sign_signing_key_with_id = NULL; const ed25519_keypair_t *use_signing = NULL; const tor_cert_t *check_signing_cert = NULL; tor_cert_t *sign_cert = NULL; tor_cert_t *auth_cert = NULL; #define FAIL(msg) do { \ log_warn(LD_OR, (msg)); \ goto err; \ } while (0) #define SET_KEY(key, newval) do { \ if ((key) != (newval)) \ ed25519_keypair_free(key); \ key = (newval); \ } while (0) #define SET_CERT(cert, newval) do { \ if ((cert) != (newval)) \ tor_cert_free(cert); \ cert = (newval); \ } while (0) #define EXPIRES_SOON(cert, interval) \ (!(cert) || (cert)->valid_until < now + (interval)) /* XXXX support encrypted identity keys fully */ /* First try to get the signing key to see how it is. */ { char *fname = options_get_datadir_fname2(options, "keys", "ed25519_signing"); sign = ed_key_init_from_file( fname, INIT_ED_KEY_NEEDCERT| INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT, LOG_INFO, NULL, 0, 0, CERT_TYPE_ID_SIGNING, &sign_cert); tor_free(fname); check_signing_cert = sign_cert; use_signing = sign; } if (!use_signing && master_signing_key) { check_signing_cert = signing_key_cert; use_signing = master_signing_key; } const int offline_master = options->OfflineMasterKey && options->command != CMD_KEYGEN; const int need_new_signing_key = NULL == use_signing || EXPIRES_SOON(check_signing_cert, 0) || (options->command == CMD_KEYGEN && ! options->change_key_passphrase); const int want_new_signing_key = need_new_signing_key || EXPIRES_SOON(check_signing_cert, options->TestingSigningKeySlop); /* We can only create a master key if we haven't been told that the * master key will always be offline. Also, if we have a signing key, * then we shouldn't make a new master ID key. */ const int can_make_master_id_key = !offline_master && NULL == use_signing; if (need_new_signing_key) { log_notice(LD_OR, "It looks like I need to generate and sign a new " "medium-term signing key, because %s. To do that, I need to " "load%s the permanent master identity key.", (NULL == use_signing) ? "I don't have one" : EXPIRES_SOON(check_signing_cert, 0) ? "the one I have is expired" : "you asked me to make one with --keygen", can_make_master_id_key ? " (or create)" : ""); } else if (want_new_signing_key && !offline_master) { log_notice(LD_OR, "It looks like I should try to generate and sign a " "new medium-term signing key, because the one I have is " "going to expire soon. To do that, I'm going to have to try to " "load the permanent master identity key."); } else if (want_new_signing_key) { log_notice(LD_OR, "It looks like I should try to generate and sign a " "new medium-term signing key, because the one I have is " "going to expire soon. But OfflineMasterKey is set, so I " "won't try to load a permanent master identity key is set. " "You will need to use 'tor --keygen' make a new signing key " "and certificate."); } { uint32_t flags = (INIT_ED_KEY_SPLIT| INIT_ED_KEY_EXTRA_STRONG|INIT_ED_KEY_NO_REPAIR); if (can_make_master_id_key) flags |= INIT_ED_KEY_CREATE; if (! need_new_signing_key) flags |= INIT_ED_KEY_MISSING_SECRET_OK; if (! want_new_signing_key || offline_master) flags |= INIT_ED_KEY_OMIT_SECRET; if (offline_master) flags |= INIT_ED_KEY_OFFLINE_SECRET; if (options->command == CMD_KEYGEN) flags |= INIT_ED_KEY_TRY_ENCRYPTED; /* Check the key directory */ if (check_private_dir(options->DataDirectory, CPD_CREATE, options->User)) { log_err(LD_OR, "Can't create/check datadirectory %s", options->DataDirectory); goto err; } char *fname = get_datadir_fname("keys"); if (check_private_dir(fname, CPD_CREATE, options->User) < 0) { log_err(LD_OR, "Problem creating/checking key directory %s", fname); tor_free(fname); goto err; } tor_free(fname); if (options->master_key_fname) { fname = tor_strdup(options->master_key_fname); flags |= INIT_ED_KEY_EXPLICIT_FNAME; } else { fname = options_get_datadir_fname2(options, "keys", "ed25519_master_id"); } id = ed_key_init_from_file( fname, flags, LOG_WARN, NULL, 0, 0, 0, NULL); tor_free(fname); if (!id) { if (need_new_signing_key) { if (offline_master) FAIL("Can't load master identity key; OfflineMasterKey is set."); else FAIL("Missing identity key"); } else { log_warn(LD_OR, "Master public key was absent; inferring from " "public key in signing certificate and saving to disk."); tor_assert(check_signing_cert); id = tor_malloc_zero(sizeof(*id)); memcpy(&id->pubkey, &check_signing_cert->signing_key, sizeof(ed25519_public_key_t)); fname = options_get_datadir_fname2(options, "keys", "ed25519_master_id_public_key"); if (ed25519_pubkey_write_to_file(&id->pubkey, fname, "type0") < 0) { log_warn(LD_OR, "Error while attempting to write master public key " "to disk"); tor_free(fname); goto err; } tor_free(fname); } } if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey))) sign_signing_key_with_id = NULL; else sign_signing_key_with_id = id; } if (master_identity_key && !ed25519_pubkey_eq(&id->pubkey, &master_identity_key->pubkey)) { FAIL("Identity key on disk does not match key we loaded earlier!"); } if (need_new_signing_key && NULL == sign_signing_key_with_id) FAIL("Can't load master key make a new signing key."); if (sign_cert) { if (! sign_cert->signing_key_included) FAIL("Loaded a signing cert with no key included!"); if (! ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey)) FAIL("The signing cert we have was not signed with the master key " "we loaded!"); if (tor_cert_checksig(sign_cert, &id->pubkey, 0) < 0) FAIL("The signing cert we loaded was not signed correctly!"); } if (want_new_signing_key && sign_signing_key_with_id) { uint32_t flags = (INIT_ED_KEY_CREATE| INIT_ED_KEY_REPLACE| INIT_ED_KEY_EXTRA_STRONG| INIT_ED_KEY_NEEDCERT| INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT); char *fname = options_get_datadir_fname2(options, "keys", "ed25519_signing"); ed25519_keypair_free(sign); tor_cert_free(sign_cert); sign = ed_key_init_from_file(fname, flags, LOG_WARN, sign_signing_key_with_id, now, options->SigningKeyLifetime, CERT_TYPE_ID_SIGNING, &sign_cert); tor_free(fname); if (!sign) FAIL("Missing signing key"); use_signing = sign; tor_assert(sign_cert->signing_key_included); tor_assert(ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey)); tor_assert(ed25519_pubkey_eq(&sign_cert->signed_key, &sign->pubkey)); } else if (want_new_signing_key) { static ratelim_t missing_master = RATELIM_INIT(3600); log_fn_ratelim(&missing_master, LOG_WARN, LD_OR, "Signing key will expire soon, but I can't load the " "master key to sign a new one!"); } tor_assert(use_signing); /* At this point we no longer need our secret identity key. So wipe * it, if we loaded it in the first place. */ memwipe(id->seckey.seckey, 0, sizeof(id->seckey)); if (options->command == CMD_KEYGEN) goto end; if (!rsa_ed_crosscert && server_mode(options)) { uint8_t *crosscert; ssize_t crosscert_len = tor_make_rsa_ed25519_crosscert(&id->pubkey, get_server_identity_key(), now+10*365*86400,/*XXXX*/ &crosscert); rsa_ed_crosscert_len = crosscert_len; rsa_ed_crosscert = crosscert; } if (!current_auth_key || EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop)) { auth = ed_key_new(use_signing, INIT_ED_KEY_NEEDCERT, now, options->TestingAuthKeyLifetime, CERT_TYPE_SIGNING_AUTH, &auth_cert); if (!auth) FAIL("Can't create auth key"); } /* We've generated or loaded everything. Put them in memory. */ end: if (! master_identity_key) { SET_KEY(master_identity_key, id); } else { tor_free(id); } if (sign) { SET_KEY(master_signing_key, sign); SET_CERT(signing_key_cert, sign_cert); } if (auth) { SET_KEY(current_auth_key, auth); SET_CERT(auth_key_cert, auth_cert); } return 0; err: ed25519_keypair_free(id); ed25519_keypair_free(sign); ed25519_keypair_free(auth); tor_cert_free(sign_cert); tor_cert_free(auth_cert); return -1; }
/** * Program entry point * * @param[in] argc Number of CLI arguments * @param[in] argv Array of CLI arguments */ int main(int argc, const char **argv) { /* Local variables */ struct hostent *host; /* host info container */ unsigned int port; /* Listen on (server) / connect to (client) port number */ /* Check CLI arguments count */ if (argc < 4) { /* On error print USAGE notice */ printf( "USAGE: %s <mode = client / server> <hostname> <port> [<client::filename> <...>]\n", argv[0]); /* Return with error */ return ARGUMENT_ERROR; } /* Compute port number argument */ if (sscanf(argv[3], "%u", &port) != 1) { /* Drop error message */ puts("Invalid port number argument !"); /* Return with error */ return ARGUMENT_ERROR; } /* Get host info according specified remote / local address */ if ((host = gethostbyname(argv[2])) == NULL ) { /* Drop error message */ perror("gethostbyname()"); /* Return with error */ return HOSTNAME_ERROR; } /* Switch to client mode according to the mode argument */ if (strcmp(argv[1], "client") == 0) { /* Start client runtime */ return client_mode(host, port, argv + 4, argc - 4); } else { /* Switch to server mode according to the mode argument */ if (strcmp(argv[1], "server") == 0) { /* Start server runtime */ return server_mode(host, port); } else { /* Unknown mode */ /* Drop error message */ puts("Invalid mode argument !"); /* Return with error */ return ARGUMENT_ERROR; } } /* Return without error */ return NO_ERROR; }
gint scalliontor_start(ScallionTor* stor, gint argc, gchar *argv[]) { time_t now = time(NULL); update_approx_time(now); tor_threads_init(); init_logging(); /* tor_init() loses our logging, so set it before AND after */ scalliontor_setLogging(); if (tor_init(argc, argv) < 0) { return -1; } // scalliontor_setLogging(); /* load the private keys, if we're supposed to have them, and set up the * TLS context. */ gpointer idkey; #ifdef SCALLION_NEWIDKEYNAME idkey = client_identitykey; #else idkey = identitykey; #endif if (idkey == NULL) { if (init_keys() < 0) { log_err(LD_BUG,"Error initializing keys; exiting"); return -1; } } /* Set up the packed_cell_t memory pool. */ init_cell_pool(); /* Set up our buckets */ connection_bucket_init(); stats_prev_global_read_bucket = global_read_bucket; stats_prev_global_write_bucket = global_write_bucket; /* initialize the bootstrap status events to know we're starting up */ control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); if (trusted_dirs_reload_certs()) { log_warn(LD_DIR, "Couldn't load all cached v3 certificates. Starting anyway."); } #ifndef SCALLION_NOV2DIR if (router_reload_v2_networkstatus()) { return -1; } #endif if (router_reload_consensus_networkstatus()) { return -1; } /* load the routers file, or assign the defaults. */ if (router_reload_router_list()) { return -1; } /* load the networkstatuses. (This launches a download for new routers as * appropriate.) */ directory_info_has_arrived(now, 1); /* !note that scallion intercepts the cpuworker functionality (rob) */ if (server_mode(get_options())) { /* launch cpuworkers. Need to do this *after* we've read the onion key. */ cpu_init(); } /* set up once-a-second callback. */ if (! second_timer) { // struct timeval one_second; // one_second.tv_sec = 1; // one_second.tv_usec = 0; // // second_timer = periodic_timer_new(tor_libevent_get_base(), // &one_second, // second_elapsed_callback, // NULL); // tor_assert(second_timer); _scalliontor_secondCallback(stor); } #ifdef SCALLION_DOREFILLCALLBACKS #ifndef USE_BUFFEREVENTS if (!refill_timer) { int msecs = get_options()->TokenBucketRefillInterval; // struct timeval refill_interval; // // refill_interval.tv_sec = msecs/1000; // refill_interval.tv_usec = (msecs%1000)*1000; // // refill_timer = periodic_timer_new(tor_libevent_get_base(), // &refill_interval, // refill_callback, // NULL); // tor_assert(refill_timer); stor->refillmsecs = msecs; _scalliontor_refillCallback(stor); } #endif #endif /* run the startup events */ scalliontor_notify(stor); return 0; }
/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create_cell(cell_t *cell, or_connection_t *conn) { or_circuit_t *circ; int id_is_high; if (we_are_hibernating()) { log_info(LD_OR, "Received create cell but we're shutting down. Sending back " "destroy."); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_HIBERNATING); return; } if (!server_mode(get_options())) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell (type %d) from %s:%d, but we're a client. " "Sending back a destroy.", (int)cell->command, conn->_base.address, conn->_base.port); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } /* If the high bit of the circuit ID is not as expected, close the * circ. */ id_is_high = cell->circ_id & (1<<15); if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) || (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %d. Closing.", cell->circ_id); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) { routerinfo_t *router = router_get_by_digest(conn->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " "Dropping (age %d).", cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created)); if (router) log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Details: nickname \"%s\", platform %s.", router->nickname, escaped(router->platform)); return; } circ = or_circuit_new(cell->circ_id, conn); circ->_base.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); /* hand it off to the cpuworkers, and then return. */ if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) { log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } log_debug(LD_OR,"success: handed off onionskin."); } else { /* This is a CREATE_FAST cell; we can handle it immediately without using * a CPU worker. */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply[DIGEST_LEN*2]; tor_assert(cell->command == CELL_CREATE_FAST); if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) { log_warn(LD_OR,"Failed to generate key material. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } } }
/** * Running as a server: load, reload, or refresh our ed25519 keys and * certificates, creating and saving new ones as needed. * * Return -1 on failure; 0 on success if the signing key was not replaced; * and 1 on success if the signing key was replaced. */ int load_ed_keys(const or_options_t *options, time_t now) { ed25519_keypair_t *id = NULL; ed25519_keypair_t *sign = NULL; ed25519_keypair_t *auth = NULL; const ed25519_keypair_t *sign_signing_key_with_id = NULL; const ed25519_keypair_t *use_signing = NULL; const tor_cert_t *check_signing_cert = NULL; tor_cert_t *sign_cert = NULL; tor_cert_t *auth_cert = NULL; int signing_key_changed = 0; // It is later than 1972, since otherwise there would be no C compilers. // (Try to diagnose #22466.) tor_assert_nonfatal(now >= 2 * 365 * 86400); #define FAIL(msg) do { \ log_warn(LD_OR, (msg)); \ goto err; \ } while (0) #define SET_KEY(key, newval) do { \ if ((key) != (newval)) \ ed25519_keypair_free(key); \ key = (newval); \ } while (0) #define SET_CERT(cert, newval) do { \ if ((cert) != (newval)) \ tor_cert_free(cert); \ cert = (newval); \ } while (0) #define HAPPENS_SOON(when, interval) \ ((when) < now + (interval)) #define EXPIRES_SOON(cert, interval) \ (!(cert) || HAPPENS_SOON((cert)->valid_until, (interval))) /* XXXX support encrypted identity keys fully */ /* First try to get the signing key to see how it is. */ { char *fname = options_get_keydir_fname(options, "ed25519_signing"); sign = ed_key_init_from_file( fname, INIT_ED_KEY_NEEDCERT| INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT, LOG_INFO, NULL, 0, 0, CERT_TYPE_ID_SIGNING, &sign_cert); tor_free(fname); check_signing_cert = sign_cert; use_signing = sign; } if (use_signing) { /* We loaded a signing key with its certificate. */ if (! master_signing_key) { /* We didn't know one before! */ signing_key_changed = 1; } else if (! ed25519_pubkey_eq(&use_signing->pubkey, &master_signing_key->pubkey) || ! tor_memeq(use_signing->seckey.seckey, master_signing_key->seckey.seckey, ED25519_SECKEY_LEN)) { /* We loaded a different signing key than the one we knew before. */ signing_key_changed = 1; } } if (!use_signing && master_signing_key) { /* We couldn't load a signing key, but we already had one loaded */ check_signing_cert = signing_key_cert; use_signing = master_signing_key; } const int offline_master = options->OfflineMasterKey && options->command != CMD_KEYGEN; const int need_new_signing_key = NULL == use_signing || EXPIRES_SOON(check_signing_cert, 0) || (options->command == CMD_KEYGEN && ! options->change_key_passphrase); const int want_new_signing_key = need_new_signing_key || EXPIRES_SOON(check_signing_cert, options->TestingSigningKeySlop); /* We can only create a master key if we haven't been told that the * master key will always be offline. Also, if we have a signing key, * then we shouldn't make a new master ID key. */ const int can_make_master_id_key = !offline_master && NULL == use_signing; if (need_new_signing_key) { log_notice(LD_OR, "It looks like I need to generate and sign a new " "medium-term signing key, because %s. To do that, I " "need to load%s the permanent master identity key. " "If the master identity key was not moved or encrypted " "with a passphrase, this will be done automatically and " "no further action is required. Otherwise, provide the " "necessary data using 'tor --keygen' to do it manually.", (NULL == use_signing) ? "I don't have one" : EXPIRES_SOON(check_signing_cert, 0) ? "the one I have is expired" : "you asked me to make one with --keygen", can_make_master_id_key ? " (or create)" : ""); } else if (want_new_signing_key && !offline_master) { log_notice(LD_OR, "It looks like I should try to generate and sign a " "new medium-term signing key, because the one I have is " "going to expire soon. To do that, I'm going to have to " "try to load the permanent master identity key. " "If the master identity key was not moved or encrypted " "with a passphrase, this will be done automatically and " "no further action is required. Otherwise, provide the " "necessary data using 'tor --keygen' to do it manually."); } else if (want_new_signing_key) { log_notice(LD_OR, "It looks like I should try to generate and sign a " "new medium-term signing key, because the one I have is " "going to expire soon. But OfflineMasterKey is set, so I " "won't try to load a permanent master identity key. You " "will need to use 'tor --keygen' to make a new signing " "key and certificate."); } { uint32_t flags = (INIT_ED_KEY_SPLIT| INIT_ED_KEY_EXTRA_STRONG|INIT_ED_KEY_NO_REPAIR); if (can_make_master_id_key) flags |= INIT_ED_KEY_CREATE; if (! need_new_signing_key) flags |= INIT_ED_KEY_MISSING_SECRET_OK; if (! want_new_signing_key || offline_master) flags |= INIT_ED_KEY_OMIT_SECRET; if (offline_master) flags |= INIT_ED_KEY_OFFLINE_SECRET; if (options->command == CMD_KEYGEN) flags |= INIT_ED_KEY_TRY_ENCRYPTED; /* Check/Create the key directory */ if (create_keys_directory(options) < 0) return -1; char *fname; if (options->master_key_fname) { fname = tor_strdup(options->master_key_fname); flags |= INIT_ED_KEY_EXPLICIT_FNAME; } else { fname = options_get_keydir_fname(options, "ed25519_master_id"); } id = ed_key_init_from_file( fname, flags, LOG_WARN, NULL, 0, 0, 0, NULL); tor_free(fname); if (!id) { if (need_new_signing_key) { if (offline_master) FAIL("Can't load master identity key; OfflineMasterKey is set."); else FAIL("Missing identity key"); } else { log_warn(LD_OR, "Master public key was absent; inferring from " "public key in signing certificate and saving to disk."); tor_assert(check_signing_cert); id = tor_malloc_zero(sizeof(*id)); memcpy(&id->pubkey, &check_signing_cert->signing_key, sizeof(ed25519_public_key_t)); fname = options_get_keydir_fname(options, "ed25519_master_id_public_key"); if (ed25519_pubkey_write_to_file(&id->pubkey, fname, "type0") < 0) { log_warn(LD_OR, "Error while attempting to write master public key " "to disk"); tor_free(fname); goto err; } tor_free(fname); } } if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey))) sign_signing_key_with_id = NULL; else sign_signing_key_with_id = id; } if (master_identity_key && !ed25519_pubkey_eq(&id->pubkey, &master_identity_key->pubkey)) { FAIL("Identity key on disk does not match key we loaded earlier!"); } if (need_new_signing_key && NULL == sign_signing_key_with_id) FAIL("Can't load master key make a new signing key."); if (sign_cert) { if (! sign_cert->signing_key_included) FAIL("Loaded a signing cert with no key included!"); if (! ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey)) FAIL("The signing cert we have was not signed with the master key " "we loaded!"); if (tor_cert_checksig(sign_cert, &id->pubkey, 0) < 0) { log_warn(LD_OR, "The signing cert we loaded was not signed " "correctly: %s!", tor_cert_describe_signature_status(sign_cert)); goto err; } } if (want_new_signing_key && sign_signing_key_with_id) { uint32_t flags = (INIT_ED_KEY_CREATE| INIT_ED_KEY_REPLACE| INIT_ED_KEY_EXTRA_STRONG| INIT_ED_KEY_NEEDCERT| INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT); char *fname = options_get_keydir_fname(options, "ed25519_signing"); ed25519_keypair_free(sign); tor_cert_free(sign_cert); sign = ed_key_init_from_file(fname, flags, LOG_WARN, sign_signing_key_with_id, now, options->SigningKeyLifetime, CERT_TYPE_ID_SIGNING, &sign_cert); tor_free(fname); if (!sign) FAIL("Missing signing key"); use_signing = sign; signing_key_changed = 1; tor_assert(sign_cert->signing_key_included); tor_assert(ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey)); tor_assert(ed25519_pubkey_eq(&sign_cert->signed_key, &sign->pubkey)); } else if (want_new_signing_key) { static ratelim_t missing_master = RATELIM_INIT(3600); log_fn_ratelim(&missing_master, LOG_WARN, LD_OR, "Signing key will expire soon, but I can't load the " "master key to sign a new one!"); } tor_assert(use_signing); /* At this point we no longer need our secret identity key. So wipe * it, if we loaded it in the first place. */ memwipe(id->seckey.seckey, 0, sizeof(id->seckey)); if (options->command == CMD_KEYGEN) goto end; if (server_mode(options) && (!rsa_ed_crosscert || HAPPENS_SOON(rsa_ed_crosscert_expiration, 30*86400))) { uint8_t *crosscert; time_t expiration = now+6*30*86400; /* 6 months in the future. */ ssize_t crosscert_len = tor_make_rsa_ed25519_crosscert(&id->pubkey, get_server_identity_key(), expiration, &crosscert); tor_free(rsa_ed_crosscert); rsa_ed_crosscert_len = crosscert_len; rsa_ed_crosscert = crosscert; rsa_ed_crosscert_expiration = expiration; } if (!current_auth_key || signing_key_changed || EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop)) { auth = ed_key_new(use_signing, INIT_ED_KEY_NEEDCERT, now, options->TestingAuthKeyLifetime, CERT_TYPE_SIGNING_AUTH, &auth_cert); if (!auth) FAIL("Can't create auth key"); } /* We've generated or loaded everything. Put them in memory. */ end: if (! master_identity_key) { SET_KEY(master_identity_key, id); } else { tor_free(id); } if (sign) { SET_KEY(master_signing_key, sign); SET_CERT(signing_key_cert, sign_cert); } if (auth) { SET_KEY(current_auth_key, auth); SET_CERT(auth_key_cert, auth_cert); } return signing_key_changed; err: ed25519_keypair_free(id); ed25519_keypair_free(sign); ed25519_keypair_free(auth); tor_cert_free(sign_cert); tor_cert_free(auth_cert); return -1; }
int main(int argc, char **argv) { char *ifname = NULL; u_int8_t *sysname = NULL, *srvname = NULL; char ifnambuf[IFNAMSIZ]; struct ether_addr ea; int bpffd, smode = 0, c; struct passwd *pw; if ((pw = getpwnam("_ppp")) == NULL) err(EX_CONFIG, "getpwnam(\"_ppp\")"); while ((c = getopt(argc, argv, "svi:n:p:")) != -1) { switch (c) { case 'i': if (ifname != NULL) { usage(); return (EX_USAGE); } ifname = optarg; break; case 'n': if (srvname != NULL) { usage(); return (EX_USAGE); } srvname = (u_int8_t *)optarg; break; case 'p': if (sysname != NULL) { usage(); return (EX_USAGE); } sysname = (u_int8_t *)optarg; break; case 's': if (smode) { usage(); return (EX_USAGE); } smode = 1; break; case 'v': option_verbose++; break; default: usage(); return (EX_USAGE); } } argc -= optind; if (argc != 0) { usage(); return (EX_USAGE); } if (getifhwaddr(ifname, ifnambuf, &ea) < 0) return (EX_IOERR); bpffd = setupfilter(ifnambuf, &ea, smode); if (bpffd < 0) return (EX_IOERR); drop_privs(pw, smode); signal_init(); if (smode) server_mode(bpffd, sysname, srvname, &ea); else client_mode(bpffd, sysname, srvname, &ea); return (0); }
/** Tell the nodelist that the current usable consensus is <b>ns</b>. * This makes the nodelist change all of the routerstatus entries for * the nodes, drop nodes that no longer have enough info to get used, * and grab microdescriptors into nodes as appropriate. */ void nodelist_set_consensus(networkstatus_t *ns) { const or_options_t *options = get_options(); int authdir = authdir_mode_v3(options); int client = !server_mode(options); init_nodelist(); if (ns->flavor == FLAV_MICRODESC) (void) get_microdesc_cache(); /* Make sure it exists first. */ SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node, node->rs = NULL); SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { node_t *node = node_get_or_create(rs->identity_digest); node->rs = rs; if (ns->flavor == FLAV_MICRODESC) { if (node->md == NULL || tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) { if (node->md) node->md->held_by_nodes--; node->md = microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest); if (node->md) node->md->held_by_nodes++; } } node_set_country(node); /* If we're not an authdir, believe others. */ if (!authdir) { node->is_valid = rs->is_valid; node->is_running = rs->is_flagged_running; node->is_fast = rs->is_fast; node->is_stable = rs->is_stable; node->is_possible_guard = rs->is_possible_guard; node->is_exit = rs->is_exit; node->is_bad_directory = rs->is_bad_directory; node->is_bad_exit = rs->is_bad_exit; node->is_hs_dir = rs->is_hs_dir; node->ipv6_preferred = 0; if (client && options->ClientPreferIPv6ORPort == 1 && (tor_addr_is_null(&rs->ipv6_addr) == 0 || (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0))) node->ipv6_preferred = 1; } } SMARTLIST_FOREACH_END(rs); nodelist_purge(); if (! authdir) { SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { /* We have no routerstatus for this router. Clear flags so we can skip * it, maybe.*/ if (!node->rs) { tor_assert(node->ri); /* if it had only an md, or nothing, purge * would have removed it. */ if (node->ri->purpose == ROUTER_PURPOSE_GENERAL) { /* Clear all flags. */ node->is_valid = node->is_running = node->is_hs_dir = node->is_fast = node->is_stable = node->is_possible_guard = node->is_exit = node->is_bad_exit = node->is_bad_directory = node->ipv6_preferred = 0; } } } SMARTLIST_FOREACH_END(node); }
int main (int argc, char *argv[], char **envp) { int index; set_program_name (argv[0]); #ifdef HAVE_TZSET tzset (); /* In case no timezone database in ~ftp. */ #endif #ifdef HAVE_INITSETPROCTITLE /* Save start and extent of argv for setproctitle. */ initsetproctitle (argc, argv, envp); #endif /* HAVE_INITSETPROCTITLE */ /* Parse the command line */ iu_argp_init ("ftpd", default_program_authors); argp_parse (&argp, argc, argv, 0, &index, NULL); /* Bail out, wrong usage */ argc -= index; if (argc != 0) error (1, 0, "surplus arguments; try `%s --help' for more info", program_name); /* LOG_NDELAY sets up the logging connection immediately, necessary for anonymous ftp's that chroot and can't do it later. */ openlog ("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); freopen (PATH_DEVNULL, "w", stderr); /* If not running via inetd, we detach and dup(fd, 0), dup(fd, 1) the fd = accept(). tcpd is check if compile with the support */ if (daemon_mode) { if (server_mode (pid_file, &his_addr) < 0) exit (1); } else { socklen_t addrlen = sizeof (his_addr); if (getpeername (STDIN_FILENO, (struct sockaddr *) &his_addr, &addrlen) < 0) { syslog (LOG_ERR, "getpeername (%s): %m", program_name); exit (1); } } signal (SIGHUP, sigquit); signal (SIGINT, sigquit); signal (SIGQUIT, sigquit); signal (SIGTERM, sigquit); signal (SIGPIPE, lostconn); signal (SIGCHLD, SIG_IGN); if (signal (SIGURG, myoob) == SIG_ERR) syslog (LOG_ERR, "signal: %m"); /* Get info on the ctrl connection. */ { socklen_t addrlen = sizeof (ctrl_addr); if (getsockname (STDIN_FILENO, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) { syslog (LOG_ERR, "getsockname (%s): %m", program_name); exit (1); } } #if defined (IP_TOS) && defined (IPTOS_LOWDELAY) && defined (IPPROTO_IP) /* To minimize delays for interactive traffic. */ { int tos = IPTOS_LOWDELAY; if (setsockopt (STDIN_FILENO, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof (int)) < 0) syslog (LOG_WARNING, "setsockopt (IP_TOS): %m"); } #endif #ifdef SO_OOBINLINE /* Try to handle urgent data inline. */ { int on = 1; if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on)) < 0) syslog (LOG_ERR, "setsockopt: %m"); } #endif #ifdef SO_KEEPALIVE /* Set keepalives on the socket to detect dropped connections. */ { int keepalive = 1; if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, sizeof (keepalive)) < 0) syslog (LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); } #endif #ifdef F_SETOWN if (fcntl (STDIN_FILENO, F_SETOWN, getpid ()) == -1) syslog (LOG_ERR, "fcntl F_SETOWN: %m"); #endif dolog (&his_addr, &cred); /* Deal with login disable. */ if (display_file (PATH_NOLOGIN, 530) == 0) { reply (530, "System not available."); exit (0); } /* Display a Welcome message if exists, N.B. reply(220,) must follow. */ display_file (PATH_FTPWELCOME, 220); hostname = localhost (); if (!hostname) perror_reply (550, "Local resource failure: malloc"); /* Tell them we're ready to roll. */ if (!no_version) reply (220, "%s FTP server (%s %s) ready.", hostname, PACKAGE_NAME, PACKAGE_VERSION); else reply (220, "%s FTP server ready.", hostname); /* Set the jump, if we have an error parsing, come here and start fresh. */ setjmp (errcatch); /* Roll. */ for (;;) yyparse (); }
/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create_cell(cell_t *cell, or_connection_t *conn) { or_circuit_t *circ; const or_options_t *options = get_options(); int id_is_high; if (we_are_hibernating()) { log_info(LD_OR, "Received create cell but we're shutting down. Sending back " "destroy."); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_HIBERNATING); return; } if (!server_mode(options) || (!public_server_mode(options) && conn->is_outgoing)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell (type %d) from %s:%d, but we're connected " "to it as a client. " "Sending back a destroy.", (int)cell->command, conn->_base.address, conn->_base.port); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } /* If the high bit of the circuit ID is not as expected, close the * circ. */ id_is_high = cell->circ_id & (1<<15); if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) || (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %d. Closing.", cell->circ_id); connection_or_send_destroy(cell->circ_id, conn, END_CIRC_REASON_TORPROTOCOL); return; } if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) { const node_t *node = node_get_by_id(conn->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %d) for known circ. " "Dropping (age %d).", cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created)); if (node) { char *p = esc_for_log(node_get_platform(node)); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Details: router %s, platform %s.", node_describe(node), p); tor_free(p); } return; } circ = or_circuit_new(cell->circ_id, conn); circ->_base.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); if (cell->command == CELL_CREATE) { char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN); memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN); /* hand it off to the cpuworkers, and then return. */ if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) { #define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60) static ratelim_t handoff_warning = RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL); char *m; if ((m = rate_limit_log(&handoff_warning, approx_time()))) { log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m); tor_free(m); } circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } log_debug(LD_OR,"success: handed off onionskin."); } else { /* This is a CREATE_FAST cell; we can handle it immediately without using * a CPU worker. */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply[DIGEST_LEN*2]; tor_assert(cell->command == CELL_CREATE_FAST); /* Make sure we never try to use the OR connection on which we * received this cell to satisfy an EXTEND request, */ conn->is_connection_with_client = 1; if (fast_server_handshake(cell->payload, (uint8_t*)reply, (uint8_t*)keys, sizeof(keys))<0) { log_warn(LD_OR,"Failed to generate key material. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } } }
/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a * new circuit with the p_circ_id specified in cell. Put the circuit in state * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get * picked up again when the cpuworker finishes decrypting it. */ static void command_process_create_cell(cell_t *cell, channel_t *chan) { or_circuit_t *circ; const or_options_t *options = get_options(); int id_is_high; create_cell_t *create_cell; tor_assert(cell); tor_assert(chan); log_debug(LD_OR, "Got a CREATE cell for circ_id %u on channel " U64_FORMAT " (%p)", (unsigned)cell->circ_id, U64_PRINTF_ARG(chan->global_identifier), chan); if (we_are_hibernating()) { log_info(LD_OR, "Received create cell but we're shutting down. Sending back " "destroy."); channel_send_destroy(cell->circ_id, chan, END_CIRC_REASON_HIBERNATING); return; } if (!server_mode(options) || (!public_server_mode(options) && channel_is_outgoing(chan))) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell (type %d) from %s, but we're connected " "to it as a client. " "Sending back a destroy.", (int)cell->command, channel_get_canonical_remote_descr(chan)); channel_send_destroy(cell->circ_id, chan, END_CIRC_REASON_TORPROTOCOL); return; } if (cell->circ_id == 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received a create cell (type %d) from %s with zero circID; " " ignoring.", (int)cell->command, channel_get_actual_remote_descr(chan)); return; } /* If the high bit of the circuit ID is not as expected, close the * circ. */ if (chan->wide_circ_ids) id_is_high = cell->circ_id & (1u<<31); else id_is_high = cell->circ_id & (1u<<15); if ((id_is_high && chan->circ_id_type == CIRC_ID_TYPE_HIGHER) || (!id_is_high && chan->circ_id_type == CIRC_ID_TYPE_LOWER)) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received create cell with unexpected circ_id %u. Closing.", (unsigned)cell->circ_id); channel_send_destroy(cell->circ_id, chan, END_CIRC_REASON_TORPROTOCOL); return; } if (circuit_id_in_use_on_channel(cell->circ_id, chan)) { const node_t *node = node_get_by_id(chan->identity_digest); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received CREATE cell (circID %u) for known circ. " "Dropping (age %d).", (unsigned)cell->circ_id, (int)(time(NULL) - channel_when_created(chan))); if (node) { char *p = esc_for_log(node_get_platform(node)); log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Details: router %s, platform %s.", node_describe(node), p); tor_free(p); } return; } circ = or_circuit_new(cell->circ_id, chan); circ->base_.purpose = CIRCUIT_PURPOSE_OR; circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); create_cell = tor_malloc_zero(sizeof(create_cell_t)); if (create_cell_parse(create_cell, cell) < 0) { tor_free(create_cell); log_fn(LOG_PROTOCOL_WARN, LD_OR, "Bogus/unrecognized create cell; closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); return; } if (create_cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) { /* hand it off to the cpuworkers, and then return. */ if (connection_or_digest_is_known_relay(chan->identity_digest)) rep_hist_note_circuit_handshake_requested(create_cell->handshake_type); if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) { log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); return; } log_debug(LD_OR,"success: handed off onionskin."); } else { /* This is a CREATE_FAST cell; we can handle it immediately without using * a CPU worker. */ uint8_t keys[CPATH_KEY_MATERIAL_LEN]; uint8_t rend_circ_nonce[DIGEST_LEN]; int len; created_cell_t created_cell; /* Make sure we never try to use the OR connection on which we * received this cell to satisfy an EXTEND request, */ channel_mark_client(chan); memset(&created_cell, 0, sizeof(created_cell)); len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST, create_cell->onionskin, create_cell->handshake_len, NULL, created_cell.reply, keys, CPATH_KEY_MATERIAL_LEN, rend_circ_nonce); tor_free(create_cell); if (len < 0) { log_warn(LD_OR,"Failed to generate key material. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); tor_free(create_cell); return; } created_cell.cell_type = CELL_CREATED_FAST; created_cell.handshake_len = len; if (onionskin_answer(circ, &created_cell, (const char *)keys, rend_circ_nonce)<0) { log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return; } memwipe(keys, 0, sizeof(keys)); } }