|
@@ -264,16 +264,20 @@ typedef struct rend_introduction_t {
|
|
|
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 @@ rend_service_introduce(circuit_t *circuit, char *request, int request_len)
|
|
|
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 @@ rend_service_introduce(circuit_t *circuit, char *request, int request_len)
|
|
|
/* 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 @@ rend_service_introduce(circuit_t *circuit, char *request, int request_len)
|
|
|
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 @@ int rend_services_init(void) {
|
|
|
|
|
|
// 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?
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|