1 /* Copyright 2004 Roger Dingledine */
2 /* See LICENSE for licensing information */
7 /* Respond to an ESTABLISH_INTRO cell by setting the circuit's purpose and
11 rend_mid_establish_intro(circuit_t
*circ
, char *request
, int request_len
)
13 crypto_pk_env_t
*pk
= NULL
;
15 char expected_digest
[20];
20 if (circ
->purpose
!= CIRCUIT_PURPOSE_INTERMEDIATE
) {
21 log_fn(LOG_WARN
, "Rejecting ESTABLISH_INTRO on non-intermediate circuit");
26 /* First 2 bytes: length of asn1-encoded key. */
27 asn1len
= get_uint16(request
);
29 /* Next asn1len bytes: asn1-encoded key. */
30 if (request_len
< 22+asn1len
)
32 pk
= crypto_pk_asn1_decode(request
+2, asn1len
);
34 log_fn(LOG_WARN
, "Couldn't decode public key");
38 /* Next 20 bytes: Hash of handshake_digest | "INTRODUCE" */
39 memcpy(buf
, circ
->handshake_digest
, 20);
40 memcpy(buf
+20, "INTRODUCE", 9);
41 if (crypto_SHA_digest(buf
, 29, expected_digest
)<0) {
42 log_fn(LOG_WARN
, "Error computing digest");
45 if (memcmp(expected_digest
, buf
+2+asn1len
, 20)) {
46 log_fn(LOG_WARN
, "Hash of session info was not as expected");
50 /* Rest of body: signature of previous data */
51 if (crypto_pk_public_checksig_digest(pk
, buf
, 22+asn1len
,
52 buf
+22+asn1len
, request_len
-(22+asn1len
))<0) {
53 log_fn(LOG_WARN
, "Incorrect signature on ESTABLISH_INTRO cell; rejecting");
57 /* The request is valid. First, compute the hash of Bob's PK.*/
58 if (crypto_pk_get_digest(pk
, pk_digest
)<0) {
59 log_fn(LOG_WARN
, "Couldn't hash public key.");
63 /* Close any other intro circuits with the same pk. */
65 while ((c
= circuit_get_next_by_service_and_purpose(
66 c
,pk_digest
,CIRCUIT_PURPOSE_INTRO_POINT
))) {
67 circuit_mark_for_close(c
);
70 /* Now, set up this circuit. */
71 circ
->purpose
= CIRCUIT_PURPOSE_INTRO_POINT
;
72 memcpy(circ
->rend_service
, pk_digest
, 20);
76 log_fn(LOG_WARN
, "Rejecting truncated ESTABLISH_INTRO cell");
78 if (pk
) crypto_free_pk_env(pk
);
79 circuit_mark_for_close(circ
);
83 /* Process an INTRODUCE1 cell by finding the corresponding introduction
84 * circuit, and relaying the body of the INTRODUCE1 cell inside an
88 rend_mid_introduce(circuit_t
*circ
, char *request
, int request_len
)
90 circuit_t
*intro_circ
;
92 if (request_len
< 276) {
93 log_fn(LOG_WARN
, "Impossibly short INTRODUCE2 cell; dropping.");
97 /* The first 20 bytes are all we look at: they have a hash of Bob's PK. */
98 intro_circ
= circuit_get_next_by_service_and_purpose(
99 NULL
, request
, CIRCUIT_PURPOSE_INTRO_POINT
);
102 "No introduction circuit matching INTRODUCE2 cell; dropping");
106 /* Great. Now we just relay the cell down the circuit. */
107 if (connection_edge_send_command(NULL
, intro_circ
,
108 RELAY_COMMAND_INTRODUCE2
,
109 request
, request_len
, NULL
)) {
110 log_fn(LOG_WARN
, "Unable to send INTRODUCE2 cell to OP.");
116 circuit_mark_for_close(circ
); /* Is this right? */
120 /* Process an ESTABLISH_RENDEZVOUS cell by settingthe circuit's purpose and
124 rend_mid_establish_rendezvous(circuit_t
*circ
, char *request
, int request_len
)
126 if (circ
->purpose
!= CIRCUIT_PURPOSE_INTERMEDIATE
) {
127 log_fn(LOG_WARN
, "Tried to establish rendezvous on non-intermediate circuit");
131 if (request_len
!= REND_COOKIE_LEN
) {
132 log_fn(LOG_WARN
, "Invalid length on ESTABLISH_RENDEZVOUS");
136 if (circuit_get_rendezvous(request
)) {
137 log_fn(LOG_WARN
, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS");
141 circ
->purpose
= CIRCUIT_PURPOSE_REND_POINT_WAITING
;
142 memcpy(circ
->rend_cookie
, request
, REND_COOKIE_LEN
);
146 circuit_mark_for_close(circ
);
150 /* Process a RENDEZVOUS1 cell by looking up the correct rendezvous circuit by its
151 * relaying the cell's body in a RENDEZVOUS2 cell, and connecting the two circuits.
154 rend_mid_rendezvous(circuit_t
*circ
, char *request
, int request_len
)
156 circuit_t
*rend_circ
;
158 if (circ
->purpose
!= CIRCUIT_PURPOSE_INTERMEDIATE
) {
159 log_fn(LOG_WARN
, "Tried to complete rendezvous on non-intermediate circuit");
163 if (request_len
< 20+128+20) {
164 log_fn(LOG_WARN
, "Rejecting impossibly short RENDEZVOUS1 cell");
168 rend_circ
= circuit_get_rendezvous(request
);
170 log_fn(LOG_WARN
, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie");
174 /* Send the RENDEZVOUS2 cell to Alice. */
175 if (connection_edge_send_command(NULL
, rend_circ
,
176 RELAY_COMMAND_RENDEZVOUS2
,
177 request
+20, request_len
-20, NULL
)) {
178 log_fn(LOG_WARN
, "Unable to send RENDEZVOUS2 cell to OP.");
182 /* Join the circuits. */
183 circ
->purpose
= CIRCUIT_PURPOSE_REND_ESTABLISHED
;
184 rend_circ
->purpose
= CIRCUIT_PURPOSE_REND_ESTABLISHED
;
185 memset(circ
->rend_cookie
, 0, 20);
187 rend_circ
->rend_splice
= circ
;
188 circ
->rend_splice
= rend_circ
;
192 circuit_mark_for_close(circ
);