Loading doc/rend-spec.txt +2 −2 Original line number Diff line number Diff line Loading @@ -111,7 +111,7 @@ Tor Rendezvous Spec TS A timestamp [4 octets] NI Number of introduction points [2 octets] Ipt A list of NUL-terminated OR nicknames [variable] SIG Signature of above fields [KL octets] SIG Signature of above fields [variable] KL is the length of PK, in octets. (Currently, KL must be 128.) TS is the number of seconds elapsed since Jan 1, 1970. Loading @@ -131,7 +131,7 @@ Tor Rendezvous Spec KL Key length [2 octets] PK Bob's public key [KL octets] HS Hash of session info [20 octets] SIG Signature of above information [KL octets] SIG Signature of above information [variable] To prevent replay attacks, the HS field contains a SHA-1 hash based on the shared secret KH between Bob's OP and the introduction point, as Loading src/or/circuit.c +38 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) Loading @@ -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 Loading Loading @@ -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; } Loading src/or/or.h +5 −3 Original line number Diff line number Diff line Loading @@ -560,7 +560,7 @@ 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]; Loading Loading @@ -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); Loading src/or/rendmid.c +165 −0 Original line number Diff line number Diff line Loading @@ -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; } /* Loading src/or/rendservice.c +1 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. */ Loading Loading
doc/rend-spec.txt +2 −2 Original line number Diff line number Diff line Loading @@ -111,7 +111,7 @@ Tor Rendezvous Spec TS A timestamp [4 octets] NI Number of introduction points [2 octets] Ipt A list of NUL-terminated OR nicknames [variable] SIG Signature of above fields [KL octets] SIG Signature of above fields [variable] KL is the length of PK, in octets. (Currently, KL must be 128.) TS is the number of seconds elapsed since Jan 1, 1970. Loading @@ -131,7 +131,7 @@ Tor Rendezvous Spec KL Key length [2 octets] PK Bob's public key [KL octets] HS Hash of session info [20 octets] SIG Signature of above information [KL octets] SIG Signature of above information [variable] To prevent replay attacks, the HS field contains a SHA-1 hash based on the shared secret KH between Bob's OP and the introduction point, as Loading
src/or/circuit.c +38 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) Loading @@ -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 Loading Loading @@ -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; } Loading
src/or/or.h +5 −3 Original line number Diff line number Diff line Loading @@ -560,7 +560,7 @@ 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]; Loading Loading @@ -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); Loading
src/or/rendmid.c +165 −0 Original line number Diff line number Diff line Loading @@ -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; } /* Loading
src/or/rendservice.c +1 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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. */ Loading