Skip to content

Commit

Permalink
[IPSEC]: Add support for combined mode algorithms
Browse files Browse the repository at this point in the history
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: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed Feb 1, 2008
1 parent 6fbf2cb commit 1a6509d
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 32 deletions.
6 changes: 6 additions & 0 deletions include/linux/pfkeyv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand Down
8 changes: 8 additions & 0 deletions include/linux/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
71 changes: 58 additions & 13 deletions net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand Down
77 changes: 61 additions & 16 deletions net/ipv6/esp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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) {
Expand Down
Loading

0 comments on commit 1a6509d

Please sign in to comment.