aboutsummaryrefslogtreecommitdiff
path: root/spec/tor-spec/relay-cells.md
diff options
context:
space:
mode:
Diffstat (limited to 'spec/tor-spec/relay-cells.md')
-rw-r--r--spec/tor-spec/relay-cells.md159
1 files changed, 159 insertions, 0 deletions
diff --git a/spec/tor-spec/relay-cells.md b/spec/tor-spec/relay-cells.md
new file mode 100644
index 0000000..2f89832
--- /dev/null
+++ b/spec/tor-spec/relay-cells.md
@@ -0,0 +1,159 @@
+<a id="tor-spec.txt-6.1"></a>
+## Relay cells
+
+Within a circuit, the OP and the end node use the contents of
+RELAY packets to tunnel end-to-end commands and TCP connections
+("Streams") across circuits. End-to-end commands can be initiated
+by either edge; streams are initiated by the OP.
+
+End nodes that accept streams may be:
+* exit relays (RELAY_BEGIN, anonymous),
+* directory servers (RELAY_BEGIN_DIR, anonymous or non-anonymous),
+* onion services (RELAY_BEGIN, anonymous via a rendezvous point).
+
+The payload of each unencrypted RELAY cell consists of:
+
+```text
+ Relay command [1 byte]
+ 'Recognized' [2 bytes]
+ StreamID [2 bytes]
+ Digest [4 bytes]
+ Length [2 bytes]
+ Data [Length bytes]
+ Padding [PAYLOAD_LEN - 11 - Length bytes]
+
+ The relay commands are:
+
+ 1 -- RELAY_BEGIN [forward]
+ 2 -- RELAY_DATA [forward or backward]
+ 3 -- RELAY_END [forward or backward]
+ 4 -- RELAY_CONNECTED [backward]
+ 5 -- RELAY_SENDME [forward or backward] [sometimes control]
+ 6 -- RELAY_EXTEND [forward] [control]
+ 7 -- RELAY_EXTENDED [backward] [control]
+ 8 -- RELAY_TRUNCATE [forward] [control]
+ 9 -- RELAY_TRUNCATED [backward] [control]
+ 10 -- RELAY_DROP [forward or backward] [control]
+ 11 -- RELAY_RESOLVE [forward]
+ 12 -- RELAY_RESOLVED [backward]
+ 13 -- RELAY_BEGIN_DIR [forward]
+ 14 -- RELAY_EXTEND2 [forward] [control]
+ 15 -- RELAY_EXTENDED2 [backward] [control]
+
+ 16..18 -- Reserved for UDP; Not yet in use, see prop339.
+
+ 19..22 -- Reserved for Conflux, see prop329.
+
+ 32..40 -- Used for hidden services; see rend-spec-{v2,v3}.txt.
+
+ 41..42 -- Used for circuit padding; see Section 3 of padding-spec.txt.
+
+ Used for flow control; see Section 4 of prop324.
+ 43 -- XON [forward or backward]
+ 44 -- XOFF [forward or backward]
+```
+
+Commands labelled as "forward" must only be sent by the originator
+of the circuit. Commands labelled as "backward" must only be sent by
+other nodes in the circuit back to the originator. Commands marked
+as either can be sent either by the originator or other nodes.
+
+The 'recognized' field is used as a simple indication that the cell
+is still encrypted. It is an optimization to avoid calculating
+expensive digests for every cell. When sending cells, the unencrypted
+'recognized' MUST be set to zero.
+
+When receiving and decrypting cells the 'recognized' will always be
+zero if we're the endpoint that the cell is destined for. For cells
+that we should relay, the 'recognized' field will usually be nonzero,
+but will accidentally be zero with P=2^-16.
+
+When handling a relay cell, if the 'recognized' in field in a
+decrypted relay payload is zero, the 'digest' field is computed as
+the first four bytes of the running digest of all the bytes that have
+been destined for this hop of the circuit or originated from this hop
+of the circuit, seeded from Df or Db respectively (obtained in
+section 5.2 above), and including this RELAY cell's entire payload
+(taken with the digest field set to zero). Note that these digests
+_do_ include the padding bytes at the end of the cell, not only those up
+to "Len". If the digest is correct, the cell is considered "recognized"
+for the purposes of decryption (see section 5.5 above).
+
+(The digest does not include any bytes from relay cells that do
+not start or end at this hop of the circuit. That is, it does not
+include forwarded data. Therefore if 'recognized' is zero but the
+digest does not match, the running digest at that node should
+not be updated, and the cell should be forwarded on.)
+
+All RELAY cells pertaining to the same tunneled stream have the same
+stream ID. StreamIDs are chosen arbitrarily by the OP. No stream
+may have a StreamID of zero. Rather, RELAY cells that affect the
+entire circuit rather than a particular stream use a StreamID of zero
+-- they are marked in the table above as "[control]" style
+cells. (Sendme cells are marked as "sometimes control" because they
+can include a StreamID or not depending on their purpose -- see
+Section 7.)
+
+The 'Length' field of a relay cell contains the number of bytes in
+the relay payload which contain real payload data. The remainder of
+the unencrypted payload is padded with padding bytes. Implementations
+handle padding bytes of unencrypted relay cells as they do padding
+bytes for other cell types; see Section 3.
+
+The 'Padding' field is used to make relay cell contents unpredictable, to
+avoid certain attacks (see proposal 289 for rationale). Implementations
+SHOULD fill this field with four zero-valued bytes, followed by as many
+random bytes as will fit. (If there are fewer than 4 bytes for padding,
+then they should all be filled with zero.
+
+Implementations MUST NOT rely on the contents of the 'Padding' field.
+
+If the RELAY cell is recognized but the relay command is not
+understood, the cell must be dropped and ignored. Its contents
+still count with respect to the digests and flow control windows, though.
+
+<a id="tor-spec.txt-6.1.1"></a>
+### Calculating the 'Digest' field
+
+The 'Digest' field itself serves the purpose to check if a cell has been
+fully decrypted, that is, all onion layers have been removed. Having a
+single field, namely 'Recognized' is not sufficient, as outlined above.
+
+When ENCRYPTING a RELAY cell, an implementation does the following:
+
+```text
+ # Encode the cell in binary (recognized and digest set to zero)
+ tmp = cmd + [0, 0] + stream_id + [0, 0, 0, 0] + length + data + padding
+
+ # Update the digest with the encoded data
+ digest_state = hash_update(digest_state, tmp)
+ digest = hash_calculate(digest_state)
+
+ # The encoded data is the same as above with the digest field not being
+ # zero anymore
+ encoded = cmd + [0, 0] + stream_id + digest[0..4] + length + data +
+ padding
+
+ # Now we can encrypt the cell by adding the onion layers ...
+
+ When DECRYPTING a RELAY cell, an implementation does the following:
+
+ decrypted = decrypt(cell)
+
+ # Replace the digest field in decrypted by zeros
+ tmp = decrypted[0..5] + [0, 0, 0, 0] + decrypted[9..]
+
+ # Update the digest field with the decrypted data and its digest field
+ # set to zero
+ digest_state = hash_update(digest_state, tmp)
+ digest = hash_calculate(digest_state)
+
+ if digest[0..4] == decrypted[5..9]
+ # The cell has been fully decrypted ...
+```
+
+The caveat itself is that only the binary data with the digest bytes set to
+zero are being taken into account when calculating the running digest. The
+final plain-text cells (with the digest field set to its actual value) are
+not taken into the running digest.
+