Subject: [TLS] implementation of cookies in DTLS

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Sun, 13 Mar 2011 18:44:50 +0100

Hello,
 I've been reading the section "Denial of Service Countermeasures"
of DTLS and as I understand it the proposed subsystem (client-hello
and client-hello-verify-request) is expected to operate before
allocating state for the session to discard requests from clients with
forged addresses.

Some comments:
1. The document says: If a server receives a ClientHello with an invalid
cookie, it SHOULD treat it the same as a ClientHello with no cookie.

What does it mean with regards to the handshake sequence. Does the
second HelloVerifyRequest has seq=0 or seq=1?

2. There should be some text on how to determine the sequence
numbers for the initial conversation without keeping state. As I
understand one follows the peer's sequence numbers as reference?

e.g. if I receive
ClientHello (record_seq=0, seq=0)  ------>

<-- HelloVerifyRequest (record_seq=0, seq=0)

ClientHello (record_seq=1, seq=1)  ------> (wrong cookie)

<-- HelloVerifyRequest (record_seq=1, seq=1) [seq copied from clienthello]

ClientHello (record_seq=2, seq=2)  ------> (wrong cookie)

<-- HelloVerifyRequest (record_seq=2, seq=2) [seq copied from clienthello]

ClientHello (record_seq=3, seq=3)  ------>

[server allocates session and continues handshake]

3. The document describes a potential attack of an adversary
collecting multiple cookies from several servers.
Wouldn't adding a 40-bit or more salt to the cookie
eliminate that threat? Given that cookie is pretty
long (32-bytes) spending 5 or more bytes for a salt
and 16 or 20 bytes for an HMAC would be practical.

regards,
Nikos

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Sun, 13 Mar 2011 18:55:45 +0100

On 03/13/2011 06:44 PM, Nikos Mavrogiannopoulos wrote:
> Hello, I've been reading the section "Denial of Service
> Countermeasures" of DTLS and as I understand it the proposed
> subsystem (client-hello and client-hello-verify-request) is expected
> to operate before allocating state for the session to discard
> requests from clients with forged addresses.

Moreover I think that the requirement that the version field
in Client Hello Verify request message, matches the version field
in the Server Hello is pretty awkward.  The Client Hello Verify request
is being sent by the server without allocating any state. Its
quite difficult to mandate that he makes the same decision as if
state was allocated. Requiring the version of DTLS 1.0 would
be more sensible there...

regards,
Nikos

---

From: Robin Seggelmann <[email-masked]>
Date: Mon, 14 Mar 2011 16:12:51 +0100

Hi,

> second HelloVerifyRequest has seq=0 or seq=1?

The second HelloVerifyRequest should have seq=0 again, since the server must not change its state. That's how I implemented it in OpenSSL.  The server does not change any sequence numbers until a cookie has been verified and the regular handshake continues.

> [server allocates session and continues handshake]

That may be helpful, but in my opinion "must not change its state" includes not changing any sequence numbers.

> and 16 or 20 bytes for an HMAC would be practical.

RFC 4347 only makes suggestions how the cookie may look like and also states the problems of the suggested approach which may also apply to similar strategies. You can easily add a timestamp, random number, encryption, etc. for increased security in your implementation. OpenSSL leaves the implementation of cookie generation and verification callback functions to the user. This could be anything from doing nothing to generating a fully featured cookie.

Best regards
Robin

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Mon, 14 Mar 2011 16:30:15 +0100

On 03/14/2011 04:12 PM, Robin Seggelmann wrote:

>> subsystem (client-hello and client-hello-verify-request) is
>> expected to operate before allocating state for the session to
>> discard requests from clients with forged addresses.
>> 
>> Some comments: 1. The document says: If a server receives a
>> ClientHello with an invalid cookie, it SHOULD treat it the same as
>> a ClientHello with no cookie.
>> 
> The second HelloVerifyRequest should have seq=0 again, since the
> server must not change its state. That's how I implemented it in
> OpenSSL.  The server does not change any sequence numbers until a
> cookie has been verified and the regular handshake continues.

What about the record_seq. Is it also 0? If yes  a client
would see this record packet as a replay and discard it. If no
it seems you have to keep state...

>> e.g. if I receive ClientHello (record_seq=0, seq=0)  ------>
>> 
> That may be helpful, but in my opinion "must not change its state"
> includes not changing any sequence numbers.

What is of most concern is the record_seq. A client would just discard
packets with the same sequence number.

regards,
Nikos

---

From: Robin Seggelmann <[email-masked]>
Date: Mon, 14 Mar 2011 16:52:55 +0100

> it seems you have to keep state...

The record_seq is still increased, because it has to be unique. I wouldn't consider this as a problem because it's just a counter you're increasing. There is no resource allocation necessary and there is no benefit for an attacker to send many ClientHellos to increase the sequence number. It's only used for HMAC verification and replay check and will be reset to 0 after the ChangCipherSpec anyway.

However, I see your point. Maybe the document should state more explicitly that handshake sequence numbers must not be increased, because they always have to be the same and always have to start with 0, while the record_seq has to be unique and therefore has to change.

Regards,
Robin

---

From: Robin Seggelmann <[email-masked]>
Date: Mon, 14 Mar 2011 17:20:33 +0100

> However, I see your point. Maybe the document should state more explicitly that handshake sequence numbers must not be increased, because they always have to be the same and always have to start wi…

I forgot to mention that in OpenSSL I'm using the same record_seq counter for every incoming request until a CH with a valid cookie arrives. This is due to a workaround to implement an UDP based and thus one-to-many style protocol in OpenSSL's one-to-one architecture, but so I'm not required to allocate anything.

---

From: Michael Tüxen <[email-masked]>
Date: Mon, 14 Mar 2011 19:01:17 +0100

> I forgot to mention that in OpenSSL I'm using the same record_seq counter for every incoming request until a CH with a valid cookie arrives. This is due to a workaround to implement an UDP based an…
Hi Robin,

can you be more specific? Did you implement it such that Nikos
message exchange is valid? So do you copy the rec. seq. number
from the incoming packet? Do you use the same counter for multiple
client until you receive a CH with a valid cookie?

Best regards
Michael
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls

---

From: Robin Seggelmann <[email-masked]>
Date: Mon, 14 Mar 2011 19:16:18 +0100

> client until you receive a CH with a valid cookie?

I don't copy the record sequence. The server is using one counter for multiple clients until the CH with a valid cookie. So the first HelloVerifyRequest has record seq 0, the second 1 and so on. When a cookie has been verified, the ServerHello will have the next record seq, while the next HelloVerifyRequest for an other client will have 0 again.

This is because I'm using an SSL object (and its rec seq counter) for listening, which will be assigned to the first client with a valid cookie to continue the connection, so the next handshake message, that is the ServerHello, will habe the next record seq. A new SSL object (with reset counters) is then created to continue listening and responding to ClientHellos.

Best reagards,
Robin

>>>> packets with the same sequence number.

Viele Grüße
Robin

---

From: Michael Tüxen <[email-masked]>
Date: Mon, 14 Mar 2011 20:13:20 +0100

> I don't copy the record sequence. The server is using one counter for multiple clients until the CH with a valid cookie. So the first HelloVerifyRequest has record seq 0, the second 1 and so on. Wh…
So does this mean that one client affects the other?

Best regards
Michael

---

From: Robin Seggelmann <[email-masked]>
Date: Mon, 14 Mar 2011 20:26:58 +0100

> So does this mean that one client affects the other?

Only by increasing the record sequence. As an example, a scenario with a low RTT client (lc), a high RTT (hc) client, the server listening with SSL object s1 and then s2:

hc: ClientHello(rseq:0, hseq: 0)
s1: HelloVerifyRequest(rseq:0, hseq:0)
lc: ClientHello(rseq:0, hseq: 0)
s1: HelloVerifyRequest(rseq:1, hseq:0)
lc: ClientHelloCookie(rseq:1, hseq: 1)
s1 will be connected to lc, now s2 listens
s1: ServerHello(rseq:2, hseq:1)
hc: ClientHelloCookie(rseq:1, hseq: 1)
s2 will be connected to hc, now s3 listens
s1: ServerHello(rseq:0, hseq:1)

So the more ClientHellos arrive before one with a valid cookie, the higher is the record sequence number. That's the only "state" in the server that changes. Otherwise I would have to maintain the record sequence per client which would require resource allocation or always use the same with the retransmission issues Nikos pointed out.

Regards,
Robin

---

From: Michael Tüxen <[email-masked]>
Date: Mon, 14 Mar 2011 20:42:33 +0100

> So the more ClientHellos arrive before one with a valid cookie, the higher is the record sequence number. That's the only "state" in the server that changes. Otherwise I would have to maintain the…
I would prefer if different clients would not affect each other. Why can't you just
reflect the record sequence number? Then there is no need to store it per client.

Best regards
Michael

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 14 Mar 2011 16:27:40 -0700

FWIW, I believe the correct answer is that the server should always use
sequence number 0 for HelloVerifyRequest, and that clients should not do
duplicate suppression during the initial handshake. I agree it's a
tiny bit clunky,
but IMO it's the best option.

-Ekr

---

From: Michael Tüxen <[email-masked]>
Date: Tue, 15 Mar 2011 00:34:15 +0100

> but IMO it's the best option.
Hmmm. I'm not a big fan of adding special cases. Another possibility
would be reflecting them. But whatever we use, it needs to be
specified.

Best regards
Michael

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 14 Mar 2011 16:37:34 -0700

I suspect either reflecting or the special case would work. I'm trying
to get all the other
changes in before the deadline so I'll leave it with =0 and the
special case and an
open issue marker and let's just resolve in Prague.

-Ekr

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Tue, 15 Mar 2011 10:38:18 +0100

> but IMO it's the best option.

I can see that using handshake_seq of 0 for HelloVerifyRequest is a
good option, but using 0 for record_seq requires a special handling of
those records and thus extra complexity. The reflection method has
no requirements from the record layer, thus I'd prefer that unless
there are implications of course.

regards,
Nikos

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Tue, 15 Mar 2011 10:59:28 +0100

> open issue marker and let's just resolve in Prague.

I will not be there but I'd like to make these points:
1. Define precisely the behavior of initial pre-handshake before state
is allocated. My opinion is that I don't like special cases such as
use 0 always
and do not case about re-use because they are more likely to introduce
bugs and new attacks. Copying the client's numbers should solve the
issue with no special cases and no state. Also I suppose that if
handshake_seq=0 is used for HelloVerifyRequest then handshake_seq=1
should be used for ServerHello and this should be clear as well to
avoid having another special case.

2. Drop requirement: The server MUST use the same
   version number in the HelloVerifyRequest that it would use when
   sending a ServerHello.  Upon receipt of the ServerHello, the client
   MUST verify that the server version values match.
This will create incompatibilities when more than 1 DTLS protocols are
implemented
in a single client or server. It is not really possible for a server
to do an emulation of
the decisions it would do as if a state existed. What are the reasons for this
requirement?

regards,
Nikos

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 15 Mar 2011 04:18:39 -0700

> avoid having another special case.

Noted.  Let's see how that discussion shakes out in the meeting.

> the decisions it would do as if a state existed. What are the reasons for this

I don't understand why this is an issue: the server can remember what the
client offered (indeed, he must remember a whole pile of other stuff in order
to verify that it hasn't changed) by stuffing a digest into the cookie.

-Ekr

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Tue, 15 Mar 2011 12:37:16 +0100

> to verify that it hasn't changed) by stuffing a digest into the cookie.

My issue is not about server remembering stuff, but the fact that at this point
the server has minimum information  and has to do actual negotiation of the
protocol version.

Depending on the implementation chosing the version to negotiate might not
be simple. I.e. the application might have configured that DTLS 1.0 and DTLS
1.2 are allowed, but say for example only ciphersuite 0xfb, 0xbf is enabled for
this client, that has the constraint that it can be used with DTLS 1.0
(probably
this is not an issue now in DTLS but this scenario is common in TLS).
Thus the server cannot readily negotiate the highest DTLS 1.2, but has to also
check ciphersuites for conflicts, meaning that this pre-handshake cannot really
be kept as minimal as possible.

I think the pre-handshake should be as dumb as possible to serve its
role as DoS
protection and no more. In typical cases it is expected to be implemented as
something external to the handshake process, thus would be nice to require
as less information and information interpreting as possible.

regards,
Nikos

---

From: Michael Tüxen <[email-masked]>
Date: Tue, 15 Mar 2011 12:51:27 +0100

> Noted.  Let's see how that discussion shakes out in the meeting.
Hi Eric,

I can't attend the IETF meeting and would also prefer the reflection
for the same reasons Nikos pointed out.

Best regards
Michael

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 15 Mar 2011 04:52:45 -0700

> as less information and information interpreting as possible.

Ah, I see your point. I'll have to think a bit about what I think the
best approach is
here.

-Ekr