diff options
author | Nick Mathewson <nickm@torproject.org> | 2004-04-01 22:21:01 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2004-04-01 22:21:01 +0000 |
commit | 79fc52170edb4919a231234fc14c05640e1ec279 (patch) | |
tree | 894f1842937647832b8942e4e00798038a6627fd /src/or | |
parent | 6b958494f3a5c538a62b1aa0b113d4741085dec1 (diff) | |
download | tor-79fc52170edb4919a231234fc14c05640e1ec279.tar tor-79fc52170edb4919a231234fc14c05640e1ec279.tar.gz |
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)
svn:r1438
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuit.c | 75 | ||||
-rw-r--r-- | src/or/onion.c | 25 | ||||
-rw-r--r-- | src/or/or.h | 23 | ||||
-rw-r--r-- | src/or/rendservice.c | 155 |
4 files changed, 226 insertions, 52 deletions
diff --git a/src/or/circuit.c b/src/or/circuit.c index 08acf187b..429651132 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -129,8 +129,8 @@ void circuit_free(circuit_t *circ) { 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 @@ static void circuit_is_ready(circuit_t *circ) { 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 @@ static void circuit_is_ready(circuit_t *circ) { /* 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 @@ static void circuit_failed(circuit_t *circ) { /* 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 @@ int circuit_extend(cell_t *cell, circuit_t *circ) { 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 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) { 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; } diff --git a/src/or/onion.c b/src/or/onion.c index 1703d93ed..2b68cc17c 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -156,6 +156,8 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key 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 @@ static void remove_twins_from_smartlist(smartlist_t *sl, routerinfo_t *twin) { } } +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 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout 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; diff --git a/src/or/or.h b/src/or/or.h index ceea9e1eb..84e34d0ca 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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 @@ struct crypt_path_t { 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 crypt_path_t crypt_path_t; 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 @@ struct circuit_t { 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_reset_failure_count(void); 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 @@ void onion_pending_remove(circuit_t *circ); 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_config_services(or_options_t *options); 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 /* diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 31f0d2600..ed5a37183 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -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? + } } /* |