<a id="rend-spec-v3.txt-4"></a>

# The rendezvous protocol

Before connecting to a hidden service, the client first builds a
circuit to an arbitrarily chosen Tor node (known as the rendezvous
point), and sends an ESTABLISH_RENDEZVOUS message. The hidden service
later connects to the same node and sends a RENDEZVOUS message. Once
this has occurred, the relay forwards the contents of the RENDEZVOUS
message to the client, and joins the two circuits together.

Single Onion Services attempt to build a non-anonymous single-hop circuit,
but use an anonymous 3-hop circuit if:

```text
     * the rend point is on an address that is configured as unreachable via
       a direct connection, or
     * the initial attempt to connect to the rend point over a single-hop
       circuit fails, and they are retrying the rend point connection.
```

<a id="rend-spec-v3.txt-4.1"></a>

## Establishing a rendezvous point {#EST_REND_POINT}

The client sends the rendezvous point a RELAY_COMMAND_ESTABLISH_RENDEZVOUS
message containing a 20-byte value.

RENDEZVOUS_COOKIE         \[20 bytes\]

Rendezvous points MUST ignore any extra bytes in an
ESTABLISH_RENDEZVOUS message. (Older versions of Tor did not.)

The rendezvous cookie is an arbitrary 20-byte value, chosen randomly
by the client. The client SHOULD choose a new rendezvous cookie for
each new connection attempt. If the rendezvous cookie is already in
use on an existing circuit, the rendezvous point should reject it and
destroy the circuit.

Upon receiving an ESTABLISH_RENDEZVOUS message, the rendezvous point associates
the cookie with the circuit on which it was sent. It replies to the client
with an empty RENDEZVOUS_ESTABLISHED message to indicate success. Clients MUST
ignore any extra bytes in a RENDEZVOUS_ESTABLISHED message.

The client MUST NOT use the circuit which sent the message for any
purpose other than rendezvous with the given location-hidden service.

The client should establish a rendezvous point BEFORE trying to
connect to a hidden service.

<a id="rend-spec-v3.txt-4.2"></a>

## Joining to a rendezvous point {#JOIN_REND}

To complete a rendezvous, the hidden service host builds a circuit to
the rendezvous point and sends a RENDEZVOUS1 message containing:

```text
       RENDEZVOUS_COOKIE          [20 bytes]
       HANDSHAKE_INFO             [variable; depends on handshake type
                                   used.]
```

where RENDEZVOUS_COOKIE is the cookie suggested by the client during the
introduction (see \[PROCESS_INTRO2\]) and HANDSHAKE_INFO is defined in
\[NTOR-WITH-EXTRA-DATA\].

If the cookie matches the rendezvous cookie set on any
not-yet-connected circuit on the rendezvous point, the rendezvous
point connects the two circuits, and sends a RENDEZVOUS2 message to the
client containing the HANDSHAKE_INFO field of the RENDEZVOUS1 message.

Upon receiving the RENDEZVOUS2 message, the client verifies that HANDSHAKE_INFO
correctly completes a handshake. To do so, the client parses SERVER_PK from
HANDSHAKE_INFO and reverses the final operations of section
\[NTOR-WITH-EXTRA-DATA\] as shown here:

```text
      rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID
      NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
      verify = MAC(rend_secret_hs_input, t_hsverify)
      auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
      AUTH_INPUT_MAC = MAC(auth_input, t_hsmac)
```

Finally the client verifies that the received AUTH field of HANDSHAKE_INFO
is equal to the computed AUTH_INPUT_MAC.

Now both parties use the handshake output to derive shared keys for use on
the circuit as specified in the section below:

<a id="rend-spec-v3.txt-4.2.1"></a>

### Key expansion

The hidden service and its client need to derive crypto keys from the
NTOR_KEY_SEED part of the handshake output. To do so, they use the KDF
construction as follows:

K = KDF(NTOR_KEY_SEED | m_hsexpand,    HASH_LEN *2 + S_KEY_LEN* 2)

The first HASH_LEN bytes of K form the forward digest Df; the next HASH_LEN
bytes form the backward digest Db; the next S_KEY_LEN bytes form Kf, and the
final S_KEY_LEN bytes form Kb.  Excess bytes from K are discarded.

Subsequently, the rendezvous point passes RELAY cells, unchanged, from each
of the two circuits to the other.  When Alice's OP sends RELAY cells along
the circuit, it authenticates with Df, and encrypts them with the Kf, then
with all of the keys for the ORs in Alice's side of the circuit; and when
Alice's OP receives RELAY cells from the circuit, it decrypts them with the
keys for the ORs in Alice's side of the circuit, then decrypts them with Kb,
and checks integrity with Db.  Bob's OP does the same, with Kf and Kb
interchanged.

\[TODO: Should we encrypt HANDSHAKE_INFO as we did INTRODUCE2
contents? It's not necessary, but it could be wise. Similarly, we
should make it extensible.\]

<a id="rend-spec-v3.txt-4.3"></a>

## Using legacy hosts as rendezvous points {#legacy-rend-hosts}

\[This section is obsolete and refers to a workaround for now-obsolete Tor
relay versions. It is included for historical reasons.\]

The behavior of ESTABLISH_RENDEZVOUS is unchanged from older versions
of this protocol, except that relays should now ignore unexpected
bytes at the end.

Old versions of Tor required that RENDEZVOUS message bodies be exactly
168 bytes long. All shorter rendezvous bodies should be padded to
this length with random bytes, to make them difficult to distinguish from
older protocols at the rendezvous point.

Relays older than 0.2.9.1 should not be used for rendezvous points by next
generation onion services because they enforce too-strict length checks to
RENDEZVOUS messages. Hence the "HSRend" protocol from proposal#264 should be
used to select relays for rendezvous points.
