diff mbox series

[API-NEXT,v2,1/11] linux-gen: ipsec: use counter instead of random IV for GCM

Message ID 1508518809-27877-2-git-send-email-odpbot@yandex.ru
State Superseded
Headers show
Series [API-NEXT,v2,1/11] linux-gen: ipsec: use counter instead of random IV for GCM | expand

Commit Message

Github ODP bot Oct. 20, 2017, 4:59 p.m. UTC
From: Dmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org>


Reusing IV block with GCM results in disastrous consequences. Use
counter instead of random-generated IV to remove possibility for IV
reuse.

Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org>

---
/** Email created from pull request 243 (lumag:ipsec-packet-impl-3)
 ** https://github.com/Linaro/odp/pull/243
 ** Patch: https://github.com/Linaro/odp/pull/243.patch
 ** Base sha: e3108af2f0b58c2ceca422b418439bba5de04b11
 ** Merge commit sha: 1ac4107a19a46e35c46e3a96416279c6ef0a33d1
 **/
 platform/linux-generic/include/odp_ipsec_internal.h | 16 +++++++++++++---
 platform/linux-generic/odp_ipsec.c                  | 19 ++++++++++++++++++-
 platform/linux-generic/odp_ipsec_sad.c              |  6 ++++++
 3 files changed, 37 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/platform/linux-generic/include/odp_ipsec_internal.h b/platform/linux-generic/include/odp_ipsec_internal.h
index 1340ca7bd..afc2f686e 100644
--- a/platform/linux-generic/include/odp_ipsec_internal.h
+++ b/platform/linux-generic/include/odp_ipsec_internal.h
@@ -118,9 +118,17 @@  struct ipsec_sa_s {
 	uint8_t		salt[IPSEC_MAX_SALT_LEN];
 	uint32_t	salt_length;
 
-	unsigned	dec_ttl : 1;
-	unsigned	copy_dscp : 1;
-	unsigned	copy_df : 1;
+	union {
+		unsigned flags;
+		struct {
+			unsigned	dec_ttl : 1;
+			unsigned	copy_dscp : 1;
+			unsigned	copy_df : 1;
+
+			/* Only for outbound */
+			unsigned	use_counter_iv : 1;
+		};
+	};
 
 	union {
 		struct {
@@ -136,6 +144,8 @@  struct ipsec_sa_s {
 			odp_atomic_u32_t tun_hdr_id;
 			odp_atomic_u32_t seq;
 
+			odp_atomic_u64_t counter; /* for CTR/GCM */
+
 			uint8_t		tun_ttl;
 			uint8_t		tun_dscp;
 			uint8_t		tun_df;
diff --git a/platform/linux-generic/odp_ipsec.c b/platform/linux-generic/odp_ipsec.c
index e57736c2a..1aa437b8e 100644
--- a/platform/linux-generic/odp_ipsec.c
+++ b/platform/linux-generic/odp_ipsec.c
@@ -676,7 +676,24 @@  static ipsec_sa_t *ipsec_out_single(odp_packet_t pkt,
 			       ip_data_len +
 			       ipsec_sa->icv_len;
 
-		if (ipsec_sa->esp_iv_len) {
+		if (ipsec_sa->use_counter_iv) {
+			uint64_t ctr;
+
+			/* Both GCM and CTR use 8-bit counters */
+			ODP_ASSERT(sizeof(ctr) == ipsec_sa->esp_iv_len);
+
+			ctr = odp_atomic_fetch_add_u64(&ipsec_sa->out.counter,
+						       1);
+			/* Check for overrun */
+			if (ctr == 0)
+				goto out;
+
+			memcpy(iv, ipsec_sa->salt, ipsec_sa->salt_length);
+			memcpy(iv + ipsec_sa->salt_length, &ctr,
+			       ipsec_sa->esp_iv_len);
+
+			param.override_iv_ptr = iv;
+		} else if (ipsec_sa->esp_iv_len) {
 			uint32_t len;
 
 			len = odp_random_data(iv + ipsec_sa->salt_length,
diff --git a/platform/linux-generic/odp_ipsec_sad.c b/platform/linux-generic/odp_ipsec_sad.c
index f0b5b9e4a..5d20bb66c 100644
--- a/platform/linux-generic/odp_ipsec_sad.c
+++ b/platform/linux-generic/odp_ipsec_sad.c
@@ -207,6 +207,7 @@  odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
 	ipsec_sa->context = param->context;
 	ipsec_sa->queue = param->dest_queue;
 	ipsec_sa->mode = param->mode;
+	ipsec_sa->flags = 0;
 	if (ODP_IPSEC_DIR_INBOUND == param->dir) {
 		ipsec_sa->in.lookup_mode = param->inbound.lookup_mode;
 		if (ODP_IPSEC_LOOKUP_DSTADDR_SPI == ipsec_sa->in.lookup_mode)
@@ -315,6 +316,7 @@  odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
 	case ODP_CIPHER_ALG_AES128_GCM:
 #endif
 	case ODP_CIPHER_ALG_AES_GCM:
+		ipsec_sa->use_counter_iv = 1;
 		ipsec_sa->esp_iv_len = 8;
 		ipsec_sa->esp_block_len = 16;
 		crypto_param.iv.length = 12;
@@ -323,6 +325,10 @@  odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
 		return ODP_IPSEC_SA_INVALID;
 	}
 
+	if (1 == ipsec_sa->use_counter_iv &&
+	    ODP_IPSEC_DIR_OUTBOUND == param->dir)
+		odp_atomic_init_u64(&ipsec_sa->out.counter, 1);
+
 	crypto_param.auth_digest_len = ipsec_sa->icv_len;
 
 	if (param->crypto.cipher_key_extra.length) {