Subject: Re: [IPsec] HA protocol replay protection

From: Pekka Riikonen <[email-masked]>
Date: Fri, 3 Dec 2010 06:48:26 +0100 (CET)

On Tue, 23 Nov 2010, Tero Kivinen wrote:

: >       EXPECTED_SEND_REQ_MESSAGE_ID payload and should not wait for a
: >       response to message 3 anymore.
: 
: This opens new attacks, because now receiving sync message with
: message ID zero has also other effects than just syncing the max
: message ID for future use, it also causes existing exchanges to be
: destroyed.
: 
: I.e. if host A and B have done sync earlier, meaning attacker has a
: copy of IKE SA Message ID sync message having message ID of zero, then
: attacker can wait for host B to start few exchanges and then reply the
: old sync message. If host A now immediately while processing the
: request destroys old existing exchanges then this allows attackers to
: delete exchanges at will.
: 
: Nonce in the Message ID sync message will not help in this case, but
: the failover counter will help, as in that case the host A will reject
: the replay because of the reused failover counter. 
: 
: > Are the Security Considerations in the draft valid anymore at all?  And 
: > are the nonce and failover count needed?  Yaron wanted to eliminate these, 
: > and I'm all for it.
: 
: I think we still need both. The failover counter protects against the
: attack I explained in this email (i.e. attacker replaying request),
: and nonce protects against the attacks where attacker tries to replay
: response message. 
:
I'd like to return to this failover counter.  It's the single issue in the 
protocol which I don't like.  The reasons are, first, that it makes an 
assumption how clustering and sync has been implemented, that is this 
value has to be synced in the cluster and the protocol cannot work without 
it, and second, that the protocol itself becomes vulnerable to the very 
issues it tries to combat, namely the fact that sync messages can be 
dropped.

Consider for example three node cluster where node 1 fails.  Node 2 
increments the failover counter but fails to sync it to node 3 (the packet 
is dropped or node 2 fails immediately itself).  Node 3 now hasn't the 
updated failover counter and will create a request that is effectively a 
replay.

The draft has the following text:

   In case multiple successive failover events and sync request getting
   lost, the failover count value at peer will not be updated and new
   standby member will become active with incremented failover count
   value.  So, peer can receive valid failover count value which is not
   just incremented by 1 in case of multiple failover.  Accepting
   incremented failover count within a range is allowed and increases
   interoperability.

Which is vague, and I don't even completely understand what it tries to 
tell here.  In case of multiple failovers the failover counter might *not* 
be incremented at all because the sync may have been dropped.

I think the protocol should not have a feature that depends on the sync 
itself working.  That's the very issue it tries to fix in HA, the fact 
that IKE SA message IDs in failover may be in desync.  The failover 
counter may be in desync as well.  And if implementations are expected to 
be lax about the value (due to the issues listed above) then it doesn't 
really provide replay protection either.

I think we should try to find alternative methods to combat the replay of 
requests.  Here's some thoughts:

 o Some kind of expiration timestamp to requests.  Not sure how easy or 
   practical it would be to implement but would not require any sync 
   expectations.

 o Request could always propose message_id + delta, so that if it is 
   replayed it's already too old and can be detected.  This is something
   that Yaron suggested as well, I believe.  It does have some issues,
   some of them already discussed earlier.

Some other way?

	Pekka

---

From: Tero Kivinen <[email-masked]>
Date: Fri, 3 Dec 2010 15:22:17 +0200

> issues it tries to combat, namely the fact that sync messages can be 

Depends how we define failover counter. If we define so it is
monotonously increasing counter which can skip forward there are ways
to do it without syncing the information. As most of the sync
protocols already have either timestamps or some kind of message ids
using those as failover counter would work. I.e. in the simplest case
just use last failover time as failover counter.

There is no reason for failover counter to increment by one for every
failover, its value just needs to be bigger than the previous failover
counter so we can detect whether this is old failover message or
whether it is something we haven't seen before.

> updated failover counter and will create a request that is effectively a 

So the node 2 should first agree that it really is the one who is
going to take care of the failing node 1 traffic, thus it needs to
communiate with node 3 and agree on that (to prevent both node 2 and
node 3 acting as failover hosts). During this communication it can
also sync the failover counter.

Also if node 3 just detects that node 2 crashed by snooping the
traffic, then it can also snoop the IKEv2 message ID sync messages and
get the failover counter from there (it do have the keying material to
decrypt the IKEv2 messages if it is going to be acting as failover
node). 

> be incremented at all because the sync may have been dropped.

I think that text tries to say that as the node 2 might have synced
with node 3, but it might be that it failed before it actually managed
to send out IKEV2_MESSAGE_ID_SYNC message, thus other end never knows
that node 2 was active at all, and the first thing they see is the
message from node 3, where the failover counter is incremented twice.

I think the current text should be clear that failover counter can be
incremented by any number, and message is accepted if failover counter
is larger than any previous failover counter node has seen.

This kind of text would allow using for example timestamp instead of
failover counters, on those clusters where they do have good enough
synced clocks. 
-- 
[email-masked]

---

From: Pekka Riikonen <[email-masked]>
Date: Fri, 3 Dec 2010 20:47:19 +0100 (CET)

On Fri, 3 Dec 2010, Tero Kivinen wrote:

: Depends how we define failover counter. If we define so it is
: monotonously increasing counter which can skip forward there are ways
: to do it without syncing the information. As most of the sync
: protocols already have either timestamps or some kind of message ids
: using those as failover counter would work. I.e. in the simplest case
: just use last failover time as failover counter.
: 
: There is no reason for failover counter to increment by one for every
: failover, its value just needs to be bigger than the previous failover
: counter so we can detect whether this is old failover message or
: whether it is something we haven't seen before.
: 
That's a good point, but there's still the receiving end that has to 
consistently be able to determine whether given failover counter is replay 
or not.  Let say, both ends are clusters, this means that the receiving 
end has to somehow sync the information between its nodes.  Otherwise its 
nodes might not know which value is old and which isn't (for example due 
to failover or load balancing).  Unless, of course, this is somekind of 
timestamp (an actual clock or something like that) that can be 
consistently verified also at the receiving end without syncing.

On the other hand, I do say that this is better than what it is now in the 
draft; even if the receiving end has to sync it and fails to do so 
properly the protocol still works, it just opens a possibilty for a replay 
attack.

: > Consider for example three node cluster where node 1 fails.  Node 2 
: > increments the failover counter but fails to sync it to node 3 (the packet 
: > is dropped or node 2 fails immediately itself).  Node 3 now hasn't the 
: > updated failover counter and will create a request that is effectively a 
: > replay.
: 
: So the node 2 should first agree that it really is the one who is
: going to take care of the failing node 1 traffic, thus it needs to
: communiate with node 3 and agree on that (to prevent both node 2 and
: node 3 acting as failover hosts). During this communication it can
: also sync the failover counter.
: 
Here it usually would be determined by the IKE SAs that were "owned" by 
node 1 that are now owned by node 2.  It's quite possible, by the way, 
that both node 2 and node 3 can now "own" some of node 1's IKE SAs, and 
have to perform the HA protocol for those independently.  This would be a 
cluster were all nodes are "online" and one of them fails.  The case 
described in the draft is a hot stanbdy cluster case where only one node 
is online and others are standby until the online node fails.  This would 
imply that the standby node that becomes online after failover gets all of 
the SAs of the failed node.

All this is implementation specific.  Though, in my opinion the protocol 
should be able to work in all scenarios, including in one were multiple 
nodes independently perform HA protocol for their IKE SAs (a case not 
described in the draft currently.  This would change the original scope of 
the draft from hot standby cluster case to include online cluster case 
were load balancing change (failover, online/offline transition or other 
artificial load balancing change) re-balances SAs among multiple online 
nodes).

: I think the current text should be clear that failover counter can be
: incremented by any number, and message is accepted if failover counter
: is larger than any previous failover counter node has seen.
: 
: This kind of text would allow using for example timestamp instead of
: failover counters, on those clusters where they do have good enough
: synced clocks. 
:
I agree, but it needs to be carefully defined so that the receiver can 
actually verify its validity in case it's a cluster.

	Pekka