2009-11-25 10:53:32

by Martin Willi

[permalink] [raw]
Subject: [PATCH 0/3] xfrm: Custom truncation lengths for authentication algorithms

The following patchset adds support for defining truncation lengths
for authentication algorithms in userspace. The main purpose for this
is to support SHA256 in IPsec using the standardized 128 bit
instead of the currently used 96 bit truncation.

Martin Willi (3):
xfrm: Define new XFRM netlink auth attribute with specified
truncation bits
xfrm: Store aalg in xfrm_state with a user specified truncation
length
xfrm: Use the user specified truncation length in ESP and AH

include/linux/xfrm.h | 8 +++
include/net/xfrm.h | 12 ++++-
net/ipv4/ah4.c | 2 +-
net/ipv4/esp4.c | 2 +-
net/ipv6/ah6.c | 2 +-
net/ipv6/esp6.c | 2 +-
net/xfrm/xfrm_state.c | 2 +-
net/xfrm/xfrm_user.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++---
8 files changed, 145 insertions(+), 14 deletions(-)



2009-11-25 10:29:53

by Martin Willi

[permalink] [raw]
Subject: [PATCH 3/3] xfrm: Use the user specified truncation length in ESP and AH

Instead of using the hardcoded truncation for authentication
algorithms, use the truncation length specified on xfrm_state.

Signed-off-by: Martin Willi <[email protected]>
---
net/ipv4/ah4.c | 2 +-
net/ipv4/esp4.c | 2 +-
net/ipv6/ah6.c | 2 +-
net/ipv6/esp6.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 5c66270..b7be5ed 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -261,7 +261,7 @@ static int ah_init_state(struct xfrm_state *x)
}

ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
- ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
+ ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;

BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 12f7287..1948895 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -530,7 +530,7 @@ static int esp_init_authenc(struct xfrm_state *x)
}

err = crypto_aead_setauthsize(
- aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
+ aead, x->aalg->alg_trunc_len / 8);
if (err)
goto free_key;
}
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index c1589e2..0c2ae68 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -469,7 +469,7 @@ static int ah6_init_state(struct xfrm_state *x)
}

ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
- ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
+ ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;

BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);

diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index af597c7..668a46b 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -473,7 +473,7 @@ static int esp_init_authenc(struct xfrm_state *x)
}

err = crypto_aead_setauthsize(
- aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
+ aead, x->aalg->alg_trunc_len / 8);
if (err)
goto free_key;
}
--
1.6.3.3


2009-11-25 10:53:36

by Martin Willi

[permalink] [raw]
Subject: [PATCH 1/3] xfrm: Define new XFRM netlink auth attribute with specified truncation bits

The new XFRMA_ALG_AUTH_TRUNC attribute taking a xfrm_algo_auth as
argument allows the installation of authentication algorithms with
a truncation length specified in userspace, i.e. SHA256 with 128 bit
instead of 96 bit truncation.

Signed-off-by: Martin Willi <[email protected]>
---
include/linux/xfrm.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 2d4ec15..d28e853 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -96,6 +96,13 @@ struct xfrm_algo {
char alg_key[0];
};

+struct xfrm_algo_auth {
+ char alg_name[64];
+ unsigned int alg_key_len; /* in bits */
+ unsigned int alg_trunc_len; /* in bits */
+ char alg_key[0];
+};
+
struct xfrm_algo_aead {
char alg_name[64];
unsigned int alg_key_len; /* in bits */
@@ -283,6 +290,7 @@ enum xfrm_attr_type_t {
XFRMA_MIGRATE,
XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */
XFRMA_KMADDRESS, /* struct xfrm_user_kmaddress */
+ XFRMA_ALG_AUTH_TRUNC, /* struct xfrm_algo_auth */
__XFRMA_MAX

#define XFRMA_MAX (__XFRMA_MAX - 1)
--
1.6.3.3


2009-11-25 10:29:52

by Martin Willi

[permalink] [raw]
Subject: [PATCH 2/3] xfrm: Store aalg in xfrm_state with a user specified truncation length

Adding a xfrm_state requires an authentication algorithm specified
either as xfrm_algo or as xfrm_algo_auth with a specific truncation
length. For compatibility, both attributes are dumped to userspace,
and we also accept both attributes, but prefer the new syntax.

If no truncation length is specified, or the authentication algorithm
is specified using xfrm_algo, the truncation length from the algorithm
description in the kernel is used.

Signed-off-by: Martin Willi <[email protected]>
---
include/net/xfrm.h | 12 ++++-
net/xfrm/xfrm_state.c | 2 +-
net/xfrm/xfrm_user.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 133 insertions(+), 10 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 223e90a..762327d 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -160,7 +160,7 @@ struct xfrm_state
struct xfrm_lifetime_cfg lft;

/* Data for transformer */
- struct xfrm_algo *aalg;
+ struct xfrm_algo_auth *aalg;
struct xfrm_algo *ealg;
struct xfrm_algo *calg;
struct xfrm_algo_aead *aead;
@@ -1541,12 +1541,22 @@ static inline int xfrm_alg_len(struct xfrm_algo *alg)
return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
}

+static inline int xfrm_alg_auth_len(struct xfrm_algo_auth *alg)
+{
+ return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
#ifdef CONFIG_XFRM_MIGRATE
static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
{
return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
}

+static inline struct xfrm_algo_auth *xfrm_algo_auth_clone(struct xfrm_algo_auth *orig)
+{
+ return kmemdup(orig, xfrm_alg_auth_len(orig), GFP_KERNEL);
+}
+
static inline void xfrm_states_put(struct xfrm_state **states, int n)
{
int i;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f2f7c63..67121ce 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1110,7 +1110,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
x->props.saddr = orig->props.saddr;

if (orig->aalg) {
- x->aalg = xfrm_algo_clone(orig->aalg);
+ x->aalg = xfrm_algo_auth_clone(orig->aalg);
if (!x->aalg)
goto error;
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b95a2d6..fb42d77 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -62,6 +62,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
return 0;
}

+static int verify_auth_trunc(struct nlattr **attrs)
+{
+ struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC];
+ struct xfrm_algo_auth *algp;
+
+ if (!rt)
+ return 0;
+
+ algp = nla_data(rt);
+ if (nla_len(rt) < xfrm_alg_auth_len(algp))
+ return -EINVAL;
+
+ algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
+ return 0;
+}
+
static int verify_aead(struct nlattr **attrs)
{
struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
@@ -128,7 +144,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
err = -EINVAL;
switch (p->id.proto) {
case IPPROTO_AH:
- if (!attrs[XFRMA_ALG_AUTH] ||
+ if ((!attrs[XFRMA_ALG_AUTH] &&
+ !attrs[XFRMA_ALG_AUTH_TRUNC]) ||
attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ALG_COMP])
@@ -139,10 +156,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
if (attrs[XFRMA_ALG_COMP])
goto out;
if (!attrs[XFRMA_ALG_AUTH] &&
+ !attrs[XFRMA_ALG_AUTH_TRUNC] &&
!attrs[XFRMA_ALG_CRYPT] &&
!attrs[XFRMA_ALG_AEAD])
goto out;
if ((attrs[XFRMA_ALG_AUTH] ||
+ attrs[XFRMA_ALG_AUTH_TRUNC] ||
attrs[XFRMA_ALG_CRYPT]) &&
attrs[XFRMA_ALG_AEAD])
goto out;
@@ -152,6 +171,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
if (!attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_AUTH] ||
+ attrs[XFRMA_ALG_AUTH_TRUNC] ||
attrs[XFRMA_ALG_CRYPT])
goto out;
break;
@@ -161,6 +181,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
case IPPROTO_ROUTING:
if (attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_ALG_AUTH] ||
+ attrs[XFRMA_ALG_AUTH_TRUNC] ||
attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ENCAP] ||
@@ -176,6 +197,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,

if ((err = verify_aead(attrs)))
goto out;
+ if ((err = verify_auth_trunc(attrs)))
+ goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
@@ -229,6 +252,66 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
return 0;
}

+static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
+ struct nlattr *rta)
+{
+ struct xfrm_algo *ualg;
+ struct xfrm_algo_auth *p;
+ struct xfrm_algo_desc *algo;
+
+ if (!rta)
+ return 0;
+
+ ualg = nla_data(rta);
+
+ algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
+ if (!algo)
+ return -ENOSYS;
+ *props = algo->desc.sadb_alg_id;
+
+ p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ strcpy(p->alg_name, algo->name);
+ p->alg_key_len = ualg->alg_key_len;
+ p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
+ memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8);
+
+ *algpp = p;
+ return 0;
+}
+
+static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
+ struct nlattr *rta)
+{
+ struct xfrm_algo_auth *p, *ualg;
+ struct xfrm_algo_desc *algo;
+
+ if (!rta)
+ return 0;
+
+ ualg = nla_data(rta);
+
+ algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
+ if (!algo)
+ return -ENOSYS;
+ if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
+ return -EINVAL;
+ *props = algo->desc.sadb_alg_id;
+
+ p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ strcpy(p->alg_name, algo->name);
+ if (!p->alg_trunc_len)
+ p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
+
+ *algpp = p;
+ return 0;
+}
+
static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
struct nlattr *rta)
{
@@ -332,10 +415,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
if ((err = attach_aead(&x->aead, &x->props.ealgo,
attrs[XFRMA_ALG_AEAD])))
goto error;
- if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
- xfrm_aalg_get_byname,
- attrs[XFRMA_ALG_AUTH])))
+ if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
+ attrs[XFRMA_ALG_AUTH_TRUNC])))
goto error;
+ if (!x->props.aalgo) {
+ if ((err = attach_auth(&x->aalg, &x->props.aalgo,
+ attrs[XFRMA_ALG_AUTH])))
+ goto error;
+ }
if ((err = attach_one_algo(&x->ealg, &x->props.ealgo,
xfrm_ealg_get_byname,
attrs[XFRMA_ALG_CRYPT])))
@@ -548,6 +635,24 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
return 0;
}

+static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
+{
+ struct xfrm_algo *algo;
+ struct nlattr *nla;
+
+ nla = nla_reserve(skb, XFRMA_ALG_AUTH,
+ sizeof(*algo) + (auth->alg_key_len + 7) / 8);
+ if (!nla)
+ return -EMSGSIZE;
+
+ algo = nla_data(nla);
+ strcpy(algo->alg_name, auth->alg_name);
+ memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
+ algo->alg_key_len = auth->alg_key_len;
+
+ return 0;
+}
+
/* Don't change this without updating xfrm_sa_len! */
static int copy_to_user_state_extra(struct xfrm_state *x,
struct xfrm_usersa_info *p,
@@ -563,8 +668,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,

if (x->aead)
NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
- if (x->aalg)
- NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
+ if (x->aalg) {
+ if (copy_to_user_auth(x->aalg, skb))
+ goto nla_put_failure;
+
+ NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC,
+ xfrm_alg_auth_len(x->aalg), x->aalg);
+ }
if (x->ealg)
NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
if (x->calg)
@@ -2117,8 +2227,11 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
size_t l = 0;
if (x->aead)
l += nla_total_size(aead_len(x->aead));
- if (x->aalg)
- l += nla_total_size(xfrm_alg_len(x->aalg));
+ if (x->aalg) {
+ l += nla_total_size(sizeof(struct xfrm_algo) +
+ (x->aalg->alg_key_len + 7) / 8);
+ l += nla_total_size(xfrm_alg_auth_len(x->aalg));
+ }
if (x->ealg)
l += nla_total_size(xfrm_alg_len(x->ealg));
if (x->calg)
--
1.6.3.3


2009-11-25 12:10:35

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 0/3] xfrm: Custom truncation lengths for authentication algorithms

On Wed, Nov 25, 2009 at 11:29:50AM +0100, Martin Willi wrote:
> The following patchset adds support for defining truncation lengths
> for authentication algorithms in userspace. The main purpose for this
> is to support SHA256 in IPsec using the standardized 128 bit
> instead of the currently used 96 bit truncation.
>
> Martin Willi (3):
> xfrm: Define new XFRM netlink auth attribute with specified
> truncation bits
> xfrm: Store aalg in xfrm_state with a user specified truncation
> length
> xfrm: Use the user specified truncation length in ESP and AH

Looks great to me. Thanks Martin!
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2009-11-25 23:48:36

by David Miller

[permalink] [raw]
Subject: Re: [PATCH 0/3] xfrm: Custom truncation lengths for authentication algorithms

From: Martin Willi <[email protected]>
Date: Wed, 25 Nov 2009 11:29:50 +0100

> The following patchset adds support for defining truncation lengths
> for authentication algorithms in userspace. The main purpose for this
> is to support SHA256 in IPsec using the standardized 128 bit
> instead of the currently used 96 bit truncation.
>
> Martin Willi (3):
> xfrm: Define new XFRM netlink auth attribute with specified
> truncation bits
> xfrm: Store aalg in xfrm_state with a user specified truncation
> length
> xfrm: Use the user specified truncation length in ESP and AH

All applied to net-next-2.6, thanks!