hs-test: move nginx tests into one file
[vpp.git] / src / plugins / ikev2 / ikev2_payload.c
index 509483a..5801a1b 100644 (file)
@@ -24,7 +24,6 @@
 #include <plugins/ikev2/ikev2.h>
 #include <plugins/ikev2/ikev2_priv.h>
 
-/* *INDENT-OFF* */
 typedef CLIB_PACKED (struct {
   u8 nextpayload;
   u8 flags;
@@ -34,21 +33,26 @@ typedef CLIB_PACKED (struct {
   u16 msg_type;
   u8 payload[0];
 }) ike_notify_payload_header_t;
-/* *INDENT-ON* */
 
-/* *INDENT-OFF* */
+typedef CLIB_PACKED (struct {
+  ip4_address_t start_addr;
+  ip4_address_t end_addr;
+}) ikev2_ip4_addr_pair_t;
+
+typedef CLIB_PACKED (struct {
+  ip6_address_t start_addr;
+  ip6_address_t end_addr;
+}) ikev2_ip6_addr_pair_t;
+
 typedef CLIB_PACKED (struct {
   u8 ts_type;
   u8 protocol_id;
   u16 selector_len;
   u16 start_port;
   u16 end_port;
-  ip4_address_t start_addr;
-  ip4_address_t end_addr;
+  u8 addr_pair[0];
 }) ikev2_ts_payload_entry_t;
-/* *INDENT-OFF* */
 
-/* *INDENT-OFF* */
 typedef CLIB_PACKED (struct {
   u8 nextpayload;
   u8 flags;
@@ -57,9 +61,7 @@ typedef CLIB_PACKED (struct {
   u8 reserved[3];
   ikev2_ts_payload_entry_t ts[0];
 }) ike_ts_payload_header_t;
-/* *INDENT-OFF* */
 
-/* *INDENT-OFF* */
 typedef CLIB_PACKED (struct {
   u8 last_or_more;
   u8 reserved;
@@ -69,9 +71,7 @@ typedef CLIB_PACKED (struct {
   u8 spi_size;
   u8 num_transforms; u32 spi[0];
 }) ike_sa_proposal_data_t;
-/* *INDENT-OFF* */
 
-/* *INDENT-OFF* */
 typedef CLIB_PACKED (struct {
   u8 last_or_more;
   u8 reserved;
@@ -81,9 +81,7 @@ typedef CLIB_PACKED (struct {
   u16 transform_id;
   u8 attributes[0];
 }) ike_sa_transform_data_t;
-/* *INDENT-OFF* */
 
-/* *INDENT-OFF* */
 typedef CLIB_PACKED (struct {
   u8 nextpayload;
   u8 flags;
@@ -93,7 +91,6 @@ typedef CLIB_PACKED (struct {
   u16 num_of_spi;
   u32 spi[0];
 }) ike_delete_payload_header_t;
-/* *INDENT-OFF* */
 
 static ike_payload_header_t *
 ikev2_payload_add_hdr (ikev2_payload_chain_t * c, u8 payload_type, int len)
@@ -158,8 +155,8 @@ ikev2_payload_add_notify_2 (ikev2_payload_chain_t * c, u16 msg_type,
 }
 
 void
-ikev2_payload_add_sa (ikev2_payload_chain_t * c,
-                     ikev2_sa_proposal_t * proposals)
+ikev2_payload_add_sa (ikev2_payload_chain_t *c, ikev2_sa_proposal_t *proposals,
+                     u8 force_spi)
 {
   ike_payload_header_t *ph;
   ike_sa_proposal_data_t *prop;
@@ -175,7 +172,13 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c,
 
   vec_foreach (p, proposals)
   {
-    int spi_size = (p->protocol_id == IKEV2_PROTOCOL_ESP) ? 4 : 0;
+    int spi_size = 0;
+
+    if (p->protocol_id == IKEV2_PROTOCOL_ESP)
+      spi_size = 4;
+    else if (force_spi && p->protocol_id == IKEV2_PROTOCOL_IKE)
+      spi_size = 8;
+
     pr_data = vec_new (u8, sizeof (ike_sa_proposal_data_t) + spi_size);
     prop = (ike_sa_proposal_data_t *) pr_data;
     prop->last_or_more = proposals - p + 1 < vec_len (proposals) ? 2 : 0;
@@ -184,13 +187,13 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c,
     prop->spi_size = spi_size;
     prop->num_transforms = vec_len (p->transforms);
 
-    if (spi_size)
+    if (spi_size == 4)
       prop->spi[0] = clib_host_to_net_u32 (p->spi);
-
-    DBG_PLD ("proposal num %u protocol_id %u last_or_more %u spi_size %u%s%U",
-            prop->proposal_num, prop->protocol_id, prop->last_or_more,
-            prop->spi_size, prop->spi_size ? " spi_data " : "",
-            format_hex_bytes, prop->spi, prop->spi_size);
+    else if (spi_size == 8)
+      {
+       u64 s = clib_host_to_net_u64 (p->spi);
+       clib_memcpy_fast (prop->spi, &s, sizeof (s));
+      }
 
     vec_foreach (t, p->transforms)
     {
@@ -205,13 +208,6 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c,
 
       if (vec_len (t->attrs) > 0)
        clib_memcpy_fast (tr->attributes, t->attrs, vec_len (t->attrs));
-
-      DBG_PLD
-       ("transform type %U transform_id %u last_or_more %u attr_size %u%s%U",
-        format_ikev2_transform_type, tr->transform_type, t->transform_id,
-        tr->last_or_more, vec_len (t->attrs),
-        vec_len (t->attrs) ? " attrs " : "", format_hex_bytes,
-        tr->attributes, vec_len (t->attrs));
     }
 
     prop->proposal_len =
@@ -298,12 +294,46 @@ ikev2_payload_add_auth (ikev2_payload_chain_t * c, ikev2_auth_t * auth)
   ikev2_payload_add_data (c, auth->data);
 }
 
+static void
+ikev2_payload_add_ts_entry (u8 ** data, ikev2_ts_t * ts)
+{
+  u8 * tmp;
+  ikev2_ts_payload_entry_t *entry;
+  int len = sizeof (*entry);
+
+  if (ts->ts_type == TS_IPV4_ADDR_RANGE)
+    len += sizeof (ikev2_ip4_addr_pair_t);
+  else
+    len += sizeof (ikev2_ip6_addr_pair_t);
+
+  vec_add2 (data[0], tmp, len);
+  entry = (ikev2_ts_payload_entry_t *) tmp;
+  entry->ts_type = ts->ts_type;
+  entry->protocol_id = ts->protocol_id;
+  entry->selector_len = clib_host_to_net_u16 (len);
+  entry->start_port = clib_host_to_net_u16 (ts->start_port);
+  entry->end_port = clib_host_to_net_u16 (ts->end_port);
+
+  if (ts->ts_type == TS_IPV4_ADDR_RANGE)
+  {
+    ikev2_ip4_addr_pair_t *pair = (ikev2_ip4_addr_pair_t*) entry->addr_pair;
+    ip_address_copy_addr (&pair->start_addr, &ts->start_addr);
+    ip_address_copy_addr (&pair->end_addr, &ts->end_addr);
+  }
+  else
+  {
+    ikev2_ip6_addr_pair_t *pair = (ikev2_ip6_addr_pair_t*) entry->addr_pair;
+    ip_address_copy_addr (&pair->start_addr, &ts->start_addr);
+    ip_address_copy_addr (&pair->end_addr, &ts->end_addr);
+  }
+}
+
 void
 ikev2_payload_add_ts (ikev2_payload_chain_t * c, ikev2_ts_t * ts, u8 type)
 {
   ike_ts_payload_header_t *tsh;
   ikev2_ts_t *ts2;
-  u8 *data = 0, *tmp;
+  u8 *data = 0;
 
   tsh =
     (ike_ts_payload_header_t *) ikev2_payload_add_hdr (c, type,
@@ -312,17 +342,9 @@ ikev2_payload_add_ts (ikev2_payload_chain_t * c, ikev2_ts_t * ts, u8 type)
 
   vec_foreach (ts2, ts)
   {
-    ASSERT (ts2->ts_type == 7);        /*TS_IPV4_ADDR_RANGE */
-    ikev2_ts_payload_entry_t *entry;
-    vec_add2 (data, tmp, sizeof (*entry));
-    entry = (ikev2_ts_payload_entry_t *) tmp;
-    entry->ts_type = ts2->ts_type;
-    entry->protocol_id = ts2->protocol_id;
-    entry->selector_len = clib_host_to_net_u16 (16);
-    entry->start_port = clib_host_to_net_u16 (ts2->start_port);
-    entry->end_port = clib_host_to_net_u16 (ts2->end_port);
-    entry->start_addr.as_u32 = ts2->start_addr.as_u32;
-    entry->end_addr.as_u32 = ts2->end_addr.as_u32;
+    ASSERT (ts2->ts_type == TS_IPV4_ADDR_RANGE ||
+        ts2->ts_type == TS_IPV6_ADDR_RANGE);
+    ikev2_payload_add_ts_entry (&data, ts2);
   }
 
   ikev2_payload_add_data (c, data);
@@ -339,31 +361,31 @@ ikev2_payload_chain_add_padding (ikev2_payload_chain_t * c, int bs)
 }
 
 ikev2_sa_proposal_t *
-ikev2_parse_sa_payload (ike_payload_header_t * ikep)
+ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen)
 {
   ikev2_sa_proposal_t *v = 0;
   ikev2_sa_proposal_t *proposal;
   ikev2_sa_transform_t *transform;
 
   u32 plen = clib_net_to_host_u16 (ikep->length);
-
   ike_sa_proposal_data_t *sap;
   int proposal_ptr = 0;
 
+  if (sizeof (*ikep) > rlen)
+    return 0;
+
+  rlen -= sizeof (*ikep);
   do
     {
-      sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr];
-      int i;
-      int transform_ptr;
+      if (proposal_ptr + sizeof (*sap) > rlen)
+        goto data_corrupted;
 
-      DBG_PLD ("proposal num %u len %u last_or_more %u id %u "
-              "spi_size %u num_transforms %u",
-              sap->proposal_num, clib_net_to_host_u16 (sap->proposal_len),
-              sap->last_or_more, sap->protocol_id, sap->spi_size,
-              sap->num_transforms);
+      sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr];
+      int i, transform_ptr;
 
-      /* IKE proposal should not have SPI */
-      if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0)
+      /* IKE proposal should have 8 bytes or no SPI */
+      if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0 &&
+         sap->spi_size != 8)
        goto data_corrupted;
 
       /* IKE proposal should not have SPI */
@@ -371,6 +393,8 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep)
        goto data_corrupted;
 
       transform_ptr = proposal_ptr + sizeof (*sap) + sap->spi_size;
+      if (transform_ptr > rlen)
+        goto data_corrupted;
 
       vec_add2 (v, proposal, 1);
       proposal->proposal_num = sap->proposal_num;
@@ -380,11 +404,19 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep)
        {
          proposal->spi = clib_net_to_host_u32 (sap->spi[0]);
        }
+      else if (sap->spi_size == 8)
+       {
+         u64 s;
+         clib_memcpy_fast (&s, &sap->spi[0], sizeof (s));
+         proposal->spi = clib_net_to_host_u64 (s);
+       }
 
       for (i = 0; i < sap->num_transforms; i++)
        {
          ike_sa_transform_data_t *tr =
-           (ike_sa_transform_data_t *) & ikep->payload[transform_ptr];
+            (ike_sa_transform_data_t *) & ikep->payload[transform_ptr];
+          if (transform_ptr + sizeof (*tr) > rlen)
+            goto data_corrupted;
          u16 tlen = clib_net_to_host_u16 (tr->transform_len);
 
          if (tlen < sizeof (*tr))
@@ -394,17 +426,11 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep)
 
          transform->type = tr->transform_type;
          transform->transform_id = clib_net_to_host_u16 (tr->transform_id);
+          if (transform_ptr + tlen > rlen)
+            goto data_corrupted;
          if (tlen > sizeof (*tr))
            vec_add (transform->attrs, tr->attributes, tlen - sizeof (*tr));
-
-         DBG_PLD
-           ("transform num %u len %u last_or_more %u type %U id %u%s%U", i,
-            tlen, tr->last_or_more, format_ikev2_sa_transform, transform,
-            clib_net_to_host_u16 (tr->transform_id),
-            tlen > sizeof (*tr) ? " attrs " : "", format_hex_bytes,
-            tr->attributes, tlen - sizeof (*tr));
-
-         transform_ptr += tlen;
+          transform_ptr += tlen;
        }
 
       proposal_ptr += clib_net_to_host_u16 (sap->proposal_len);
@@ -418,49 +444,79 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep)
   return v;
 
 data_corrupted:
-  DBG_PLD ("SA payload data corrupted");
+  ikev2_elog_detail ("SA payload data corrupted");
   ikev2_sa_free_proposal_vector (&v);
   return 0;
 }
 
 ikev2_ts_t *
-ikev2_parse_ts_payload (ike_payload_header_t * ikep)
+ikev2_parse_ts_payload (ike_payload_header_t * ikep, u32 rlen)
 {
   ike_ts_payload_header_t *tsp = (ike_ts_payload_header_t *) ikep;
   ikev2_ts_t *r = 0, *ts;
-  u8 i;
+  ikev2_ip4_addr_pair_t *pair4;
+  ikev2_ip6_addr_pair_t *pair6;
+  int p = 0, n_left;
+  ikev2_ts_payload_entry_t *pe;
+
+  if (sizeof (*tsp) > rlen)
+    return 0;
 
-  for (i = 0; i < tsp->num_ts; i++)
+  rlen -= sizeof (*tsp);
+  n_left = tsp->num_ts;
+
+  while (n_left && p + sizeof (*pe) < rlen)
     {
-      if (tsp->ts[i].ts_type != 7)     /*  TS_IPV4_ADDR_RANGE */
-       {
-         DBG_PLD ("unsupported TS type received (%u)", tsp->ts[i].ts_type);
-         continue;
-       }
+      pe = (ikev2_ts_payload_entry_t *) (((u8 *)tsp->ts) + p);
+      p += sizeof (*pe);
+
+      if (pe->ts_type != TS_IPV4_ADDR_RANGE &&
+          pe->ts_type != TS_IPV6_ADDR_RANGE)
+        {
+          ikev2_elog_uint (IKEV2_LOG_ERROR,
+              "unsupported TS type received (%u)", pe->ts_type);
+          return 0;
+        }
 
       vec_add2 (r, ts, 1);
-      ts->ts_type = tsp->ts[i].ts_type;
-      ts->protocol_id = tsp->ts[i].protocol_id;
-      ts->start_port = tsp->ts[i].start_port;
-      ts->end_port = tsp->ts[i].end_port;
-      ts->start_addr.as_u32 = tsp->ts[i].start_addr.as_u32;
-      ts->end_addr.as_u32 = tsp->ts[i].end_addr.as_u32;
+      ts->ts_type = pe->ts_type;
+      ts->protocol_id = pe->protocol_id;
+      ts->start_port = pe->start_port;
+      ts->end_port = pe->end_port;
+
+      if (pe->ts_type == TS_IPV4_ADDR_RANGE)
+        {
+          pair4 = (ikev2_ip4_addr_pair_t*) pe->addr_pair;
+          ip_address_set (&ts->start_addr, &pair4->start_addr, AF_IP4);
+          ip_address_set (&ts->end_addr, &pair4->end_addr, AF_IP4);
+          p += sizeof (*pair4);
+        }
+      else
+        {
+          pair6 = (ikev2_ip6_addr_pair_t*) pe->addr_pair;
+          ip_address_set (&ts->start_addr, &pair6->start_addr, AF_IP6);
+          ip_address_set (&ts->end_addr, &pair6->end_addr, AF_IP6);
+          p += sizeof (*pair6);
+        }
+      n_left--;
     }
+
+  if (n_left)
+    return 0;
+
   return r;
 }
 
 ikev2_notify_t *
-ikev2_parse_notify_payload (ike_payload_header_t * ikep)
+ikev2_parse_notify_payload (ike_payload_header_t * ikep, u32 rlen)
 {
   ike_notify_payload_header_t *n = (ike_notify_payload_header_t *) ikep;
-  u32 plen = clib_net_to_host_u16 (ikep->length);
+  u32 plen = clib_net_to_host_u16 (n->length);
   ikev2_notify_t *r = 0;
   u32 spi;
 
-  DBG_PLD ("msg_type %U len %u%s%U",
-          format_ikev2_notify_msg_type, clib_net_to_host_u16 (n->msg_type),
-          plen, plen > sizeof (*n) ? " data " : "",
-          format_hex_bytes, n->payload, plen - sizeof (*n));
+  if (sizeof (*n) > rlen)
+    return 0;
 
   r = vec_new (ikev2_notify_t, 1);
   r->msg_type = clib_net_to_host_u16 (n->msg_type);
@@ -468,9 +524,11 @@ ikev2_parse_notify_payload (ike_payload_header_t * ikep)
 
   if (n->spi_size == 4)
     {
+      if (sizeof (spi) + sizeof (*n) > rlen)
+        goto cleanup;
+
       clib_memcpy (&spi, n->payload, n->spi_size);
       r->spi = clib_net_to_host_u32 (spi);
-      DBG_PLD ("spi %lx", r->spi);
     }
   else if (n->spi_size == 0)
     {
@@ -479,49 +537,42 @@ ikev2_parse_notify_payload (ike_payload_header_t * ikep)
   else
     {
       clib_warning ("invalid SPI Size %d", n->spi_size);
+      goto cleanup;
     }
 
   if (plen > (sizeof (*n) + n->spi_size))
     {
-      vec_add (r->data, n->payload + n->spi_size,
-              plen - sizeof (*n) - n->spi_size);
-    }
+      if (plen <= sizeof (*n) + n->spi_size)
+        goto cleanup;
 
+      u32 data_len = plen - sizeof (*n) - n->spi_size;
+      vec_add (r->data, n->payload + n->spi_size, data_len);
+    }
   return r;
+
+cleanup:
+  vec_free (r);
+  return 0;
 }
 
 void
 ikev2_parse_vendor_payload (ike_payload_header_t * ikep)
 {
   u32 plen = clib_net_to_host_u16 (ikep->length);
-  int i;
-  int is_string = 1;
-
-  for (i = 0; i < plen - 4; i++)
-    if (!isprint (ikep->payload[i]))
-      is_string = 0;
-
-  DBG_PLD ("len %u data %s:%U",
-          plen,
-          is_string ? "string" : "hex",
-          is_string ? format_ascii_bytes : format_hex_bytes,
-          ikep->payload, plen - sizeof (*ikep));
+  ikev2_elog_uint (IKEV2_LOG_DEBUG, "vendor payload skipped, len %d", plen);
 }
 
 ikev2_delete_t *
-ikev2_parse_delete_payload (ike_payload_header_t * ikep)
+ikev2_parse_delete_payload (ike_payload_header_t * ikep, u32 rlen)
 {
-  ike_delete_payload_header_t *d = (ike_delete_payload_header_t *) ikep;
-  u32 plen = clib_net_to_host_u16 (ikep->length);
+  ike_delete_payload_header_t * d = (ike_delete_payload_header_t *) ikep;
   ikev2_delete_t *r = 0, *del;
-  u16 num_of_spi = clib_net_to_host_u16 (d->num_of_spi);
-  u16 i = 0;
+  u16 i, num_of_spi;
 
-  DBG_PLD ("protocol_id %u spi_size %u num_of_spi %u len %u%s%U",
-          d->protocol_id, d->spi_size, num_of_spi,
-          plen, plen > sizeof (d) ? " data " : "",
-          format_hex_bytes, d->spi, plen - sizeof (*d));
+  if (rlen < sizeof (*d))
+    return 0;
 
+  num_of_spi = clib_net_to_host_u16 (d->num_of_spi);
   if (d->protocol_id == IKEV2_PROTOCOL_IKE)
     {
       r = vec_new (ikev2_delete_t, 1);
@@ -529,17 +580,44 @@ ikev2_parse_delete_payload (ike_payload_header_t * ikep)
     }
   else
     {
-      r = vec_new (ikev2_delete_t, num_of_spi);
-      vec_foreach (del, r)
+      if (sizeof (*d) + num_of_spi * sizeof (u32) > rlen)
+        return 0;
+
+      for (i = 0; i < num_of_spi; i++)
       {
-       del->protocol_id = d->protocol_id;
-       del->spi = clib_net_to_host_u32 (d->spi[i++]);
+        vec_add2 (r, del, 1);
+        del->protocol_id = d->protocol_id;
+       del->spi = clib_net_to_host_u32 (d->spi[i]);
       }
     }
 
   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
  *