ikev2: fix false positive NAT detection
[vpp.git] / src / plugins / ikev2 / ikev2.c
index d8c94ff..96b8e7d 100644 (file)
@@ -296,9 +296,12 @@ static void
 ikev2_sa_free_all_vec (ikev2_sa_t * sa)
 {
   vec_free (sa->i_nonce);
-  vec_free (sa->i_dh_data);
+  vec_free (sa->r_nonce);
+
   vec_free (sa->dh_shared_key);
   vec_free (sa->dh_private_key);
+  vec_free (sa->i_dh_data);
+  vec_free (sa->r_dh_data);
 
   ikev2_sa_free_proposal_vector (&sa->r_proposals);
   ikev2_sa_free_proposal_vector (&sa->i_proposals);
@@ -312,14 +315,24 @@ ikev2_sa_free_all_vec (ikev2_sa_t * sa)
   vec_free (sa->sk_pr);
 
   vec_free (sa->i_id.data);
-  vec_free (sa->i_auth.data);
   vec_free (sa->r_id.data);
+
+  vec_free (sa->i_auth.data);
+  if (sa->i_auth.key)
+    EVP_PKEY_free (sa->i_auth.key);
   vec_free (sa->r_auth.data);
   if (sa->r_auth.key)
     EVP_PKEY_free (sa->r_auth.key);
 
   vec_free (sa->del);
 
+  vec_free (sa->rekey);
+
+  vec_free (sa->last_sa_init_req_packet_data);
+  vec_free (sa->last_sa_init_res_packet_data);
+
+  vec_free (sa->last_res_packet_data);
+
   ikev2_sa_free_all_child_sa (&sa->childs);
 }
 
@@ -537,6 +550,7 @@ ikev2_calc_keys (ikev2_sa_t * sa)
   pos += tr_prf->key_len;
 
   vec_free (keymat);
+  sa->keys_generated = 1;
 }
 
 static void
@@ -640,7 +654,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa,
   sa->ispi = clib_net_to_host_u64 (ike->ispi);
 
   /* store whole IKE payload - needed for PSK auth */
-  vec_free (sa->last_sa_init_req_packet_data);
+  vec_reset_length (sa->last_sa_init_req_packet_data);
   vec_add (sa->last_sa_init_req_packet_data, ike, len);
 
   while (p < len && payload != IKEV2_PAYLOAD_NONE)
@@ -673,11 +687,9 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa,
          ikev2_notify_t *n = ikev2_parse_notify_payload (ikep);
          if (n->msg_type == IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP)
            {
-             u8 *src_sha =
-               ikev2_compute_nat_sha1 (clib_net_to_host_u64 (ike->ispi), 0,
-                                       clib_net_to_host_u32 (sa->
-                                                             iaddr.as_u32),
-                                       udp->src_port);
+             u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi, 0,
+                                                   sa->iaddr.as_u32,
+                                                   udp->src_port);
              if (clib_memcmp (src_sha, n->data, vec_len (src_sha)))
                {
                  sa->natt = 1;
@@ -689,11 +701,9 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa,
          else if (n->msg_type ==
                   IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP)
            {
-             u8 *dst_sha =
-               ikev2_compute_nat_sha1 (clib_net_to_host_u64 (ike->ispi), 0,
-                                       clib_net_to_host_u32 (sa->
-                                                             raddr.as_u32),
-                                       udp->dst_port);
+             u8 *dst_sha = ikev2_compute_nat_sha1 (ike->ispi, 0,
+                                                   sa->raddr.as_u32,
+                                                   udp->dst_port);
              if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha)))
                {
                  sa->natt = 1;
@@ -742,7 +752,7 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa,
                       sa->raddr.as_u32);
 
   /* store whole IKE payload - needed for PSK auth */
-  vec_free (sa->last_sa_init_res_packet_data);
+  vec_reset_length (sa->last_sa_init_res_packet_data);
   vec_add (sa->last_sa_init_res_packet_data, ike, len);
 
   while (p < len && payload != IKEV2_PAYLOAD_NONE)
@@ -783,8 +793,7 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa,
            {
              u8 *src_sha = ikev2_compute_nat_sha1 (ike->ispi,
                                                    ike->rspi,
-                                                   clib_net_to_host_u32
-                                                   (sa->raddr.as_u32),
+                                                   sa->raddr.as_u32,
                                                    udp->src_port);
              if (clib_memcmp (src_sha, n->data, vec_len (src_sha)))
                {
@@ -2125,7 +2134,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user,
          u8 *nat_detection_sha1 =
            ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi),
                                    clib_host_to_net_u64 (sa->rspi),
-                                   clib_host_to_net_u32 (sa->raddr.as_u32),
+                                   sa->raddr.as_u32,
                                    udp->dst_port);
          ikev2_payload_add_notify (chain,
                                    IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP,
@@ -2322,7 +2331,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user,
       clib_memcpy_fast (ike->payload, chain->data, vec_len (chain->data));
 
       /* store whole IKE payload - needed for PSK auth */
-      vec_free (sa->last_sa_init_res_packet_data);
+      vec_reset_length (sa->last_sa_init_res_packet_data);
       vec_add (sa->last_sa_init_res_packet_data, ike, tlen);
     }
   else
@@ -2371,7 +2380,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user,
        }
 
       /* store whole IKE payload - needed for retransmit */
-      vec_free (sa->last_res_packet_data);
+      vec_reset_length (sa->last_res_packet_data);
       vec_add (sa->last_res_packet_data, ike, tlen);
     }
 
@@ -2680,7 +2689,7 @@ ikev2_node_fn (vlib_main_t * vm,
                    {
                      is_req = 1;
                      ike0->exchange = IKEV2_EXCHANGE_IKE_AUTH;
-                     uword *p = hash_get (km->sa_by_ispi, ike0->ispi);
+                     uword *p = hash_get (km->sa_by_ispi, sa0->ispi);
                      if (p)
                        {
                          ikev2_sa_t *sai =
@@ -2757,7 +2766,7 @@ ikev2_node_fn (vlib_main_t * vm,
 
                  if (sa0->is_initiator)
                    {
-                     ikev2_del_sa_init (ike0->ispi);
+                     ikev2_del_sa_init (sa0->ispi);
                    }
                  else
                    {
@@ -3196,6 +3205,8 @@ ikev2_set_local_key (vlib_main_t * vm, u8 * file)
 {
   ikev2_main_t *km = &ikev2_main;
 
+  if (km->pkey)
+    EVP_PKEY_free (km->pkey);
   km->pkey = ikev2_load_key_file (file);
   if (km->pkey == NULL)
     return clib_error_return (0, "load key '%s' failed", file);
@@ -3344,6 +3355,19 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p)
   vec_free (del_sai);
 }
 
+static void
+ikev2_profile_free (ikev2_profile_t * p)
+{
+  vec_free (p->name);
+
+  vec_free (p->auth.data);
+  if (p->auth.key)
+    EVP_PKEY_free (p->auth.key);
+
+  vec_free (p->loc_id.data);
+  vec_free (p->rem_id.data);
+}
+
 clib_error_t *
 ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add)
 {
@@ -3373,7 +3397,7 @@ ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add)
       ikev2_unregister_udp_port (p);
       ikev2_cleanup_profile_sessions (km, p);
 
-      vec_free (p->name);
+      ikev2_profile_free (p);
       pool_put (km->profiles, p);
       mhash_unset (&km->profile_index_by_name, name, 0);
     }
@@ -3394,7 +3418,11 @@ ikev2_set_profile_auth (vlib_main_t * vm, u8 * name, u8 auth_method,
       r = clib_error_return (0, "unknown profile %v", name);
       return r;
     }
+
+  if (p->auth.key)
+    EVP_PKEY_free (p->auth.key);
   vec_free (p->auth.data);
+
   p->auth.method = auth_method;
   p->auth.data = vec_dup (auth_data);
   p->auth.hex = data_hex_format;
@@ -3402,8 +3430,6 @@ ikev2_set_profile_auth (vlib_main_t * vm, u8 * name, u8 auth_method,
   if (auth_method == IKEV2_AUTH_METHOD_RSA_SIG)
     {
       vec_add1 (p->auth.data, 0);
-      if (p->auth.key)
-       EVP_PKEY_free (p->auth.key);
       p->auth.key = ikev2_load_cert_file (p->auth.data);
       if (p->auth.key == NULL)
        return clib_error_return (0, "load cert '%s' failed", p->auth.data);
@@ -3739,7 +3765,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
     u8 *nat_detection_sha1 =
       ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi),
                              clib_host_to_net_u64 (sa.rspi),
-                             clib_host_to_net_u32 (if_ip->as_u32),
+                             if_ip->as_u32,
                              clib_host_to_net_u16 (IKEV2_PORT));
 
     ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP,
@@ -3748,7 +3774,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
     nat_detection_sha1 =
       ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa.ispi),
                              clib_host_to_net_u64 (sa.rspi),
-                             clib_host_to_net_u32 (p->responder.ip4.as_u32),
+                             p->responder.ip4.as_u32,
                              clib_host_to_net_u16 (sa.dst_port));
     ikev2_payload_add_notify (chain,
                              IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP,
@@ -3774,12 +3800,12 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
     ike0->version = IKE_VERSION_2;
     ike0->flags = IKEV2_HDR_FLAG_INITIATOR;
     ike0->exchange = IKEV2_EXCHANGE_SA_INIT;
-    ike0->ispi = sa.ispi;
+    ike0->ispi = clib_host_to_net_u64 (sa.ispi);
     ike0->rspi = 0;
     ike0->msgid = 0;
 
     /* store whole IKE payload - needed for PSK auth */
-    vec_free (sa.last_sa_init_req_packet_data);
+    vec_reset_length (sa.last_sa_init_req_packet_data);
     vec_add (sa.last_sa_init_req_packet_data, ike0, len);
 
     /* add data to the SA then add it to the pool */
@@ -4313,7 +4339,7 @@ ikev2_mngr_process_responder_sas (ikev2_sa_t * sa)
   ikev2_main_t *km = &ikev2_main;
   vlib_main_t *vm = km->vlib_main;
 
-  if (!sa->sk_ai || !sa->sk_ar)
+  if (!sa->keys_generated)
     return 0;
 
   if (sa->liveness_retries >= km->liveness_max_retries)