Subject: [tcpm] I-D Action:draft-ietf-tcpm-tcp-auth-opt-01.txt

From: [email-masked]
Date: Mon, 14 Jul 2008 16:45:02 -0700 (PDT)

A New Internet-Draft is available from the on-line Internet-Drafts directories.
This draft is a work item of the TCP Maintenance and Minor Extensions Working Group of the IETF.

	Title           : The TCP Authentication Option
	Author(s)       : J. Touch, et al.
	Filename        : draft-ietf-tcpm-tcp-auth-opt-01.txt
	Pages           : 30
	Date            : 2008-07-14

This document specifies a TCP Authentication Option (TCP-AO) which is 
intended to replace the TCP MD5 Signature option of RFC-2385 (TCP 
MD5). TCP-AO specifies the use of stronger Message Authentication 
Codes (MACs) and provides more details on the association of security 
associations with TCP connections. TCP-AO assumes an external, out-
of-band mechanism (manual or via a separate protocol) for session key 
establishment, parameter negotiation, and rekeying, replicating the 

 separation of key management and key use as in the IPsec suite. The 
result is intended to be a simple modification to support current 
infrastructure uses of TCP MD5, such as to protect BGP and LDP, and 
to support a larger set of MACs with minimal other system and 
operational changes. TCP-AO uses a new option identifier, even though 
it is intended to be mutually exclusive with TCP MD5 on a given TCP 
connection. It supports IPv6, and is fully compatible with 
requirements under development for an update to TCP MD5.

A URL for this Internet-Draft is:
http://www.ietf.org/internet-drafts/draft-ietf-tcpm-tcp-auth-opt-01.txt

Internet-Drafts are also available by anonymous FTP at:
ftp://ftp.ietf.org/internet-drafts/

Below is the data which will enable a MIME compliant mail reader
implementation to automatically retrieve the ASCII version of the
Internet-Draft.
_______________________________________________
tcpm mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/tcpm

---

From: "Adam Langley" <[email-masked]>
Date: Mon, 14 Jul 2008 19:04:58 -0700

Going by the changes section:

> requiring an algorithm for nonce introduction based on ISNs"
...
> The presence of TCP's pair of
>   Initial Sequence Numbers presents a nonce that may be useful in that
>   case. Such a nonce could be computed as the concatenation of the ISNs
>   (initiator, responder), and the socket pair (addresses, ports):

>   o  Nonce = ISN_i, ISN_r, IP_address_i, IP_address_r, port_i, port_r

I'd like to step back and review this for a moment:

We have a couple of reasons for wanting to define an nonce:

Reason 1: Without a monotonic counter, a MAC is open to replay
attacks. I'm not sure how serious this is. Certainly you can elicit
different behaviour from stacks by replaying, say, an ACK very
quickly. This is undesirable, but it might be acceptable. More
troubling is the possibility of exploiting sequence number rollover to
inject a valid packet from 2^32 bytes in the past into the current
stream. A monotonic nonce would mean that we could reject replays.

Reason 2: Some MAC functions require an nonce as an input and their
security depends on the nonce never being reused for any other message
with the same key. Consider a connection where all the
application-level data transfer is one way and a packet, seq number n,
is lost by the network. Here, it's very possible that an ACK for n-1
is transmitted, followed by an ACK for n-1 with a SACK option. Now
we've transmitted two different messages with the same nonce. Any
nonce based only the sequence numbers has this problem unless we
disable/don't include SACK. Also, if we are only including 32-bits of
seq, then we trivially repeat every 2^32 bytes.

The suggested nonce scheme, above, thus doesn't suffice for reason 2.
However, since the ISNs and pseudoheader are already included in the
MAC's input, it doesn't do anything for reason 1 either. I don't
believe adding in the IP ID would help either.

Option 1: don't define an nonce, accept the reply-attack implications
and disallow MACs which require strong nonces

Option 2: define a 64-bit message counter in each direction, include
the bottom n-bits in the AO option and allow some small amount of
reordering. Reject duplicate messages. This solves reasons 1 and 2 but
requires extra option data and extra state.

Option 3: use the seq number as the bottom 32-bits of a 64-bit
sequence. It solves replay attacks after 2^32 bytes, but not some
other replay attacks. It doesn't solve reason 2. It involves extra
state. However, if options are not included in the message, then this
*does* solve reason 2 I suspect. I'd want some wiser minds to confirm
this however.

Option 2 is the cryptographically strong solution. Consider the
options in a packet:
  10 bytes of timestamp option
  18 bytes of AO (96-bit MAC + 2 bytes of option header + key id + nonce)
  12 bytes remaining (enough for one SACK block)

If the key id was only a bit, then we have 31 low bits of message
counter. That's acceptable I think. It would require a packet loss
burst of 3^30 packets to de-sync the hosts (which implies a window of
> 1 TB @ 1500 MTU). It's really cramming things, however and the
storing the counter-space holes to allow for reordering might become
expensive if the reorder window is large.

So, although I like option 2, any of them would be ok. But I think the
current wording in the spec needs to be clearer about which we're
choosing.

> Clarify NAT interaction

I do believe that some method of getting through common NATs (other
than wrapping the packets in a tunnel) is needed. There was my
previous suggestion of making pseudo-header inclusion optional and
having userspace specify a 20-byte bit mask, which is applied to the
TCP header (I'll concede that it's a painful 20-bytes of extra state).
Alternatively, the common case can be specified with a single bit to
remove the pseudo-header and port numbers from the MAC's input.

AGL

-- 
Adam Langley [email-masked] http://www.imperialviolet.org
_______________________________________________
tcpm mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/tcpm

---

From: Joe Touch <[email-masked]>
Date: Mon, 14 Jul 2008 20:33:11 -0700

Hi, Adam,

Adam Langley wrote:
> attacks. 

The nonce is for generating per-session keys, not for per-packet 
operations. Per packet uniqueness is discussed in the replay section of 
the Security Considerations, and is governed primarily by the TCP 
sequence number, and the strong suggestion (elsewhere) to change the key 
every 2^31 bytes if uniqueness is a concern.

...
> believe adding in the IP ID would help either.

We can't add in the IP ID as a rule; this mechanism needs to work for 
IPv6 - which, when not source fragmented, has no such ID (see also my 
other I-D deprecating IPv4 ID uniqueness for related reasons).

This is, as noted above, only to ensure session key uniqueness. It 
removes the need to check for key reuse.

----

As to per-packet uniqueness...

> *does* solve reason 2 I suspect. I'd want some wiser minds to confirm

Option 4 is what we currently suggest, which is:
use the 32-bit sequence number as the per-packet nonce, and encourage 
rekeying every 2^31 bytes or so.

This is preferable to the above because:
	- it avoids the need for additional state in TCP that
	can be hard to manage when retransmissions straddle
	rollover (i.e., state changes not already inside TCP);
	this state is complex whether it's the top part of a
	counter or a new counter

	- it avoids the space a full new counter would consume
	in the option

	- it still provides a nonce (I don't see how to "disallow"
	MACs that require a nonce. I don't know what a "strong"
	nonce is, though - nonce just means unique. If 'strong'
	means 'random', that's different (i.e., entropy inducer,
	vs. just unique).

Finally, if none of that is sufficient and users need true nonces, then 
other protocols might be preferable (e.g., IPsec); this isn't intended 
to be a complete solution for all situations.

> remove the pseudo-header and port numbers from the MAC's input.

I prefer including the expected addrs and port numbers for the following 
reason:

1. TCP-AO needs to know what the addr/port pair is at the receiver 
behind the NAT anyway in order to match keys to connections

2. if the addr/port pair at the dest is known, it could be coordinated 
with the source and the source can include those values when computing 
the MAC

i.e., if you have enough information to make keying work properly, you 
have enough to compute a valid received MAC that includes the addrs and 
ports, and thus validates that info when a message is received.

Joe

---

From: "Adam Langley" <[email-masked]>
Date: Mon, 14 Jul 2008 21:58:41 -0700

On Mon, Jul 14, 2008 at 8:33 PM, Joe Touch <[email-masked]> wrote:
> The nonce is for generating per-session keys, not for per-packet operations.
> Per packet uniqueness is discussed in the replay section of the Security
> Considerations, and is governed primarily by the TCP sequence number, and
> the strong suggestion (elsewhere) to change the key every 2^31 bytes if
> uniqueness is a concern.

Right, sorry I misunderstood that.

> rekeying every 2^31 bytes or so.

Ok. That's what I called option one,

>        means 'random', that's different (i.e., entropy inducer,

Some MACs accept a pair as their input (M,n) where n is a strong
nonce. These MACs require that a given nonce, n, never be used with
two different messages. If you do, then you may well be exposing key
information etc (the security proof is invalid so anything's
possible). Since we can't guarantee this, we just have to exclude them
I believe. Since the well known MACs (MD5, SHA family etc) are not of
this type it's not a big issue.

> 1. TCP-AO needs to know what the addr/port pair is at the receiver behind
> the NAT anyway in order to match keys to connections

Only in the case where a listening socket is configured with a list of
(source, key) pairs. That's the case with routers and BGP sessions
etc, but one could certainly imagine TCP-AO as a (better) alternative
to port-knocking schemes. Also, it doesn't work for connections where
the AO key is established by the application level after the TCP
handshake. (Although, in the latter case, one could argue that each
host should tell the other its NAT translated identity just to make AO
work).

AGL

---

From: Joe Touch <[email-masked]>
Date: Tue, 15 Jul 2008 11:58:48 -0700

Hi, all,

> 	Filename        : draft-ietf-tcpm-tcp-auth-opt-01.txt

FYI, a list of changes and remaining open issues is contained in the 
document.

Joe

---

From: "Adam Langley" <[email-masked]>
Date: Tue, 15 Jul 2008 17:36:32 -0700

...

Simple typo, section 4:

"       a. TCP option exclusion flag. When 0, this flag allows default
          operation, i.e., TCP options are  When 1, all options "

I think there should be "included" after "are".

AGL

---

From: Joe Touch <[email-masked]>
Date: Tue, 15 Jul 2008 17:46:35 -0700

> I think there should be "included" after "are".

Yes - simple typo ;-(

Joe

---

From: "Adam Langley" <[email-masked]>
Date: Wed, 16 Jul 2008 10:40:06 -0700

>>        Filename        : draft-ietf-tcpm-tcp-auth-opt-01.txt

Another thought: the keyid should be at the beginning of the MAC. We
want the options to be 4-byte aligned if at all possible and we want
the MAC to also be 4 byte aligned because CPUs have an easier time the
aligned data.

Currently (with the key ID at the end) the option, on the wire, looks like:
  NOP OPT 15 <12 bytes of MAC> KeyID   (16 bytes, 96-bit MAC)
or
  NOP OPT 19 <16 bytes of MAC> KeyID   (20 bytes, 128-bit MAC)

Both MACs are unaligned. Moving the KeyID to the beginning means that
the MACs would be 4-byte aligned:
  NOP OPT 15 KeyID <12 bytes of MAC> etc

Cheers,

AGL

---

From: Joe Touch <[email-masked]>
Date: Wed, 16 Jul 2008 14:13:25 -0700

> the MAC to also be 4 byte aligned because CPUs have an easier time the

We can place the keyID wherever it's most useful; note that putting the 
KeyID at the front will probably make the MAC non-wordaligned.

>   NOP OPT 15 KeyID <12 bytes of MAC> etc

This presumes that we misalign the option to start, using the NOP. I 
would prefer to assume that the option starts word-aligned. I don't see 
a way to do that, though, without wasting another byte in the option. 
The goal is currently to assume a half-word aligned start, and let the 
next option decide whether to pad or not. At that point, it's better to 
leave the MAC half-word aligned too.

I.e., there are various concerns here, and a solution isn't very clear. 
Thoughts from anyone else on this?

Joe

---

From: "Adam Langley" <[email-masked]>
Date: Wed, 16 Jul 2008 14:54:13 -0700

On Wed, Jul 16, 2008 at 2:13 PM, Joe Touch <[email-masked]> wrote:
> This presumes that we misalign the option to start, using the NOP. I would
> prefer to assume that the option starts word-aligned. I don't see a way to
> do that, though, without wasting another byte in the option. The goal is
> currently to assume a half-word aligned start, and let the next option
> decide whether to pad or not. At that point, it's better to leave the MAC
> half-word aligned too.

Just as a couple of data points:
  * Linux writes options in 32-bit chunks and pads with NOPs before
the option to make the option a multiple of 4 bytes long
  * FreeBSD appears to pad with NOPs before the option too[1]

[1] http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/sys/netinet/tcp_output.c?rev=1.151;content-type=text%2Fplain
  tcp_addoptions function

AGL

---

From: Joe Touch <[email-masked]>
Date: Wed, 16 Jul 2008 15:38:17 -0700

>   * FreeBSD appears to pad with NOPs before the option too[1]

Both of these seem strange. They end up making the end of the option 
align, but disturb the front of the option. Why don't they pad at the end?

(TCP requires only that the last option have that pad, too)

Joe

---

From: "Adam Langley" <[email-masked]>
Date: Wed, 16 Jul 2008 16:09:15 -0700

On Wed, Jul 16, 2008 at 3:38 PM, Joe Touch <[email-masked]> wrote:
> Both of these seem strange. They end up making the end of the option align,
> but disturb the front of the option. Why don't they pad at the end?

So here's my hypothesis (and it's only a guess really):

It's good to write in 32-bit words for speed reasons. Also, some
architectures make writing non-aligned 32-bit words hard. Now,
consider the SACK and timestamp options, you want to write a 32-bit
header followed by a payload (2 32-bit words for timestamp and 2*n
words for SACK). So you want the payload to be 32-bit aligned for both
writing and reading. So you end up with:
  uint32_t *ptr;

  *ptr++ = htonl((NOP << 24) | (NOP << 16) | (TCP_OPT_TS << 8) | length)
  *ptr++ = htonl(timestamp_1)
  *ptr++ = htonl(timestamp_2)

and, from the timestamp and SACK options all the others keep the same
style of padding with NOPs before the option.

AGL

---

From: Joe Touch <[email-masked]>
Date: Wed, 16 Jul 2008 16:13:32 -0700

Adam Langley wrote:
> writing and reading. 

That makes sense, but putting the pad at the beginning of every option 
vs. at the end of that option makes no sense AFIACT.

(putting the pad for each option is inefficient, esp. since options 
aren't all that big a space and need to be byte-parsed anyway).

Joe

---

From: Stefanos Harhalakis <[email-masked]>
Date: Thu, 17 Jul 2008 03:25:59 +0300

> vs. at the end of that option makes no sense AFIACT.

If I see this correctly, it makes no difference at all since the padding will 
be added after all. It seems more as a matter of programming convenience. 
Indeed TIMESTAMPs, SACK and MD5 are added with 16 bit padding each in data 
segments and something similar happens for syn segments too.

> aren't all that big a space and need to be byte-parsed anyway).

(In linux kernel) When using timestamps and SACK, a word (32bits) is filled 
with NOPs.I believe that the current approach is an accepted one since it 
doesn't violate any RFC and it doesn't reduce the available space long enough 
to cause problems. Is there a way that the extra 32 bits could be used (as of 
today)?

Apart from that, I believe that you (we) should fill a bug report.

FYI: Git shows that the oldest corresponding lines were last changed at 2006 
by Stephen Hemminger and Yoshifuji Hideaki.
_______________________________________________
tcpm mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/tcpm

---

From: "Adam Langley" <[email-masked]>
Date: Wed, 16 Jul 2008 17:41:10 -0700

> Apart from that, I believe that you (we) should fill a bug report.

Well, since I was the last person to rewrite the options code in
Linux(*), you might as well tell me here :)

I'm not sure exactly what the issue is here. There isn't excessive
padding: 99.9% of packets have only a timestamp option and thus have
the minimal amount of padding. The advantage of writing/reading
aligned data outweighs better compaction in SYN frames since there's
(currently) no options that we excluded because of the padding.

(*) it should be in .27, maybe .28

AGL

---

From: Stefanos Harhalakis <[email-masked]>
Date: Fri, 18 Jul 2008 17:32:50 +0300

> (currently) no options that we excluded because of the padding.

There are not many more things to report that those discussed in the list:
* The ability to store more options when necessary
* 4 bytes of extra space for data when TSs and SACKs are included
* 4xN less bytes transmitted over the network in each session (where N is the 
number of segments with TS+SACK that are sent)

>From a very sallow test/accounting I've just performed (1 minute run) on a 
linux firewall for a not so large, not congested network, it seems that about 
3-4% of the TS segments also include a SACK header and that there could be 
saved about 1 byte every 7-8 TS-enabled segments (not counting SYN segments).

Sample results:

ts: 7497, tssack: 255, noop: 1020
ts: 8133, tssack: 347, noop: 1388
ts: 7295, tssack: 270, noop: 1080
ts: 7030, tssack: 265, noop: 1060
ts: 7162, tssack: 234, noop: 936
ts: 7328, tssack: 294, noop: 1176

1st column is segments with TS, second is segments with TS+SACK (also counted 
in first column), third column is SUM(floor(NOOP_count/4)*4) (number of bytes 
that where transmitted as NOOP and could be saved (only counts 32 bit 
words)).

Is it worth?

---

From: [email-masked]
Date: Fri, 18 Jul 2008 08:59:51 -0700

Quoting Stefanos Harhalakis <[email-masked]>:

..
> saved about 1 byte every 7-8 TS-enabled segments (not counting SYN
..
> that where transmitted as NOOP and could be saved (only counts 32 bit 

If nothing changes, probably not. However, legacy TCP is likely to be around for
a while, so conservation is critical to using that space for other things.

Also, the space is most critical in the SYNs; that is the only place where
capabilities are negotiated.

Joe

---

From: "Adam Langley" <[email-masked]>
Date: Mon, 21 Jul 2008 12:43:58 -0700

>        Filename        : draft-ietf-tcpm-tcp-auth-opt-01.txt

An item which I believe is unclear in the spec:

Are KeyIDs specific to a single direction? E.g if A and B are
transmitting with different keys, could they both call them KeyID 0?
At the moment the wording around the TSAD seems to allow this
(specifically 6.1).

Also, comments on the linux netdev mailing list got me thinking more
about key rotation and I think the spec probably needs a sentence or
two advising about the use of key rotation.

The spec currently suggests that rotation occur every 2**31 bytes
sent. It's not clear if the keys for each direction are assumed to
rotate independently or not.

If the directions are independent then a large one-way transfer allows
an attacker to build up a dictionary of valid ACKs. Since the transfer
is only one way, the ACKing side will never rotate keys. Thus an
attacker could step in and convince the sender that everything was
fine even if the true destination was dead.

If the keys rotate after 2**31 bytes sent or recved there is a
possible window issue. Consider a host which is sending with a very
large window over a high delay link. It transmits several key
rotations worth of data before the first ack comes back from the other
side. Since this ack was elicited by the beginning of the data, it
will be transmitted with the first key. If the first key is still
active, everything is fine, but if the key window has rotated to the
point where old keys are getting evicted then the ACK will be
rejected.

This currently shouldn't be a problem because the max window size is
1GB, which is less than 2**31 bytes. At some point in the future, if
window scaling is allowed to grow past 2**14, then key rotation could
limit the window size.

Given all these questions, I think the spec should make some advisory remarks.

I'm not too sure, but I think I like rotating a per-direction key
better. The ACK dictionary attack is unfortunate, but if we aren't
having real sequence numbers then our security is limited at best
anyway. Based on that I'd suggest a 2-key pair, where, for a
half-connection from A to B: B RX enables key 1 at 2**30 bytes
received, A switches to key 1 at 2**31 bytes, B RX enables a new key 0
at 2**31 + 2**30 bytes, A switches to new key 0 at 2**32 etc. That
would also mean that KeyIDs are specific to a given half-connection.

AGL

---

From: Joe Touch <[email-masked]>
Date: Mon, 21 Jul 2008 13:44:56 -0700

Hi, Adam,

Adam Langley wrote:
| 2008/7/14  <[email-masked]>:
|> A New Internet-Draft is available from the on-line Internet-Drafts
directories.
|>        Title           : The TCP Authentication Option
|>        Author(s)       : J. Touch, et al.
|>        Filename        : draft-ietf-tcpm-tcp-auth-opt-01.txt
|
| An item which I believe is unclear in the spec:
|
| Are KeyIDs specific to a single direction? E.g if A and B are
| transmitting with different keys, could they both call them KeyID 0?
| At the moment the wording around the TSAD seems to allow this
| (specifically 6.1).

Yes.

| Also, comments on the linux netdev mailing list got me thinking more
| about key rotation and I think the spec probably needs a sentence or
| two advising about the use of key rotation.

How often would be in the key management document; we don't specify that.

| The spec currently suggests that rotation occur every 2**31 bytes
| sent. It's not clear if the keys for each direction are assumed to
| rotate independently or not.

They are. The purpose of key rotation based on 2**31 is replay attacks,
not frequency of rotation for other reasons. Others have noted that such
rotation may not be needed with modern HMACs.

| If the directions are independent then a large one-way transfer allows
| an attacker to build up a dictionary of valid ACKs. Since the transfer
| is only one way, the ACKing side will never rotate keys. Thus an
| attacker could step in and convince the sender that everything was
| fine even if the true destination was dead.

The ACKing side needs to rotate keys only when its seqnums rollover, not
the ones it's ACKing.

| If the keys rotate after 2**31 bytes sent or recved there is a
| possible window issue. Consider a host which is sending with a very
| large window over a high delay link. It transmits several key
| rotations worth of data before the first ack comes back from the other
| side. Since this ack was elicited by the beginning of the data, it
| will be transmitted with the first key. If the first key is still
| active, everything is fine, but if the key window has rotated to the
| point where old keys are getting evicted then the ACK will be
| rejected.

The key rotations are supposed to be reasonably synchronized and/or
overlapped to avoid such issues.

| This currently shouldn't be a problem because the max window size is
| 1GB, which is less than 2**31 bytes. At some point in the future, if
| window scaling is allowed to grow past 2**14, then key rotation could
| limit the window size.

This isn't an issue of window scaling; it's an issue of replaying. Keys
are rotated per 2**31 (recommended, at least) based on the rollover of
the seqno; they can be rotated for other reasons as well.

| Given all these questions, I think the spec should make some advisory
remarks.
|
| I'm not too sure, but I think I like rotating a per-direction key
| better. The ACK dictionary attack is unfortunate, but if we aren't
| having real sequence numbers then our security is limited at best
| anyway. Based on that I'd suggest a 2-key pair, where, for a
| half-connection from A to B: B RX enables key 1 at 2**30 bytes
| received, A switches to key 1 at 2**31 bytes, B RX enables a new key 0
| at 2**31 + 2**30 bytes, A switches to new key 0 at 2**32 etc. That
| would also mean that KeyIDs are specific to a given half-connection.

They should already be; the TSAD entries are specified per-direction for
that reason.

Joe