Subject: [IPsec] TCP and MOBIKE

From: "Valery Smyslov" <[email-masked]>
Date: Thu, 8 Nov 2018 12:07:12 +0700

Hi,

coming back to the yesterday discussion. There seems to be another issue 
if implementation first sends request to update address over UDP and
then switches to TCP. The problem arises if NO_NATS_ALLOWED is included - 
it contains IP addresses and ports for initiator and responder. If you
leave it intact while switching to TCP, then it won't match real addresses
and the responder will treat it as NAT presence. In this case RFC 4555
suggests to retry sending request several times with a new INFORMATIONAL
request. Probably we could clarify in TCP guidelines draft that the content
of NO_NATS_ALLOWED MUST be recalculated in this case? Or is it obvious?

Regards,
Valery.

---

From: David Schinazi <[email-masked]>
Date: Thu, 8 Nov 2018 12:16:28 +0700

I'm having a hard time imagining why anyone would want to use
NO_NATS_ALLOWED with TCP encapsulation. If you're encapsulating in TCP it
means that there is something on path even worse than a NAT, right?

Perhaps we could simply say you MUST NOT use NO_NATS_ALLOWED with TCP
encaps?

David

On Thu, Nov 8, 2018 at 12:07 PM Valery Smyslov <[email-masked]>
wrote:

> _______________________________________________
> IPsec mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/ipsec
>

---

From: "Valery Smyslov" <[email-masked]>
Date: Thu, 8 Nov 2018 12:36:14 +0700

Hmm, maybe. Or maybe not. Or maybe just ignore it in case of TCP?

I think that in general the co-existence of MOBIKE and TCP must be

elaborated in more detail in the draft.

I'm having a hard time imagining why anyone would want to use NO_NATS_ALLOWED with TCP encapsulation. If you're encapsulating in TCP it means that there is something on path even worse than a NAT, right?

Perhaps we could simply say you MUST NOT use NO_NATS_ALLOWED with TCP encaps?

David

On Thu, Nov 8, 2018 at 12:07 PM Valery Smyslov <[email-masked] <mailto:[email-masked]> > wrote:

Hi,

Regards,
Valery.

_______________________________________________
IPsec mailing list
[email-masked] <mailto:[email-masked]> 
https://www.ietf.org/mailman/listinfo/ipsec

---

From: Tero Kivinen <[email-masked]>
Date: Wed, 14 Nov 2018 09:56:01 +0200

> Hmm, maybe. Or maybe not. Or maybe just ignore it in case of TCP?

I would say that is better approach. I.e., ignore NO_NATS_ALLOWED and
NAT_DETECTION_SOURCE_IP and NAT_DETECTION_DESTINATION_IP o receiver
when connection comes in with TCP.

There is nothing we want to do even if detected NAT on the tcp path,
we are not going to switc to switch to another port, we are not going
to allow dynamic updates (as they would not work with TCP anyways),
there is no point of sending keepalives on TCP etc.

So on tcp just ignore those payloads. 

> elaborated in more detail in the draft.

I agree. There are also several cases where we some of the mobike
processing does not really make sense. Things like return routability
checks, changing nat mappings, etc. The initial UPDATE_SA_ADDRESSES
should be enough to just say that use this connection for return
traffic. I do not think there is anything else for the responder to do
for it. 
>     of NO_NATS_ALLOWED MUST be recalculated in this case? Or is it obvious?

Modifying the packet after it has been sent over any transport once,
is impossible, and will break things.

I.e., if client send packet using UDP and it did reach the destination
correctly, but return packet got lost, and then client decided to move
to TCP, and resend the packet.

If the packet is modified, then responder will see it as an attack, as
it is using message-id that where it has already processed and
responded to, but the content of the frame is not same. As the content
is not same, it will not retransmit its reply, so both ends just stop
and finally the connection times out.

>From the RFC7296 section 2.1:

   A retransmission from the initiator MUST be bitwise identical to
   the original request. That is, everything starting from the IKE
   header (the IKE SA initiator's SPI onwards) must be bitwise
   identical; items before it (such as the IP and UDP headers) do not
   have to be identical.

That is the reason why mobike for example does the processing so that
if it needs to change address during UPDATE_SA_ADDRESSES it will not
modify packet it is sending out, it will simply run the process to
end, and then redo it again from the start. It needs to do if it ever
used more than one address, regardless which of them succeeded. I.e.,
if it send UPDATE_SA_ADDRESSES using source IP1 and does not get
reply, moves to IP2, does not get reply, moves back IP1, and now do
get reply, it still needs to do UPDATE_SA_ADDRESSES again because it
did not know which of his frames got to the other end. It could have
been that first packet ever reaching responder was sent from IP2, but
the reply got lost, and then when initiator resent the packet from
IP1, the responder just repeated the reply generated earlier packet
from IP2... 
-- 
[email-masked]

---

From: "Valery Smyslov" <[email-masked]>
Date: Wed, 14 Nov 2018 11:55:44 +0300

Hi Tero,

> So on tcp just ignore those payloads.

Makes sense.

> traffic. I do not think there is anything else for the responder to do

The uselessness of the return routability check in case of TCP
is already mentioned in the draft.

> and finally the connection times out.

Depending on the implementation, the content in this case might
not be checked, the latest response might just be sent.
There is no point to re-check the content of the replayed
packet, it's only waste of CPU resources.

> IP1, the responder just repeated the reply generated earlier packet

These exchanges (trying out IP1, IP2 etc.) will have different
Message IDs anyway (*). So the responder won't reply with 
previously saved response, because Message IDs will differ.
And the content of NAT_DETECTION_*_IP can be recalculated
accordingly

(*)  From RFC 4555:
   If the request to update the addresses is retransmitted using several
   different source addresses, a new INFORMATIONAL request MUST be sent.

Anyway, I agree that the current exchange must be finished off (either
completed or deemed timed out) before a new one is started 
from (to) a different IP. But with TCP we don't change address,
we only change transport, so the exchange must remain the same
when switching from UDP to TCP... And this would break 
some things, like NO_NATS_ALLOWED and NAT_DETECTION.

Regards,
Valery.

---

From: Tero Kivinen <[email-masked]>
Date: Thu, 15 Nov 2018 04:23:40 +0200

> not be checked, the latest response might just be sent.

Could be, but there are implementations which do the check (or
actually check that the hash of the incoming packet is same, they
might not store the whole original packet). And this is something that
is clearly allowed in the RF7296, as request must be bitwise
identical. 

> packet, it's only waste of CPU resources.

You do open yourself of (semi) blind reflection attacks if you do not
check the frame. I.e., someone might send 28 byte empty IKEv2 packets
having correct SPI and message ID, and cause you to resend much larger
result.

If you do check the incoming frame attacker needs to see original
frame, and needs to also send as big packet than original sender sent.

CPU is cheap, transmission of frames is more costly. 

> Message IDs anyway (*).

No they do not. They have all same Message ID, as you can only send
one frame out at time if using window size 1, so you need to wait for
response for message you sent out before you can modify it and send
another frame out. 

> So the responder won't reply with previously saved response, because
> Message IDs will differ. And the content of NAT_DETECTION_*_IP can
> be recalculated accordingly
> 
> (*)  From RFC 4555:

Yes, this means that we need to start new exchange AFTER the one we
are doing now finished. It does not mean that while we sent frame out
using different source IP addresses used different message IDs.

I.e., the exchange is as follows:

 Initiator                  Responder
 ---------                  ---------
      
 (IP_I1:500 -> IP_R1:500, MID=12I)
         HDR, SK { N(UPDATE_SA_ADDRESSES),
	           N(NAT_DETECTION_SOURCE_IP),
                   N(NAT_DETECTION_DESTINATION_IP) } --> 

 (IP_I1:500 -> IP_R1:500, MID=12I)
         HDR, SK { N(UPDATE_SA_ADDRESSES),
	           N(NAT_DETECTION_SOURCE_IP),
                   N(NAT_DETECTION_DESTINATION_IP)  } --> 

 (IP_I2:500 -> IP_R1:500, MID=12I)
         HDR, SK { N(UPDATE_SA_ADDRESSES),
	           N(NAT_DETECTION_SOURCE_IP),
                   N(NAT_DETECTION_DESTINATION_IP)  } -->

 (IP_I2:500 -> IP_R1:500, MID=12I)
         HDR, SK { N(UPDATE_SA_ADDRESSES),
	           N(NAT_DETECTION_SOURCE_IP),
                   N(NAT_DETECTION_DESTINATION_IP)  } -->

 (IP_I1:500 -> IP_R1:500, MID=12I)
         HDR, SK { N(UPDATE_SA_ADDRESSES),
	           N(NAT_DETECTION_SOURCE_IP),
                   N(NAT_DETECTION_DESTINATION_IP)  } -->

                            <-- (IP_R1:500 -> IP_I1:500, MID=12R)
                                HDR, SK { N(NAT_DETECTION_SOURCE_IP),
                                          N(NAT_DETECTION_DESTINATION_IP) }

Now, the UPDATE_SA_ADDRESSES is done, but as the request used multiple
IP addresses the initiator needs to redo it:

 Initiator                  Responder
 ---------                  ---------
      
 (IP_I1:500 -> IP_R1:500, MID=13I)
         HDR, SK { N(UPDATE_SA_ADDRESSES),
	           N(NAT_DETECTION_SOURCE_IP),
                   N(NAT_DETECTION_DESTINATION_IP)  } -->

                            <-- (IP_R1:500 -> IP_I1:500, MID=13R)
                                HDR, SK { N(NAT_DETECTION_SOURCE_IP),
                                          N(NAT_DETECTION_DESTINATION_IP) }

> Anyway, I agree that the current exchange must be finished off
> (either completed or deemed timed out) before a new one is started
> from (to) a different IP.

It MUST be finished, which is why you use all possible IP address
pairs for that ONE exchange before you decide it failed. If it failed,
you delete the IKE SA, and you cannot start any exchange on different
IP after that for that IKE SA, as there is no longer IKE SA you could
use.

See RFC4621 section 6.2 for more datails. 

> But with TCP we don't change address, we only change transport, so
> the exchange must remain the same when switching from UDP to TCP...
> And this would break some things, like NO_NATS_ALLOWED and
> NAT_DETECTION.

It is exactly same for MOBIKE with UDP. NAT detection, IP addresses
used etc can be wrong after the UPDATE_SA_ADDRESSES, and the initiator
MUST detect thiss possibility, and redo the UPDATE_SA_ADDRESSES so
that they will get fixed. Initiator is responsible to try to fix this
until it gets exchange through in a way there cannot be issues which
frame was acted on in the responder, i.e., it MUST ensure that
initiator and responder stays in sync.

In tcp encapsulation the situation is same. Once we move to TCP, or
from TCP to UDP, that is deteced by the initiator that something
changed during UPDATE_SA_ADDRESSES, so after that exchange finishs
successfully, it needs to redo it using the path it thinks work, and
verify that both ends are in sync. 
-- 
[email-masked]

---

From: "Valery Smyslov" <[email-masked]>
Date: Thu, 15 Nov 2018 10:12:53 +0300

> frame, and needs to also send as big packet than original sender sent.

It's much easier to rate limit responses, say no more than one per second.
You may also check the length.

> CPU is cheap, transmission of frames is more costly.

True, but still doesn't justify wasting CPU.

> I.e., the exchange is as follows:

OK, that only justifies my thought that MOBIKE is fragile :-)
What if both paths work, but the networks are lossy?
In this case with high probability your second exchange 
will look like the first: you won't get reply on IP_R1,
switch to IP_R2, got reply and initiate new exchange again. 
And so on. The process won't converge well.

> IP after that for that IKE SA, as there is no longer IKE SA you could

OK.

> initiator and responder stays in sync.

Not exactly. The MOBIKE currently is only concerned with IP addresses.
It doesn't take transport into consideration. If you formally follow MOBIKE
you don't need to initiate new exchange, because when you switch from
UDP to TCP the IP will remain the same. 

> verify that both ends are in sync.

Again, the path doesn't change, the transport changes.
So, this must be clarified in the draft...

---

From: Tero Kivinen <[email-masked]>
Date: Thu, 15 Nov 2018 13:50:45 +0200

> You may also check the length.

True, but this is what some implementations did and perhaps do still.
And the RFC7296 mandates that retransmission must be bitwise identical
(there are other reasons for that too). 

> What if both paths work, but the networks are lossy?

In normal cases you do bit more tries for the first IP, before you
move to second or third. I.e., something like 5 retries on first
address (0.5, 1, 2, 4, 8 second intervals using 15.5 seconds or first
address), and then move to 2nd address and so on. 

> And so on. The process won't converge well.

True. On the other hand you only need to succeed once to converge it,
and you only need to do this if you have so bad connection that you
really start timing out lots of request. In that case there will be
other usage issues anyway....

> UDP to TCP the IP will remain the same. 

Not true.

> So, this must be clarified in the draft...

The rfc4555 does not defined path, but rfc4621 does:

   Path

      The sequence of routers traversed by the MOBIKE and IPsec
      packets exchanged between the two peers. Note that this path may
      be affected not only by the involved source and destination IP
      addresses, but also by the transport protocol. Since MOBIKE and
      IPsec packets have a different appearance on the wire, they
      might be routed along a different path, for example, due to load
      balancing. This definition is taken from [RFC2960] and adapted
      to the MOBIKE context.

So the transport protocol should be taken in to account. Unfortunately
the section 1.3 do not refer to the rfc4621 for terminology, but I
think it should have done that, as I think it defines other terms
too (available address, current path etc).
-- 
[email-masked]