Obsolete circuit extension handshakes

Older versions of Tor used a set of non-extensible cells and messages to create and extend circuits.

They also had older cryptographic handshakes to do so.

In this section, we describe those cells, messages, and handshakes.

Clients and relays SHOULD NOT generate or support these.

Support for these formats was removed entirely in Tor 0.4.9.1-alpha. Once all earlier versions of Tor are unsupported, we can move this section to the “historical” heading.

CREATE and CREATED cells

The CREATE and CREATED cells were older versions of CREATE2 and CREATED2, which could only be used for the obsolete TAP circuit extension protocol.

The format of a CREATE cell is one of the following:

FieldDescriptionSize
HDATAClient Handshake DataTAP_C_HANDSHAKE_LEN bytes

or

FieldDescriptionSize
HTAGClient Handshake Type Tag16 bytes
HDATAClient Handshake DataTAP_C_HANDSHAKE_LEN-16 bytes

The first format is equivalent to a CREATE2 cell with HTYPE of ‘tap’ and length of TAP_C_HANDSHAKE_LEN.

The second format is a way to encapsulate new handshake types into the old CREATE cell format for migration. Recognized HTAG values are:

ValueDescription
‘ntorNTORntorNTOR’ntor

Clients SHOULD NOT send the second format of CREATE cells (the one with the handshake type tag) to a server directly. Instead, it was only generated to tunnel ntor requests inside a legacy EXTEND cell.

The format of a CREATED cell is:

FieldDescriptionSize
HDATAServer Handshake DataTAP_S_HANDSHAKE_LEN bytes

(It’s equivalent to a CREATED2 cell with length of TAP_S_HANDSHAKE_LEN.)

Servers always reply to a successful CREATE with a CREATED, On failure, a server sends a DESTROY cell to tear down the circuit.

EXTEND and EXTENDED messages

The body for an (obsolete) EXTEND relay message consists of:

FieldSize
Address4 bytes
Port2 bytes
Onion skinTAP_C_HANDSHAKE_LEN bytes
Identity fingerprintSHA1_LEN bytes

Clients SHOULD NOT send EXTEND messages; relays SHOULD NOT accept them.

The body of an (obsolete) EXTENDED message is the same as the body of a CREATED cell.

Clients SHOULD use the EXTEND format whenever sending a TAP handshake, and MUST use it whenever the EXTEND message will be handled by a node running a version of Tor too old to support EXTEND2. In other cases, clients SHOULD use EXTEND2.

When encoding a non-TAP handshake in an EXTEND message, clients SHOULD use the format with ‘client handshake type tag’.

The “TAP” handshake

This obsolete handshake uses Diffie-Hellman in Zp and RSA to compute a set of shared keys which the client knows are shared only with a particular server, and the server knows are shared with whomever sent the original handshake (or with nobody at all). It’s not very fast and not very good. (See Goldberg’s “On the Security of the Tor Authentication Protocol”.)

Clients SHOULD NOT use this handshake. Relays SHOULD NOT accept this handshake, and MAY reply to it with a DESTROY cell.

Define TAP_C_HANDSHAKE_LEN as DH_LEN+KEY_LEN+KP_PAD_LEN. Define TAP_S_HANDSHAKE_LEN as DH_LEN+SHA1_LEN.

The body for a CREATE cell is an ‘onion skin’, which consists of the first step of the DH handshake data (also known as g^x). This value is encrypted using the “legacy hybrid encryption” algorithm described below, to the server’s onion key (KP_onion_tap), giving a client handshake:

FieldSize
KP-encrypted:
- PaddingKP_PAD_LEN bytes
- Symmetric keyKEY_LEN bytes
- First part of g^xKP_ENC_LEN-KP_PAD_LEN-KEY_LEN bytes
Symmetrically encrypted
- Second part of g^xDH_LEN-(KP_ENC_LEN-KP_PAD_LEN-KEY_LEN) bytes

The body for a CREATED cell, or the body for an EXTENDED relay message, contains:

FieldSize
DH data (g^y)DH_LEN bytes
Derivative key data (KH)SHA1_LEN bytes (see “Setting Circuit Keys”)

As usual with DH, x and y MUST be generated randomly.

Once the handshake between the client and a relay is completed, both can now calculate g^xy with ordinary DH. Before computing g^xy, both parties MUST verify that the received g^x or g^y value is not degenerate; that is, it must be strictly greater than 1 and strictly less than p-1 where p is the DH modulus. Implementations MUST NOT complete a handshake with degenerate keys. Implementations MUST NOT discard other “weak” g^x values.

(Discarding degenerate keys is critical for security; if bad keys are not discarded, an attacker can substitute the relay’s CREATED cell’s g^y with 0 or 1, thus creating a known g^xy and impersonating the relay. Discarding other keys may allow attacks to learn bits of the private key.)

Once both parties have g^xy, they derive their shared circuit keys and ‘derivative key data’ value via the KDF-TOR function.

Before using the circuit, the client must verify that the KH value it has received from the relay matches the KH value that it computed from the KDF.

Note that this “KH” value is unsuitable for some use cases elsewhere in the protocol. That’s fine: This handshake is obsolete, deprecated, and unsupported by modern implementations.

TAP’s bad hybrid encryption algorithm

The description of TAP above refer to the “legacy hybrid encryption” of a byte sequence M with a public key KP. It is computed as follows:

      1. If the length of M is no more than KP_ENC_LEN-KP_PAD_LEN,
         pad and encrypt M with KP.
      2. Otherwise, generate a KEY_LEN byte random key K.
         Let M1 = the first KP_ENC_LEN-KP_PAD_LEN-KEY_LEN bytes of M,
         and let M2 = the rest of M.
         Pad and encrypt K|M1 with KP.  Encrypt M2 with our stream cipher,
         using the key K.  Concatenate these encrypted values.

Note that this “hybrid encryption” approach does not prevent an attacker from adding or removing bytes to the end of M. It also allows attackers to modify the bytes not covered by the OAEP – see Goldberg’s PET2006 paper for details. Do not use it as the basis for new protocols! Also note that as used in TAP protocols, case 1 never occurs.