|
@@ -26,6 +26,7 @@
|
|
|
#include "connection.h"
|
|
|
#include "circpathbias.h"
|
|
|
#include "connection.h"
|
|
|
+#include "hs_ntor.h"
|
|
|
|
|
|
/* Get all connections that are waiting on a circuit and flag them back to
|
|
|
* waiting for a hidden service descriptor for the given service key
|
|
@@ -584,6 +585,68 @@ handle_introduce_ack(origin_circuit_t *circ, const uint8_t *payload,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/* Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The
|
|
|
+ * encoded cell is in payload of length payload_len. Return 0 on success or a
|
|
|
+ * negative value on error. On error, the circuit is marked for close. */
|
|
|
+static int
|
|
|
+handle_rendezvous2(origin_circuit_t *circ, const uint8_t *payload,
|
|
|
+ size_t payload_len)
|
|
|
+{
|
|
|
+ int ret = -1;
|
|
|
+ curve25519_public_key_t server_pk;
|
|
|
+ uint8_t auth_mac[DIGEST256_LEN] = {0};
|
|
|
+ uint8_t handshake_info[CURVE25519_PUBKEY_LEN + sizeof(auth_mac)] = {0};
|
|
|
+ hs_ntor_rend_cell_keys_t keys;
|
|
|
+ const hs_ident_circuit_t *ident;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(payload);
|
|
|
+
|
|
|
+ /* Make things easier. */
|
|
|
+ ident = circ->hs_ident;
|
|
|
+ tor_assert(ident);
|
|
|
+
|
|
|
+ if (hs_cell_parse_rendezvous2(payload, payload_len, handshake_info,
|
|
|
+ sizeof(handshake_info)) < 0) {
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ /* Get from the handshake info the SERVER_PK and AUTH_MAC. */
|
|
|
+ memcpy(&server_pk, handshake_info, CURVE25519_PUBKEY_LEN);
|
|
|
+ memcpy(auth_mac, handshake_info + CURVE25519_PUBKEY_LEN, sizeof(auth_mac));
|
|
|
+
|
|
|
+ /* Generate the handshake info. */
|
|
|
+ if (hs_ntor_client_get_rendezvous1_keys(&ident->intro_auth_pk,
|
|
|
+ &ident->rendezvous_client_kp,
|
|
|
+ &ident->intro_enc_pk, &server_pk,
|
|
|
+ &keys) < 0) {
|
|
|
+ log_info(LD_REND, "Unable to compute the rendezvous keys.");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Critical check, make sure that the MAC matches what we got with what we
|
|
|
+ * computed just above. */
|
|
|
+ if (!hs_ntor_client_rendezvous2_mac_is_good(&keys, auth_mac)) {
|
|
|
+ log_info(LD_REND, "Invalid MAC in RENDEZVOUS2. Rejecting cell.");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Setup the e2e encryption on the circuit and finalize its state. */
|
|
|
+ if (hs_circuit_setup_e2e_rend_circ(circ, keys.ntor_key_seed,
|
|
|
+ sizeof(keys.ntor_key_seed), 0) < 0) {
|
|
|
+ log_info(LD_REND, "Unable to setup the e2e encryption.");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ /* Success. Hidden service connection finalized! */
|
|
|
+ ret = 0;
|
|
|
+ goto end;
|
|
|
+
|
|
|
+ err:
|
|
|
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
|
|
+ end:
|
|
|
+ memwipe(&keys, 0, sizeof(keys));
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/* ========== */
|
|
|
/* Public API */
|
|
|
/* ========== */
|
|
@@ -881,3 +944,36 @@ hs_client_receive_introduce_ack(origin_circuit_t *circ,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/* Called when get a RENDEZVOUS2 cell on the rendezvous circuit circ. Return
|
|
|
+ * 0 on success else a negative value is returned. The circuit will be closed
|
|
|
+ * on error. */
|
|
|
+int
|
|
|
+hs_client_receive_rendezvous2(origin_circuit_t *circ,
|
|
|
+ const uint8_t *payload, size_t payload_len)
|
|
|
+{
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ tor_assert(circ);
|
|
|
+ tor_assert(payload);
|
|
|
+
|
|
|
+ /* Circuit can possibly be in both state because we could receive a
|
|
|
+ * RENDEZVOUS2 cell before the INTRODUCE_ACK has been received. */
|
|
|
+ if (TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
|
|
|
+ TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) {
|
|
|
+ log_warn(LD_PROTOCOL, "Unexpected RENDEZVOUS2 cell on circuit %u. "
|
|
|
+ "Closing circuit.",
|
|
|
+ (unsigned int) TO_CIRCUIT(circ)->n_circ_id);
|
|
|
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ log_info(LD_REND, "Got RENDEZVOUS2 cell from hidden service on circuit %u.",
|
|
|
+ TO_CIRCUIT(circ)->n_circ_id);
|
|
|
+
|
|
|
+ ret = (circ->hs_ident) ? handle_rendezvous2(circ, payload, payload_len) :
|
|
|
+ rend_client_receive_rendezvous(circ, payload,
|
|
|
+ payload_len);
|
|
|
+ end:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|