ipsec: make pre-shared keys harder to misuse
[vpp.git] / src / vnet / ipsec / ipsec_sa.h
index 4ef8f87..ab1e3cd 100644 (file)
 #define __IPSEC_SPD_SA_H__
 
 #include <vlib/vlib.h>
+#include <vppinfra/pcg.h>
 #include <vnet/crypto/crypto.h>
 #include <vnet/ip/ip.h>
 #include <vnet/fib/fib_node.h>
 #include <vnet/tunnel/tunnel.h>
 
+#define ESP_MAX_ICV_SIZE   (32)
+#define ESP_MAX_IV_SIZE           (16)
+#define ESP_MAX_BLOCK_SIZE (16)
+
 #define foreach_ipsec_crypto_alg                                              \
   _ (0, NONE, "none")                                                         \
   _ (1, AES_CBC_128, "aes-cbc-128")                                           \
@@ -151,47 +156,27 @@ typedef struct
 {
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
 
-  /* flags */
-  ipsec_sa_flags_t flags;
-
-  u8 crypto_iv_size;
-  u8 esp_block_align;
-  u8 integ_icv_size;
-
-  u8 __pad1[3];
+  clib_pcg64i_random_t iv_prng;
 
-  u32 thread_index;
-
-  u32 spi;
-  u32 seq;
-  u32 seq_hi;
   u64 replay_window;
-  u64 iv_counter;
   dpo_id_t dpo;
 
   vnet_crypto_key_index_t crypto_key_index;
   vnet_crypto_key_index_t integ_key_index;
 
-  /* Union data shared by sync and async ops, updated when mode is
-   * changed. */
-  union
-  {
-    struct
-    {
-      vnet_crypto_op_id_t crypto_enc_op_id:16;
-      vnet_crypto_op_id_t crypto_dec_op_id:16;
-      vnet_crypto_op_id_t integ_op_id:16;
-    };
+  u32 spi;
+  u32 seq;
+  u32 seq_hi;
 
-    struct
-    {
-      vnet_crypto_async_op_id_t crypto_async_enc_op_id:16;
-      vnet_crypto_async_op_id_t crypto_async_dec_op_id:16;
-      vnet_crypto_key_index_t linked_key_index;
-    };
+  u16 crypto_enc_op_id;
+  u16 crypto_dec_op_id;
+  u16 integ_op_id;
+  ipsec_sa_flags_t flags;
+  u16 thread_index;
 
-    u64 crypto_op_data;
-  };
+  u16 integ_icv_size : 6;
+  u16 crypto_iv_size : 5;
+  u16 esp_block_align : 5;
 
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
 
@@ -213,30 +198,7 @@ typedef struct
     CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);
 
   /* Elements with u64 size multiples */
-  union
-  {
-    struct
-    {
-      vnet_crypto_op_id_t crypto_enc_op_id:16;
-      vnet_crypto_op_id_t crypto_dec_op_id:16;
-      vnet_crypto_op_id_t integ_op_id:16;
-    };
-    u64 data;
-  } sync_op_data;
-
-  union
-  {
-    struct
-    {
-      vnet_crypto_async_op_id_t crypto_async_enc_op_id:16;
-      vnet_crypto_async_op_id_t crypto_async_dec_op_id:16;
-      vnet_crypto_key_index_t linked_key_index;
-    };
-    u64 data;
-  } async_op_data;
-
   tunnel_t tunnel;
-
   fib_node_t node;
 
   /* elements with u32 size */
@@ -244,6 +206,16 @@ typedef struct
   u32 stat_index;
   vnet_crypto_alg_t integ_calg;
   vnet_crypto_alg_t crypto_calg;
+  u32 crypto_sync_key_index;
+  u32 integ_sync_key_index;
+  u32 crypto_async_key_index;
+
+  /* elements with u16 size */
+  u16 crypto_sync_enc_op_id;
+  u16 crypto_sync_dec_op_id;
+  u16 integ_sync_op_id;
+  u16 crypto_async_enc_op_id;
+  u16 crypto_async_dec_op_id;
 
   /* else u8 packed */
   ipsec_crypto_alg_t crypto_alg;
@@ -253,6 +225,10 @@ typedef struct
   ipsec_key_t crypto_key;
 } ipsec_sa_t;
 
+STATIC_ASSERT (VNET_CRYPTO_N_OP_IDS < (1 << 16), "crypto ops overflow");
+STATIC_ASSERT (ESP_MAX_ICV_SIZE < (1 << 6), "integer icv overflow");
+STATIC_ASSERT (ESP_MAX_IV_SIZE < (1 << 5), "esp iv overflow");
+STATIC_ASSERT (ESP_MAX_BLOCK_SIZE < (1 << 5), "esp alignment overflow");
 STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline1, CLIB_CACHE_LINE_BYTES);
 STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline2, 2 * CLIB_CACHE_LINE_BYTES);
 
@@ -316,6 +292,7 @@ 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 void ipsec_sa_set_async_mode (ipsec_sa_t *sa, int is_enabled);
 
 typedef walk_rc_t (*ipsec_sa_walk_cb_t) (ipsec_sa_t * sa, void *ctx);
 extern void ipsec_sa_walk (ipsec_sa_walk_cb_t cd, void *ctx);
@@ -668,8 +645,8 @@ ipsec_sa_anti_replay_advance (ipsec_sa_t *sa, u32 thread_index, u32 seq,
  * Makes choice for thread_id should be assigned.
  *  if input ~0, gets random worker_id based on unix_time_now_nsec
 */
-always_inline u32
-ipsec_sa_assign_thread (u32 thread_id)
+always_inline u16
+ipsec_sa_assign_thread (u16 thread_id)
 {
   return ((thread_id) ? thread_id
          : (unix_time_now_nsec () % vlib_num_workers ()) + 1);