
* Moved the current net's reseed URL to a different location than where the old net looks (dev.i2p.net/i2pdb2/ vs .../i2pdb/) * More aggressively expire inbound messages (on receive, not just on send) * Add in a hook for breaking backwards compatibility in the SSU wire protocol directly by including a version as part of the handshake. The version is currently set to 0, however, so the wire protocol from this build is compatible with all earlier SSU implementations. * Increased the number of complete message readers, cutting down substantially on the delay processing inbound messages. * Delete the message history file on startup * Reworked the restart/shutdown display on the console (thanks bd_!)
760 lines
32 KiB
HTML
760 lines
32 KiB
HTML
<code>$Id: udp.html,v 1.19 2006/02/15 00:33:32 jrandom Exp $</code>
|
|
|
|
<h1>Secure Semireliable UDP (SSU)</h1>
|
|
<b>DRAFT</b>
|
|
|
|
<p>
|
|
The goal of this protocol is to provide secure, authenticated,
|
|
semireliable, and unordered message delivery, exposing only a minimal
|
|
amount of data easily discernible to third parties. It should
|
|
support high degree communication as well as TCP-friendly congestion
|
|
control, and may include PMTU detection. It should be capable of
|
|
efficiently moving bulk data at rates sufficient for home users.
|
|
In addition, it should support techniques for addressing network
|
|
obstacles, like most NATs or firewalls.</p>
|
|
|
|
<h2><a name="addressing">Addressing and introduction</a></h2>
|
|
|
|
<p>To contact an SSU peer, one of two sets of information is necessary:
|
|
a direct address, for when the peer is publicly reachable, or an
|
|
indirect address, for using a third party to introduce the peer.
|
|
There is no restriction on the number of addresses a peer may have.</p>
|
|
|
|
<pre>
|
|
Direct: ssu://host:port/introKey[?opts=[A-Z]*]
|
|
Indirect: ssu://tag@relayhost:port/relayIntroKey/targetIntroKey[?opts=[A-Z]*]
|
|
</pre>
|
|
|
|
<p>These introduction keys are delivered through an external channel
|
|
and must be used when establishing a session key. For the indirect
|
|
address, the peer must first contact the relayhost and ask them for
|
|
an introduction to the peer known at that relayhost under the given
|
|
tag. If possible, the relayhost sends a message to the addressed
|
|
peer telling them to contact the requesting peer, and also gives
|
|
the requesting peer the IP and port on which the addressed peer is
|
|
located. In addition, the peer establishing the connection must
|
|
already know the public keys of the peer they are connecting to (but
|
|
not necessary to any intermediary relay peer).</p>
|
|
|
|
<p>Each of the addresses may also expose a series of options - special
|
|
capabilities of that particular peer. For a list of available
|
|
capabilities, see <a href="#capabilities">below</a>.</p>
|
|
|
|
<h2><a name="header">Header</a></h2>
|
|
|
|
<p>All UDP datagrams begin with a MAC and an IV, followed by a variable
|
|
size payload encrypted with the appropriate key. The MAC used is
|
|
HMAC-MD5, truncated to 16 bytes, while the key is a full AES256
|
|
key. The specific construct of the MAC is the first 16 bytes from:</p>
|
|
<pre>
|
|
HMAC-MD5(payload || IV || (payloadLength ^ protocolVersion), macKey)
|
|
</pre>
|
|
|
|
<p>The payload itself is AES256/CBC encrypted with the IV and the
|
|
sessionKey, with replay prevention addressed within its body,
|
|
explained below. The payloadLength in the MAC is a 2 byte unsigned
|
|
integer in 2s complement.</p>
|
|
|
|
<p>The protocolVersion is a 2 byte unsigned integer in 2s complement,
|
|
and currently set to 0. Peers using a different protocol version will
|
|
not be able to communicate with this peer, though earlier versions not
|
|
using this flag are.</p>
|
|
|
|
<h2><a name="payload">Payload</a></h2>
|
|
|
|
<p>Within the AES encrypted payload, there is a minimal common structure
|
|
to the various messages - a one byte flag and a four byte sending
|
|
timestamp (*seconds* since the unix epoch). The flag byte contains
|
|
the following bitfields:</p>
|
|
<pre>
|
|
bits 0-3: payload type
|
|
bit 4: rekey?
|
|
bit 5: extended options included
|
|
bits 6-7: reserved
|
|
</pre>
|
|
|
|
<p>If the rekey flag is set, 64 bytes of keying material follow the
|
|
timestamp. If the extended options flag is set, a one byte option
|
|
size value is appended to, followed by that many extended option
|
|
bytes, which are currently uninterpreted.</p>
|
|
|
|
<p>When rekeying, the first 32 bytes of the keying material is fed
|
|
into a SHA256 to produce the new MAC key, and the next 32 bytes are
|
|
fed into a SHA256 to produce the new session key, though the keys are
|
|
not immediately used. The other side should also reply with the
|
|
rekey flag set and that same keying material. Once both sides have
|
|
sent and received those values, the new keys should be used and the
|
|
previous keys discarded. It may be useful to keep the old keys
|
|
around briefly, to address packet loss and reordering.</p>
|
|
|
|
<pre>
|
|
Header: 37+ bytes
|
|
+----+----+----+----+----+----+----+----+
|
|
| MAC |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| IV |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|flag| time | (optionally |
|
|
+----+----+----+----+----+ |
|
|
| this may have 64 byte keying material |
|
|
| and/or a one+N byte extended options) |
|
|
+---------------------------------------|
|
|
</pre>
|
|
|
|
<h2><a name="messages">Messages</a></h2>
|
|
|
|
<h3><a name="sessionRequest">SessionRequest (type 0)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Alice to Bob</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>256 byte X, to begin the DH agreement</li>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Bob's IP address</li>
|
|
<li>N bytes, currently uninterpreted (later, for challenges)</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>introKey</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
| X, as calculated from DH |
|
|
| |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| that many byte IP address (4-16) |
|
|
+----+----+----+----+----+----+----+----+
|
|
| arbitrary amount |
|
|
| of uninterpreted data |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="sessionCreated">SessionCreated (type 1)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Bob to Alice</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>256 byte Y, to complete the DH agreement</li>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Alice's IP address</li>
|
|
<li>2 byte port number (unsigned, big endian 2s complement)</li>
|
|
<li>4 byte relay tag which Alice can publish (else 0x0)</li>
|
|
<li>4 byte timestamp (seconds from the epoch) for use in the DSA
|
|
signature</li>
|
|
<li>40 byte DSA signature of the critical exchanged data
|
|
(X + Y + Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's
|
|
new relay tag + Bob's signed on time), encrypted with another
|
|
layer of encryption using the negotiated sessionKey. The IV
|
|
is reused here.</li>
|
|
<li>8 bytes padding, encrypted with an additional layer of encryption
|
|
using the negotiated session key as part of the DSA block</li>
|
|
<li>N bytes, currently uninterpreted (later, for challenges)</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>introKey, with an additional layer of encryption over the 40 byte
|
|
signature and the following 8 bytes padding.</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
| Y, as calculated from DH |
|
|
| |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| that many byte IP address (4-16) |
|
|
+----+----+----+----+----+----+----+----+
|
|
| Port (A)| public relay tag | signed
|
|
+----+----+----+----+----+----+----+----+
|
|
on time | |
|
|
+----+----+ |
|
|
| DSA signature |
|
|
| |
|
|
| |
|
|
| |
|
|
| +----+----+----+----+----+----+
|
|
| | (8 bytes of padding)
|
|
+----+----+----+----+----+----+----+----+
|
|
| |
|
|
+----+----+ |
|
|
| arbitrary amount |
|
|
| of uninterpreted data |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="sessionConfirmed">SessionConfirmed (type 2)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Alice to Bob</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>1 byte identity fragment info:<pre>
|
|
bits 0-3: current identity fragment #
|
|
bits 4-7: total identity fragments</pre></li>
|
|
<li>2 byte size of the current identity fragment</li>
|
|
<li>that many byte fragment of Alice's identity.</li>
|
|
<li>on the last identity fragment, the signed on time is
|
|
included after the identity fragment, and the last 40
|
|
bytes contain the DSA signature of the critical exchanged
|
|
data (X + Y + Alice's IP + Alice's port + Bob's IP + Bob's port
|
|
+ Alice's new relay key + Alice's signed on time)</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>sessionKey</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
<b>Fragment 1 through N-1</b>
|
|
+----+----+----+----+----+----+----+----+
|
|
|info| cursize | |
|
|
+----+----+----+ |
|
|
| fragment of Alice's full |
|
|
| identity keys |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
<b>Fragment N:</b>
|
|
+----+----+----+----+----+----+----+----+
|
|
|info| cursize | |
|
|
+----+----+----+ |
|
|
| fragment of Alice's full |
|
|
| identity keys |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| signed on time | |
|
|
+----+----+----+----+ |
|
|
| arbitrary amount of uninterpreted |
|
|
| data, up from the end of the |
|
|
| identity key to 40 bytes prior to |
|
|
| end of the current packet |
|
|
+----+----+----+----+----+----+----+----+
|
|
| DSA signature |
|
|
| |
|
|
| |
|
|
| |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="relayRequest">RelayRequest (type 3)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Alice to Bob</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>4 byte relay tag</li>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Alice's IP address</li>
|
|
<li>2 byte port number (of Alice)</li>
|
|
<li>1 byte challenge size</li>
|
|
<li>that many bytes to be relayed to Charlie in the intro</li>
|
|
<li>Alice's intro key (so Bob can reply with Charlie's info)</li>
|
|
<li>4 byte nonce of alice's relay request</li>
|
|
<li>N bytes, currently uninterpreted</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>introKey (or sessionKey, if Alice/Bob is established)</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
| relay tag |size| that many |
|
|
+----+----+----+----+----+ +----|
|
|
| bytes for Alice's IP address |port
|
|
+----+----+----+----+----+----+----+----+
|
|
(A) |size| that many challenge bytes |
|
|
+----+----+ |
|
|
| to be delivered to Charlie |
|
|
+----+----+----+----+----+----+----+----+
|
|
| Alice's intro key |
|
|
| |
|
|
| |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| nonce | |
|
|
+----+----+----+----+ |
|
|
| arbitrary amount of uninterpreted data|
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="relayResponse">RelayResponse (type 4)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Bob to Alice</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Charlie's IP address</li>
|
|
<li>2 byte port number</li>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Alice's IP address</li>
|
|
<li>2 byte port number</li>
|
|
<li>4 byte nonce sent by Alice</li>
|
|
<li>N bytes, currently uninterpreted</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>introKey (or sessionKey, if Alice/Bob is established)</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| that many bytes making up |
|
|
+----+ +----+----+
|
|
| Charlie's IP address | Port (C)|
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| that many bytes making up |
|
|
+----+ +----+----+
|
|
| Alice's IP address | Port (A)|
|
|
+----+----+----+----+----+----+----+----+
|
|
| nonce | |
|
|
+----+----+----+----+ |
|
|
| arbitrary amount of uninterpreted data|
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="relayIntro">RelayIntro (type 5)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Bob to Charlie</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Alice's IP address</li>
|
|
<li>2 byte port number (of Alice)</li>
|
|
<li>1 byte challenge size</li>
|
|
<li>that many bytes relayed from Alice</li>
|
|
<li>N bytes, currently uninterpreted</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>sessionKey</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| that many bytes making up |
|
|
+----+ +----+----+
|
|
| Alice's IP address | Port (A)|
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| that many bytes of challenge |
|
|
+----+ |
|
|
| data relayed from Alice |
|
|
+----+----+----+----+----+----+----+----+
|
|
| arbitrary amount of uninterpreted data|
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="data">Data (type 6)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td>Any</td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>1 byte flags:<pre>
|
|
bit 0: explicit ACKs included
|
|
bit 1: ACK bitfields included
|
|
bit 2: reserved
|
|
bit 3: explicit congestion notification
|
|
bit 4: request previous ACKs
|
|
bit 5: want reply
|
|
bit 6: extended data included
|
|
bit 7: reserved</pre></li>
|
|
<li>if explicit ACKs are included:<ul>
|
|
<li>a 1 byte number of ACKs</li>
|
|
<li>that many 4 byte MessageIds being fully ACKed</li>
|
|
</ul></li>
|
|
<li>if ACK bitfields are included:<ul>
|
|
<li>a 1 byte number of ACK bitfields</li>
|
|
<li>that many 4 byte MessageIds + a 1 or more byte ACK bitfield.
|
|
The bitfield uses the 7 low bits of each byte, with the high
|
|
bit specifying whether an additional bitfield byte follows it
|
|
(1 = true, 0 = the current bitfield byte is the last). These
|
|
sequence of 7 bit arrays represent whether a fragment has been
|
|
received - if a bit is 1, the fragment has been received. To
|
|
clarify, assuming fragments 0, 2, 5, and 9 have been received,
|
|
the bitfield bytes would be as follows:<pre>
|
|
byte 0
|
|
bit 0: 1 (further bitfield bytes follow)
|
|
bit 1: 1 (fragment 0 received)
|
|
bit 2: 0 (fragment 1 not received)
|
|
bit 3: 1 (fragment 2 received)
|
|
bit 4: 0 (fragment 3 not received)
|
|
bit 5: 0 (fragment 4 not received)
|
|
bit 6: 1 (fragment 5 received)
|
|
bit 7: 0 (fragment 6 not received)
|
|
byte 1
|
|
bit 0: 0 (no further bitfield bytes)
|
|
bit 1: 0 (fragment 7 not received)
|
|
bit 1: 0 (fragment 8 not received)
|
|
bit 1: 1 (fragment 9 received)
|
|
bit 1: 0 (fragment 10 not received)
|
|
bit 1: 0 (fragment 11 not received)
|
|
bit 1: 0 (fragment 12 not received)
|
|
bit 1: 0 (fragment 13 not received)</pre></li>
|
|
</ul></li>
|
|
<li>If extended data included:<ul>
|
|
<li>1 byte data size</li>
|
|
<li>that many bytes of extended data (currently uninterpreted)</li</ul></li>
|
|
<li>1 byte number of fragments</li>
|
|
<li>that many message fragments:<ul>
|
|
<li>4 byte messageId</li>
|
|
<li>3 byte fragment info:<pre>
|
|
bits 0-6: fragment #
|
|
bit 7: isLast (1 = true)
|
|
bits 8-9: unused
|
|
bits 10-23: fragment size</pre></li>
|
|
<li>that many bytes</li></ul>
|
|
<li>N bytes padding, uninterpreted</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>sessionKey</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
|flag| (additional headers, determined |
|
|
+----+ |
|
|
| by the flags, such as ACKs or |
|
|
| bitfields |
|
|
+----+----+----+----+----+----+----+----+
|
|
|#frg| messageId | frag info |
|
|
+----+----+----+----+----+----+----+----+
|
|
| that many bytes of fragment data |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| messageId | frag info | |
|
|
+----+----+----+----+----+----+----+ |
|
|
| that many bytes of fragment data |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| messageId | frag info | |
|
|
+----+----+----+----+----+----+----+ |
|
|
| that many bytes of fragment data |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| arbitrary amount of uninterpreted data|
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h3><a name="peerTest">PeerTest (type 7)</a></h3>
|
|
<table border="1">
|
|
<tr><td align="right" valign="top"><b>Peer:</b></td>
|
|
<td><a href="#peerTesting">Any</a></td></tr>
|
|
<tr><td align="right" valign="top"><b>Data:</b></td>
|
|
<td><ul>
|
|
<li>4 byte nonce</li>
|
|
<li>1 byte IP address size</li>
|
|
<li>that many byte representation of Alice's IP address</li>
|
|
<li>2 byte port number</li>
|
|
<li>Alice's introduction key</li>
|
|
<li>N bytes, currently uninterpreted</li>
|
|
</ul></td></tr>
|
|
<tr><td align="right" valign="top"><b>Key used:</b></td>
|
|
<td>introKey (or sessionKey if the connection has already been established)</td></tr>
|
|
</table>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
| test nonce |size| that many |
|
|
+----+----+----+----+----+ |
|
|
|bytes making up Alice's IP address |
|
|
|----+----+----+----+----+----+----+----+
|
|
| Port (A)| Alice or Charlie's |
|
|
+----+----+ |
|
|
| introduction key (Alice's is sent to |
|
|
| Bob and Charlie, while Charlie's is | |
|
|
| sent to Alice) |
|
|
| +----+----+----+----+----+----+
|
|
| | arbitrary amount of |
|
|
|----+----+ |
|
|
| uninterpreted data |
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h2><a name="congestioncontrol">Congestion control</a></h2>
|
|
|
|
<p>SSU's need for only semireliable delivery, TCP-friendly operation,
|
|
and the capacity for high throughput allows a great deal of latitude in
|
|
congestion control. The congestion control algorithm outlined below is
|
|
meant to be both efficient in bandwidth as well as simple to implement.</p>
|
|
|
|
<p>Packets are scheduled according to the the router's policy, taking care
|
|
not to exceed the router's outbound capacity or to exceed the measured
|
|
capacity of the remote peer. The measured capacity should operate along the
|
|
lines of TCP's slow start and congestion avoidance, with additive increases
|
|
to the sending capacity and multiplicative decreases in face of congestion.
|
|
Veering away from TCP, however, routers may give up on some messages after
|
|
a given period or number of retransmissions while continuing to transmit
|
|
other messages.</p>
|
|
|
|
<p>The congestion detection techniques vary from TCP as well, since each
|
|
message has its own unique and nonsequential identifier, and each message
|
|
has a limited size - at most, 32KB. To efficiently transmit this feedback
|
|
to the sender, the receiver periodically includes a list of fully ACKed
|
|
message identifiers and may also include bitfields for partially received
|
|
messages, where each bit represents the reception of a fragment. If
|
|
duplicate fragments arrive, the message should be ACKed again, or if the
|
|
message has still not been fully received, the bitfield should be
|
|
retransmitted with any new updates.</p>
|
|
|
|
<p>The simplest possible implementation does not need to pad the packets to
|
|
any particular size, but instead just places a single message fragment into
|
|
a packet and sends it off (careful not to exceed the MTU). A more efficient
|
|
strategy would be to bundle multiple message fragments into the same packet,
|
|
so long as it doesn't exceed the MTU, but this is not necessary. Eventually,
|
|
a set of fixed packet sizes may be appropriate to further hide the data
|
|
fragmentation to external adversaries, but the tunnel, garlic, and end to
|
|
end padding should be sufficient for most needs until then.</p>
|
|
|
|
<h2><a name="keys">Keys</a></h2>
|
|
|
|
<p>All encryption used is AES256/CBC with 32 byte keys and 16 byte IVs.
|
|
The MAC and session keys are negotiated as part of the DH exchange, used
|
|
for the HMAC and encryption, respectively. Prior to the DH exchange,
|
|
the publicly knowable introKey is used for the MAC and encryption.</p>
|
|
|
|
<p>When using the introKey, both the initial message and any subsequent
|
|
reply use the introKey of the responder (Bob) - the responder does
|
|
not need to know the introKey of the requestor (Alice). The DSA
|
|
signing key used by Bob should already be known to Alice when she
|
|
contacts him, though Alice's DSA key may not already be known by
|
|
Bob.</p>
|
|
|
|
<p>Upon receiving a message, the receiver checks the from IP address
|
|
with any established sessions - if there is one or more matches,
|
|
those session's MAC keys are tested sequentially in the HMAC. If none
|
|
of those verify or if there are no matching IP addresses, the
|
|
receiver tries their introKey in the MAC. If that does not verify,
|
|
the packet is dropped. If it does verify, it is interpreted
|
|
according to the message type, though if the receiver is overloaded,
|
|
it may be dropped anyway.</p>
|
|
|
|
<p>If Alice and Bob have an established session, but Alice loses the
|
|
keys for some reason and she wants to contact Bob, she may at any
|
|
time simply establish a new session through the SessionRequest and
|
|
related messages. If Bob has lost the key but Alice does not know
|
|
that, she will first attempt to prod him to reply, by sending a
|
|
DataMessage with the wantReply flag set, and if Bob continually
|
|
fails to reply, she will assume the key is lost and reestablish a
|
|
new one.</p>
|
|
|
|
<p>For the DH key agreement,
|
|
<a href="http://www.faqs.org/rfcs/rfc3526.html">RFC3526</a> 2048bit
|
|
MODP group (#14) is used:</p>
|
|
<pre>
|
|
p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
|
|
g = 2
|
|
</pre>
|
|
|
|
<p>The DSA p, q, and g are shared according to the scope of the
|
|
identity which created them.</p>
|
|
|
|
<h2><a name="replay">Replay prevention</a></h2>
|
|
|
|
<p>Replay prevention at the SSU layer occurs by rejecting packets
|
|
with exceedingly old timestamps or those which reuse an IV. To
|
|
detect duplicate IVs, a sequence of Bloom filters are employed to
|
|
"decay" periodically so that only recently added IVs are detected.</p>
|
|
|
|
<p>The messageIds used in DataMessages are defined at layers above
|
|
the SSU transport and are passed through transparently. These IDs
|
|
are not in any particular order - in fact, they are likely to be
|
|
entirely random. The SSU layer makes no attempt at messageId
|
|
replay prevention - higher layers should take that into account.</p>
|
|
|
|
<h2><a name="introduction">Introduction</a></h2>
|
|
|
|
<p>Indirect session establishment by means of a third party introduction
|
|
is necessary for efficient NAT traversal. Charlie, a router behind a
|
|
NAT or firewall which does not allow unsolicited inbound UDP packets,
|
|
first contacts a few peers, choosing some to serve as introducers. Each
|
|
of these peers (Bob, Bill, Betty, etc) provide Charlie with an introduction
|
|
tag - a 4 byte random number - which he then makes available to the public
|
|
as methods of contacting him. Alice, a router who has Charlie's published
|
|
contact methods, first sends a RelayRequest packet to one or more of the
|
|
introducers, asking each to introduce her to Charlie (offering the
|
|
introduction tag to identify Charlie). Bob then forwards a RelayIntro
|
|
packet to Charlie including Alice's public IP and port number, then sends
|
|
Alice back a RelayResponse packet containing Charlie's public IP and port
|
|
number. When Charlie receives the RelayIntro packet, he sends off a small
|
|
random packet to Alice's IP and port (poking a hole in his NAT/firewall),
|
|
and when Alice receive's Bob's RelayResponse packet, she begins a new
|
|
full direction session establishment with the specified IP and port.</p>
|
|
|
|
<!--
|
|
should Bob wait for Charlie to ack the RelayIntro packet to avoid
|
|
situations where that packet is lost yet Alice gets Charlie's IP with
|
|
Charlie not yet punching a hole in his NAT for her to get through?
|
|
Perhaps Alice should send to multiple Bobs at once, hoping that at
|
|
least one of them gets through
|
|
-->
|
|
|
|
<h2><a name="peerTesting">Peer testing</a></h2>
|
|
|
|
<p>The automation of collaborative reachability testing for peers is
|
|
enabled by a sequence of PeerTest messages. With its proper
|
|
execution, a peer will be able to determine their own reachability
|
|
and may update its behavior accordingly. The testing process is
|
|
quite simple:</p>
|
|
|
|
<pre>
|
|
Alice Bob Charlie
|
|
PeerTest ------------------->
|
|
PeerTest-------------------->
|
|
<-------------------PeerTest
|
|
<-------------------PeerTest
|
|
<------------------------------------------PeerTest
|
|
PeerTest------------------------------------------>
|
|
<------------------------------------------PeerTest
|
|
</pre>
|
|
|
|
<p>Each of the PeerTest messages carry a nonce identifying the
|
|
test series itself, as initialized by Alice. If Alice doesn't
|
|
get a particular message that she expects, she will retransmit
|
|
accordingly, and based upon the data received or the messages
|
|
missing, she will know her reachability. The various end states
|
|
that may be reached are as follows:</p>
|
|
|
|
<ul>
|
|
<li>If she doesn't receive a response from Bob, she will retransmit
|
|
up to a certain number of times, but if no response ever arrives,
|
|
she will know that her firewall or NAT is somehow misconfigured,
|
|
rejecting all inbound UDP packets even in direct response to an
|
|
outbound packet. Alternately, Bob may be down or unable to get
|
|
Charlie to reply.</li>
|
|
|
|
<li>If Alice doesn't receive a PeerTest message with the
|
|
expected nonce from a third party (Charlie), she will retransmit
|
|
her initial request to Bob up to a certain number of times, even
|
|
if she has received Bob's reply already. If Charlie's first message
|
|
still doesn't get through but Bob's does, she knows that she is
|
|
behind a NAT or firewall that is rejecting unsolicited connection
|
|
attempts and that port forwarding is not operating properly (the
|
|
IP and port that Bob offered up should be forwarded).</li>
|
|
|
|
<li>If Alice receives Bob's PeerTest message and both of Charlie's
|
|
PeerTest messages but the enclosed IP and port numbers in Bob's
|
|
and Charlie's second messages don't match, she knows that she is
|
|
behind a symmetric NAT, rewriting all of her outbound packets with
|
|
different 'from' ports for each peer contacted. She will need to
|
|
explicitly forward a port and always have that port exposed for
|
|
remote connectivity, ignoring further port discovery.</li>
|
|
|
|
<li>If Alice receives Charlie's first message but not his second,
|
|
she will retransmit her PeerTest message to Charlie up to a
|
|
certain number of times, but if no response is received she knows
|
|
that Charlie is either confused or no longer online.</li>
|
|
</ul>
|
|
|
|
<p>Alice should choose Bob arbitrarily from known peers who seem
|
|
to be capable of participating in peer tests. Bob in turn should
|
|
choose Charlie arbitrarily from peers that he knows who seem to be
|
|
capable of participating in peer tests and who are on a different
|
|
IP from both Bob and Alice. If the first error condition occurs
|
|
(Alice doesn't get PeerTest messages from Bob), Alice may decide
|
|
to designate a new peer as Bob and try again with a different nonce.</p>
|
|
|
|
<p>Alice's introduction key is included in all of the PeerTest
|
|
messages so that she doesn't need to already have an established
|
|
session with Bob and so that Charlie can contact her without knowing
|
|
any additional information. Alice may go on to establish a session
|
|
with either Bob or Charlie, but it is not required.</p>
|
|
|
|
<h2><a name="messageSequences">Message sequences</a></h2>
|
|
|
|
<h3><a name="establishDirect">Connection establishment (direct)</a></h3>
|
|
|
|
<pre>
|
|
Alice Bob
|
|
SessionRequest--------------------->
|
|
<---------------------SessionCreated
|
|
SessionConfirmed------------------->
|
|
SessionConfirmed------------------->
|
|
SessionConfirmed------------------->
|
|
SessionConfirmed------------------->
|
|
<--------------------------Data
|
|
</pre>
|
|
|
|
<h3><a name="establishIndirect">Connection establishment (indirect)</a></h3>
|
|
|
|
<pre>
|
|
Alice Bob Charlie
|
|
RelayRequest ---------------------->
|
|
<--------------RelayResponse RelayIntro----------->
|
|
<--------------------------------------------Data (ignored)
|
|
SessionRequest-------------------------------------------->
|
|
<--------------------------------------------SessionCreated
|
|
SessionConfirmed------------------------------------------>
|
|
SessionConfirmed------------------------------------------>
|
|
SessionConfirmed------------------------------------------>
|
|
SessionConfirmed------------------------------------------>
|
|
<---------------------------------------------------Data
|
|
</pre>
|
|
|
|
<h2><a name="sampleDatagrams">Sample datagrams</a></h2>
|
|
|
|
<b>Minimal data message (no fragments, no ACKs, no NACKs, etc)</b><br />
|
|
<i>(Size: 39 bytes)</i>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
| MAC |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| IV |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|flag| time |flag|#frg| |
|
|
+----+----+----+----+----+----+----+ |
|
|
| padding to fit a full AES256 block |
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<b>Minimal data message with payload</b><br />
|
|
<i>(Size: 46+fragmentSize bytes)</i>
|
|
|
|
<pre>
|
|
+----+----+----+----+----+----+----+----+
|
|
| MAC |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| IV |
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|flag| time |flag|#frg|
|
|
+----+----+----+----+----+----+----+----+
|
|
messageId | frag info | |
|
|
+----+----+----+----+----+----+ |
|
|
| that many bytes of fragment data |
|
|
. . .
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
</pre>
|
|
|
|
<h2><a name="capabilities">Peer capabilities</a></h2>
|
|
|
|
<dl>
|
|
<dt>B</dt>
|
|
<dd>If the peer address contains the 'B' capability, that means
|
|
they are willing and able to participate in peer tests as
|
|
a 'Bob' or 'Charlie'.</dd>
|
|
<dt>C</dt>
|
|
<dd>If the peer address contains the 'C' capability, that means
|
|
they are willing and able to serve as an introducer - serving
|
|
as a Bob for an otherwise unreachable Alice.</dd>
|
|
</dl>
|