aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/ipsec/ipsec_sa.h
diff options
context:
space:
mode:
authorBenoît Ganne <bganne@cisco.com>2022-01-18 15:56:41 +0100
committerBeno�t Ganne <bganne@cisco.com>2023-03-23 08:59:31 +0000
commit5527a78ed96043d2c26e3271066c50b44dd7fc0b (patch)
tree3e4186cb439e10051d013cc71c1f7d8d81ad9613 /src/vnet/ipsec/ipsec_sa.h
parentad95b06181c354291f4433c5e550cb89c5122252 (diff)
ipsec: make pre-shared keys harder to misuse
Using pre-shared keys is usually a bad idea, one should use eg. IKEv2 instead, but one does not always have the choice. For AES-CBC, the IV must be unpredictable (see NIST SP800-38a Appendix C) whereas for AES-CTR or AES-GCM, the IV should never be reused with the same key material (see NIST SP800-38a Appendix B and NIST SP800-38d section 8). If one uses pre-shared keys and VPP is restarted, the IV counter restarts at 0 and the same IVs are generated with the same pre-shared keys materials. To fix those issues we follow the recommendation from NIST SP800-38a and NIST SP800-38d: - we use a PRNG (not cryptographically secured) to generate IVs to avoid generating the same IV sequence between VPP restarts. The PRNG is chosen so that there is a low chance of generating the same sequence - for AES-CBC, the generated IV is encrypted as part of the message. This makes the (predictable) PRNG-generated IV unpredictable as it is encrypted with the secret key - for AES-CTR and GCM, we use the IV as-is as predictable IVs are fine Most of the changes in this patch are caused by the need to shoehorn an additional state of 2 u64 for the PRNG in the 1st cacheline of the SA object. Type: improvement Change-Id: I2af89c21ae4b2c4c33dd21aeffcfb79c13c9d84c Signed-off-by: Benoît Ganne <bganne@cisco.com>
Diffstat (limited to 'src/vnet/ipsec/ipsec_sa.h')
-rw-r--r--src/vnet/ipsec/ipsec_sa.h91
1 files changed, 34 insertions, 57 deletions
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index 4ef8f87dbef..ab1e3cdb1f9 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -16,11 +16,16 @@
#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);