ipsec: keep crypto data inside SA

Change-Id: Ie8986bd3652d25c4befe681cea77df95aba37ebc
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/vnet/ipsec/ah_decrypt.c b/src/vnet/ipsec/ah_decrypt.c
index 2488fa9..b128dfa 100644
--- a/src/vnet/ipsec/ah_decrypt.c
+++ b/src/vnet/ipsec/ah_decrypt.c
@@ -172,7 +172,7 @@
 	    (&ipsec_sa_counters, thread_index, sa_index0,
 	     1, i_b0->current_length);
 
-	  icv_size = im->integ_algs[sa0->integ_alg].trunc_size;
+	  icv_size = sa0->integ_trunc_size;
 	  if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
 	    {
 	      u8 sig[64];
@@ -203,9 +203,7 @@
 		  icv_padding_len =
 		    ah_calc_icv_padding_len (icv_size, 0 /* is_ipv6 */ );
 		}
-	      hmac_calc (vm, sa0->integ_alg, sa0->integ_key.data,
-			 sa0->integ_key.len, (u8 *) ih4, i_b0->current_length,
-			 sig, sa0->use_esn, sa0->seq_hi);
+	      hmac_calc (vm, sa0, (u8 *) ih4, i_b0->current_length, sig);
 
 	      if (PREDICT_FALSE (memcmp (digest, sig, icv_size)))
 		{
diff --git a/src/vnet/ipsec/ah_encrypt.c b/src/vnet/ipsec/ah_encrypt.c
index ce930bd..c6dbe57 100644
--- a/src/vnet/ipsec/ah_encrypt.c
+++ b/src/vnet/ipsec/ah_encrypt.c
@@ -152,7 +152,7 @@
 	      adv = -sizeof (ah_header_t);
 	    }
 
-	  icv_size = im->integ_algs[sa0->integ_alg].trunc_size;
+	  icv_size = sa0->integ_trunc_size;
 	  const u8 padding_len = ah_calc_icv_padding_len (icv_size, is_ip6);
 	  adv -= padding_len;
 	  /* transport mode save the eth header before it is overwritten */
@@ -265,11 +265,8 @@
 	    sizeof (ah_header_t);
 	  clib_memset (digest, 0, icv_size);
 
-	  unsigned size = hmac_calc (vm, sa0->integ_alg, sa0->integ_key.data,
-				     sa0->integ_key.len,
-				     vlib_buffer_get_current (i_b0),
-				     i_b0->current_length, sig, sa0->use_esn,
-				     sa0->seq_hi);
+	  unsigned size = hmac_calc (vm, sa0, vlib_buffer_get_current (i_b0),
+				     i_b0->current_length, sig);
 
 	  memcpy (digest, sig, size);
 	  if (is_ip6)
diff --git a/src/vnet/ipsec/esp.h b/src/vnet/ipsec/esp.h
index 1730038..74ab1f0 100644
--- a/src/vnet/ipsec/esp.h
+++ b/src/vnet/ipsec/esp.h
@@ -205,19 +205,17 @@
 
 
 always_inline unsigned int
-hmac_calc (vlib_main_t * vm, ipsec_integ_alg_t alg, u8 * key, int key_len,
-	   u8 * data, int data_len, u8 * signature, u8 use_esn, u32 seq_hi)
+hmac_calc (vlib_main_t * vm, ipsec_sa_t * sa, u8 * data, int data_len,
+	   u8 * signature)
 {
-  ipsec_main_t *im = &ipsec_main;
   vnet_crypto_op_t _op, *op = &_op;
-  ASSERT (alg < IPSEC_INTEG_N_ALG);
 
-  if (PREDICT_FALSE (im->integ_algs[alg].op_type == 0))
+  if (PREDICT_FALSE (sa->integ_op_type == 0))
     return 0;
 
-  op->op = im->integ_algs[alg].op_type;
-  op->key = key;
-  op->key_len = key_len;
+  op->op = sa->integ_op_type;
+  op->key = sa->integ_key.data;
+  op->key_len = sa->integ_key.len;
   op->src = data;
   op->len = data_len;
   op->dst = signature;
@@ -233,7 +231,7 @@
 
 #endif
   vnet_crypto_process_ops (vm, op, 1);
-  return im->integ_algs[alg].trunc_size;
+  return sa->integ_trunc_size;
 }
 
 #endif /* __ESP_H__ */
diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c
index 1ee7ce8..7860ca3 100644
--- a/src/vnet/ipsec/esp_decrypt.c
+++ b/src/vnet/ipsec/esp_decrypt.c
@@ -82,21 +82,16 @@
 }
 
 always_inline void
-esp_decrypt_cbc (vlib_main_t * vm, ipsec_crypto_alg_t alg,
+esp_decrypt_cbc (vlib_main_t * vm, ipsec_sa_t * sa,
 		 u8 * in, u8 * out, size_t in_len, u8 * key, u8 * iv)
 {
-  ipsec_main_t *im = &ipsec_main;
-  ipsec_main_crypto_alg_t *a;
   vnet_crypto_op_t _op, *op = &_op;
 
-  ASSERT (alg < IPSEC_CRYPTO_N_ALG);
 
-  a = &im->crypto_algs[alg];
-
-  if (PREDICT_FALSE (a->dec_op_type == VNET_CRYPTO_OP_NONE))
+  if (PREDICT_FALSE (sa->crypto_dec_op_type == VNET_CRYPTO_OP_NONE))
     return;
 
-  op->op = a->dec_op_type;
+  op->op = sa->crypto_dec_op_type;
   op->iv = iv;
   op->src = in;
   op->dst = out;
@@ -181,15 +176,13 @@
       if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
 	{
 	  u8 sig[64];
-	  int icv_size = im->integ_algs[sa0->integ_alg].trunc_size;
+	  int icv_size = sa0->integ_trunc_size;
 	  clib_memset (sig, 0, sizeof (sig));
 	  u8 *icv = vlib_buffer_get_current (ib[0]) + ib[0]->current_length -
 	    icv_size;
 	  ib[0]->current_length -= icv_size;
 
-	  hmac_calc (vm, sa0->integ_alg, sa0->integ_key.data,
-		     sa0->integ_key.len, (u8 *) esp0,
-		     ib[0]->current_length, sig, sa0->use_esn, sa0->seq_hi);
+	  hmac_calc (vm, sa0, (u8 *) esp0, ib[0]->current_length, sig);
 
 	  if (PREDICT_FALSE (memcmp (icv, sig, icv_size)))
 	    {
@@ -217,8 +210,8 @@
 	  (sa0->crypto_alg >= IPSEC_CRYPTO_ALG_DES_CBC &&
 	   sa0->crypto_alg <= IPSEC_CRYPTO_ALG_3DES_CBC))
 	{
-	  const int BLOCK_SIZE = im->crypto_algs[sa0->crypto_alg].block_size;
-	  const int IV_SIZE = im->crypto_algs[sa0->crypto_alg].iv_size;
+	  const int BLOCK_SIZE = sa0->crypto_block_size;
+	  const int IV_SIZE = sa0->crypto_block_size;
 	  esp_footer_t *f0;
 	  u8 ip_hdr_size = 0;
 
@@ -251,8 +244,7 @@
 		}
 	    }
 
-	  esp_decrypt_cbc (vm, sa0->crypto_alg,
-			   esp0->data + IV_SIZE,
+	  esp_decrypt_cbc (vm, sa0, esp0->data + IV_SIZE,
 			   (u8 *) vlib_buffer_get_current (ob[0]) +
 			   ip_hdr_size, BLOCK_SIZE * blocks,
 			   sa0->crypto_key.data, esp0->data);
diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c
index 37c2c95..1e29ee3 100644
--- a/src/vnet/ipsec/esp_encrypt.c
+++ b/src/vnet/ipsec/esp_encrypt.c
@@ -87,21 +87,16 @@
 }
 
 always_inline void
-esp_encrypt_cbc (vlib_main_t * vm, ipsec_crypto_alg_t alg,
+esp_encrypt_cbc (vlib_main_t * vm, ipsec_sa_t * sa,
 		 u8 * in, u8 * out, size_t in_len, u8 * key, u8 * iv)
 {
-  ipsec_main_t *im = &ipsec_main;
-  ipsec_main_crypto_alg_t *a;
   vnet_crypto_op_t _op, *op = &_op;
 
-  ASSERT (alg < IPSEC_CRYPTO_N_ALG);
 
-  a = &im->crypto_algs[alg];
-
-  if (PREDICT_FALSE (a->enc_op_type == VNET_CRYPTO_OP_NONE))
+  if (PREDICT_FALSE (sa->crypto_enc_op_type == VNET_CRYPTO_OP_NONE))
     return;
 
-  op->op = a->enc_op_type;
+  op->op = sa->crypto_enc_op_type;
   op->flags = VNET_CRYPTO_OP_FLAG_INIT_IV;
   op->iv = iv;
   op->src = in;
@@ -282,8 +277,8 @@
       if (PREDICT_TRUE (sa0->crypto_alg != IPSEC_CRYPTO_ALG_NONE))
 	{
 
-	  const int BLOCK_SIZE = im->crypto_algs[sa0->crypto_alg].block_size;
-	  const int IV_SIZE = im->crypto_algs[sa0->crypto_alg].iv_size;
+	  const int BLOCK_SIZE = sa0->crypto_block_size;
+	  const int IV_SIZE = sa0->crypto_iv_size;
 	  int blocks = 1 + (ib[0]->current_length + 1) / BLOCK_SIZE;
 
 	  /* pad packet in input buffer */
@@ -311,10 +306,9 @@
 
 	  clib_memcpy_fast ((u8 *) vlib_buffer_get_current (ob[0]) +
 			    ip_udp_hdr_size + sizeof (esp_header_t), iv,
-			    im->crypto_algs[sa0->crypto_alg].iv_size);
+			    IV_SIZE);
 
-	  esp_encrypt_cbc (vm, sa0->crypto_alg,
-			   (u8 *) vlib_buffer_get_current (ib[0]),
+	  esp_encrypt_cbc (vm, sa0, (u8 *) vlib_buffer_get_current (ib[0]),
 			   (u8 *) vlib_buffer_get_current (ob[0]) +
 			   ip_udp_hdr_size + sizeof (esp_header_t) +
 			   IV_SIZE, BLOCK_SIZE * blocks,
@@ -322,11 +316,9 @@
 	}
 
       ob[0]->current_length +=
-	hmac_calc (vm, sa0->integ_alg, sa0->integ_key.data,
-		   sa0->integ_key.len, (u8 *) o_esp0,
+	hmac_calc (vm, sa0, (u8 *) o_esp0,
 		   ob[0]->current_length - ip_udp_hdr_size,
-		   vlib_buffer_get_current (ob[0]) + ob[0]->current_length,
-		   sa0->use_esn, sa0->seq_hi);
+		   vlib_buffer_get_current (ob[0]) + ob[0]->current_length);
 
 
       if (is_ip6)
diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c
index f40e94d..33cac4c 100644
--- a/src/vnet/ipsec/ipsec_if.c
+++ b/src/vnet/ipsec/ipsec_if.c
@@ -493,25 +493,25 @@
   if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
     {
       sa = pool_elt_at_index (im->sad, t->output_sa_index);
-      sa->crypto_alg = alg;
+      ipsec_sa_set_crypto_alg (sa, alg);
       ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
     }
   else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
     {
       sa = pool_elt_at_index (im->sad, t->output_sa_index);
-      sa->integ_alg = alg;
+      ipsec_sa_set_integ_alg (sa, alg);
       ipsec_mk_key (&sa->integ_key, key, vec_len (key));
     }
   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
     {
       sa = pool_elt_at_index (im->sad, t->input_sa_index);
-      sa->crypto_alg = alg;
+      ipsec_sa_set_crypto_alg (sa, alg);
       ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
     }
   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
     {
       sa = pool_elt_at_index (im->sad, t->input_sa_index);
-      sa->integ_alg = alg;
+      ipsec_sa_set_integ_alg (sa, alg);
       ipsec_mk_key (&sa->integ_key, key, vec_len (key));
     }
   else
diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c
index fc8520d..337ca34 100644
--- a/src/vnet/ipsec/ipsec_sa.c
+++ b/src/vnet/ipsec/ipsec_sa.c
@@ -88,6 +88,26 @@
   dpo_reset (&tmp);
 }
 
+void
+ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg)
+{
+  ipsec_main_t *im = &ipsec_main;
+  sa->crypto_alg = crypto_alg;
+  sa->crypto_iv_size = im->crypto_algs[crypto_alg].iv_size;
+  sa->crypto_block_size = im->crypto_algs[crypto_alg].block_size;
+  sa->crypto_enc_op_type = im->crypto_algs[crypto_alg].enc_op_type;
+  sa->crypto_dec_op_type = im->crypto_algs[crypto_alg].dec_op_type;
+}
+
+void
+ipsec_sa_set_integ_alg (ipsec_sa_t * sa, ipsec_integ_alg_t integ_alg)
+{
+  ipsec_main_t *im = &ipsec_main;
+  sa->integ_alg = integ_alg;
+  sa->integ_trunc_size = im->integ_algs[integ_alg].trunc_size;
+  sa->integ_op_type = im->integ_algs[integ_alg].op_type;
+}
+
 int
 ipsec_sa_add (u32 id,
 	      u32 spi,
@@ -123,9 +143,9 @@
   sa->spi = spi;
   sa->stat_index = sa_index;
   sa->protocol = proto;
-  sa->crypto_alg = crypto_alg;
+  ipsec_sa_set_crypto_alg (sa, crypto_alg);
   clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
-  sa->integ_alg = integ_alg;
+  ipsec_sa_set_integ_alg (sa, integ_alg);
   clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key));
   ip46_address_copy (&sa->tunnel_src_addr, tun_src);
   ip46_address_copy (&sa->tunnel_dst_addr, tun_dst);
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index 2601f51..a6ade60 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -106,9 +106,15 @@
 
   ipsec_crypto_alg_t crypto_alg;
   ipsec_key_t crypto_key;
+  u8 crypto_iv_size;
+  u8 crypto_block_size;
+  vnet_crypto_op_type_t crypto_enc_op_type;
+  vnet_crypto_op_type_t crypto_dec_op_type;
 
   ipsec_integ_alg_t integ_alg;
   ipsec_key_t integ_key;
+  vnet_crypto_op_type_t integ_op_type;
+  u8 integ_trunc_size;
 
   u8 use_esn;
   u8 use_anti_replay;
@@ -156,6 +162,10 @@
 			 u32 * sa_index);
 extern u32 ipsec_sa_del (u32 id);
 extern void ipsec_sa_stack (ipsec_sa_t * sa);
+extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa,
+				     ipsec_crypto_alg_t crypto_alg);
+extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa,
+				    ipsec_integ_alg_t integ_alg);
 
 extern u8 ipsec_is_sa_used (u32 sa_index);
 extern int ipsec_set_sa_key (u32 id,