|
@@ -0,0 +1,310 @@
|
|
|
+$Id$
|
|
|
+
|
|
|
+Tor Rendezvous Spec
|
|
|
+
|
|
|
+0. Overview and preliminaries
|
|
|
+
|
|
|
+ Rendezvous points provide location-hidden services (server
|
|
|
+ anonymity) for the onion routing network. With rendezvous points,
|
|
|
+ Bob can offer a TCP service (say, a webserver) via the onion
|
|
|
+ routing network, without revealing the IP of that service.
|
|
|
+
|
|
|
+ Bob does this by anonymously advertising a public key for his
|
|
|
+ service, along with a list of onion routers to act as "Introduction
|
|
|
+ Points" for his service. He creates forward OR circuits to those
|
|
|
+ introduction points, and tells them about his public key. To
|
|
|
+ connect to Bob, Alice first builds an OR circuit to an OR to act as
|
|
|
+ her "Rendezvous Point", then connects to one of Bob's chosen
|
|
|
+ introduction points, and asks it to tell him about her Rendezvous
|
|
|
+ Point (RP). If Bob chooses to answer, he builds an OR circuit to her
|
|
|
+ RP, and tells it to connect him to Alice. The RP joints their
|
|
|
+ circuits together, and begins relaying cells. Alice's 'BEGIN'
|
|
|
+ cells are received directly by Bob's OP, which responds by
|
|
|
+ communication with the local server implementing Bob's service.
|
|
|
+
|
|
|
+ Below, we describe a network-level specification of this service,
|
|
|
+ along with interfaces to make this process transparent to Alice
|
|
|
+ (so long as she is using an OP).
|
|
|
+
|
|
|
+0.1. Notation, conventions and prerequisites
|
|
|
+
|
|
|
+ In the specifications below, we use the same notation as in
|
|
|
+ "tor-spec.txt". The service specified here also requires the existence of
|
|
|
+ an onion routing network as specified in "tor-spec.txt".
|
|
|
+
|
|
|
+ H(x) is a SHA1 digest of x.
|
|
|
+ PKSign(SK,x) is a PKCS.1-padded RSA signature of x with SK.
|
|
|
+ PKEncrypt(SK,x) is a PKCS.1-padded RSA encryption of x with SK.
|
|
|
+ Public keys are all RSA, and encoded in ASN.1.
|
|
|
+ All integers are stored in network (big-endian) order.
|
|
|
+ All symmetric encryption uses AES in counter mode, except where
|
|
|
+ otherwise noted.
|
|
|
+
|
|
|
+ In all discussions, "Alice" will refer to a user connecting to a
|
|
|
+ location-hidden service, and "Bob" will refer to a user running a
|
|
|
+ location-hidden service.
|
|
|
+
|
|
|
+0.2. Protocol outline
|
|
|
+
|
|
|
+ 1. Bob->Bob's OP: "Offer IP:Port as public-key-name:Port". [configuration]
|
|
|
+ (We do not specify this step; it is left to the implementor of
|
|
|
+ Bob's OP.)
|
|
|
+
|
|
|
+ 2. Bob's OP generates keypair and rendezvous service descriptor:
|
|
|
+ "Meet public-key X at introduction point A, B, or C." (signed)
|
|
|
+
|
|
|
+ 3. Bob's OP->Introduction point via Tor: [introduction setup]
|
|
|
+ "This pk is me."
|
|
|
+
|
|
|
+ 4. Bob's OP->directory service via Tor: publishes Bob's service descriptor
|
|
|
+ [advertisement]
|
|
|
+
|
|
|
+ 5. Out of band, Alice receives a y.onion:port address. She opens a
|
|
|
+ SOCKS connection to her OP, and requests y.onion:port.
|
|
|
+
|
|
|
+ 6. Alice's OP retrieves Bob's descriptor via Tor: [descriptor lookup.]
|
|
|
+
|
|
|
+ 7. Alice's OP chooses a rendezvous point, opens a circuit to that
|
|
|
+ rendezvous point, and establishes a rendezvous circuit. [rendezvous
|
|
|
+ setup.]
|
|
|
+
|
|
|
+ 8. Alice connects to the Introduction point via Tor, and tells it about
|
|
|
+ her rendezvous point. (Encrypted to Bob.) [Introduction 1]
|
|
|
+
|
|
|
+ 9. The Introduction point passes this on to Bob's OP via Tor, along the
|
|
|
+ introduction circuit. [Introduction 2]
|
|
|
+
|
|
|
+ 10. Bob's OP decides whether to connect to Alice, and if so, creates a
|
|
|
+ circuit to Alice's RP via Tor. Establishes a shared circuit.
|
|
|
+ [Rendezvous.]
|
|
|
+
|
|
|
+ 11. Alice's OP sends begin cells to Bob's OP. [Connection]
|
|
|
+
|
|
|
+0.3. Constants and new cell types
|
|
|
+
|
|
|
+ Relay cell types
|
|
|
+ 32 -- RELAY_ESTABLISH_INTRO
|
|
|
+ 33 -- RELAY_ESTABLISH_RENDEZVOUS
|
|
|
+ 34 -- RELAY_INTRODUCE1
|
|
|
+ 35 -- RELAY_INTRODUCE2
|
|
|
+ 36 -- RELAY_RENDEZVOUS1
|
|
|
+ 37 -- RELAY_RENDEZVOUS2
|
|
|
+
|
|
|
+1. The Protocol
|
|
|
+
|
|
|
+1.1. Bob configures his local OP.
|
|
|
+
|
|
|
+ We do not specify a format for the OP configuration file. However,
|
|
|
+ OPs SHOULD allow Bob to provide more than one advertised service
|
|
|
+ per OP, and MUST allow Bob to specify one or more virtual ports per
|
|
|
+ service. Bob provides a mapping from each of these virtual ports
|
|
|
+ to a local IP:Port pair.
|
|
|
+
|
|
|
+1.2. Bob's OP generates service descriptors.
|
|
|
+
|
|
|
+ The first time the OP provides an advertised service, it generates
|
|
|
+ a public/private keypair (stored locally). Periodically, the OP
|
|
|
+ generates service descriptor, containing:
|
|
|
+
|
|
|
+ KL Key length [2 octets]
|
|
|
+ PK Bob's public key [KL octets]
|
|
|
+ TS A timestamp [8 octets]
|
|
|
+ NI Number of introduction points [2 octets]
|
|
|
+ Ipt A list of NUL-terminated OR nicknames [variable]
|
|
|
+ SIG Signature of above fields [KL octets]
|
|
|
+
|
|
|
+ KL is the length of PK, in octets. (Currently, KL must be 128.)
|
|
|
+ TS is the number of milliseconds elapsed since Jan 1, 1970.
|
|
|
+
|
|
|
+ [Shouldn't the nicknames be hostname:port's instead? That way, Alice's
|
|
|
+ directory servers don't need to know Bob's chosen introduction points.
|
|
|
+ Not important now, but essential if we ever have a non-total-knowledge
|
|
|
+ design. -NM]
|
|
|
+
|
|
|
+1.3. Bob's OP establishes his introduction points.
|
|
|
+
|
|
|
+ The OP establishes a new introduction circuit to each introduction
|
|
|
+ point. These circuits MUST NOT be used for anything but rendezvous
|
|
|
+ introduction. To establish the introduction, Bob sends a
|
|
|
+ RELAY_ESTABLISH_INTRO cell, containing:
|
|
|
+
|
|
|
+ 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]
|
|
|
+
|
|
|
+ To prevent replay attacks, the HS field contains a SHA-1 hash based on the
|
|
|
+ shared secret g^xy between Bob's OP and the introduction point, as
|
|
|
+ follows:
|
|
|
+ HS = H(g^xy | "INTRODUCE")
|
|
|
+ That is:
|
|
|
+ HS = H(g^xy | [49 4E 54 52 4F 44 55 43 45])
|
|
|
+
|
|
|
+ Upon receiving such a cell, the OR first checks that the signature is
|
|
|
+ correct with the included public key. If so, it checks whether HS is
|
|
|
+ correct given the shared state between Bob's OP and the OR. If either
|
|
|
+ check fails, the OP discards the cell; otherwise, it associates the
|
|
|
+ circuit with Bob's public key, and dissociates any other circuits
|
|
|
+ currently associated with PK.
|
|
|
+
|
|
|
+1.4. Bob's OP advertises his server descriptor
|
|
|
+
|
|
|
+ Bob's OP opens a stream to each directory server's directory port via Tor.
|
|
|
+ Over this stream, Bob's OP makes an HTTP 'POST' request, to the URL
|
|
|
+ '/rendezvous/publish' (relative to the directory server's root),
|
|
|
+ containing as its body Bob's service descriptor. Upon receiving a
|
|
|
+ descriptor, the director server checks the signature, and discards the
|
|
|
+ descriptor if the signature does not match the enclosed public key. Next,
|
|
|
+ the directory server checks the timestamp. If the timestamp is more than
|
|
|
+ 24 hours in the past or more than 1 hour in the future, or the directory
|
|
|
+ server already has a newer descriptor with the same public key, the server
|
|
|
+ discards the descriptor. Otherwise, the server discards any older
|
|
|
+ descriptors with the same public key, and associates the new descriptor
|
|
|
+ with the public key. The directory server remembers this descriptor for
|
|
|
+ at least 24 hours after its timestamp. At least every 24 hours, Bob's OP
|
|
|
+ uploads a fresh descriptor.
|
|
|
+
|
|
|
+1.5. Alice receives a y.onion address
|
|
|
+
|
|
|
+ When Alice receives a pointer to a location-hidden service, it is as a
|
|
|
+ hostname of the form "y.onion", where y is a base-32 encoding of a
|
|
|
+ ~16-octet hash of Bob's service's public key, computed as follows:
|
|
|
+
|
|
|
+ 1. Let H = H(PK).
|
|
|
+ 2. Let H' = the first 130 bits of H, considering each octet from
|
|
|
+ most significant bit to least significant big.
|
|
|
+ 2. Generate a 26-character encoding of H', taking H' 5 bits at
|
|
|
+ a time, and mapping each 5-bit value to a character as follows:
|
|
|
+ 0..25 map to the characters 'a'...'z', respectively.
|
|
|
+ 26..31 map to the characters '0'...'5', respectively.
|
|
|
+
|
|
|
+ (We only use 130 bits instead of the 160 bits from SHA1 because we don't
|
|
|
+ need to worry about man-in-the-middle attacks. We use 130 instead of 128
|
|
|
+ in order to have an even multiple of 5.)
|
|
|
+
|
|
|
+ [Yes, numbers are allowed at the beginning. See RFC1123. -NM]
|
|
|
+
|
|
|
+1.6. Alice's OP retrieves a service descriptor
|
|
|
+
|
|
|
+ Alice opens a stream to a directory server via Tor, and makes an HTTP GET
|
|
|
+ request for the document '/rendevous/<y>', where '<y> is replaced with the
|
|
|
+ encoding of Bob's public key as described above. The directory replies
|
|
|
+ with a 404 HTTP response if it does not recognize <y>, and otherwise
|
|
|
+ returns Bob's most recently uploaded service descriptor.
|
|
|
+
|
|
|
+ If Alice's OP receives a 404 response, it tries the other directory
|
|
|
+ servers, and only fails the lookup if none recognizes the public key hash.
|
|
|
+
|
|
|
+ Upon receiving a service descriptor, Alice verifies with the same process
|
|
|
+ as the directory server uses, described above in section 1.4.
|
|
|
+
|
|
|
+ [XXXX can Alice cache the descriptor? It may make her
|
|
|
+ partitionable. -NM]
|
|
|
+
|
|
|
+1.7. Alice's OP establishes a rendezvous point.
|
|
|
+
|
|
|
+ When Alice requests a connection to a given location-hidden service,
|
|
|
+ and Alice's OP has not already established a circuit to that circuit,
|
|
|
+ the OP establishes a rendezvous service. It does this by establishing
|
|
|
+ a circuit to a randomly chosen OR, and sending a
|
|
|
+ RELAY_ESTABLISH_RENDEZVOUS cell to that OR. The body of that cell
|
|
|
+ contains:
|
|
|
+
|
|
|
+ RC Rendezvous cookie [20 octets]
|
|
|
+
|
|
|
+ The rendezvous cookie is an arbitrary 20-byte value, chosen randomly by
|
|
|
+ Alice's OP.
|
|
|
+
|
|
|
+ Upon receiving a RELAY_ESTABLISH_RENDEZVOUS cell, the OP associates the
|
|
|
+ RC with the circuit that sent it.
|
|
|
+
|
|
|
+ Alice's OP MUST NOT use the circuit which sent the cell for any purpose
|
|
|
+ other than rendezvous with the given location-hidden service.
|
|
|
+
|
|
|
+1.8. Introduction: from Alice's OP to Introduction Point
|
|
|
+
|
|
|
+ Via another circuit, Alice sends a RELAY_INTRODUCE1 cell to once of Bob's
|
|
|
+ chosen introduction points. This cell contains:
|
|
|
+
|
|
|
+ Cleartext
|
|
|
+ PK_ID Identifier for Bob's PK [16 octets]
|
|
|
+
|
|
|
+ Encrypted to Bob's PK:
|
|
|
+ RP Rendezvous point's nickname [variable]
|
|
|
+ RC Rendezvous cookie [20 octets]
|
|
|
+ g^x Diffie-Hellman data, part 1 [128 octetes]
|
|
|
+
|
|
|
+ PK_ID is the first 16 octets of the hash of Bob's public key. RP is
|
|
|
+ NUL-terminated.
|
|
|
+
|
|
|
+ The data is encrypted to Bob's PK as follows: Suppose Bob's PK is L octets
|
|
|
+ long. If the data to be encrypted is shorter than L, then it is encrypted
|
|
|
+ directly (with no padding). If the data is at least as long as L, then a
|
|
|
+ randomly generated 16-byte symmetric key is prepended to the data, after
|
|
|
+ which the first L-1 bytes of the data are encrypted with Bob's PK; and the
|
|
|
+ rest of the data is encrypted with the symmetric key.
|
|
|
+
|
|
|
+1.9. Introduction: From the Introduction Point to Bob's OP
|
|
|
+
|
|
|
+ If the Introduction Point recognizes PK_ID as a public key which has
|
|
|
+ established a circuit for introductions as in 1.3 above, it sends the
|
|
|
+ encrypted portion of the cell in a new RELAY_INTRODUCE2 cell down the
|
|
|
+ corresponding circuit. (If the PK_ID is unrecognized, the
|
|
|
+ RELAY_INTRODUCE1 cell is discarded.)
|
|
|
+
|
|
|
+ When Bob's OP receives the RELAY_INTRODUCE2 cell, it decrypts it with
|
|
|
+ the private key for the corresponding hidden service, and extracts the
|
|
|
+ rendezvous point's nickname, the rendezvous cookie, and the value of g^x
|
|
|
+ chosen by Alice.
|
|
|
+
|
|
|
+1.10. Rendezvous
|
|
|
+
|
|
|
+ Bob's OP build a new Tor circuit ending at Alice's chosen rendezvous
|
|
|
+ point, and sends a RELAY_RENDEZVOUS1 cell along this circuit, containing:
|
|
|
+ RC Rendezvous cookie [20 octets]
|
|
|
+ g^y Diffie-Hellman [128 octets]
|
|
|
+ H(KH) Handshake digest [20 octets]
|
|
|
+
|
|
|
+ (Bob's OP MUST NOT use this circuit for any other purpose.)
|
|
|
+
|
|
|
+ If the RP recognizes RC, it relays the rest of the cell down the
|
|
|
+ corresponding circuit in a RELAY_RENDEZVOUS2 cell, containing:
|
|
|
+
|
|
|
+ g^y Diffie-Hellman [128 octets]
|
|
|
+ H(KH) Handshake digest [20 octets]
|
|
|
+
|
|
|
+ (If the RP does not recognize the RC, it discards the cell and
|
|
|
+ tears down the circuit.)
|
|
|
+
|
|
|
+ When Alice's OP receives a RELAY_RENDEZVOUS2 cell on a circuit which
|
|
|
+ has sent a RELAY_ESTABLISH_RENDEZVOUS cell but which has not yet received
|
|
|
+ a reply, it uses g^y and H(g^xy) to complete the handshake as in the Tor
|
|
|
+ circuit extend process: they establish a 60-octet string as
|
|
|
+ K = SHA1(g^xy | [00]) | SHA1(g^xy | [01]) | SHA1(g^xy | [02])
|
|
|
+ and generate
|
|
|
+ KH = K[0..15]
|
|
|
+ Kf = K[16..31]
|
|
|
+ Kb = K[32..47]
|
|
|
+
|
|
|
+ Subsequently, the rendezvous point passes relay cells, unchained, from
|
|
|
+ each of the two circuits to the other. When Alice's OP sends
|
|
|
+ sends RELAY cells along the circuit, it first 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. Bob's OP does the same, with Kf and Kb
|
|
|
+ interchanged.
|
|
|
+
|
|
|
+1.11. Creating streams
|
|
|
+
|
|
|
+ To open TCP connections to Bob's location-hidden service, Alice's OP sends
|
|
|
+ a RELAY_BEGIN cell along the established circuit, using the special
|
|
|
+ address "", and a chosen port. Bob's OP chooses a destination IP and
|
|
|
+ port, based on the configuration of the service connected to the circuit,
|
|
|
+ and opens a TCP stream. From then on, Bob's OP treats the stream as an
|
|
|
+ ordinary exit connection.
|
|
|
+
|
|
|
+ Alice MAY send multiple RELAY_BEGIN cells along the circuit, to open
|
|
|
+ multiple streams to Bob. Alice SHOULD NOT send RELAY_BEGIN cells for any
|
|
|
+ other address along her circuit to Bob; if she does, Bob MUST reject them.
|
|
|
+
|