diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-29 06:37:29 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-02-01 06:27:03 +0300 |
commit | 1a6509d991225ad210de54c63314fd9542922095 (patch) | |
tree | afe5c560388558bebd3e21b7c6f789a28a323a51 /net/ipv6/esp6.c | |
parent | 6fbf2cb77461a0cd0675228d20dd0f70d7b2251f (diff) | |
download | linux-1a6509d991225ad210de54c63314fd9542922095.tar.xz |
[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: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/esp6.c')
-rw-r--r-- | net/ipv6/esp6.c | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index dc821acf3d33..ca48c56c4b17 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -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) { |