Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a6509d9 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[IPSEC]: Add support for combined mode algorithms



This patch adds support for combined mode algorithms with GCM being
the first algorithm supported.

Combined mode algorithms can be added through the xfrm_user interface
using the new algorithm payload type XFRMA_ALG_AEAD.  Each algorithms
is identified by its name and the ICV length.

For the purposes of matching algorithms in xfrm_tmpl structures,
combined mode algorithms occupy the same name space as encryption
algorithms.  This is in line with how they are negotiated using IKE.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6fbf2cb7
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -298,6 +298,12 @@ struct sadb_x_sec_ctx {
#define SADB_X_EALG_BLOWFISHCBC		7
#define SADB_EALG_NULL			11
#define SADB_X_EALG_AESCBC		12
#define SADB_X_EALG_AES_CCM_ICV8	14
#define SADB_X_EALG_AES_CCM_ICV12	15
#define SADB_X_EALG_AES_CCM_ICV16	16
#define SADB_X_EALG_AES_GCM_ICV8	18
#define SADB_X_EALG_AES_GCM_ICV12	19
#define SADB_X_EALG_AES_GCM_ICV16	20
#define SADB_X_EALG_CAMELLIACBC		22
#define SADB_EALG_MAX                   253 /* last EALG */
/* private allocations should use 249-255 (RFC2407) */
+8 −0
Original line number Diff line number Diff line
@@ -96,6 +96,13 @@ struct xfrm_algo {
	char		alg_key[0];
};

struct xfrm_algo_aead {
	char	alg_name[64];
	int	alg_key_len;	/* in bits */
	int	alg_icv_len;	/* in bits */
	char	alg_key[0];
};

struct xfrm_stats {
	__u32	replay_window;
	__u32	replay;
@@ -270,6 +277,7 @@ enum xfrm_attr_type_t {
	XFRMA_LASTUSED,
	XFRMA_POLICY_TYPE,	/* struct xfrm_userpolicy_type */
	XFRMA_MIGRATE,
	XFRMA_ALG_AEAD,		/* struct xfrm_algo_aead */
	__XFRMA_MAX

#define XFRMA_MAX (__XFRMA_MAX - 1)
+8 −0
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ struct xfrm_state
	struct xfrm_algo	*aalg;
	struct xfrm_algo	*ealg;
	struct xfrm_algo	*calg;
	struct xfrm_algo_aead	*aead;

	/* Data for encapsulator */
	struct xfrm_encap_tmpl	*encap;
@@ -1108,6 +1109,10 @@ static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
/*
 * xfrm algorithm information
 */
struct xfrm_algo_aead_info {
	u16 icv_truncbits;
};

struct xfrm_algo_auth_info {
	u16 icv_truncbits;
	u16 icv_fullbits;
@@ -1127,6 +1132,7 @@ struct xfrm_algo_desc {
	char *compat;
	u8 available:1;
	union {
		struct xfrm_algo_aead_info aead;
		struct xfrm_algo_auth_info auth;
		struct xfrm_algo_encr_info encr;
		struct xfrm_algo_comp_info comp;
@@ -1343,6 +1349,8 @@ extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len,
						   int probe);

struct hash_desc;
struct scatterlist;
+58 −13
Original line number Diff line number Diff line
@@ -439,32 +439,53 @@ static void esp_destroy(struct xfrm_state *x)
	kfree(esp);
}

static int esp_init_state(struct xfrm_state *x)
static int esp_init_aead(struct xfrm_state *x)
{
	struct esp_data *esp = NULL;
	struct esp_data *esp = x->data;
	struct crypto_aead *aead;
	int err;

	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
	err = PTR_ERR(aead);
	if (IS_ERR(aead))
		goto error;

	esp->aead = aead;

	err = crypto_aead_setkey(aead, x->aead->alg_key,
				 (x->aead->alg_key_len + 7) / 8);
	if (err)
		goto error;

	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
	if (err)
		goto error;

error:
	return err;
}

static int esp_init_authenc(struct xfrm_state *x)
{
	struct esp_data *esp = x->data;
	struct crypto_aead *aead;
	struct crypto_authenc_key_param *param;
	struct rtattr *rta;
	char *key;
	char *p;
	char authenc_name[CRYPTO_MAX_ALG_NAME];
	u32 align;
	unsigned int keylen;
	int err;

	err = -EINVAL;
	if (x->ealg == NULL)
		return -EINVAL;
		goto error;

	err = -ENAMETOOLONG;
	if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
		     x->aalg ? x->aalg->alg_name : "digest_null",
		     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
		return -ENAMETOOLONG;

	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
	if (esp == NULL)
		return -ENOMEM;

	x->data = esp;
		goto error;

	aead = crypto_alloc_aead(authenc_name, 0, 0);
	err = PTR_ERR(aead);
@@ -512,8 +533,6 @@ static int esp_init_state(struct xfrm_state *x)
			goto free_key;
	}

	esp->padlen = 0;

	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);

@@ -522,9 +541,35 @@ static int esp_init_state(struct xfrm_state *x)
free_key:
	kfree(key);

error:
	return err;
}

static int esp_init_state(struct xfrm_state *x)
{
	struct esp_data *esp;
	struct crypto_aead *aead;
	u32 align;
	int err;

	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
	if (esp == NULL)
		return -ENOMEM;

	x->data = esp;

	if (x->aead)
		err = esp_init_aead(x);
	else
		err = esp_init_authenc(x);

	if (err)
		goto error;

	aead = esp->aead;

	esp->padlen = 0;

	x->props.header_len = sizeof(struct ip_esp_hdr) +
			      crypto_aead_ivsize(aead);
	if (x->props.mode == XFRM_MODE_TUNNEL)
+61 −16
Original line number Diff line number Diff line
@@ -382,35 +382,53 @@ static void esp6_destroy(struct xfrm_state *x)
	kfree(esp);
}

static int esp6_init_state(struct xfrm_state *x)
static int esp_init_aead(struct xfrm_state *x)
{
	struct esp_data *esp = x->data;
	struct crypto_aead *aead;
	int err;

	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
	err = PTR_ERR(aead);
	if (IS_ERR(aead))
		goto error;

	esp->aead = aead;

	err = crypto_aead_setkey(aead, x->aead->alg_key,
				 (x->aead->alg_key_len + 7) / 8);
	if (err)
		goto error;

	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
	if (err)
		goto error;

error:
	return err;
}

static int esp_init_authenc(struct xfrm_state *x)
{
	struct esp_data *esp = NULL;
	struct esp_data *esp = x->data;
	struct crypto_aead *aead;
	struct crypto_authenc_key_param *param;
	struct rtattr *rta;
	char *key;
	char *p;
	char authenc_name[CRYPTO_MAX_ALG_NAME];
	u32 align;
	unsigned int keylen;
	int err;

	err = -EINVAL;
	if (x->ealg == NULL)
		return -EINVAL;

	if (x->encap)
		return -EINVAL;
		goto error;

	err = -ENAMETOOLONG;
	if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
		     x->aalg ? x->aalg->alg_name : "digest_null",
		     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
		return -ENAMETOOLONG;

	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
	if (esp == NULL)
		return -ENOMEM;

	x->data = esp;
		goto error;

	aead = crypto_alloc_aead(authenc_name, 0, 0);
	err = PTR_ERR(aead);
@@ -458,8 +476,6 @@ static int esp6_init_state(struct xfrm_state *x)
			goto free_key;
	}

	esp->padlen = 0;

	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);

@@ -468,9 +484,38 @@ static int esp6_init_state(struct xfrm_state *x)
free_key:
	kfree(key);

error:
	return err;
}

static int esp6_init_state(struct xfrm_state *x)
{
	struct esp_data *esp;
	struct crypto_aead *aead;
	u32 align;
	int err;

	if (x->encap)
		return -EINVAL;

	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
	if (esp == NULL)
		return -ENOMEM;

	x->data = esp;

	if (x->aead)
		err = esp_init_aead(x);
	else
		err = esp_init_authenc(x);

	if (err)
		goto error;

	aead = esp->aead;

	esp->padlen = 0;

	x->props.header_len = sizeof(struct ip_esp_hdr) +
			      crypto_aead_ivsize(aead);
	switch (x->props.mode) {
Loading