diff options
author | Nick Mathewson <nickm@torproject.org> | 2004-04-02 21:56:52 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2004-04-02 21:56:52 +0000 |
commit | a981c4099af25e8e38ca1fbe4870d09c54d0d20b (patch) | |
tree | 4c69fc20103513cb0ff17c0409d241010458fa0e /src | |
parent | 79fc52170edb4919a231234fc14c05640e1ec279 (diff) | |
download | tor-a981c4099af25e8e38ca1fbe4870d09c54d0d20b.tar tor-a981c4099af25e8e38ca1fbe4870d09c54d0d20b.tar.gz |
Implement midpoint functionality for rendezvous points.
svn:r1439
Diffstat (limited to 'src')
-rw-r--r-- | src/or/circuit.c | 44 | ||||
-rw-r--r-- | src/or/or.h | 8 | ||||
-rw-r--r-- | src/or/rendmid.c | 165 | ||||
-rw-r--r-- | src/or/rendservice.c | 14 |
4 files changed, 209 insertions, 22 deletions
diff --git a/src/or/circuit.c b/src/or/circuit.c index 429651132..b7502cfca 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -88,7 +88,6 @@ void circuit_close_all_marked() } } - circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) { circuit_t *circ; @@ -307,14 +306,21 @@ circuit_t *circuit_get_newest(connection_t *conn, return NULL; } -/* Return the first circuit in global_circuitlist whose rend_service - * field is servid and whose purpose is purpose. Returns NULL if no circuit - * is found. +/* Return the first circuit in global_circuitlist after 'start' whose + * rend_service field is servid and whose purpose is purpose. Returns + * NULL if no circuit is found. If 'start' is null, begin at the start of + * the list. */ -circuit_t *circuit_get_by_service_and_purpose(const char *servid, int purpose) +circuit_t *circuit_get_next_by_service_and_purpose(circuit_t *start, + const char *servid, int purpose) { circuit_t *circ; - for(circ=global_circuitlist; circ; circ = circ->next) { + if (start == NULL) + circ = global_circuitlist; + else + circ = start->next; + + for( ; circ; circ = circ->next) { if (circ->marked_for_close) continue; if (circ->purpose != purpose) @@ -325,6 +331,21 @@ circuit_t *circuit_get_by_service_and_purpose(const char *servid, int purpose) return NULL; } +/* Return the circuit waiting for a rendezvous with the provided cookie. + * Return NULL if no such circuit is found. + */ +circuit_t *circuit_get_rendezvous(const char *cookie) +{ + circuit_t *circ; + for (circ = global_circuitlist; circ; circ = circ->next) { + if (! circ->marked_for_close && + circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING && + ! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) ) + return circ; + } + return NULL; +} + #define MIN_SECONDS_BEFORE_EXPIRING_CIRC 10 /* circuits that were born at the end of their second might be expired * after 10.1 seconds; circuits born at the beginning might be expired @@ -516,6 +537,17 @@ int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ, } if(!conn) { + if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) { + assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + assert(circ->rend_splice->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED); + cell->circ_id = circ->rend_splice->p_circ_id; + if (circuit_receive_relay_cell(cell, circ->rend_splice, CELL_DIRECTION_IN)<0) { + log_fn(LOG_WARN, "Error relaying cell across rendezvous; closing circuits"); + circuit_mark_for_close(circ); /* XXXX Do this here, or just return -1? */ + return -1; + } + return 0; + } log_fn(LOG_WARN,"Didn't recognize cell, but circ stops here! Closing circ."); return -1; } diff --git a/src/or/or.h b/src/or/or.h index 84e34d0ca..0686d4e05 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -560,8 +560,8 @@ struct circuit_t { char rend_service[CRYPTO_SHA1_DIGEST_LEN]; /* Holds rendezvous cookie if purpose is REND_POINT_WAITING or - * S_RENDEZVOUSING or C_ESTABLISH_REND. Filled with zeroes otherwise. - */ + * C_ESTABLISH_REND. Filled with zeroes otherwise. + */ char rend_cookie[REND_COOKIE_LEN]; /* Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit @@ -692,7 +692,9 @@ circuit_t *circuit_get_by_circ_id_conn(uint16_t circ_id, connection_t *conn); circuit_t *circuit_get_by_conn(connection_t *conn); circuit_t *circuit_get_newest(connection_t *conn, int must_be_open, int must_be_clean); -circuit_t *circuit_get_by_service_and_purpose(const char *servid, int purpose); +circuit_t *circuit_get_next_by_service_and_purpose(circuit_t *circuit, + const char *servid, int purpose); +circuit_t *circuit_get_rendezvous(const char *cookie); void circuit_expire_building(void); int circuit_count_building(void); diff --git a/src/or/rendmid.c b/src/or/rendmid.c index fd151916a..7fe4d0d4a 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -4,28 +4,193 @@ #include "or.h" +/* Respond to an ESTABLISH_INTRO cell by setting the circuit's purpose and + * rendevous service. + */ int rend_mid_establish_intro(circuit_t *circ, char *request, int request_len) { + crypto_pk_env_t *pk = NULL; + char buf[20+9]; + char expected_digest[20]; + char pk_digest[20]; + int asn1len; + circuit_t *c; + + if (circ->purpose != CIRCUIT_PURPOSE_INTERMEDIATE) { + log_fn(LOG_WARN, "Rejecting ESTABLISH_INTRO on non-intermediate circuit"); + goto err; + } + if (request_len < 22) + goto truncated; + /* First 2 bytes: length of asn1-encoded key. */ + asn1len = get_uint16(request); + + /* Next asn1len bytes: asn1-encoded key. */ + if (request_len < 22+asn1len) + goto truncated; + pk = crypto_pk_asn1_decode(request+2, asn1len); + if (!pk) { + log_fn(LOG_WARN, "Couldn't decode public key"); + goto err; + } + + /* Next 20 bytes: Hash of handshake_digest | "INTRODUCE" */ + memcpy(buf, circ->handshake_digest, 20); + memcpy(buf+20, "INTRODUCE", 9); + if (crypto_SHA_digest(buf, 29, expected_digest)<0) { + log_fn(LOG_WARN, "Error computing digest"); + goto err; + } + if (memcmp(expected_digest, buf+2+asn1len, 20)) { + log_fn(LOG_WARN, "Hash of session info was not as expected"); + goto err; + } + + /* Rest of body: signature of previous data */ + if (crypto_pk_public_checksig_digest(pk, buf, 22+asn1len, + buf+22+asn1len, request_len-(22+asn1len))<0) { + log_fn(LOG_WARN, "Incorrect signature on ESTABLISH_INTRO cell; rejecting"); + goto err; + } + + /* The request is valid. First, compute the hash of Bob's PK.*/ + if (crypto_pk_get_digest(pk, pk_digest)<0) { + log_fn(LOG_WARN, "Couldn't hash public key."); + goto err; + } + + /* Close any other intro circuits with the same pk. */ + c = NULL; + while ((c = circuit_get_next_by_service_and_purpose( + c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) { + circuit_mark_for_close(c); + } + + /* Now, set up this circuit. */ + circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT; + memcpy(circ->rend_service, pk_digest, 20); + return 0; + truncated: + log_fn(LOG_WARN, "Rejecting truncated ESTABLISH_INTRO cell"); + err: + if (pk) crypto_free_pk_env(pk); + circuit_mark_for_close(circ); + return -1; } +/* Process an INTRODUCE1 cell by finding the corresponding introduction + * circuit, and relaying the body of the INTRODUCE1 cell inside an + * INTRODUCE2 cell. + */ int rend_mid_introduce(circuit_t *circ, char *request, int request_len) { + circuit_t *intro_circ; + + if (request_len < 276) { + log_fn(LOG_WARN, "Impossibly short INTRODUCE2 cell; dropping."); + goto err; + } + + /* The first 20 bytes are all we look at: they have a hash of Bob's PK. */ + intro_circ = circuit_get_next_by_service_and_purpose( + NULL, request, CIRCUIT_PURPOSE_INTRO_POINT); + if (!intro_circ) { + log_fn(LOG_WARN, + "No introduction circuit matching INTRODUCE2 cell; dropping"); + goto err; + } + + /* Great. Now we just relay the cell down the circuit. */ + if (connection_edge_send_command(NULL, intro_circ, + RELAY_COMMAND_INTRODUCE2, + request, request_len, NULL)) { + log_fn(LOG_WARN, "Unable to send INTRODUCE2 cell to OP."); + goto err; + } + return 0; + err: + circuit_mark_for_close(circ); /* Is this right? */ + return -1; } +/* Process an ESTABLISH_RENDEZVOUS cell by settingthe circuit's purpose and + * rendezvous cookie. + */ int rend_mid_establish_rendezvous(circuit_t *circ, char *request, int request_len) { + if (circ->purpose != CIRCUIT_PURPOSE_INTERMEDIATE) { + log_fn(LOG_WARN, "Tried to establish rendezvous on non-intermediate circuit"); + goto err; + } + + if (request_len != REND_COOKIE_LEN) { + log_fn(LOG_WARN, "Invalid length on ESTABLISH_RENDEZVOUS"); + goto err; + } + + if (circuit_get_rendezvous(request)) { + log_fn(LOG_WARN, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS"); + goto err; + } + + circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; + memcpy(circ->rend_cookie, request, REND_COOKIE_LEN); + return 0; + err: + circuit_mark_for_close(circ); + return -1; } +/* Process a RENDEZVOUS1 cell by looking up the correct rendezvous circuit by its + * relaying the cell's body in a RENDEZVOUS2 cell, and connecting the two circuits. + */ int rend_mid_rendezvous(circuit_t *circ, char *request, int request_len) { + circuit_t *rend_circ; + + if (circ->purpose != CIRCUIT_PURPOSE_INTERMEDIATE) { + log_fn(LOG_WARN, "Tried to complete rendezvous on non-intermediate circuit"); + goto err; + } + + if (request_len < 20+128+20) { + log_fn(LOG_WARN, "Rejecting impossibly short RENDEZVOUS1 cell"); + goto err; + } + + rend_circ = circuit_get_rendezvous(request); + if (!rend_circ) { + log_fn(LOG_WARN, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie"); + goto err; + } + + /* Send the RENDEZVOUS2 cell to Alice. */ + if (connection_edge_send_command(NULL, rend_circ, + RELAY_COMMAND_RENDEZVOUS2, + request+20, request_len-20, NULL)) { + log_fn(LOG_WARN, "Unable to send RENDEZVOUS2 cell to OP."); + goto err; + } + + /* Join the circuits. */ + circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; + rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED; + memset(circ->rend_cookie, 0, 20); + + rend_circ->rend_splice = circ; + circ->rend_splice = rend_circ; + return 0; + err: + circuit_mark_for_close(circ); + return -1; } /* diff --git a/src/or/rendservice.c b/src/or/rendservice.c index ed5a37183..4bb48f4fd 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -235,8 +235,7 @@ int rend_service_init_keys(void) return 0; } -/*DOCDOC*/ -rend_service_t * +static rend_service_t * rend_service_get_by_pk_digest(const char* digest) { int i; @@ -253,17 +252,6 @@ rend_service_get_by_pk_digest(const char* digest) * Handle cells ******/ -typedef struct rend_introduction_t { - /* Digest of the hidden service's PK. */ - char key_digest[20]; - /* Nickname of OR running rendezvous point. */ - char *rendezvous_point; - /* Cookie that we'll use to recognize the rendezvous point. */ - char cookie[20]; - /* g^xy */ - char shared_secret[128]; -} rend_introduction_t; - /* Respond to an INTRODUCE2 cell by launching a circuit to the chosen * rendezvous points. */ |