/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys * 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) */ void setup_server_onion_keys(server_onion_keys_t *keys) { memset(keys, 0, 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); }
/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys * 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) */ void setup_server_onion_keys(server_onion_keys_t *keys) { memset(keys, 0, sizeof(server_onion_keys_t)); memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN); #ifdef IPC_MODE if(get_relay_num() == 3) { keys->onion_key = NULL; keys->last_onion_key = NULL; } else dup_onion_keys(&keys->onion_key, &keys->last_onion_key); #endif #ifndef IPC_MODE dup_onion_keys(&keys->onion_key, &keys->last_onion_key); #endif #ifdef CURVE25519_ENABLED 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); #endif }
void scalliontor_newCPUWorker(ScallionTor* stor, int fd) { g_assert(stor); if(stor->cpuw) { g_free(stor->cpuw); } vtor_cpuworker_tp cpuw = calloc(1, sizeof(vtor_cpuworker_t)); cpuw->fd = fd; cpuw->state = CPUW_NONE; #ifdef SCALLION_USEV2CPUWORKER cpuw->magic1 = SCALLION_CPUWORKER_MAGIC1; cpuw->magic2 = SCALLION_CPUWORKER_MAGIC2; cpuw->magic3 = SCALLION_CPUWORKER_MAGIC3; setup_server_onion_keys(&(cpuw->onion_keys)); #else dup_onion_keys(&(cpuw->onion_key), &(cpuw->last_onion_key)); #endif /* setup event so we will get a callback */ event_assign(&(cpuw->read_event), tor_libevent_get_base(), cpuw->fd, EV_READ|EV_PERSIST, scalliontor_readCPUWorkerCallback, cpuw); event_add(&(cpuw->read_event), NULL); }
/** Implement a cpuworker. 'data' is an fdarray as returned by socketpair. * Read and writes from fdarray[1]. Reads requests, writes answers. * * Request format: * Task type [1 byte, always CPUWORKER_TASK_ONION] * Opaque tag TAG_LEN * Onionskin challenge ONIONSKIN_CHALLENGE_LEN * Response format: * Success/failure [1 byte, boolean.] * Opaque tag TAG_LEN * Onionskin challenge ONIONSKIN_REPLY_LEN * Negotiated keys KEY_LEN*2+DIGEST_LEN*2 * * (Note: this _should_ be by addr/port, since we're concerned with specific * connections, not with routers (where we'd use identity).) */ static void cpuworker_main(void *data) { char question[ONIONSKIN_CHALLENGE_LEN]; uint8_t question_type; int *fdarray = data; int fd; /* variables for onion processing */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply_to_proxy[ONIONSKIN_REPLY_LEN]; char buf[LEN_ONION_RESPONSE]; char tag[TAG_LEN]; crypto_pk_env_t *onion_key = NULL, *last_onion_key = NULL; fd = fdarray[1]; /* this side is ours */ #ifndef TOR_IS_MULTITHREADED tor_close_socket(fdarray[0]); /* this is the side of the socketpair the * parent uses */ tor_free_all(1); /* so the child doesn't hold the parent's fd's open */ handle_signals(0); /* ignore interrupts from the keyboard, etc */ #endif tor_free(data); dup_onion_keys(&onion_key, &last_onion_key); for (;;) { ssize_t r; if ((r = recv(fd, &question_type, 1, 0)) != 1) { // log_fn(LOG_ERR,"read type failed. Exiting."); if (r == 0) { log_info(LD_OR, "CPU worker exiting because Tor process closed connection " "(either rotated keys or died)."); } else { log_info(LD_OR, "CPU worker exiting because of error on connection to Tor " "process."); log_info(LD_OR,"(Error on %d was %s)", fd, tor_socket_strerror(tor_socket_errno(fd))); } goto end; } tor_assert(question_type == CPUWORKER_TASK_ONION); if (read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) { log_err(LD_BUG,"read tag failed. Exiting."); goto end; } if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) != ONIONSKIN_CHALLENGE_LEN) { log_err(LD_BUG,"read question failed. Exiting."); goto end; } if (question_type == CPUWORKER_TASK_ONION) { if (onion_skin_server_handshake(question, onion_key, last_onion_key, reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); *buf = 0; /* indicate failure in first byte */ memcpy(buf+1,tag,TAG_LEN); /* send all zeros as answer */ memset(buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN)); } else { /* success */ log_debug(LD_OR,"onion_skin_server_handshake succeeded."); buf[0] = 1; /* 1 means success */ memcpy(buf+1,tag,TAG_LEN); memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN); memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_LEN); } if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) { log_err(LD_BUG,"writing response buf failed. Exiting."); goto end; } log_debug(LD_OR,"finished writing response."); } } end: if (onion_key) crypto_free_pk_env(onion_key); if (last_onion_key) crypto_free_pk_env(last_onion_key); tor_close_socket(fd); crypto_thread_cleanup(); spawn_exit(); }