[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