[or-cvs] For hidden services: handle INTRODUCE2, send ESTABLISH_INTR...
Nick Mathewson
nickm at seul.org
Thu Apr 1 22:21:03 UTC 2004
Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv30152/src/or
Modified Files:
circuit.c onion.c or.h rendservice.c
Log Message:
For hidden services: handle INTRODUCE2, send ESTABLISH_INTRO, RENDEZVOUS1.
Also:
- Add a pending final cpath element to build_state
- Rename S_RENDEZVOUSING to S_CONNECT_REND
- Add [CS]_REND_JOINED
- Split out logic to initialize cpath crypto objects.
- Have circuits/cpaths remember the KH element from their handshake, so they
can use it for other authentication later. (As in ESTABLISH_INTRO)
Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.167
retrieving revision 1.168
diff -u -d -r1.167 -r1.168
--- circuit.c 1 Apr 2004 20:33:28 -0000 1.167
+++ circuit.c 1 Apr 2004 22:21:01 -0000 1.168
@@ -129,8 +129,8 @@
crypto_free_digest_env(circ->p_digest);
if(circ->build_state) {
tor_free(circ->build_state->chosen_exit);
- if (circ->build_state->rend_handshake_state)
- crypto_dh_free(circ->build_state->rend_handshake_state);
+ if (circ->build_state->pending_final_cpath)
+ circuit_free_cpath_node(circ->build_state->pending_final_cpath);
}
tor_free(circ->build_state);
circuit_free_cpath(circ->cpath);
@@ -997,7 +997,7 @@
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at Bob, waiting for introductions */
- // do nothing?
+ rend_service_intro_is_ready(circ);
break;
case CIRCUIT_PURPOSE_C_INTRODUCING:
/* at Alice, connecting to intro point */
@@ -1007,9 +1007,9 @@
/* at Alice, waiting for Bob */
// alice launches a circuit to bob's intro point
break;
- case CIRCUIT_PURPOSE_S_RENDEZVOUSING:
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
/* at Bob, connecting to rend point */
- // bob sends rend2 cell
+ rend_service_rendezvous_is_ready(circ);
break;
}
}
@@ -1042,7 +1042,7 @@
/* at Alice, waiting for Bob */
// alice needs to pick a new rend point
break;
- case CIRCUIT_PURPOSE_S_RENDEZVOUSING:
+ case CIRCUIT_PURPOSE_S_CONNECT_REND:
/* at Bob, connecting to rend point */
//
break;
@@ -1308,13 +1308,50 @@
return 0;
}
-int circuit_finish_handshake(circuit_t *circ, char *reply) {
+/* Initialize cpath->{f|b}_{crypto|digest} from the key material in
+ * key_data. key_data must contain CPATH_KEY_MATERIAL bytes, which are
+ * used as follows:
+ * 20 to initialize f_digest
+ * 20 to initialize b_digest
+ * 16 to key f_crypto
+ * 16 to key b_crypto
+ */
+int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data)
+{
unsigned char iv[16];
- unsigned char keys[40+32];
- crypt_path_t *hop;
+ assert(cpath && key_data);
+ assert(!(cpath->f_crypto || cpath->b_crypto ||
+ cpath->f_digest || cpath->b_digest));
memset(iv, 0, 16);
+ log_fn(LOG_DEBUG,"hop init digest forward 0x%.8x, backward 0x%.8x.",
+ (unsigned int)*(uint32_t*)key_data, (unsigned int)*(uint32_t*)(key_data+20));
+ cpath->f_digest = crypto_new_digest_env(CRYPTO_SHA1_DIGEST);
+ crypto_digest_add_bytes(cpath->f_digest, key_data, 20);
+ cpath->b_digest = crypto_new_digest_env(CRYPTO_SHA1_DIGEST);
+ crypto_digest_add_bytes(cpath->b_digest, key_data+20, 20);
+
+ log_fn(LOG_DEBUG,"hop init cipher forward 0x%.8x, backward 0x%.8x.",
+ (unsigned int)*(uint32_t*)(key_data+40), (unsigned int)*(uint32_t*)(key_data+40+16));
+ if (!(cpath->f_crypto =
+ crypto_create_init_cipher(CIRCUIT_CIPHER,key_data+40,iv,1))) {
+ log(LOG_WARN,"forward cipher initialization failed.");
+ return -1;
+ }
+ if (!(cpath->b_crypto =
+ crypto_create_init_cipher(CIRCUIT_CIPHER,key_data+40+16,iv,0))) {
+ log(LOG_WARN,"backward cipher initialization failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+int circuit_finish_handshake(circuit_t *circ, char *reply) {
+ unsigned char keys[CPATH_KEY_MATERIAL_LEN];
+ crypt_path_t *hop;
+
assert(circ->cpath);
if(circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath;
@@ -1336,24 +1373,10 @@
crypto_dh_free(hop->handshake_state); /* don't need it anymore */
hop->handshake_state = NULL;
+ /* Remember hash of g^xy */
+ memcpy(hop->handshake_digest, reply+DH_KEY_LEN, CRYPTO_SHA1_DIGEST_LEN);
- log_fn(LOG_DEBUG,"hop init digest forward 0x%.8x, backward 0x%.8x.",
- (unsigned int)*(uint32_t*)keys, (unsigned int)*(uint32_t*)(keys+20));
- hop->f_digest = crypto_new_digest_env(CRYPTO_SHA1_DIGEST);
- crypto_digest_add_bytes(hop->f_digest, keys, 20);
- hop->b_digest = crypto_new_digest_env(CRYPTO_SHA1_DIGEST);
- crypto_digest_add_bytes(hop->b_digest, keys+20, 20);
-
- log_fn(LOG_DEBUG,"hop init cipher forward 0x%.8x, backward 0x%.8x.",
- (unsigned int)*(uint32_t*)(keys+40), (unsigned int)*(uint32_t*)(keys+40+16));
- if (!(hop->f_crypto =
- crypto_create_init_cipher(CIRCUIT_CIPHER,keys+40,iv,1))) {
- log(LOG_WARN,"forward cipher initialization failed.");
- return -1;
- }
- if (!(hop->b_crypto =
- crypto_create_init_cipher(CIRCUIT_CIPHER,keys+40+16,iv,0))) {
- log(LOG_WARN,"backward cipher initialization failed.");
+ if (circuit_init_cpath_crypto(hop, keys)<0) {
return -1;
}
Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.136
retrieving revision 1.137
diff -u -d -r1.136 -r1.137
--- onion.c 1 Apr 2004 20:33:28 -0000 1.136
+++ onion.c 1 Apr 2004 22:21:01 -0000 1.137
@@ -156,6 +156,8 @@
return -1;
}
+ memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, CRYPTO_SHA1_DIGEST_LEN);
+
connection_or_write_cell_to_buf(&cell, circ->p_conn);
log_fn(LOG_DEBUG,"Finished sending 'created' cell.");
@@ -465,6 +467,19 @@
}
}
+void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop)
+{
+ if (*head_ptr) {
+ new_hop->next = (*head_ptr);
+ new_hop->prev = (*head_ptr)->prev;
+ (*head_ptr)->prev->next = new_hop;
+ (*head_ptr)->prev = new_hop;
+ } else {
+ *head_ptr = new_hop;
+ new_hop->prev = new_hop->next = new_hop;
+ }
+}
+
int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, routerinfo_t **router_out)
{
int cur_len;
@@ -554,15 +569,7 @@
hop = (crypt_path_t *)tor_malloc_zero(sizeof(crypt_path_t));
/* 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;
- }
+ onion_append_to_cpath(head_ptr, hop);
hop->state = CPATH_STATE_CLOSED;
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.277
retrieving revision 1.278
diff -u -d -r1.277 -r1.278
--- or.h 1 Apr 2004 21:32:01 -0000 1.277
+++ or.h 1 Apr 2004 22:21:01 -0000 1.278
@@ -207,8 +207,10 @@
#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 6 /* at Bob, waiting for introductions */
#define CIRCUIT_PURPOSE_C_INTRODUCING 7 /* at Alice, connecting to intro point */
#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 8 /* at Alice, waiting for Bob */
-#define CIRCUIT_PURPOSE_S_RENDEZVOUSING 9 /* at Bob, connecting to rend point */
-#define _CIRCUIT_PURPOSE_MAX 9
+#define CIRCUIT_PURPOSE_S_CONNECT_REND 9 /* at Bob, connecting to rend point */
+#define CIRCUIT_PURPOSE_C_REND_JOINED 10 /* at Alice, rendezvous established.*/
+#define CIRCUIT_PURPOSE_S_REND_JOINED 11 /* at Bob, rendezvous established.*/
+#define _CIRCUIT_PURPOSE_MAX 11
#define RELAY_COMMAND_BEGIN 1
#define RELAY_COMMAND_DATA 2
@@ -477,6 +479,7 @@
crypto_digest_env_t *b_digest;
crypto_dh_env_t *handshake_state;
+ char handshake_digest[CRYPTO_SHA1_DIGEST];/* KH in tor-spec.txt */
uint32_t addr;
uint16_t port;
@@ -501,9 +504,10 @@
typedef struct {
int desired_path_len;
- char *chosen_exit; /* nickname of planned exit node */
- crypto_dh_env_t *rend_handshake_state; /*XXXXDOCDOC*/
- unsigned char rend_key_material[52]; /*XXXXDOCDOC*/
+ /* nickname of planned exit node */
+ char *chosen_exit;
+ /* cpath to append after rendezvous. */
+ struct crypt_path_t *pending_final_cpath;
} cpath_build_state_t;
/* struct for a path (circuit) through the network */
@@ -538,6 +542,8 @@
crypt_path_t *cpath;
char onionskin[ONIONSKIN_CHALLENGE_LEN]; /* for storage while onionskin pending */
+ char handshake_digest[CRYPTO_SHA1_DIGEST_LEN]; /* Stores KH for intermediate hops */
+
time_t timestamp_created;
time_t timestamp_dirty; /* when the circuit was first used, or 0 if clean */
@@ -714,6 +720,8 @@
void circuit_n_conn_open(connection_t *or_conn);
int circuit_send_next_onion_skin(circuit_t *circ);
int circuit_extend(cell_t *cell, circuit_t *circ);
+#define CPATH_KEY_MATERIAL_LEN (20*2+16*2)
+int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data);
int circuit_finish_handshake(circuit_t *circ, char *reply);
int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
@@ -917,6 +925,8 @@
int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys);
+
+void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state,
routerinfo_t **router_out);
@@ -1038,6 +1048,9 @@
int rend_service_init_keys(void);
int rend_services_init(void);
+void rend_service_intro_is_ready(circuit_t *circuit);
+void rend_service_rendezvous_is_ready(circuit_t *circuit);
+
#endif
/*
Index: rendservice.c
===================================================================
RCS file: /home/or/cvsroot/src/or/rendservice.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- rendservice.c 1 Apr 2004 20:05:57 -0000 1.6
+++ rendservice.c 1 Apr 2004 22:21:01 -0000 1.7
@@ -264,16 +264,20 @@
char shared_secret[128];
} rend_introduction_t;
+/* Respond to an INTRODUCE2 cell by launching a circuit to the chosen
+ * rendezvous points.
+ */
int
rend_service_introduce(circuit_t *circuit, char *request, int request_len)
{
char *ptr, *rp_nickname, *r_cookie;
char buf[RELAY_PAYLOAD_SIZE];
- char secret[20+2*16]; /* Holds KH, Kf, Kb */
+ char keys[20+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
rend_service_t *service;
int len, keylen;
crypto_dh_env_t *dh = NULL;
circuit_t *launched = NULL;
+ crypt_path_t *cpath = NULL;
if (circuit->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_fn(LOG_WARN, "Got an INTRODUCE2 over a non-introduction circuit.");
@@ -334,14 +338,15 @@
log_fn(LOG_WARN, "Couldn't build DH state or generate public key");
goto err;
}
- if (crypto_dh_compute_secret(dh, ptr+20, 128, secret, 20+16*2)<0) {
+ if (crypto_dh_compute_secret(dh, ptr+20, DH_KEY_LEN, keys,
+ 20+CPATH_KEY_MATERIAL_LEN)<0) {
log_fn(LOG_WARN, "Couldn't complete DH handshake");
goto err;
}
/* Launch a circuit to alice's chosen rendezvous point.
*/
- launched = circuit_launch_new(CIRCUIT_PURPOSE_S_RENDEZVOUSING, rp_nickname);
+ launched = circuit_launch_new(CIRCUIT_PURPOSE_S_CONNECT_REND, rp_nickname);
if (!launched) {
log_fn(LOG_WARN, "Can't launch circuit to rendezvous point '%s'",
rp_nickname);
@@ -351,9 +356,14 @@
/* Fill in the circuit's state. */
memcpy(launched->rend_service, circuit->rend_service,CRYPTO_SHA1_DIGEST_LEN);
memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN);
- memcpy(launched->build_state->rend_key_material, secret, 20+16*2);
- launched->build_state->rend_handshake_state = dh;
+ launched->build_state->pending_final_cpath = cpath =
+ tor_malloc_zero(sizeof(crypt_path_t));
+
+ cpath->handshake_state = dh;
dh = NULL;
+ if (circuit_init_cpath_crypto(cpath,keys+20)<0)
+ goto err;
+ memcpy(cpath->handshake_digest, keys, 20);
return 0;
err:
@@ -362,24 +372,144 @@
return -1;
}
+/* Launch a circuit to serve as an introduction point.
+ */
+static int
+rend_service_launch_establish_intro(rend_service_t *service, char *nickname)
+{
+ circuit_t *launched;
+
+ assert(service && nickname);
+
+ launched = circuit_launch_new(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, nickname);
+ if (!launched) {
+ log_fn(LOG_WARN, "Can't launch circuit to establish introduction at '%s'",
+ nickname);
+ return -1;
+ }
+ memcpy(launched->rend_service, service->pk_digest, CRYPTO_SHA1_DIGEST_LEN);
+
+ return 0;
+}
+
+/* Called when we're done building a circuit to an introduction point:
+ * sends a RELAY_ESTABLISH_INTRO cell.
+ */
+void
+rend_service_intro_is_ready(circuit_t *circuit)
+{
+ rend_service_t *service;
+ int len, r;
+ char buf[RELAY_PAYLOAD_SIZE];
+ char auth[CRYPTO_SHA1_DIGEST_LEN + 10];
+
+ assert(circuit->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
+ assert(circuit->cpath);
+ service = rend_service_get_by_pk_digest(circuit->rend_service);
+ if (!service) {
+ log_fn(LOG_WARN, "Internal error: unrecognized service ID on introduction circuit");
+ goto err;
+ }
+
+ /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
+ len = crypto_pk_asn1_encode(service->private_key, buf+2,
+ RELAY_PAYLOAD_SIZE-2);
+ set_uint16(buf, len);
+ len += 2;
+ memcpy(auth, circuit->cpath->prev->handshake_digest, CRYPTO_SHA1_DIGEST_LEN);
+ memcpy(auth+CRYPTO_SHA1_DIGEST_LEN, "INTRODUCE", 9);
+ if (crypto_SHA_digest(auth, CRYPTO_SHA1_DIGEST_LEN+9, buf+len))
+ goto err;
+ len += 20;
+ r = crypto_pk_private_sign_digest(service->private_key, buf, len, buf+len);
+ if (r<0) {
+ log_fn(LOG_WARN, "Couldn't sign introduction request");
+ goto err;
+ }
+ len += r;
+
+ if (connection_edge_send_command(NULL, circuit,RELAY_COMMAND_ESTABLISH_INTRO,
+ buf, len, circuit->cpath->prev)<0) {
+ log_fn(LOG_WARN, "Couldn't send introduction request");
+ goto err;
+ }
+
+ return;
+ err:
+ circuit_mark_for_close(circuit);
+}
+
+/* Called once a circuit to a rendezvous point is ready: sends a
+ * RELAY_COMMAND_RENDEZVOUS1 cell.
+ */
+void
+rend_service_rendezvous_is_ready(circuit_t *circuit)
+{
+ rend_service_t *service;
+ char buf[RELAY_PAYLOAD_SIZE];
+ crypt_path_t *hop;
+
+ assert(circuit->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ assert(circuit->cpath);
+ assert(circuit->build_state);
+ hop = circuit->build_state->pending_final_cpath;
+ assert(hop);
+
+ service = rend_service_get_by_pk_digest(circuit->rend_service);
+ if (!service) {
+ log_fn(LOG_WARN, "Internal error: unrecognized service ID on introduction circuit");
+ goto err;
+ }
+
+ /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
+ memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN);
+ if (crypto_dh_get_public(hop->handshake_state,
+ buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
+ log_fn(LOG_WARN,"Couldn't get DH public key");
+ goto err;
+ }
+ memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->handshake_digest,
+ CRYPTO_SHA1_DIGEST_LEN);
+
+ /* Send the cell */
+ if (connection_edge_send_command(NULL, circuit, RELAY_COMMAND_RENDEZVOUS1,
+ buf, REND_COOKIE_LEN+DH_KEY_LEN+1,
+ circuit->cpath->prev)<0) {
+ log_fn(LOG_WARN, "Couldn't send RENDEZVOUS1 cell");
+ goto err;
+ }
+
+ /* Append the cpath entry. */
+ onion_append_to_cpath(&circuit->cpath, hop);
+ circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
+
+ /* Change the circuit purpose. */
+ circuit->purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
+
+ return;
+ err:
+ circuit_mark_for_close(circuit);
+}
+
/******
* Manage introduction points
******/
#define NUM_INTRO_POINTS 3
int rend_services_init(void) {
- int i;
+ int i,j,r;
routerinfo_t *router;
routerlist_t *rl;
- circuit_t *circ;
+ rend_service_t *service;
router_get_routerlist(&rl);
- //for each of bob's services,
+ for (i=0;i<rend_service_list->num_used;++i) {
+ service = rend_service_list->list[i];
/* The directory is now here. Pick three ORs as intro points. */
- for (i=0;i<rl->n_routers;i++) {
- router = rl->routers[i];
+ for (j=0;j<rl->n_routers;j++) {
+ router = rl->routers[j];
//...
// maybe built a smartlist of all of them, then pick at random
// until you have three? or something smarter.
@@ -393,11 +523,12 @@
// for each intro point,
{
- //circ = circuit_launch_new(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, intro->nickname);
- // tell circ which hidden service this is about
+ //r = rend_service_launch_establish_intro(service, intro->nickname);
+ //if (r<0) freak out
}
// anything else?
+ }
}
/*
More information about the tor-commits
mailing list