diff options
author | Benoît Ganne <bganne@cisco.com> | 2022-01-18 15:56:41 +0100 |
---|---|---|
committer | Beno�t Ganne <bganne@cisco.com> | 2023-03-23 08:59:31 +0000 |
commit | 5527a78ed96043d2c26e3271066c50b44dd7fc0b (patch) | |
tree | 3e4186cb439e10051d013cc71c1f7d8d81ad9613 /src/vnet/ipsec/ipsec_sa.h | |
parent | ad95b06181c354291f4433c5e550cb89c5122252 (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.h | 91 |
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); |