terminology shift:
[tor.git] / src / or / onion.c
blob168a41387b7cc705e06e3cb13dedc1f132a93804
1 /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
5 #include "or.h"
7 extern or_options_t options; /* command-line and config-file options */
9 static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len);
11 int decide_circ_id_type(char *local_nick, char *remote_nick) {
12 int result;
14 assert(remote_nick);
15 if(!local_nick)
16 return CIRC_ID_TYPE_LOWER;
17 result = strcmp(local_nick, remote_nick);
18 assert(result);
19 if(result < 0)
20 return CIRC_ID_TYPE_LOWER;
21 return CIRC_ID_TYPE_HIGHER;
24 struct onion_queue_t {
25 circuit_t *circ;
26 struct onion_queue_t *next;
29 /* global (within this file) variables used by the next few functions */
30 static struct onion_queue_t *ol_list=NULL;
31 static struct onion_queue_t *ol_tail=NULL;
32 static int ol_length=0;
34 int onion_pending_add(circuit_t *circ) {
35 struct onion_queue_t *tmp;
37 tmp = tor_malloc_zero(sizeof(struct onion_queue_t));
38 tmp->circ = circ;
40 if(!ol_tail) {
41 assert(!ol_list);
42 assert(!ol_length);
43 ol_list = tmp;
44 ol_tail = tmp;
45 ol_length++;
46 return 0;
49 assert(ol_list);
50 assert(!ol_tail->next);
52 if(ol_length >= options.MaxOnionsPending) {
53 log_fn(LOG_WARN,"Already have %d onions queued. Closing.", ol_length);
54 free(tmp);
55 return -1;
58 ol_length++;
59 ol_tail->next = tmp;
60 ol_tail = tmp;
61 return 0;
65 circuit_t *onion_next_task(void) {
66 circuit_t *circ;
68 if(!ol_list)
69 return NULL; /* no onions pending, we're done */
71 assert(ol_list->circ);
72 assert(ol_list->circ->p_conn); /* make sure it's still valid */
73 #if 0
74 if(!ol_list->circ->p_conn) {
75 log_fn(LOG_INFO,"ol_list->circ->p_conn null, must have died?");
76 onion_pending_remove(ol_list->circ);
77 return onion_next_task(); /* recurse: how about the next one? */
79 #endif
81 assert(ol_length > 0);
82 circ = ol_list->circ;
83 onion_pending_remove(ol_list->circ);
84 return circ;
87 /* go through ol_list, find the onion_queue_t element which points to
88 * circ, remove and free that element. leave circ itself alone.
90 void onion_pending_remove(circuit_t *circ) {
91 struct onion_queue_t *tmpo, *victim;
93 if(!ol_list)
94 return; /* nothing here. */
96 /* first check to see if it's the first entry */
97 tmpo = ol_list;
98 if(tmpo->circ == circ) {
99 /* it's the first one. remove it from the list. */
100 ol_list = tmpo->next;
101 if(!ol_list)
102 ol_tail = NULL;
103 ol_length--;
104 victim = tmpo;
105 } else { /* we need to hunt through the rest of the list */
106 for( ;tmpo->next && tmpo->next->circ != circ; tmpo=tmpo->next) ;
107 if(!tmpo->next) {
108 log_fn(LOG_DEBUG,"circ (p_circ_id %d) not in list, probably at cpuworker.",circ->p_circ_id);
109 return;
111 /* now we know tmpo->next->circ == circ */
112 victim = tmpo->next;
113 tmpo->next = victim->next;
114 if(ol_tail == victim)
115 ol_tail = tmpo;
116 ol_length--;
119 /* now victim points to the element that needs to be removed */
121 free(victim);
124 /* given a response payload and keys, initialize, then send a created cell back */
125 int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys) {
126 unsigned char iv[16];
127 cell_t cell;
129 memset(iv, 0, 16);
131 memset(&cell, 0, sizeof(cell_t));
132 cell.command = CELL_CREATED;
133 cell.circ_id = circ->p_circ_id;
134 cell.length = DH_KEY_LEN;
136 circ->state = CIRCUIT_STATE_OPEN;
138 log_fn(LOG_DEBUG,"Entering.");
140 memcpy(cell.payload, payload, DH_KEY_LEN);
142 log_fn(LOG_DEBUG,"init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16));
144 if (!(circ->n_crypto =
145 crypto_create_init_cipher(CIRCUIT_CIPHER,keys,iv,0))) {
146 log_fn(LOG_WARN,"Cipher initialization failed (n).");
147 return -1;
150 if (!(circ->p_crypto =
151 crypto_create_init_cipher(CIRCUIT_CIPHER,keys+16,iv,1))) {
152 log_fn(LOG_WARN,"Cipher initialization failed (p).");
153 return -1;
156 connection_or_write_cell_to_buf(&cell, circ->p_conn);
157 log_fn(LOG_DEBUG,"Finished sending 'created' cell.");
159 return 0;
162 char **parse_nickname_list(char *list, int *num) {
163 char **out;
164 char *start,*end;
165 int i;
167 while(isspace(*list)) list++;
169 i=0, start = list;
170 while(*start) {
171 while(*start && !isspace(*start)) start++;
172 i++;
173 while(isspace(*start)) start++;
176 out = tor_malloc(i * sizeof(char *));
178 i=0, start=list;
179 while(*start) {
180 end=start; while(*end && !isspace(*end)) end++;
181 out[i] = tor_malloc(MAX_NICKNAME_LEN);
182 strncpy(out[i],start,end-start);
183 out[i][end-start] = 0; /* null terminate it */
184 i++;
185 while(isspace(*end)) end++;
186 start = end;
188 *num = i;
189 return out;
192 static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) {
193 int num_acceptable_routers;
194 int routelen;
196 assert((cw >= 0) && (cw < 1) && rarray); /* valid parameters */
198 for(routelen=3; ; routelen++) { /* 3, increment until coinflip says we're done */
199 if (crypto_pseudo_rand_int(255) >= cw*255) /* don't extend */
200 break;
202 log_fn(LOG_DEBUG,"Chosen route length %d (%d routers available).",routelen, rarray_len);
204 num_acceptable_routers = count_acceptable_routers(rarray, rarray_len);
206 if(num_acceptable_routers < 2) {
207 log_fn(LOG_INFO,"Not enough acceptable routers. Failing.");
208 return -1;
211 if(num_acceptable_routers < routelen) {
212 log_fn(LOG_INFO,"Not enough routers: cutting routelen from %d to %d.",routelen, num_acceptable_routers);
213 routelen = num_acceptable_routers;
216 if (routelen < 1) {
217 log_fn(LOG_WARN,"Didn't find any acceptable routers. Failing.");
218 return -1;
221 return routelen;
224 static routerinfo_t *choose_good_exit_server(routerlist_t *dir)
226 int *n_supported;
227 int *n_maybe_supported;
228 int i, j;
229 int n_pending_connections = 0;
230 connection_t **carray;
231 int n_connections;
232 int best_support = -1;
233 int best_maybe_support = -1;
234 int best_support_idx = -1;
235 int best_maybe_support_idx = -1;
236 int n_best_support=0, n_best_maybe_support=0;
237 int n_running_routers=0;
239 get_connection_array(&carray, &n_connections);
241 /* Count how many connections are waiting for a circuit to be built.
242 * We use this for log messages now, but in the future we may depend on it.
244 for (i = 0; i < n_connections; ++i) {
245 if (carray[i]->type == CONN_TYPE_AP &&
246 carray[i]->state == AP_CONN_STATE_CIRCUIT_WAIT &&
247 !carray[i]->marked_for_close)
248 ++n_pending_connections;
250 log_fn(LOG_DEBUG, "Choosing exit node; %d connections are pending",
251 n_pending_connections);
252 /* Now we count, for each of the routers in the directory: how many
253 * of the pending connections could _definitely_ exit from that
254 * router (n_supported[i]) and how many could _possibly_ exit from
255 * that router (n_maybe_supported[i]). (We can't be sure about
256 * cases where we don't know the IP address of the pending
257 * connection.)
259 n_supported = tor_malloc(sizeof(int)*dir->n_routers);
260 n_maybe_supported = tor_malloc(sizeof(int)*dir->n_routers);
261 for (i = 0; i < dir->n_routers; ++i) { /* iterate over routers */
262 if(!dir->routers[i]->is_running) {
263 n_supported[i] = n_maybe_supported[i] = -1;
264 log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- directory says it's not running.",
265 dir->routers[i]->nickname, i);
266 continue; /* skip routers that are known to be down */
268 if(router_exit_policy_rejects_all(dir->routers[i])) {
269 n_supported[i] = n_maybe_supported[i] = -1;
270 log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.",
271 dir->routers[i]->nickname, i);
272 continue; /* skip routers that reject all */
274 n_supported[i] = n_maybe_supported[i] = 0;
275 ++n_running_routers;
276 for (j = 0; j < n_connections; ++j) { /* iterate over connections */
277 if (carray[j]->type != CONN_TYPE_AP ||
278 carray[j]->state != AP_CONN_STATE_CIRCUIT_WAIT ||
279 carray[j]->marked_for_close)
280 continue; /* Skip everything but APs in CIRCUIT_WAIT */
281 switch (connection_ap_can_use_exit(carray[j], dir->routers[i]))
283 case -1:
284 log_fn(LOG_DEBUG,"%s (index %d) would reject this stream.",
285 dir->routers[i]->nickname, i);
286 break; /* would be rejected; try next connection */
287 case 0:
288 ++n_supported[i];
289 log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.",
290 dir->routers[i]->nickname, i, n_supported[i]);
291 ; /* Fall through: If it is supported, it is also maybe supported. */
292 case 1:
293 ++n_maybe_supported[i];
294 log_fn(LOG_DEBUG,"%s is maybe supported. n_maybe_supported[%d] now %d.",
295 dir->routers[i]->nickname, i, n_maybe_supported[i]);
297 } /* End looping over connections. */
298 if (n_supported[i] > best_support) {
299 /* If this router is better than previous ones, remember its index
300 * and goodness, and start counting how many routers are this good. */
301 best_support = n_supported[i]; best_support_idx = i; n_best_support=1;
302 log_fn(LOG_DEBUG,"%s is new best supported option so far.",
303 dir->routers[i]->nickname);
304 } else if (n_supported[i] == best_support) {
305 /* If this router is _as good_ as the best one, just increment the
306 * count of equally good routers.*/
307 ++n_best_support;
309 /* As above, but for 'maybe-supported' connections */
310 if (n_maybe_supported[i] > best_maybe_support) {
311 best_maybe_support = n_maybe_supported[i]; best_maybe_support_idx = i;
312 n_best_maybe_support = 1;
313 log_fn(LOG_DEBUG,"%s is new best maybe-supported option so far.",
314 dir->routers[i]->nickname);
315 } else if (n_maybe_supported[i] == best_maybe_support) {
316 ++n_best_maybe_support;
319 log_fn(LOG_INFO, "Found %d servers that will definitely support %d/%d pending connections, and %d that might support %d/%d.",
320 n_best_support, best_support, n_pending_connections,
321 n_best_maybe_support, best_maybe_support, n_pending_connections);
322 /* If any routers definitely support any pending connections, choose one
323 * at random. */
324 if (best_support > 0) {
325 i = crypto_pseudo_rand_int(n_best_support);
326 /* Iterate over the routers, until we find the i-th one such that
327 * n_supported[j] == best_support
329 for (j = best_support_idx; j < dir->n_routers; ++j) {
330 if (n_supported[j] == best_support) {
331 if (i)
332 --i;
333 else {
334 tor_free(n_supported); tor_free(n_maybe_supported);
335 log_fn(LOG_DEBUG, "Chose exit server '%s'", dir->routers[j]->nickname);
336 return dir->routers[j];
340 /* This point should never be reached. */
341 assert(0);
343 /* If any routers _maybe_ support pending connections, choose one at
344 * random, as above. */
345 if (best_maybe_support > 0) {
346 i = crypto_pseudo_rand_int(n_best_maybe_support);
347 for (j = best_maybe_support_idx; j < dir->n_routers; ++j) {
348 if (n_maybe_supported[j] == best_maybe_support) {
349 if (i)
350 --i;
351 else {
352 tor_free(n_supported); tor_free(n_maybe_supported);
353 log_fn(LOG_DEBUG, "Chose exit server '%s'", dir->routers[j]->nickname);
354 return dir->routers[j];
358 /* This point should never be reached. */
359 assert(0);
361 /* Either there are no pending connections, or no routers even seem to
362 * possibly support any of them. Choose a router at random. */
363 if (!n_running_routers) {
364 log_fn(LOG_WARN, "No exit routers seem to be running; can't choose an exit.");
365 return NULL;
367 /* Iterate over the routers, till we find the i'th one that has ->is_running
368 * and allows exits. */
369 i = crypto_pseudo_rand_int(n_running_routers);
370 for (j = 0; j < dir->n_routers; ++j) {
371 if (n_supported[j] != -1) {
372 if (i)
373 --i;
374 else {
375 tor_free(n_supported); tor_free(n_maybe_supported);
376 log_fn(LOG_DEBUG, "Chose exit server '%s'", dir->routers[j]->nickname);
377 return dir->routers[j];
381 assert(0);
382 return NULL;
385 cpath_build_state_t *onion_new_cpath_build_state(void) {
386 routerlist_t *dir;
387 int r;
388 cpath_build_state_t *info;
389 routerinfo_t *exit;
391 router_get_routerlist(&dir);
392 r = new_route_len(options.PathlenCoinWeight, dir->routers, dir->n_routers);
393 if (r < 0)
394 return NULL;
395 exit = choose_good_exit_server(dir);
396 if(!exit)
397 return NULL;
398 info = tor_malloc(sizeof(cpath_build_state_t));
399 info->desired_path_len = r;
400 info->chosen_exit = tor_strdup(exit->nickname);
401 return info;
404 static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
405 int i, j;
406 int num=0;
407 connection_t *conn;
409 for(i=0;i<rarray_len;i++) {
410 log_fn(LOG_DEBUG,"Contemplating whether router %d is a new option...",i);
411 if(rarray[i]->is_running == 0) {
412 log_fn(LOG_DEBUG,"Nope, the directory says %d is not running.",i);
413 goto next_i_loop;
415 if(options.ORPort) {
416 conn = connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port);
417 if(!conn || conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) {
418 log_fn(LOG_DEBUG,"Nope, %d is not connected.",i);
419 goto next_i_loop;
422 for(j=0;j<i;j++) {
423 if(!crypto_pk_cmp_keys(rarray[i]->onion_pkey, rarray[j]->onion_pkey)) {
424 /* these guys are twins. so we've already counted him. */
425 log_fn(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j);
426 goto next_i_loop;
429 num++;
430 log_fn(LOG_DEBUG,"I like %d. num_acceptable_routers now %d.",i, num);
431 next_i_loop:
432 ; /* our compiler may need an explicit statement after the label */
435 return num;
438 int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, routerinfo_t **router_out)
440 int cur_len;
441 crypt_path_t *cpath, *hop;
442 routerinfo_t *r;
443 routerinfo_t *choice;
444 int i;
445 int n_failures;
447 assert(head_ptr);
448 assert(router_out);
450 if (!*head_ptr) {
451 cur_len = 0;
452 } else {
453 cur_len = 1;
454 for (cpath = *head_ptr; cpath->next != *head_ptr; cpath = cpath->next) {
455 ++cur_len;
458 if (cur_len >= state->desired_path_len) {
459 log_fn(LOG_DEBUG, "Path is complete: %d steps long",
460 state->desired_path_len);
461 return 1;
463 log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len,
464 state->desired_path_len);
466 n_failures = 0;
467 goto start;
468 again:
469 log_fn(LOG_DEBUG, "Picked an already-selected router for hop %d; retrying.",
470 cur_len);
471 ++n_failures;
472 if (n_failures == 25) {
473 /* This actually happens with P=1/30,000,000 when we _could_ build a
474 * circuit. For now, let's leave it in.
476 log_fn(LOG_INFO, "Unable to continue generating circuit path");
477 return -1;
479 start:
480 /* XXX through each of these, don't pick nodes that are down */
481 if(cur_len == 0) { /* picking entry node */
482 log_fn(LOG_DEBUG, "Contemplating first hop: random choice.");
483 choice = router_pick_randomly_from_running();
484 if(!choice) {
485 log_fn(LOG_WARN,"No routers are running while picking entry node. Failing.");
486 return -1;
488 } else if (cur_len == state->desired_path_len - 1) { /* Picking last node */
489 log_fn(LOG_DEBUG, "Contemplating last hop: choice already made.");
490 choice = router_get_by_nickname(state->chosen_exit);
491 if(!choice) {
492 log_fn(LOG_WARN,"Our chosen exit %s is no longer in the directory? Failing.",
493 state->chosen_exit);
494 return -1;
496 } else {
497 log_fn(LOG_DEBUG, "Contemplating intermediate hop: random choice.");
498 choice = router_pick_randomly_from_running();
499 if(!choice) {
500 log_fn(LOG_WARN,"No routers are running while picking intermediate node. Failing.");
501 return -1;
504 log_fn(LOG_DEBUG,"Contemplating router %s for hop %d (exit is %s)",
505 choice->nickname, cur_len, state->chosen_exit);
506 if (cur_len != state->desired_path_len-1 &&
507 !strcasecmp(choice->nickname, state->chosen_exit)) {
508 goto again;
511 for (i = 0, cpath = *head_ptr; i < cur_len; ++i, cpath=cpath->next) {
512 r = router_get_by_addr_port(cpath->addr, cpath->port);
513 if ((r && !crypto_pk_cmp_keys(r->onion_pkey, choice->onion_pkey))
514 || (cur_len != state->desired_path_len-1 &&
515 !strcasecmp(choice->nickname, state->chosen_exit))
516 || (cpath->addr == choice->addr &&
517 cpath->port == choice->or_port)
518 || (options.ORPort &&
519 !(connection_twin_get_by_addr_port(choice->addr,
520 choice->or_port)))) {
521 goto again;
525 /* Okay, so we haven't used 'choice' before. */
526 hop = (crypt_path_t *)tor_malloc_zero(sizeof(crypt_path_t));
528 /* link hop into the cpath, at the end. */
529 if (*head_ptr) {
530 hop->next = (*head_ptr);
531 hop->prev = (*head_ptr)->prev;
532 (*head_ptr)->prev->next = hop;
533 (*head_ptr)->prev = hop;
534 } else {
535 *head_ptr = hop;
536 hop->prev = hop->next = hop;
539 hop->state = CPATH_STATE_CLOSED;
541 hop->port = choice->or_port;
542 hop->addr = choice->addr;
544 hop->package_window = CIRCWINDOW_START;
545 hop->deliver_window = CIRCWINDOW_START;
547 log_fn(LOG_DEBUG, "Extended circuit path with %s for hop %d",
548 choice->nickname, cur_len);
550 *router_out = choice;
551 return 0;
554 /*----------------------------------------------------------------------*/
556 /* Given a router's public key, generates a 144-byte encrypted DH pubkey,
557 * and stores it into onion_skin out. Stores the DH private key into
558 * handshake_state_out for later completion of the handshake.
560 * The encrypted pubkey is formed as follows:
561 * 16 bytes of symmetric key
562 * 128 bytes of g^x for DH.
563 * The first 128 bytes are RSA-encrypted with the server's public key,
564 * and the last 16 are encrypted with the symmetric key.
567 onion_skin_create(crypto_pk_env_t *dest_router_key,
568 crypto_dh_env_t **handshake_state_out,
569 char *onion_skin_out) /* Must be DH_ONIONSKIN_LEN bytes long */
571 char iv[16];
572 char *pubkey = NULL;
573 crypto_dh_env_t *dh = NULL;
574 crypto_cipher_env_t *cipher = NULL;
575 int dhbytes, pkbytes;
577 *handshake_state_out = NULL;
578 memset(onion_skin_out, 0, DH_ONIONSKIN_LEN);
579 memset(iv, 0, 16);
581 if (!(dh = crypto_dh_new()))
582 goto err;
584 dhbytes = crypto_dh_get_bytes(dh);
585 pkbytes = crypto_pk_keysize(dest_router_key);
586 assert(dhbytes+16 == DH_ONIONSKIN_LEN);
587 pubkey = (char *)tor_malloc(dhbytes+16);
589 if (crypto_rand(16, pubkey))
590 goto err;
592 /* XXXX You can't just run around RSA-encrypting any bitstream: if it's
593 * greater than the RSA key, then OpenSSL will happily encrypt,
594 * and later decrypt to the wrong value. So we set the first bit
595 * of 'pubkey' to 0. This means that our symmetric key is really only
596 * 127 bits long, but since it shouldn't be necessary to encrypt
597 * DH public keys values in the first place, we should be fine.
599 pubkey[0] &= 0x7f;
601 if (crypto_dh_get_public(dh, pubkey+16, dhbytes))
602 goto err;
604 #ifdef DEBUG_ONION_SKINS
605 #define PA(a,n) \
606 { int _i; for (_i = 0; _i<n; ++_i) printf("%02x ",((int)(a)[_i])&0xFF); }
608 printf("Client: client g^x:");
609 PA(pubkey+16,3);
610 printf("...");
611 PA(pubkey+141,3);
612 puts("");
614 printf("Client: client symkey:");
615 PA(pubkey+0,16);
616 puts("");
617 #endif
619 cipher = crypto_create_init_cipher(ONION_CIPHER, pubkey, iv, 1);
621 if (!cipher)
622 goto err;
624 if (crypto_pk_public_encrypt(dest_router_key, pubkey, pkbytes,
625 onion_skin_out, RSA_NO_PADDING)==-1)
626 goto err;
628 if (crypto_cipher_encrypt(cipher, pubkey+pkbytes, dhbytes+16-pkbytes,
629 onion_skin_out+pkbytes))
630 goto err;
632 free(pubkey);
633 crypto_free_cipher_env(cipher);
634 *handshake_state_out = dh;
636 return 0;
637 err:
638 tor_free(pubkey);
639 if (dh) crypto_dh_free(dh);
640 if (cipher) crypto_free_cipher_env(cipher);
641 return -1;
644 /* Given an encrypted DH public key as generated by onion_skin_create,
645 * and the private key for this onion router, generate the 128-byte DH
646 * reply, and key_out_len bytes of key material, stored in key_out.
649 onion_skin_server_handshake(char *onion_skin, /* DH_ONIONSKIN_LEN bytes long */
650 crypto_pk_env_t *private_key,
651 char *handshake_reply_out, /* DH_KEY_LEN bytes long */
652 char *key_out,
653 int key_out_len)
655 char buf[DH_ONIONSKIN_LEN];
656 char iv[16];
657 crypto_dh_env_t *dh = NULL;
658 crypto_cipher_env_t *cipher = NULL;
659 int pkbytes;
660 int len;
662 memset(iv, 0, 16);
663 pkbytes = crypto_pk_keysize(private_key);
665 if (crypto_pk_private_decrypt(private_key,
666 onion_skin, pkbytes,
667 buf, RSA_NO_PADDING) == -1)
668 goto err;
670 #ifdef DEBUG_ONION_SKINS
671 printf("Server: client symkey:");
672 PA(buf+0,16);
673 puts("");
674 #endif
676 cipher = crypto_create_init_cipher(ONION_CIPHER, buf, iv, 0);
678 if (crypto_cipher_decrypt(cipher, onion_skin+pkbytes, DH_ONIONSKIN_LEN-pkbytes,
679 buf+pkbytes))
680 goto err;
682 #ifdef DEBUG_ONION_SKINS
683 printf("Server: client g^x:");
684 PA(buf+16,3);
685 printf("...");
686 PA(buf+141,3);
687 puts("");
688 #endif
690 dh = crypto_dh_new();
691 if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN))
692 goto err;
694 #ifdef DEBUG_ONION_SKINS
695 printf("Server: server g^y:");
696 PA(handshake_reply_out+0,3);
697 printf("...");
698 PA(handshake_reply_out+125,3);
699 puts("");
700 #endif
702 len = crypto_dh_compute_secret(dh, buf+16, DH_KEY_LEN, key_out, key_out_len);
703 if (len < 0)
704 goto err;
706 #ifdef DEBUG_ONION_SKINS
707 printf("Server: key material:");
708 PA(buf, DH_KEY_LEN);
709 puts("");
710 printf("Server: keys out:");
711 PA(key_out, key_out_len);
712 puts("");
713 #endif
715 crypto_free_cipher_env(cipher);
716 crypto_dh_free(dh);
717 return 0;
718 err:
719 if (cipher) crypto_free_cipher_env(cipher);
720 if (dh) crypto_dh_free(dh);
722 return -1;
725 /* Finish the client side of the DH handshake.
726 * Given the 128 byte DH reply as generated by onion_skin_server_handshake
727 * and the handshake state generated by onion_skin_create, generate
728 * key_out_len bytes of shared key material and store them in key_out.
730 * After the invocation, call crypto_dh_free on handshake_state.
733 onion_skin_client_handshake(crypto_dh_env_t *handshake_state,
734 char *handshake_reply,/* Must be DH_KEY_LEN bytes long*/
735 char *key_out,
736 int key_out_len)
738 int len;
739 assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN);
741 #ifdef DEBUG_ONION_SKINS
742 printf("Client: server g^y:");
743 PA(handshake_reply+0,3);
744 printf("...");
745 PA(handshake_reply+125,3);
746 puts("");
747 #endif
749 len = crypto_dh_compute_secret(handshake_state, handshake_reply, DH_KEY_LEN,
750 key_out, key_out_len);
751 if (len < 0)
752 return -1;
754 #ifdef DEBUG_ONION_SKINS
755 printf("Client: keys out:");
756 PA(key_out, key_out_len);
757 puts("");
758 #endif
760 return 0;
764 Local Variables:
765 mode:c
766 indent-tabs-mode:nil
767 c-basic-offset:2
768 End: