ikev2: fix setting responder/initiator addresses 91/29391/3
authorFilip Tehlar <ftehlar@cisco.com>
Wed, 7 Oct 2020 23:52:37 +0000 (23:52 +0000)
committerBeno�t Ganne <bganne@cisco.com>
Wed, 21 Oct 2020 13:30:41 +0000 (13:30 +0000)
Type: fix

Change-Id: Ic406aa914d92e802a5fb0f27c2ffa1b98db012b0
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
src/plugins/ikev2/ikev2.c
src/plugins/ikev2/ikev2_payload.c
src/plugins/ikev2/ikev2_priv.h
src/plugins/ikev2/test/test_ikev2.py

index 4b31860..3ce9114 100644 (file)
@@ -640,7 +640,7 @@ ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t * ia, u16 port)
   clib_memcpy_fast (&buf[8], &rspi, sizeof (rspi));
   clib_memcpy_fast (&buf[8 + 8], ip_addr_bytes (ia), ip_address_size (ia));
   clib_memcpy_fast (&buf[8 + 8 + ip_address_size (ia)], &port, sizeof (port));
-  SHA1 (buf, sizeof (buf), res);
+  SHA1 (buf, 2 * sizeof (ispi) + sizeof (port) + ip_address_size (ia), res);
   return res;
 }
 
@@ -2734,11 +2734,9 @@ ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih)
 }
 
 static_always_inline void
-ikev2_set_ip_address (ikev2_sa_t * sa, const void *src,
-                     const void *dst, const int af, const int is_initiator)
+ikev2_set_ip_address (ikev2_sa_t * sa, const void *iaddr,
+                     const void *raddr, const int af)
 {
-  const void *raddr = is_initiator ? src : dst;
-  const void *iaddr = is_initiator ? dst : src;
   ip_address_set (&sa->raddr, raddr, af);
   ip_address_set (&sa->iaddr, iaddr, af);
 }
@@ -2854,19 +2852,16 @@ ikev2_node_internal (vlib_main_t * vm,
          sa0 = &sa;
          clib_memset (sa0, 0, sizeof (*sa0));
 
-         u8 is_initiator = ike0->flags & IKEV2_HDR_FLAG_INITIATOR;
-         if (is_initiator)
+         if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR)
            {
              if (ike0->rspi == 0)
                {
                  if (is_ip4)
-                   ikev2_set_ip_address (sa0, &ip40->dst_address,
-                                         &ip40->src_address, AF_IP4,
-                                         is_initiator);
+                   ikev2_set_ip_address (sa0, &ip40->src_address,
+                                         &ip40->dst_address, AF_IP4);
                  else
-                   ikev2_set_ip_address (sa0, &ip60->dst_address,
-                                         &ip60->src_address, AF_IP6,
-                                         is_initiator);
+                   ikev2_set_ip_address (sa0, &ip60->src_address,
+                                         &ip60->dst_address, AF_IP6);
 
                  sa0->dst_port = clib_net_to_host_u16 (udp0->src_port);
 
@@ -2927,13 +2922,11 @@ ikev2_node_internal (vlib_main_t * vm,
          else                  //received sa_init without initiator flag
            {
              if (is_ip4)
-               ikev2_set_ip_address (sa0, &ip40->src_address,
-                                     &ip40->dst_address, AF_IP4,
-                                     is_initiator);
+               ikev2_set_ip_address (sa0, &ip40->dst_address,
+                                     &ip40->src_address, AF_IP4);
              else
-               ikev2_set_ip_address (sa0, &ip60->src_address,
-                                     &ip60->dst_address, AF_IP6,
-                                     is_initiator);
+               ikev2_set_ip_address (sa0, &ip60->dst_address,
+                                     &ip60->src_address, AF_IP6);
 
              ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen);
 
@@ -4757,33 +4750,12 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa)
     }
 }
 
-static ike_payload_header_t *
-ikev2_find_ike_payload (ike_header_t * ike, u32 payload_type)
-{
-  int p = 0;
-  ike_payload_header_t *ikep;
-  u32 payload = ike->nextpayload;
-
-  while (payload != IKEV2_PAYLOAD_NONE)
-    {
-      ikep = (ike_payload_header_t *) & ike->payload[p];
-      if (payload == payload_type)
-       return ikep;
-
-      u16 plen = clib_net_to_host_u16 (ikep->length);
-      payload = ikep->nextpayload;
-      p += plen;
-    }
-  return 0;
-}
-
 static void
 ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa)
 {
   ikev2_profile_t *p;
   u32 bi0;
-  u8 *nat_sha;
-  ike_payload_header_t *ph;
+  u8 *nat_sha, *np;
 
   if (ip_address_is_zero (&sa->iaddr))
     {
@@ -4794,20 +4766,20 @@ ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa)
        return;
 
       /* update NAT detection payload */
-      ph =
-       ikev2_find_ike_payload ((ike_header_t *)
-                               sa->last_sa_init_req_packet_data,
-                               IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP);
-      if (!ph)
-       return;
-
-      nat_sha =
-       ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi),
-                               clib_host_to_net_u64 (sa->rspi),
-                               &sa->iaddr,
-                               clib_host_to_net_u16 (IKEV2_PORT));
-      clib_memcpy_fast (ph->payload, nat_sha, vec_len (nat_sha));
-      vec_free (nat_sha);
+      np =
+       ikev2_find_ike_notify_payload
+       ((ike_header_t *) sa->last_sa_init_req_packet_data,
+        IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP);
+      if (np)
+       {
+         nat_sha =
+           ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi),
+                                   clib_host_to_net_u64 (sa->rspi),
+                                   &sa->iaddr,
+                                   clib_host_to_net_u16 (IKEV2_PORT));
+         clib_memcpy_fast (np, nat_sha, vec_len (nat_sha));
+         vec_free (nat_sha);
+       }
     }
 
   if (vlib_buffer_alloc (km->vlib_main, &bi0, 1) != 1)
index c03054a..294864d 100644 (file)
@@ -588,6 +588,30 @@ ikev2_parse_delete_payload (ike_payload_header_t * ikep, u32 rlen)
   return r;
 }
 
+u8 *
+ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type)
+{
+  int p = 0;
+  ike_notify_payload_header_t *n;
+  ike_payload_header_t *ikep;
+  u32 payload = ike->nextpayload;
+
+  while (payload != IKEV2_PAYLOAD_NONE)
+    {
+      ikep = (ike_payload_header_t *) & ike->payload[p];
+      if (payload == IKEV2_PAYLOAD_NOTIFY)
+      {
+        n = (ike_notify_payload_header_t *)ikep;
+        if (n->msg_type == clib_net_to_host_u16 (msg_type))
+          return n->payload;
+      }
+      u16 plen = clib_net_to_host_u16 (ikep->length);
+      payload = ikep->nextpayload;
+      p += plen;
+    }
+  return 0;
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 68a546a..115a5b2 100644 (file)
@@ -568,6 +568,7 @@ ikev2_delete_t *ikev2_parse_delete_payload (ike_payload_header_t * ikep,
 ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep,
                                            u32 rlen);
 int ikev2_set_log_level (ikev2_log_level_t log_level);
+u8 *ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type);
 
 static_always_inline ikev2_main_per_thread_data_t *
 ikev2_get_per_thread_data ()
index 4f64b56..f75a517 100644 (file)
@@ -1,4 +1,5 @@
 import os
+from socket import inet_pton
 from cryptography import x509
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import hashes, hmac
@@ -510,8 +511,10 @@ class IKEv2SA(object):
     def esp_crypto_attr(self):
         return self.crypto_attr(self.esp_crypto_key_len)
 
-    def compute_nat_sha1(self, ip, port):
-        data = self.ispi + self.rspi + ip + (port).to_bytes(2, 'big')
+    def compute_nat_sha1(self, ip, port, rspi=None):
+        if rspi is None:
+            rspi = self.rspi
+        data = self.ispi + rspi + ip + (port).to_bytes(2, 'big')
         digest = hashes.Hash(hashes.SHA1(), backend=default_backend())
         digest.update(data)
         return digest.finalize()
@@ -775,6 +778,36 @@ class TemplateInitiator(IkePeer):
     def tearDown(self):
         super(TemplateInitiator, self).tearDown()
 
+    @staticmethod
+    def find_notify_payload(packet, notify_type):
+        n = packet[ikev2.IKEv2_payload_Notify]
+        while n is not None:
+            if n.type == notify_type:
+                return n
+            n = n.payload
+        return None
+
+    def verify_nat_detection(self, packet):
+        if self.ip6:
+            iph = packet[IPv6]
+        else:
+            iph = packet[IP]
+        udp = packet[UDP]
+
+        # NAT_DETECTION_SOURCE_IP
+        s = self.find_notify_payload(packet, 16388)
+        self.assertIsNotNone(s)
+        src_sha = self.sa.compute_nat_sha1(
+                inet_pton(socket.AF_INET, iph.src), udp.sport, b'\x00' * 8)
+        self.assertEqual(s.load, src_sha)
+
+        # NAT_DETECTION_DESTINATION_IP
+        s = self.find_notify_payload(packet, 16389)
+        self.assertIsNotNone(s)
+        dst_sha = self.sa.compute_nat_sha1(
+                inet_pton(socket.AF_INET, iph.dst), udp.dport, b'\x00' * 8)
+        self.assertEqual(s.load, dst_sha)
+
     def verify_sa_init_request(self, packet):
         ih = packet[ikev2.IKEv2]
         self.assertNotEqual(ih.init_SPI, 8 * b'\x00')
@@ -798,6 +831,7 @@ class TemplateInitiator(IkePeer):
         self.assertEqual(prop.trans[2].transform_id,
                          self.p.ike_transforms['dh_group'])
 
+        self.verify_nat_detection(packet)
         self.sa.complete_dh_data()
         self.sa.calc_keys()
 
@@ -957,11 +991,6 @@ class TemplateResponder(IkePeer):
         props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2',
                  trans_nb=4, trans=trans))
 
-        if behind_nat:
-            next_payload = 'Notify'
-        else:
-            next_payload = None
-
         self.sa.init_req_packet = (
                 ikev2.IKEv2(init_SPI=self.sa.ispi,
                             flags='Initiator', exch_type='IKE_SA_INIT') /
@@ -969,19 +998,21 @@ class TemplateResponder(IkePeer):
                 ikev2.IKEv2_payload_KE(next_payload='Nonce',
                                        group=self.sa.ike_dh,
                                        load=self.sa.my_dh_pub_key) /
-                ikev2.IKEv2_payload_Nonce(next_payload=next_payload,
+                ikev2.IKEv2_payload_Nonce(next_payload='Notify',
                                           load=self.sa.i_nonce))
 
         if behind_nat:
             src_address = b'\x0a\x0a\x0a\x01'
         else:
-            src_address = bytes(self.pg0.local_ip4, 'ascii')
+            src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4)
 
         src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport)
-        dst_nat = self.sa.compute_nat_sha1(bytes(self.pg0.remote_ip4, 'ascii'),
-                                           self.sa.sport)
+        dst_nat = self.sa.compute_nat_sha1(
+                inet_pton(socket.AF_INET, self.pg0.local_ip4),
+                self.sa.dport)
         nat_src_detection = ikev2.IKEv2_payload_Notify(
-                type='NAT_DETECTION_SOURCE_IP', load=src_nat)
+                type='NAT_DETECTION_SOURCE_IP', load=src_nat,
+                next_payload='Notify')
         nat_dst_detection = ikev2.IKEv2_payload_Notify(
                 type='NAT_DETECTION_DESTINATION_IP', load=dst_nat)
         self.sa.init_req_packet = (self.sa.init_req_packet /