[qca-nss-clients] ipsecmgr: v2: support GCM mode

- Added code to support RFC4106 GCM cryptographic mode.
- The GCM key is contructed by appending nonce value to the
  the cipher key and does not use RT attributes

Change-Id: Ibcf3a149f4497803aac398746be2d503f937de17
Signed-off-by: Tanmay V Jagdale <tjagdale@codeaurora.org>
diff --git a/exports/nss_ipsecmgr.h b/exports/nss_ipsecmgr.h
index c578240..f6e81d9 100644
--- a/exports/nss_ipsecmgr.h
+++ b/exports/nss_ipsecmgr.h
@@ -92,6 +92,7 @@
 	NSS_IPSECMGR_ALGO_3DES_CBC_SHA256_HMAC,		/**< 3DES_CBC_SHA256_HMAC. */
 	NSS_IPSECMGR_ALGO_NULL_CIPHER_SHA1_HMAC,	/**< NULL_CIPHER_SHA1_HMAC. */
 	NSS_IPSECMGR_ALGO_NULL_CIPHER_SHA256_HMAC,	/**< NULL_CIPHER_SHA256_HMAC. */
+	NSS_IPSECMGR_ALGO_AES_GCM_GMAC_RFC4106,		/**< AES GCM/GMAC based on RFC4106 */
 	NSS_IPSECMGR_ALGO_MAX
 };
 
diff --git a/ipsecmgr/v2.0/nss_ipsecmgr_sa.c b/ipsecmgr/v2.0/nss_ipsecmgr_sa.c
index 3e349d2..b1ab363 100644
--- a/ipsecmgr/v2.0/nss_ipsecmgr_sa.c
+++ b/ipsecmgr/v2.0/nss_ipsecmgr_sa.c
@@ -51,7 +51,8 @@
 	"echainiv(authenc(hmac(sha1),cbc(des3_ede)))",
 	"echainiv(authenc(hmac(sha256),cbc(des3_ede)))",
 	"hmac(sha1)",
-	"hmac(sha256)"
+	"hmac(sha256)",
+	"seqiv(rfc4106(gcm(aes)))"
 };
 
 /*
@@ -237,8 +238,8 @@
  *	Allocate Crypto resources
  */
 static nss_ipsecmgr_status_t nss_ipsecmgr_sa_crypto_alloc(struct nss_ipsecmgr_priv *priv,
-							struct nss_ipsecmgr_sa_entry *sa,
-							struct nss_ipsecmgr_sa_cmn *cmn)
+							  struct nss_ipsecmgr_sa_entry *sa,
+							  struct nss_ipsecmgr_sa_cmn *cmn)
 {
 	struct nss_ipsecmgr_crypto_keys *keys = &cmn->keys;
 	struct crypto_authenc_key_param *key_param;
@@ -247,11 +248,6 @@
 	uint32_t index;
 	uint16_t keylen;
 
-	if (cmn->algo >= ARRAY_SIZE(g_ipsec_algo_name)) {
-		nss_ipsecmgr_warn("%p: invalid crypto algorithm", sa);
-		return NSS_IPSECMGR_INVALID_ALGO;
-	}
-
 	/*
 	 * If, crypto is programmed using index(s) skip key-based programming
 	 */
@@ -263,11 +259,81 @@
 		return NSS_IPSECMGR_OK;
 	}
 
-	if (!keys->cipher_keylen) {
+	switch (cmn->algo) {
+	/*
+	 * AEAD Algorithms
+	 */
+	case NSS_IPSECMGR_ALGO_AES_CBC_SHA1_HMAC:
+	case NSS_IPSECMGR_ALGO_AES_CBC_SHA256_HMAC:
+	case NSS_IPSECMGR_ALGO_3DES_CBC_SHA1_HMAC:
+	case NSS_IPSECMGR_ALGO_3DES_CBC_SHA256_HMAC:
+		sa->aead = crypto_alloc_aead(g_ipsec_algo_name[cmn->algo], 0, 0);
+		if (IS_ERR(sa->aead)) {
+			nss_ipsecmgr_warn("%p: failed to allocate crypto aead context", sa);
+			return NSS_IPSECMGR_FAIL_NOCRYPTO;
+		}
+
+		nss_ipsecmgr_trace("cipher_keylen:%d auth_keylen:%d\n", keys->cipher_keylen, keys->auth_keylen);
 
 		/*
-		 * AHASH Algorithms
+		 * Construct keys
 		 */
+		keylen = RTA_SPACE(sizeof(*key_param));
+		keylen += keys->cipher_keylen;
+		keylen += keys->auth_keylen;
+		keylen += keys->nonce_size;
+
+		rt_keys = vzalloc(keylen);
+		if (!rt_keys) {
+			nss_ipsecmgr_warn("%p: failed to allocate key memory", sa);
+			crypto_free_aead(sa->aead);
+			return NSS_IPSECMGR_FAIL_NOMEM;
+		}
+
+		p = rt_keys;
+		rta = (void *)p;
+		rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
+		rta->rta_len = RTA_LENGTH(sizeof(*key_param));
+		key_param = RTA_DATA(rta);
+		p += RTA_SPACE(sizeof(*key_param));
+
+		/*
+		 * Copy authentication key
+		 */
+		memcpy(p, keys->auth_key, keys->auth_keylen);
+		p += keys->auth_keylen;
+
+		/*
+		 * Copy cipher Key
+		 */
+		key_param->enckeylen = cpu_to_be32(keys->cipher_keylen);
+		memcpy(p, keys->cipher_key, keys->cipher_keylen);
+
+		if (crypto_aead_setkey(sa->aead, rt_keys, keylen)) {
+			nss_ipsecmgr_warn("%p: failed to configure keys", sa);
+			vfree(rt_keys);
+			crypto_free_aead(sa->aead);
+			return NSS_IPSECMGR_INVALID_KEYLEN;
+		}
+
+		/*
+		 * FIXME: ctx2session requires 32bit whereas
+		 * data has 16bit crypto index. Ideally, the message
+		 * structure should be updated to take this into account
+		 */
+		nss_cryptoapi_aead_ctx2session(sa->aead, &index);
+		sa->data.crypto_index = (uint16_t)index;
+		sa->data.cipher_blk_len = (uint8_t)crypto_aead_blocksize(sa->aead);
+		sa->data.iv_len = (uint8_t)crypto_aead_ivsize(sa->aead);
+
+		vfree(rt_keys);
+		break;
+
+	/*
+	 * AHASH Algorithms
+	 */
+	case NSS_IPSECMGR_ALGO_NULL_CIPHER_SHA1_HMAC:
+	case NSS_IPSECMGR_ALGO_NULL_CIPHER_SHA256_HMAC:
 		sa->ahash = crypto_alloc_ahash(g_ipsec_algo_name[cmn->algo], 0, 0);
 		if (IS_ERR(sa->ahash)) {
 			nss_ipsecmgr_warn("%p: failed to allocate crypto ahash context", sa);
@@ -284,74 +350,59 @@
 		sa->data.crypto_index = (uint16_t)index;
 		sa->data.cipher_blk_len = 0;
 		sa->data.iv_len = 0;
-		return NSS_IPSECMGR_OK;
-	} else {
+		break;
 
-		/*
-		 * AEAD Algorithms
-		 */
+	/*
+	 * GCM Mode
+	 */
+	case NSS_IPSECMGR_ALGO_AES_GCM_GMAC_RFC4106:
 		sa->aead = crypto_alloc_aead(g_ipsec_algo_name[cmn->algo], 0, 0);
 		if (IS_ERR(sa->aead)) {
 			nss_ipsecmgr_warn("%p: failed to allocate crypto aead context", sa);
 			return NSS_IPSECMGR_FAIL_NOCRYPTO;
 		}
-	}
 
-	nss_ipsecmgr_trace("cipher_keylen:%d auth_keylen:%d\n", keys->cipher_keylen, keys->auth_keylen);
+		keylen = keys->cipher_keylen + keys->nonce_size;
 
-	/*
-	 * Construct keys
-	 */
-	keylen = RTA_SPACE(sizeof(*key_param));
-	keylen += keys->cipher_keylen;
-	keylen += keys->auth_keylen;
-	keylen += keys->nonce_size;
+		/*
+		 * Construct key with nonce
+		 */
+		rt_keys = vzalloc(keylen);
+		if (!rt_keys) {
+			nss_ipsecmgr_warn("%p: failed to allocate key memory", sa);
+			crypto_free_aead(sa->aead);
+			return NSS_IPSECMGR_FAIL_NOMEM;
+		}
 
-	rt_keys = vzalloc(keylen);
-	if (!rt_keys) {
-		nss_ipsecmgr_warn("%p: failed to allocate key memory", sa);
-		crypto_free_aead(sa->aead);
-		return NSS_IPSECMGR_FAIL_NOMEM;
-	}
+		memcpy(rt_keys, keys->cipher_key, keys->cipher_keylen);
+		memcpy(rt_keys + keys->cipher_keylen, (uint8_t *)keys->nonce, keys->nonce_size);
 
-	p = rt_keys;
-	rta = (void *)p;
-	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
-	rta->rta_len = RTA_LENGTH(sizeof(*key_param));
-	key_param = RTA_DATA(rta);
-	p += RTA_SPACE(sizeof(*key_param));
+		if (crypto_aead_setkey(sa->aead, rt_keys, keylen)) {
+			nss_ipsecmgr_warn("%p: failed to configure keys", sa);
+			vfree(rt_keys);
+			crypto_free_aead(sa->aead);
+			return NSS_IPSECMGR_INVALID_KEYLEN;
+		}
 
-	/*
-	 * Copy authentication key
-	 */
-	memcpy(p, keys->auth_key, keys->auth_keylen);
-	p += keys->auth_keylen;
+		/*
+		 * FIXME: ctx2session requires 32bit whereas
+		 * data has 16bit crypto index. Ideally, the message
+		 * structure should be updated to take this into account
+		 */
+		nss_cryptoapi_aead_ctx2session(sa->aead, &index);
+		sa->data.crypto_index = (uint16_t)index;
+		sa->data.cipher_blk_len = (uint8_t)crypto_aead_blocksize(sa->aead);
+		sa->data.iv_len = (uint8_t)crypto_aead_ivsize(sa->aead);
 
-	/*
-	 * Copy cipher Key
-	 */
-	key_param->enckeylen = cpu_to_be32(keys->cipher_keylen);
-	memcpy(p, keys->cipher_key, keys->cipher_keylen);
-
-	if (crypto_aead_setkey(sa->aead, rt_keys, keylen)) {
-		nss_ipsecmgr_warn("%p: failed to configure keys", sa);
 		vfree(rt_keys);
-		crypto_free_aead(sa->aead);
-		return NSS_IPSECMGR_INVALID_KEYLEN;
+		break;
+
+	default:
+		nss_ipsecmgr_warn("%p: invalid crypto algorithm", sa);
+		return NSS_IPSECMGR_INVALID_ALGO;
 	}
 
-	/*
-	 * FIXME: ctx2session requires 32bit whereas
-	 * data has 16bit crypto index. Ideally, the message
-	 * structure should be updated to take this into account
-	 */
-	nss_cryptoapi_aead_ctx2session(sa->aead, &index);
-	sa->data.crypto_index = (uint16_t)index;
-	sa->data.cipher_blk_len = (uint8_t)crypto_aead_blocksize(sa->aead);
-	sa->data.iv_len = (uint8_t)crypto_aead_ivsize(sa->aead);
-
-	vfree(rt_keys);
-	return 0;
+	return NSS_IPSECMGR_OK;
 }
 
 /*