Previous Page
Next Page

8.4. Tinc

Next, we consider tinc, a system that can provide a VPN network rather than just an encrypted tunnel between two hosts or networks. We can think of a tinc VPN network as a graph of nodes, such as that shown in Figure 8.20, where the edges between the nodes are encrypted and authenticated tunnels. Typically, each node serves as a VPN gateway for one or more subnets behind it. A node could also be a stand-alone host participating in the VPN network. We examine version 1.0.3 of tinc.

Figure 8.20. A Typical Tinc Network


Routing within the VPN network is handled by tinc itself. For example, if node A wants to send a packet to node B, it can send the packet directly through the encrypted tunnel between it and node B. On the other hand, if node A wants to send a packet to node C, it must first send it to node E through the tunnel between nodes A and E. Node E will decrypt and then reencrypt the packet for the tunnel between it and node C and send it through the tunnel to node C. The nodes exchange connectivity information and calculate routing maps in a way reminiscent of OSPF (Chapter 2). This information is continually updated as nodes join or leave the network or become unreachable.

Architecturally, tinc is similar to VTun in that it is implemented entirely in user space. As with VTun, outbound packets are read from the stack, and inbound packets are written to the stack by means of the tun/tap device.

Tinc uses two channels for each VPN: a UDP-based tunnel to carry the payload data of the VPN and a TCP-based connection for the so-called metaconnection that is used to carry control data, such as routing and key-exchange messages. The tinc daemons communicate with each other over the metaconnection, using the tinc metaprotocol.

As with the other lightweight VPNs we've discussed, tinc can operate at either the IP or link layer. When operating at the IP layer, tinc is restricted to carrying IP datagrams. The link-layer mode is used to create Ethernet switches and hubs. We consider only the IP mode, but the link-layer mode is similar.

The Tinc UDP Tunnel

The tinc data-bearing channel follows the now familiar pattern of UDP encapsulation of IP datagrams, as shown in Figure 8.21 for the typical case of a TCP segment.

Figure 8.21. Tinc Encapsulation


As indicated in the figure, tinc can compress its payload data, as well as encrypt and authenticate it.

If we take the point of view of the encapsulating UDP datagram, we see that the tinc binary packet comprises the tinc header, payload data, and tinc footer. The tinc header is a 32-bit packet sequence number. The footer is some or all of an HMAC. Figure 8.22 shows the tinc binary packet format with these features exposed.

Figure 8.22. The Tinc Binary Packet


The sequence number has two purposes. First, it serves the obvious function of preventing replay attacks: Any packet having the same sequence number as a previously received packet is dropped. This task is more difficult than it might seem, because packets can arrive out of order. We'll examine the tinc sequence number-checking mechanism shortly.

The second, less obvious, function of the sequence number is to serve as an IV if tinc is using a block cipher. The sequence number isn't exclusive-ORed into the first block as a traditional IV would be but rather serves as the first 32 bits of the first block. This means that even if two packets have the same data, they will not encrypt to the same ciphertext. This is obvious for the first blocks because the first 32 bits will differ. Subsequent blocks use normal CBC-mode encryption, so they will differ because the first blocks do.

Tinc also uses a traditional IV for the first block, but it is set at key-generation time and is the same for every packet. Thus, it is not useful by itself in hiding identical packets, but because the sequence number changes for every packet, we get the effect of traditional CBC mode.

When the maximum sequence number is reached, tinc generates a new session key, so a sequence number is never reused with the same key. This is important because it prevents an attacker from replaying a packet after the sequence numbers have wrapped. It also limits the amount of data that tinc will encrypt with a single keyanother important step in preventing an attack on the cipher, as we've seen.

The HMAC field is formed by taking a standard HMAC (SHA-1 by default) of the sequence number and data fields and using some or all of the resulting bits. By default, the upper 32 bits are placed in the HMAC field, but this is a user-settable parameter.

Sequence Number Checking

As we mentioned earlier, the use of sequence numbers in a protocol that uses an unreliable transport mechanism is challenging. We can't simply check that the sequence number is one more than that of the last packet, because packets can be lost or delivered out of order. Because packets can be lost, we don't want a missing sequence number to cause us to tear down the tunnel, as we would with SSH or SSL. What we do want is to ensure that each sequence number is seen at most once.

Keeping a list of each sequence number that it's seen isn't practical, of course, so tinc confines its attention to the last 128 sequence numbers and for each one remembers whether it has received a packet with that sequence number. When tinc receives a new, higher sequence number, it forgets the oldest sequence numbers, remembering only the new sequence number and the 127 that come before it. In other words, tinc uses a sliding window that is 128 sequence numbers long, with the right-hand edge of the window at the last sequence number received.

Any packet with a sequence number to the left of the window is dropped, as is any packet with a sequence number lying within the window that tinc has seen before. When tinc receives a packet with a sequence number to the right of the window, it slides the window to the right, forgetting about the sequence numbers that fall off the left-hand edge, whether or not tinc has ever received them.

The Tinc Metaprotocol

As we noted above, tinc sends all its control messages over a separate TCP connection, using the tinc metaprotocol. The messages themselves have a simple line-oriented ASCII format. They would be human readable except that tinc encrypts them by default.

The basic format of a message is

<type> <parameters>

where <type> is an ASCII numeric code specifying the message type, and <parameters> represents one or more parameters. The message types are shown in Figure 8.23.

Figure 8.23. Metaprotocol Message Types

Value

Message

Type Purpose

0

ID

host identification

1

METAKEY

keying material for metaconnection

2

CHALLENGE

authentication challenge

3

CHAL_REPLY

reply to authentication challenge

4

ACK

acknowledgment of correction authentication

5

STATUS

status string for logging

6

ERROR

error notification

7

TERMREQ

request to terminate connection

8

PING

keep-aliveecho request

9

PONG

keep-aliveecho reply

10

ADD_SUBNET

add a subnet to graph

11

DEL_SUBNET

delete a subnet from graph

12

ADD_EDGE

add a node (host) to graph

13

DEL_EDGE

delete a node (host) from graph

14

KEY_CHANGED

node has changed its key

14

REQ_KEY

request a node's key

15

ANS_KEY

reply to key request

16

PACKET

TCP data packet length and data


When one tinc daemon connects to another, both sides send their peer an ID message of the form

ID tinc_host_name protocol_version

When a peer receives this message, it checks that the sender is a valid host and that both sides are using the same protocol version. If so, the peer responds with a METAKEY message of the form

METAKEY cipher_ID digest_ID digest_len compression_ID random_string

The cipher_ID and digest_ID are the OpenSSL cipher and digest typesBlowfish and SHA-1 by defaultthat this node will use for the data channel and also to encrypt the metachannel. The digest_len tells the peer how many bits of the HMAC this host will send with data channel messages.

Tinc can perform optional compression on data channel packets. The compress_ID parameter indicates what type of compression to use: 0 for none, 1 (fast ZLIB)9 (best ZLIB), 10 (fast LZO) and 11 (best LZO). The default is no compression.

The random_string is a hex-encoded string of random bits that are encrypted using the recipient's public RSA key. The bit string is the same length as the modulus of the public key and has the most significant bit set to 0 so that it will have a value less than the modulus of the key, as required by the RSA algorithm. These random bits are used to generate the session key and IV used for metachannel encryption; the metachannel has no integrity checking. After sending the METAKEY message, the node will encrypt all further messages on the metachannel.

The peer receiving a METAKEY message sets the encryption parameters for the incoming connection and responds with a CHALLENGE message of the form

CHALLENGE random_string

The random_string is again the hex-encoding of a random bit string the same size as the modulus of the receiver's public key. The receiver hashes the challenge, using the previously negotiated digest method, and returns the result to the challenge's originator in a CHAL_REPLY message of the form

CHAL_REPLY hash

Up until this point, the sender of the CHALLENGE could not be sure of the identity of its peer, even if it has received a METAKEY message from it. The CHAL_REPLY message is the first encrypted message that it receives from its peer. If the hash is correct, the receiver of the CHAL_REPLY message can be sure that its peer knows the session key used to encrypt the challenge and therefore that it had possession of the RSA private key corresponding to the RSA public key that the receiver of the CHAL_REPLY message used to encrypt the session key.

Once it validates the hash, the receiver of the CHAL_REPLY message responds with an ACK message of the form

ACK port estimated_weight options

The port parameter indicates the port that the node should send the data channel UDP datagrams to. The estimated_weight parameter is an estimate of the latency between the peers. This parameter is used to weight the edges when constructing a minimal spanning tree used for routing broadcast messages, and has three possible options:

IndirectData

A flag indicating that the node is willing to accept connections from nodes that it has not explicitly authorized.

TCPOnly

A flag indicating that the data channel should use TCP encapsulation rather than UDP encapsulation. As we've seen previously, this is usually a bad idea.

PMTUDiscovery

A flag indicating that tinc should try to discover the path MTU to the sending node.


When a node receives the ACK message, it sends its peer a list of all nodes and subnets that it knows about, using the ADD_EDGE and ADD_SUBNET messages that we discuss later. The peer uses this information to update its routing graph. The node will also broadcast information about its new peer and connection to all the hosts in its routing graph. Finally, the peer updates its own routing graph with the connection to its new peer.

A typical authentication protocol exchange is shown in Figure 8.24. The two sides start the protocol independently and then react to the messages from their peer, so the exact flow may differ slightly from that shown in the figure.

Figure 8.24. The Tinc Authentication Protocol


As we've seen, at the end of the authentication protocol, each tinc node will inform its peer of all the other nodes and subnets that it knows about. As other nodes enter and leave the VPN network, tinc nodes will likewise inform their peers about the event. A node informs its peer about the nodes it knows about with the ADD_EDGE message. This message has the form

ADD_EDGE random from to to_addr to_port options weight

where random is some random bytes added as a salt to make known plaintext attacks more difficult. The from parameter is the name of the source node for this connection, and the to parameter is the corresponding destination node for the connection. The to_addr and to_port parameters are the IP address and port of the destination node that the UDP datagrams should be sent to. The options and weight parameters are the same as they were for the ACK message.

Along with the ADD_EDGE message, a node will usually send one or more ADD_SUBNET messages that inform the other nodes of subnets in the VPN network and how to reach them. These messages have the form

ADD_SUBNET random owner_name IP_addr/netmask

As before, the random parameter is some salt added to make cryptanalysis more difficult. The owner_name parameter is the name of the node that owns the subnet that is being added, and the IP_addr/netmask parameter is the IP address and subnet mask of the subnetwork.

Corresponding to the ADD_EDGE and ADD_SUBNET messages, there are DELETE_EDGE and DELETE_SUBNET messages of the forms

DELETE_EDGE random from to
DELETE_SUBNET random owner_name IP_addr/netmask

where the parameters are the same as those for their corresponding ADD_* messages.

Tinc has three messages dealing with key management. If node A wishes to send an encrypted datagram to node B, it must know what session key node B is using. The nodes don't inform each other of their session keys until asked, so the first time node A wants to send a datagram, it won't have a valid key. Therefore, node A will send a REQ_KEY message to node B, asking for its session key. The REQ_KEY message has the form

REQ_KEY from to

where the from parameter is the name of the node requesting the key, and the to parameter is the name of the node from which it is requesting the key.

When a node receives a REQ_KEY message, it responds with an ANS_KEY message of the form

ANS_KEY from to key cipher_ID digest_ID digest_len compression_ID

where from is the name of the owner of the key, to is the name of the node requesting the key, and key is the key itself encoded as a hex string. The cipher_ID, digest_ID, digest_len, and compression_ID are the same as they were in the METAKEY message.

When a node's session key expires because of age or because the sequence numbers are about to wrap, it will generate a new key and notify the rest of the nodes by sending a KEY_CHANGED message. This message has the form

KEY_CHANGED random name

where random is a random salt value, and from is the name of the node whose key has changed. When a node receives this message, it will invalidate its session key for the sending node so that the next time it needs to send that node a datagram, it will first send a REQ_KEY message to get the new key.

Two messages are available to cause the teardown of a connection between two nodes. The TERMREQ message is for an orderly teardown, and the ERROR message is for a teardown caused by an error. These two messages have the forms

TERMREQ
ERROR error_code error_string

where error_code is a numeric code indicating the error, and error_string is a human-readable string that gets logged by the receiver.

A node can cause its peer to log debugging information by sending it a STATUS message. The STATUS message is similar to the ERROR message but does not cause the teardown of the connection between the peers. It has the form

STATUS status_code status_string

where status_code is a numerical status code, and status_string is the corresponding human-readable string for the log.

Recall that tinc has the ability to use TCP encapsulation. When this option is in effect, tinc sends the encrypted datagrams over the metachannel in a PACKET message. This message has the form

PACKET length data

where length is the number of bytes of data that follow, and data is the encrypted datagram.

Finally, tinc has two messages that it uses to test for connectivity. These are the PING and PONG messages, which have the forms

PING
PONG

When a node wants to ensure that its peer is still alive, it sends it a PING message. The peer will respond with a PONG message. If the sender of the PING message does not receive the PONG, it will mark the connection down.

Tinc Security

As with the other VPNs we have studied in this chapter, tinc uses OpenSSL to provide encryption primitives but does not use the SSL protocol itself. Tinc can use any of the encryption algorithms or hash methods that OpenSSL provides, so a tinc user has a large variety of crypto systems available. By default, tinc uses Blowfish and SHA-1, but algorithms with larger block and key sizes, such as AES, are also available.

Let's first look at the authentication protocol. After the ID message, the peers exchange the keys they will use for metaprotocol encryption. There are two criticisms of this procedure. First, each side determines its transmit key by itself, violating the rule that neither side should specify a key completely. On the other hand, the key is used only to transmit data from the node that specified it, so a node can't be tricked into using a weak key by its peer, which is what the rule is meant to prevent. That leaves open the possibility that one peer has a weak random number generator, but because both sides use the OpenSSL random number generator, their results will most likely be similar.

The tinc developers recognize that having one side completely determine the key is a potential weakness, and they indicate that they plan to fix this in version 2.

The second criticism is that the key is encrypted as a raw bit string without any PKCS #1 [RSA Laboratories 2002] padding or other protection. This is also probably safe because the key is a completely random-bit string of the same length as the RSA key modulus. This means that the encrypted key has no structure that an attacker can exploit and that the message is large enough that the trivial decryption we discussed in Chapter 3 is not possible. Because the bit string is completely random, the receiving node can do no verification of its value, so the receiving node will not act as an oracle for active attacks other than for a timing attack that we discuss next.

Tinc installations using older versions of the OpenSSL library are subject to timing attacks on the RSA key, such as those described in [Brumley and Boneh 2003]. These are adaptive chosen text attacks that measure the time to decrypt specially formed messages and use the results to infer the RSA private key. Newer versions of the OpenSSL library perform an operation called RSA blinding, which prevents these attacks. The details are in the Brumley and Boneh paper.

As we've seen, the UDP data channel refreshes its keys after they have been used for a certain amount of time or have been used to send more than a fixed number of messages. This is not the case with the metachannel: The same two keys are used for the life of the connection between two nodes. Although the metachannel will, in general, have much less traffic than the data channel, having long-lived keys is never a good idea.

Again, the tinc implementers recognize this weakness and intend to resolve it in version 2.

Finally, although the metachannel is encrypted, there is no integrity checking. That is, the packets don't have sequence numbers and aren't protected by a MAC. This means that the metachannel traffic is vulnerable to insertion, deletion, cut-and-paste, and replay attacks.

[Gutmann 2003b] criticizes the tinc data channel for using predictable IVs in the form of the sequence numbers and a too small HMAC. The problem with predictable IVs is that they are vulnerable to Rogaway's attack (Chapter 7), but the sequence numbers are part of the data in the packet and are not exclusive-ORed into the block in the normal CBC mode manner. Therefore, the predictability of the sequence numbers does not appear to cause a problem.

The tinc implementers indicate that they are planning to add a conventional IV and move the sequence number out of the ciphertext in a later tinc version.

Tinc's default configuration uses the first 4 bytes from the HMAC calculation for the MAC. RFC 2104 [Krawczyk, Bellare, and Canetti 1997] recommends using the greater of half the bits of the HMAC output or 80 bits. From this perspective, the 32 bits that tinc uses is too small. On the other hand, tinc allows us to specify a larger number of bits, and we should probably do so.

The final problem with the data channel is that the same key is used for encryption and for the HMAC. Cryptographers generally agree that this is a poor practice and can potentially leak information to an attacker.

In summary, tinc appears to have reasonably good security. The problems that we discussed do not appear to be fatal, and the developers have already announced plans to address many of them. We should probably ensure that we have an up-to-date version of OpenSSL (0.9.7b) installed before deploying tinc, in order to avoid the timing attacks that we discussed.


Previous Page
Next Page