2003-10-08 04:04:08 +02:00
|
|
|
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
/* $Id$ */
|
2002-06-27 00:45:49 +02:00
|
|
|
|
|
|
|
#include "or.h"
|
|
|
|
|
2002-11-27 05:08:20 +01:00
|
|
|
extern or_options_t options; /* command-line and config-file options */
|
2002-09-04 08:29:28 +02:00
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-11-11 04:01:48 +01:00
|
|
|
int decide_circ_id_type(char *local_nick, char *remote_nick) {
|
2003-10-01 03:49:53 +02:00
|
|
|
int result;
|
2003-11-16 18:00:02 +01:00
|
|
|
|
2003-10-01 03:49:53 +02:00
|
|
|
assert(remote_nick);
|
|
|
|
if(!local_nick)
|
2003-11-11 04:01:48 +01:00
|
|
|
return CIRC_ID_TYPE_LOWER;
|
2003-10-01 03:49:53 +02:00
|
|
|
result = strcmp(local_nick, remote_nick);
|
|
|
|
assert(result);
|
|
|
|
if(result < 0)
|
2003-11-11 04:01:48 +01:00
|
|
|
return CIRC_ID_TYPE_LOWER;
|
|
|
|
return CIRC_ID_TYPE_HIGHER;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2003-09-16 22:57:09 +02:00
|
|
|
struct onion_queue_t {
|
|
|
|
circuit_t *circ;
|
|
|
|
struct onion_queue_t *next;
|
|
|
|
};
|
|
|
|
|
2002-11-27 05:08:20 +01:00
|
|
|
/* global (within this file) variables used by the next few functions */
|
|
|
|
static struct onion_queue_t *ol_list=NULL;
|
|
|
|
static struct onion_queue_t *ol_tail=NULL;
|
|
|
|
static int ol_length=0;
|
|
|
|
|
|
|
|
int onion_pending_add(circuit_t *circ) {
|
|
|
|
struct onion_queue_t *tmp;
|
|
|
|
|
2003-11-18 09:20:19 +01:00
|
|
|
tmp = tor_malloc_zero(sizeof(struct onion_queue_t));
|
2002-11-27 05:08:20 +01:00
|
|
|
tmp->circ = circ;
|
|
|
|
|
|
|
|
if(!ol_tail) {
|
|
|
|
assert(!ol_list);
|
|
|
|
assert(!ol_length);
|
|
|
|
ol_list = tmp;
|
|
|
|
ol_tail = tmp;
|
|
|
|
ol_length++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(ol_list);
|
|
|
|
assert(!ol_tail->next);
|
|
|
|
|
|
|
|
if(ol_length >= options.MaxOnionsPending) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Already have %d onions queued. Closing.", ol_length);
|
2002-11-27 05:08:20 +01:00
|
|
|
free(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ol_length++;
|
|
|
|
ol_tail->next = tmp;
|
|
|
|
ol_tail = tmp;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
circuit_t *onion_next_task(void) {
|
2003-09-14 10:17:14 +02:00
|
|
|
circuit_t *circ;
|
2002-11-27 05:08:20 +01:00
|
|
|
|
|
|
|
if(!ol_list)
|
2003-08-21 01:05:22 +02:00
|
|
|
return NULL; /* no onions pending, we're done */
|
2002-11-27 05:08:20 +01:00
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
assert(ol_list->circ);
|
2003-11-18 22:12:17 +01:00
|
|
|
assert(ol_list->circ->p_conn); /* make sure it's still valid */
|
|
|
|
#if 0
|
2003-05-20 08:41:23 +02:00
|
|
|
if(!ol_list->circ->p_conn) {
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_INFO,"ol_list->circ->p_conn null, must have died?");
|
2003-05-20 08:41:23 +02:00
|
|
|
onion_pending_remove(ol_list->circ);
|
2003-08-21 01:05:22 +02:00
|
|
|
return onion_next_task(); /* recurse: how about the next one? */
|
2003-05-20 08:41:23 +02:00
|
|
|
}
|
2003-11-18 22:12:17 +01:00
|
|
|
#endif
|
2003-05-20 08:41:23 +02:00
|
|
|
|
2002-11-27 05:08:20 +01:00
|
|
|
assert(ol_length > 0);
|
2003-09-14 10:17:14 +02:00
|
|
|
circ = ol_list->circ;
|
|
|
|
onion_pending_remove(ol_list->circ);
|
|
|
|
return circ;
|
2002-11-27 05:08:20 +01:00
|
|
|
}
|
|
|
|
|
2002-12-03 23:18:23 +01:00
|
|
|
/* go through ol_list, find the onion_queue_t element which points to
|
|
|
|
* circ, remove and free that element. leave circ itself alone.
|
2002-11-27 05:08:20 +01:00
|
|
|
*/
|
|
|
|
void onion_pending_remove(circuit_t *circ) {
|
|
|
|
struct onion_queue_t *tmpo, *victim;
|
|
|
|
|
|
|
|
if(!ol_list)
|
|
|
|
return; /* nothing here. */
|
|
|
|
|
|
|
|
/* first check to see if it's the first entry */
|
|
|
|
tmpo = ol_list;
|
|
|
|
if(tmpo->circ == circ) {
|
|
|
|
/* it's the first one. remove it from the list. */
|
|
|
|
ol_list = tmpo->next;
|
|
|
|
if(!ol_list)
|
|
|
|
ol_tail = NULL;
|
|
|
|
ol_length--;
|
|
|
|
victim = tmpo;
|
|
|
|
} else { /* we need to hunt through the rest of the list */
|
|
|
|
for( ;tmpo->next && tmpo->next->circ != circ; tmpo=tmpo->next) ;
|
|
|
|
if(!tmpo->next) {
|
2003-11-11 04:01:48 +01:00
|
|
|
log_fn(LOG_DEBUG,"circ (p_circ_id %d) not in list, probably at cpuworker.",circ->p_circ_id);
|
2002-11-27 05:08:20 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* now we know tmpo->next->circ == circ */
|
|
|
|
victim = tmpo->next;
|
|
|
|
tmpo->next = victim->next;
|
|
|
|
if(ol_tail == victim)
|
|
|
|
ol_tail = tmpo;
|
|
|
|
ol_length--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now victim points to the element that needs to be removed */
|
|
|
|
|
|
|
|
free(victim);
|
|
|
|
}
|
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
/* given a response payload and keys, initialize, then send a created cell back */
|
2003-09-14 04:58:50 +02:00
|
|
|
int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys) {
|
2003-05-06 01:24:46 +02:00
|
|
|
unsigned char iv[16];
|
2002-11-27 05:08:20 +01:00
|
|
|
cell_t cell;
|
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
memset(iv, 0, 16);
|
2002-10-03 00:54:20 +02:00
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
memset(&cell, 0, sizeof(cell_t));
|
|
|
|
cell.command = CELL_CREATED;
|
2003-11-11 04:01:48 +01:00
|
|
|
cell.circ_id = circ->p_circ_id;
|
2003-05-06 07:54:42 +02:00
|
|
|
cell.length = DH_KEY_LEN;
|
2003-05-06 01:24:46 +02:00
|
|
|
|
|
|
|
circ->state = CIRCUIT_STATE_OPEN;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_DEBUG,"Entering.");
|
2003-05-06 01:24:46 +02:00
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
memcpy(cell.payload, payload, DH_KEY_LEN);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_DEBUG,"init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16));
|
2003-05-06 01:24:46 +02:00
|
|
|
|
|
|
|
if (!(circ->n_crypto =
|
2003-07-30 21:12:03 +02:00
|
|
|
crypto_create_init_cipher(CIRCUIT_CIPHER,keys,iv,0))) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Cipher initialization failed (n).");
|
2002-06-27 00:45:49 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
if (!(circ->p_crypto =
|
2003-07-30 21:12:03 +02:00
|
|
|
crypto_create_init_cipher(CIRCUIT_CIPHER,keys+16,iv,1))) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Cipher initialization failed (p).");
|
2002-06-27 00:45:49 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-10-09 20:45:14 +02:00
|
|
|
connection_or_write_cell_to_buf(&cell, circ->p_conn);
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_DEBUG,"Finished sending 'created' cell.");
|
2002-06-27 00:45:49 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-11-12 20:34:34 +01:00
|
|
|
char **parse_nickname_list(char *list, int *num) {
|
|
|
|
char **out;
|
|
|
|
char *start,*end;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
while(isspace(*list)) list++;
|
|
|
|
|
|
|
|
i=0, start = list;
|
|
|
|
while(*start) {
|
|
|
|
while(*start && !isspace(*start)) start++;
|
|
|
|
i++;
|
|
|
|
while(isspace(*start)) start++;
|
|
|
|
}
|
|
|
|
|
|
|
|
out = tor_malloc(i * sizeof(char *));
|
|
|
|
|
|
|
|
i=0, start=list;
|
|
|
|
while(*start) {
|
|
|
|
end=start; while(*end && !isspace(*end)) end++;
|
|
|
|
out[i] = tor_malloc(MAX_NICKNAME_LEN);
|
|
|
|
strncpy(out[i],start,end-start);
|
|
|
|
out[i][end-start] = 0; /* null terminate it */
|
|
|
|
i++;
|
|
|
|
while(isspace(*end)) end++;
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
*num = i;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) {
|
2003-04-08 08:44:38 +02:00
|
|
|
int num_acceptable_routers;
|
2003-11-12 03:32:20 +01:00
|
|
|
int routelen;
|
2003-04-16 08:18:31 +02:00
|
|
|
|
2003-11-14 00:01:56 +01:00
|
|
|
assert((cw >= 0) && (cw < 1) && rarray); /* valid parameters */
|
2002-07-22 06:38:36 +02:00
|
|
|
|
2003-11-14 00:01:56 +01:00
|
|
|
for(routelen=3; ; routelen++) { /* 3, increment until coinflip says we're done */
|
|
|
|
if (crypto_pseudo_rand_int(255) >= cw*255) /* don't extend */
|
|
|
|
break;
|
2002-08-23 05:35:44 +02:00
|
|
|
}
|
2003-11-12 03:32:20 +01:00
|
|
|
log_fn(LOG_DEBUG,"Chosen route length %d (%d routers available).",routelen, rarray_len);
|
2002-08-23 05:35:44 +02:00
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
num_acceptable_routers = count_acceptable_routers(rarray, rarray_len);
|
|
|
|
|
2003-04-16 08:18:31 +02:00
|
|
|
if(num_acceptable_routers < 2) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_INFO,"Not enough acceptable routers. Failing.");
|
2003-11-12 03:32:20 +01:00
|
|
|
return -1;
|
2003-04-16 08:18:31 +02:00
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
if(num_acceptable_routers < routelen) {
|
|
|
|
log_fn(LOG_INFO,"Not enough routers: cutting routelen from %d to %d.",routelen, num_acceptable_routers);
|
|
|
|
routelen = num_acceptable_routers;
|
2002-08-23 05:35:44 +02:00
|
|
|
}
|
2002-07-22 06:38:36 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
if (routelen < 1) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Didn't find any acceptable routers. Failing.");
|
2003-11-12 03:32:20 +01:00
|
|
|
return -1;
|
2002-08-23 05:35:44 +02:00
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
return routelen;
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
}
|
|
|
|
|
2003-11-16 06:33:45 +01:00
|
|
|
static routerinfo_t *choose_good_exit_server(directory_t *dir)
|
|
|
|
{
|
|
|
|
int *n_supported;
|
|
|
|
int *n_maybe_supported;
|
|
|
|
int i, j;
|
|
|
|
int n_pending_connections = 0;
|
|
|
|
connection_t **carray;
|
|
|
|
int n_connections;
|
|
|
|
int best_support = -1;
|
|
|
|
int best_maybe_support = -1;
|
|
|
|
int best_support_idx = -1;
|
|
|
|
int best_maybe_support_idx = -1;
|
|
|
|
int n_best_support=0, n_best_maybe_support=0;
|
|
|
|
|
|
|
|
get_connection_array(&carray, &n_connections);
|
|
|
|
|
2003-11-17 07:02:41 +01:00
|
|
|
/* Count how many connections are waiting for a circuit to be built.
|
|
|
|
* We use this for log messages now, but in the future we may depend on it.
|
|
|
|
*/
|
2003-11-16 06:33:45 +01:00
|
|
|
for (i = 0; i < n_connections; ++i) {
|
|
|
|
if (carray[i]->type == CONN_TYPE_AP && carray[i]->state == AP_CONN_STATE_CIRCUIT_WAIT)
|
|
|
|
++n_pending_connections;
|
|
|
|
}
|
|
|
|
log_fn(LOG_DEBUG, "Choosing exit node; %d connections are pending",
|
|
|
|
n_pending_connections);
|
2003-11-17 07:02:41 +01:00
|
|
|
/* Now we count, for each of the routers in the directory: how many
|
|
|
|
* of the pending connections could _definitely_ exit from that
|
|
|
|
* router (n_supported[i]) and how many could _possibly_ exit from
|
|
|
|
* that router (n_maybe_supported[i]). (We can't be sure about
|
|
|
|
* cases where we don't know the IP address of the pending
|
|
|
|
* connection.)
|
|
|
|
*/
|
2003-11-16 06:33:45 +01:00
|
|
|
n_supported = tor_malloc(sizeof(int)*dir->n_routers);
|
|
|
|
n_maybe_supported = tor_malloc(sizeof(int)*dir->n_routers);
|
2003-11-17 07:02:41 +01:00
|
|
|
for (i = 0; i < dir->n_routers; ++i) { /* iterate over routers */
|
2003-11-16 06:33:45 +01:00
|
|
|
n_supported[i] = n_maybe_supported[i] = 0;
|
2003-11-18 10:53:03 +01:00
|
|
|
if(!dir->routers[i]->is_running)
|
|
|
|
continue; /* skip routers which are known to be down */
|
2003-11-17 07:02:41 +01:00
|
|
|
for (j = 0; j < n_connections; ++j) { /* iterate over connections */
|
2003-11-17 02:20:35 +01:00
|
|
|
if (carray[j]->type != CONN_TYPE_AP ||
|
|
|
|
carray[j]->state == AP_CONN_STATE_CIRCUIT_WAIT ||
|
|
|
|
carray[j]->marked_for_close)
|
2003-11-18 10:53:03 +01:00
|
|
|
continue; /* Skip everything but APs in CIRCUIT_WAIT */
|
2003-11-16 06:33:45 +01:00
|
|
|
switch (connection_ap_can_use_exit(carray[j], dir->routers[i]))
|
|
|
|
{
|
|
|
|
case -1:
|
2003-11-18 10:53:03 +01:00
|
|
|
break; /* would be rejected; try next connection */
|
2003-11-16 06:33:45 +01:00
|
|
|
case 0:
|
|
|
|
++n_supported[i];
|
2003-11-17 07:02:41 +01:00
|
|
|
; /* Fall through: If it is supported, it is also maybe supported. */
|
2003-11-16 06:33:45 +01:00
|
|
|
case 1:
|
|
|
|
++n_maybe_supported[i];
|
|
|
|
}
|
2003-11-17 07:02:41 +01:00
|
|
|
} /* End looping over connections. */
|
|
|
|
if (n_supported[i] > best_support) {
|
|
|
|
/* If this router is better than previous ones, remember its index
|
|
|
|
* and goodness, and start counting how many routers are this good. */
|
2003-11-16 06:33:45 +01:00
|
|
|
best_support = n_supported[i]; best_support_idx = i; n_best_support=1;
|
|
|
|
} else if (n_supported[i] == best_support) {
|
2003-11-17 07:02:41 +01:00
|
|
|
/* If this router is _as good_ as the best one, just increment the
|
|
|
|
* count of equally good routers.*/
|
2003-11-16 06:33:45 +01:00
|
|
|
++n_best_support;
|
|
|
|
}
|
2003-11-17 07:02:41 +01:00
|
|
|
/* As above, but for 'maybe-supported' connections */
|
2003-11-16 06:33:45 +01:00
|
|
|
if (n_maybe_supported[i] > best_maybe_support) {
|
|
|
|
best_maybe_support = n_maybe_supported[i]; best_maybe_support_idx = i;
|
|
|
|
n_best_maybe_support = 1;
|
|
|
|
} else if (n_maybe_supported[i] == best_maybe_support) {
|
|
|
|
++n_best_maybe_support;
|
|
|
|
}
|
|
|
|
}
|
2003-11-17 00:43:08 +01:00
|
|
|
log_fn(LOG_INFO, "Found %d servers that will definitely support %d/%d pending connections, and %d that might support %d/%d.",
|
2003-11-16 06:33:45 +01:00
|
|
|
n_best_support, best_support, n_pending_connections,
|
|
|
|
n_best_maybe_support, best_maybe_support, n_pending_connections);
|
2003-11-17 07:02:41 +01:00
|
|
|
/* If any routers definitely support any pending connections, choose one
|
|
|
|
* at random. */
|
2003-11-16 06:33:45 +01:00
|
|
|
if (best_support) {
|
|
|
|
i = crypto_pseudo_rand_int(n_best_support);
|
2003-11-17 07:02:41 +01:00
|
|
|
/* Iterate over the routers, until we find the i-th one such that
|
|
|
|
* n_supported[j] == best_support
|
|
|
|
*/
|
2003-11-16 06:33:45 +01:00
|
|
|
for (j = best_support_idx; j < dir->n_routers; ++j) {
|
|
|
|
if (n_supported[j] == best_support) {
|
|
|
|
if (i)
|
|
|
|
--i;
|
|
|
|
else {
|
|
|
|
tor_free(n_supported); tor_free(n_maybe_supported);
|
|
|
|
return dir->routers[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-17 07:02:41 +01:00
|
|
|
/* This point should never be reached. */
|
2003-11-18 10:53:03 +01:00
|
|
|
assert(0);
|
2003-11-16 06:33:45 +01:00
|
|
|
}
|
2003-11-17 07:02:41 +01:00
|
|
|
/* If any routers _maybe_ support pending connections, choose one at
|
|
|
|
* random, as above. */
|
2003-11-16 06:33:45 +01:00
|
|
|
if (best_maybe_support) {
|
|
|
|
i = crypto_pseudo_rand_int(n_best_maybe_support);
|
|
|
|
for (j = best_maybe_support_idx; j < dir->n_routers; ++j) {
|
|
|
|
if (n_maybe_supported[j] == best_maybe_support) {
|
|
|
|
if (i)
|
|
|
|
--i;
|
|
|
|
else {
|
|
|
|
tor_free(n_supported); tor_free(n_maybe_supported);
|
|
|
|
return dir->routers[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-17 07:02:41 +01:00
|
|
|
/* This point should never be reached. */
|
2003-11-18 10:53:03 +01:00
|
|
|
assert(0);
|
2003-11-16 06:33:45 +01:00
|
|
|
}
|
2003-11-17 07:02:41 +01:00
|
|
|
/* Either there are no pending connections, or no routers even seem to
|
|
|
|
* possibly support any of them. Choose a router at random. */
|
2003-11-18 10:53:03 +01:00
|
|
|
/* XXX should change to not choose non-running routers */
|
2003-11-16 18:00:02 +01:00
|
|
|
tor_free(n_supported); tor_free(n_maybe_supported);
|
2003-11-16 06:33:45 +01:00
|
|
|
i = crypto_pseudo_rand_int(dir->n_routers);
|
|
|
|
log_fn(LOG_DEBUG, "Chose exit server '%s'", dir->routers[i]->nickname);
|
|
|
|
return dir->routers[i];
|
|
|
|
}
|
|
|
|
|
2003-11-14 21:45:47 +01:00
|
|
|
cpath_build_state_t *onion_new_cpath_build_state(void) {
|
2003-11-12 03:55:38 +01:00
|
|
|
directory_t *dir;
|
2003-11-14 21:45:47 +01:00
|
|
|
int r;
|
|
|
|
cpath_build_state_t *info;
|
|
|
|
|
2003-11-12 03:55:38 +01:00
|
|
|
router_get_directory(&dir);
|
2003-11-14 21:45:47 +01:00
|
|
|
r = new_route_len(options.PathlenCoinWeight, dir->routers, dir->n_routers);
|
|
|
|
if (r < 0)
|
|
|
|
return NULL;
|
|
|
|
info = tor_malloc(sizeof(cpath_build_state_t));
|
|
|
|
info->desired_path_len = r;
|
2003-11-16 06:33:45 +01:00
|
|
|
info->chosen_exit = tor_strdup(choose_good_exit_server(dir)->nickname);
|
2003-11-14 21:45:47 +01:00
|
|
|
return info;
|
2003-11-12 03:55:38 +01:00
|
|
|
}
|
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
|
|
|
|
int i, j;
|
|
|
|
int num=0;
|
2003-04-16 08:18:31 +02:00
|
|
|
connection_t *conn;
|
2003-04-08 08:44:38 +02:00
|
|
|
|
|
|
|
for(i=0;i<rarray_len;i++) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"Contemplating whether router %d is a new option...",i);
|
2003-11-18 10:53:03 +01:00
|
|
|
if(rarray[i]->is_running == 0) {
|
|
|
|
log_fn(LOG_DEBUG,"Nope, the directory says %d is not running.",i);
|
|
|
|
goto next_i_loop;
|
|
|
|
}
|
2003-05-28 04:03:25 +02:00
|
|
|
if(options.OnionRouter) {
|
2003-04-16 08:18:31 +02:00
|
|
|
conn = connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port);
|
|
|
|
if(!conn || conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"Nope, %d is not connected.",i);
|
2003-04-16 08:18:31 +02:00
|
|
|
goto next_i_loop;
|
|
|
|
}
|
2003-04-08 08:44:38 +02:00
|
|
|
}
|
|
|
|
for(j=0;j<i;j++) {
|
2003-09-25 07:17:11 +02:00
|
|
|
if(!crypto_pk_cmp_keys(rarray[i]->onion_pkey, rarray[j]->onion_pkey)) {
|
2003-04-08 08:44:38 +02:00
|
|
|
/* these guys are twins. so we've already counted him. */
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j);
|
2003-04-08 08:44:38 +02:00
|
|
|
goto next_i_loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
num++;
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"I like %d. num_acceptable_routers now %d.",i, num);
|
2003-04-08 08:44:38 +02:00
|
|
|
next_i_loop:
|
|
|
|
; /* our compiler may need an explicit statement after the label */
|
|
|
|
}
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2003-11-14 21:45:47 +01:00
|
|
|
int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, routerinfo_t **router_out)
|
2003-11-12 03:32:20 +01:00
|
|
|
{
|
|
|
|
int cur_len;
|
|
|
|
crypt_path_t *cpath, *hop;
|
|
|
|
routerinfo_t **rarray, *r;
|
2003-11-16 06:33:45 +01:00
|
|
|
routerinfo_t *choice;
|
2003-11-12 03:32:20 +01:00
|
|
|
int rarray_len;
|
|
|
|
int i;
|
|
|
|
directory_t *dir;
|
2003-11-16 06:33:45 +01:00
|
|
|
int n_failures;
|
2003-05-02 00:55:51 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
assert(head_ptr);
|
2003-11-12 20:34:34 +01:00
|
|
|
assert(router_out);
|
2002-11-23 07:49:01 +01:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
router_get_directory(&dir);
|
|
|
|
rarray = dir->routers;
|
|
|
|
rarray_len = dir->n_routers;
|
|
|
|
|
|
|
|
if (!*head_ptr) {
|
|
|
|
cur_len = 0;
|
|
|
|
} else {
|
|
|
|
cur_len = 1;
|
|
|
|
for (cpath = *head_ptr; cpath->next != *head_ptr; cpath = cpath->next) {
|
|
|
|
++cur_len;
|
|
|
|
}
|
2002-11-23 07:49:01 +01:00
|
|
|
}
|
2003-11-14 21:45:47 +01:00
|
|
|
if (cur_len >= state->desired_path_len) {
|
|
|
|
log_fn(LOG_DEBUG, "Path is complete: %d steps long",
|
|
|
|
state->desired_path_len);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len,
|
|
|
|
state->desired_path_len);
|
2003-05-02 00:55:51 +02:00
|
|
|
|
2003-11-16 06:33:45 +01:00
|
|
|
n_failures = 0;
|
|
|
|
goto start;
|
2003-11-12 03:32:20 +01:00
|
|
|
again:
|
2003-11-16 06:33:45 +01:00
|
|
|
log_fn(LOG_DEBUG, "Picked an already-selected router for hop %d; retrying.",
|
|
|
|
cur_len);
|
|
|
|
++n_failures;
|
|
|
|
if (n_failures == 25) {
|
|
|
|
/* This actually happens with P=1/30,000,000 when we _could_ build a
|
|
|
|
* circuit. For now, let's leave it in.
|
|
|
|
*/
|
2003-11-17 09:15:37 +01:00
|
|
|
log_fn(LOG_INFO, "Unable to continue generating circuit path");
|
|
|
|
return -1;
|
2003-11-16 06:33:45 +01:00
|
|
|
}
|
|
|
|
start:
|
2003-11-12 20:34:34 +01:00
|
|
|
if(cur_len == 0) { /* picking entry node */
|
2003-11-16 06:33:45 +01:00
|
|
|
log_fn(LOG_DEBUG, "Contemplating first hop: random choice.");
|
|
|
|
choice = rarray[crypto_pseudo_rand_int(rarray_len)];
|
|
|
|
} else if (cur_len == state->desired_path_len - 1) { /* Picking last node */
|
|
|
|
log_fn(LOG_DEBUG, "Contemplating last hop: choice already made.");
|
|
|
|
choice = router_get_by_nickname(state->chosen_exit);
|
2003-11-16 18:00:02 +01:00
|
|
|
/* XXX check if null */
|
2003-11-16 06:33:45 +01:00
|
|
|
} else {
|
|
|
|
log_fn(LOG_DEBUG, "Contemplating intermediate hop: random choice.");
|
|
|
|
choice = rarray[crypto_pseudo_rand_int(rarray_len)];
|
2003-11-12 20:34:34 +01:00
|
|
|
}
|
2003-11-16 06:33:45 +01:00
|
|
|
log_fn(LOG_DEBUG,"Contemplating router %s for hop %d (exit is %s)",
|
|
|
|
choice->nickname, cur_len, state->chosen_exit);
|
|
|
|
if (cur_len != state->desired_path_len-1 &&
|
|
|
|
!strcasecmp(choice->nickname, state->chosen_exit)) {
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
for (i = 0, cpath = *head_ptr; i < cur_len; ++i, cpath=cpath->next) {
|
|
|
|
r = router_get_by_addr_port(cpath->addr, cpath->port);
|
2003-11-16 06:33:45 +01:00
|
|
|
if ((r && !crypto_pk_cmp_keys(r->onion_pkey, choice->onion_pkey))
|
|
|
|
|| (cur_len != state->desired_path_len-1 &&
|
|
|
|
!strcasecmp(choice->nickname, state->chosen_exit))
|
|
|
|
|| (cpath->addr == choice->addr &&
|
|
|
|
cpath->port == choice->or_port)
|
2003-11-12 03:32:20 +01:00
|
|
|
|| (options.OnionRouter &&
|
2003-11-16 06:33:45 +01:00
|
|
|
!(connection_twin_get_by_addr_port(choice->addr,
|
|
|
|
choice->or_port)))) {
|
2003-11-12 03:32:20 +01:00
|
|
|
goto again;
|
2002-11-23 07:49:01 +01:00
|
|
|
}
|
2003-11-12 03:32:20 +01:00
|
|
|
}
|
2003-11-16 06:33:45 +01:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
/* Okay, so we haven't used 'choice' before. */
|
2003-11-18 09:20:19 +01:00
|
|
|
hop = (crypt_path_t *)tor_malloc_zero(sizeof(crypt_path_t));
|
2003-11-12 03:32:20 +01:00
|
|
|
|
|
|
|
/* link hop into the cpath, at the end. */
|
|
|
|
if (*head_ptr) {
|
|
|
|
hop->next = (*head_ptr);
|
|
|
|
hop->prev = (*head_ptr)->prev;
|
|
|
|
(*head_ptr)->prev->next = hop;
|
|
|
|
(*head_ptr)->prev = hop;
|
|
|
|
} else {
|
|
|
|
*head_ptr = hop;
|
|
|
|
hop->prev = hop->next = hop;
|
2002-11-23 07:49:01 +01:00
|
|
|
}
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
hop->state = CPATH_STATE_CLOSED;
|
|
|
|
|
2003-11-16 06:33:45 +01:00
|
|
|
hop->port = choice->or_port;
|
|
|
|
hop->addr = choice->addr;
|
2003-11-12 03:32:20 +01:00
|
|
|
|
|
|
|
hop->package_window = CIRCWINDOW_START;
|
|
|
|
hop->deliver_window = CIRCWINDOW_START;
|
2002-11-23 07:49:01 +01:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
log_fn(LOG_DEBUG, "Extended circuit path with %s for hop %d",
|
2003-11-16 06:33:45 +01:00
|
|
|
choice->nickname, cur_len);
|
2003-11-12 03:32:20 +01:00
|
|
|
|
2003-11-16 06:33:45 +01:00
|
|
|
*router_out = choice;
|
2003-11-12 03:32:20 +01:00
|
|
|
return 0;
|
2003-04-16 18:19:27 +02:00
|
|
|
}
|
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
|
2003-05-26 08:03:16 +02:00
|
|
|
/* Given a router's public key, generates a 144-byte encrypted DH pubkey,
|
2003-05-01 21:42:51 +02:00
|
|
|
* and stores it into onion_skin out. Stores the DH private key into
|
|
|
|
* handshake_state_out for later completion of the handshake.
|
|
|
|
*
|
|
|
|
* The encrypted pubkey is formed as follows:
|
|
|
|
* 16 bytes of symmetric key
|
2003-05-26 08:03:16 +02:00
|
|
|
* 128 bytes of g^x for DH.
|
2003-05-01 21:42:51 +02:00
|
|
|
* The first 128 bytes are RSA-encrypted with the server's public key,
|
2003-05-26 08:03:16 +02:00
|
|
|
* and the last 16 are encrypted with the symmetric key.
|
2003-05-01 21:42:51 +02:00
|
|
|
*/
|
|
|
|
int
|
2003-05-06 01:24:46 +02:00
|
|
|
onion_skin_create(crypto_pk_env_t *dest_router_key,
|
2003-05-01 21:42:51 +02:00
|
|
|
crypto_dh_env_t **handshake_state_out,
|
2003-05-06 07:54:42 +02:00
|
|
|
char *onion_skin_out) /* Must be DH_ONIONSKIN_LEN bytes long */
|
2003-05-01 21:42:51 +02:00
|
|
|
{
|
|
|
|
char iv[16];
|
|
|
|
char *pubkey = NULL;
|
|
|
|
crypto_dh_env_t *dh = NULL;
|
|
|
|
crypto_cipher_env_t *cipher = NULL;
|
|
|
|
int dhbytes, pkbytes;
|
|
|
|
|
|
|
|
*handshake_state_out = NULL;
|
2003-05-06 07:54:42 +02:00
|
|
|
memset(onion_skin_out, 0, DH_ONIONSKIN_LEN);
|
2003-05-05 06:27:00 +02:00
|
|
|
memset(iv, 0, 16);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
if (!(dh = crypto_dh_new()))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
dhbytes = crypto_dh_get_bytes(dh);
|
2003-05-06 01:24:46 +02:00
|
|
|
pkbytes = crypto_pk_keysize(dest_router_key);
|
2003-05-06 07:54:42 +02:00
|
|
|
assert(dhbytes+16 == DH_ONIONSKIN_LEN);
|
2003-05-20 08:41:23 +02:00
|
|
|
pubkey = (char *)tor_malloc(dhbytes+16);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
if (crypto_rand(16, pubkey))
|
|
|
|
goto err;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
|
|
|
/* XXXX You can't just run around RSA-encrypting any bitstream: if it's
|
|
|
|
* greater than the RSA key, then OpenSSL will happily encrypt,
|
|
|
|
* and later decrypt to the wrong value. So we set the first bit
|
|
|
|
* of 'pubkey' to 0. This means that our symmetric key is really only
|
|
|
|
* 127 bits long, but since it shouldn't be necessary to encrypt
|
|
|
|
* DH public keys values in the first place, we should be fine.
|
|
|
|
*/
|
|
|
|
pubkey[0] &= 0x7f;
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
if (crypto_dh_get_public(dh, pubkey+16, dhbytes))
|
|
|
|
goto err;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
#define PA(a,n) \
|
|
|
|
{ int _i; for (_i = 0; _i<n; ++_i) printf("%02x ",((int)(a)[_i])&0xFF); }
|
|
|
|
|
|
|
|
printf("Client: client g^x:");
|
|
|
|
PA(pubkey+16,3);
|
|
|
|
printf("...");
|
|
|
|
PA(pubkey+141,3);
|
|
|
|
puts("");
|
|
|
|
|
|
|
|
printf("Client: client symkey:");
|
|
|
|
PA(pubkey+0,16);
|
|
|
|
puts("");
|
2003-05-05 06:27:00 +02:00
|
|
|
#endif
|
|
|
|
|
2003-07-30 21:12:03 +02:00
|
|
|
cipher = crypto_create_init_cipher(ONION_CIPHER, pubkey, iv, 1);
|
2003-05-05 06:27:00 +02:00
|
|
|
|
|
|
|
if (!cipher)
|
|
|
|
goto err;
|
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
if (crypto_pk_public_encrypt(dest_router_key, pubkey, pkbytes,
|
2003-05-05 06:27:00 +02:00
|
|
|
onion_skin_out, RSA_NO_PADDING)==-1)
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
|
|
|
|
2003-05-05 06:27:00 +02:00
|
|
|
if (crypto_cipher_encrypt(cipher, pubkey+pkbytes, dhbytes+16-pkbytes,
|
2003-05-01 21:42:51 +02:00
|
|
|
onion_skin_out+pkbytes))
|
|
|
|
goto err;
|
2003-11-12 03:32:20 +01:00
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
free(pubkey);
|
|
|
|
crypto_free_cipher_env(cipher);
|
|
|
|
*handshake_state_out = dh;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
return 0;
|
|
|
|
err:
|
2003-10-21 11:48:17 +02:00
|
|
|
tor_free(pubkey);
|
2003-05-01 21:42:51 +02:00
|
|
|
if (dh) crypto_dh_free(dh);
|
|
|
|
if (cipher) crypto_free_cipher_env(cipher);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given an encrypted DH public key as generated by onion_skin_create,
|
2003-05-26 08:03:16 +02:00
|
|
|
* and the private key for this onion router, generate the 128-byte DH
|
2003-05-01 21:42:51 +02:00
|
|
|
* reply, and key_out_len bytes of key material, stored in key_out.
|
|
|
|
*/
|
|
|
|
int
|
2003-05-06 07:54:42 +02:00
|
|
|
onion_skin_server_handshake(char *onion_skin, /* DH_ONIONSKIN_LEN bytes long */
|
2003-05-01 21:42:51 +02:00
|
|
|
crypto_pk_env_t *private_key,
|
2003-05-06 07:54:42 +02:00
|
|
|
char *handshake_reply_out, /* DH_KEY_LEN bytes long */
|
2003-05-01 21:42:51 +02:00
|
|
|
char *key_out,
|
|
|
|
int key_out_len)
|
|
|
|
{
|
2003-05-06 07:54:42 +02:00
|
|
|
char buf[DH_ONIONSKIN_LEN];
|
2003-05-01 21:42:51 +02:00
|
|
|
char iv[16];
|
|
|
|
crypto_dh_env_t *dh = NULL;
|
|
|
|
crypto_cipher_env_t *cipher = NULL;
|
|
|
|
int pkbytes;
|
2003-06-14 03:30:53 +02:00
|
|
|
int len;
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
memset(iv, 0, 16);
|
|
|
|
pkbytes = crypto_pk_keysize(private_key);
|
|
|
|
|
|
|
|
if (crypto_pk_private_decrypt(private_key,
|
|
|
|
onion_skin, pkbytes,
|
2003-05-05 06:27:00 +02:00
|
|
|
buf, RSA_NO_PADDING) == -1)
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Server: client symkey:");
|
|
|
|
PA(buf+0,16);
|
|
|
|
puts("");
|
2003-05-05 06:27:00 +02:00
|
|
|
#endif
|
2003-05-01 21:42:51 +02:00
|
|
|
|
2003-07-30 21:12:03 +02:00
|
|
|
cipher = crypto_create_init_cipher(ONION_CIPHER, buf, iv, 0);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
2003-05-06 07:54:42 +02:00
|
|
|
if (crypto_cipher_decrypt(cipher, onion_skin+pkbytes, DH_ONIONSKIN_LEN-pkbytes,
|
2003-05-01 21:42:51 +02:00
|
|
|
buf+pkbytes))
|
|
|
|
goto err;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Server: client g^x:");
|
|
|
|
PA(buf+16,3);
|
|
|
|
printf("...");
|
|
|
|
PA(buf+141,3);
|
|
|
|
puts("");
|
2003-05-05 06:27:00 +02:00
|
|
|
#endif
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
dh = crypto_dh_new();
|
2003-05-06 07:54:42 +02:00
|
|
|
if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN))
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Server: server g^y:");
|
|
|
|
PA(handshake_reply_out+0,3);
|
|
|
|
printf("...");
|
|
|
|
PA(handshake_reply_out+125,3);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-07-30 21:12:03 +02:00
|
|
|
len = crypto_dh_compute_secret(dh, buf+16, DH_KEY_LEN, key_out, key_out_len);
|
2003-06-14 03:30:53 +02:00
|
|
|
if (len < 0)
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
2003-06-14 03:34:39 +02:00
|
|
|
printf("Server: key material:");
|
|
|
|
PA(buf, DH_KEY_LEN);
|
|
|
|
puts("");
|
2003-06-13 23:23:14 +02:00
|
|
|
printf("Server: keys out:");
|
|
|
|
PA(key_out, key_out_len);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
crypto_free_cipher_env(cipher);
|
|
|
|
crypto_dh_free(dh);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
if (cipher) crypto_free_cipher_env(cipher);
|
|
|
|
if (dh) crypto_dh_free(dh);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finish the client side of the DH handshake.
|
2003-05-26 08:03:16 +02:00
|
|
|
* Given the 128 byte DH reply as generated by onion_skin_server_handshake
|
2003-05-01 21:42:51 +02:00
|
|
|
* and the handshake state generated by onion_skin_create, generate
|
|
|
|
* key_out_len bytes of shared key material and store them in key_out.
|
|
|
|
*
|
|
|
|
* After the invocation, call crypto_dh_free on handshake_state.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
onion_skin_client_handshake(crypto_dh_env_t *handshake_state,
|
2003-05-06 07:54:42 +02:00
|
|
|
char *handshake_reply,/* Must be DH_KEY_LEN bytes long*/
|
2003-05-01 21:42:51 +02:00
|
|
|
char *key_out,
|
|
|
|
int key_out_len)
|
|
|
|
{
|
2003-06-14 03:30:53 +02:00
|
|
|
int len;
|
2003-05-06 07:54:42 +02:00
|
|
|
assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Client: server g^y:");
|
|
|
|
PA(handshake_reply+0,3);
|
|
|
|
printf("...");
|
|
|
|
PA(handshake_reply+125,3);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-06-14 03:30:53 +02:00
|
|
|
len = crypto_dh_compute_secret(handshake_state, handshake_reply, DH_KEY_LEN,
|
2003-07-30 21:12:03 +02:00
|
|
|
key_out, key_out_len);
|
2003-06-14 03:30:53 +02:00
|
|
|
if (len < 0)
|
2003-05-01 21:42:51 +02:00
|
|
|
return -1;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Client: keys out:");
|
|
|
|
PA(key_out, key_out_len);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-07 04:12:02 +02:00
|
|
|
/*
|
|
|
|
Local Variables:
|
|
|
|
mode:c
|
|
|
|
indent-tabs-mode:nil
|
|
|
|
c-basic-offset:2
|
|
|
|
End:
|
|
|
|
*/
|