diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-28 22:37:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:27:03 -0500 |
commit | 1a6509d991225ad210de54c63314fd9542922095 (patch) | |
tree | afe5c560388558bebd3e21b7c6f789a28a323a51 /net/xfrm/xfrm_user.c | |
parent | 6fbf2cb77461a0cd0675228d20dd0f70d7b2251f (diff) |
[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/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e0ccdf267813..78338079b7f5 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -31,6 +31,11 @@ | |||
31 | #include <linux/in6.h> | 31 | #include <linux/in6.h> |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | static inline int aead_len(struct xfrm_algo_aead *alg) | ||
35 | { | ||
36 | return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); | ||
37 | } | ||
38 | |||
34 | static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | 39 | static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) |
35 | { | 40 | { |
36 | struct nlattr *rt = attrs[type]; | 41 | struct nlattr *rt = attrs[type]; |
@@ -68,6 +73,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | |||
68 | return 0; | 73 | return 0; |
69 | } | 74 | } |
70 | 75 | ||
76 | static int verify_aead(struct nlattr **attrs) | ||
77 | { | ||
78 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; | ||
79 | struct xfrm_algo_aead *algp; | ||
80 | |||
81 | if (!rt) | ||
82 | return 0; | ||
83 | |||
84 | algp = nla_data(rt); | ||
85 | if (nla_len(rt) < aead_len(algp)) | ||
86 | return -EINVAL; | ||
87 | |||
88 | algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; | ||
89 | return 0; | ||
90 | } | ||
91 | |||
71 | static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, | 92 | static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, |
72 | xfrm_address_t **addrp) | 93 | xfrm_address_t **addrp) |
73 | { | 94 | { |
@@ -119,20 +140,28 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
119 | switch (p->id.proto) { | 140 | switch (p->id.proto) { |
120 | case IPPROTO_AH: | 141 | case IPPROTO_AH: |
121 | if (!attrs[XFRMA_ALG_AUTH] || | 142 | if (!attrs[XFRMA_ALG_AUTH] || |
143 | attrs[XFRMA_ALG_AEAD] || | ||
122 | attrs[XFRMA_ALG_CRYPT] || | 144 | attrs[XFRMA_ALG_CRYPT] || |
123 | attrs[XFRMA_ALG_COMP]) | 145 | attrs[XFRMA_ALG_COMP]) |
124 | goto out; | 146 | goto out; |
125 | break; | 147 | break; |
126 | 148 | ||
127 | case IPPROTO_ESP: | 149 | case IPPROTO_ESP: |
128 | if ((!attrs[XFRMA_ALG_AUTH] && | 150 | if (attrs[XFRMA_ALG_COMP]) |
129 | !attrs[XFRMA_ALG_CRYPT]) || | 151 | goto out; |
130 | attrs[XFRMA_ALG_COMP]) | 152 | if (!attrs[XFRMA_ALG_AUTH] && |
153 | !attrs[XFRMA_ALG_CRYPT] && | ||
154 | !attrs[XFRMA_ALG_AEAD]) | ||
155 | goto out; | ||
156 | if ((attrs[XFRMA_ALG_AUTH] || | ||
157 | attrs[XFRMA_ALG_CRYPT]) && | ||
158 | attrs[XFRMA_ALG_AEAD]) | ||
131 | goto out; | 159 | goto out; |
132 | break; | 160 | break; |
133 | 161 | ||
134 | case IPPROTO_COMP: | 162 | case IPPROTO_COMP: |
135 | if (!attrs[XFRMA_ALG_COMP] || | 163 | if (!attrs[XFRMA_ALG_COMP] || |
164 | attrs[XFRMA_ALG_AEAD] || | ||
136 | attrs[XFRMA_ALG_AUTH] || | 165 | attrs[XFRMA_ALG_AUTH] || |
137 | attrs[XFRMA_ALG_CRYPT]) | 166 | attrs[XFRMA_ALG_CRYPT]) |
138 | goto out; | 167 | goto out; |
@@ -143,6 +172,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
143 | case IPPROTO_ROUTING: | 172 | case IPPROTO_ROUTING: |
144 | if (attrs[XFRMA_ALG_COMP] || | 173 | if (attrs[XFRMA_ALG_COMP] || |
145 | attrs[XFRMA_ALG_AUTH] || | 174 | attrs[XFRMA_ALG_AUTH] || |
175 | attrs[XFRMA_ALG_AEAD] || | ||
146 | attrs[XFRMA_ALG_CRYPT] || | 176 | attrs[XFRMA_ALG_CRYPT] || |
147 | attrs[XFRMA_ENCAP] || | 177 | attrs[XFRMA_ENCAP] || |
148 | attrs[XFRMA_SEC_CTX] || | 178 | attrs[XFRMA_SEC_CTX] || |
@@ -155,6 +185,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
155 | goto out; | 185 | goto out; |
156 | } | 186 | } |
157 | 187 | ||
188 | if ((err = verify_aead(attrs))) | ||
189 | goto out; | ||
158 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) | 190 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) |
159 | goto out; | 191 | goto out; |
160 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) | 192 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) |
@@ -208,6 +240,31 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | |||
208 | return 0; | 240 | return 0; |
209 | } | 241 | } |
210 | 242 | ||
243 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, | ||
244 | struct nlattr *rta) | ||
245 | { | ||
246 | struct xfrm_algo_aead *p, *ualg; | ||
247 | struct xfrm_algo_desc *algo; | ||
248 | |||
249 | if (!rta) | ||
250 | return 0; | ||
251 | |||
252 | ualg = nla_data(rta); | ||
253 | |||
254 | algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1); | ||
255 | if (!algo) | ||
256 | return -ENOSYS; | ||
257 | *props = algo->desc.sadb_alg_id; | ||
258 | |||
259 | p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL); | ||
260 | if (!p) | ||
261 | return -ENOMEM; | ||
262 | |||
263 | strcpy(p->alg_name, algo->name); | ||
264 | *algpp = p; | ||
265 | return 0; | ||
266 | } | ||
267 | |||
211 | static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) | 268 | static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) |
212 | { | 269 | { |
213 | int len = 0; | 270 | int len = 0; |
@@ -286,6 +343,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
286 | 343 | ||
287 | copy_from_user_state(x, p); | 344 | copy_from_user_state(x, p); |
288 | 345 | ||
346 | if ((err = attach_aead(&x->aead, &x->props.ealgo, | ||
347 | attrs[XFRMA_ALG_AEAD]))) | ||
348 | goto error; | ||
289 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, | 349 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, |
290 | xfrm_aalg_get_byname, | 350 | xfrm_aalg_get_byname, |
291 | attrs[XFRMA_ALG_AUTH]))) | 351 | attrs[XFRMA_ALG_AUTH]))) |
@@ -510,6 +570,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
510 | if (x->lastused) | 570 | if (x->lastused) |
511 | NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); | 571 | NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); |
512 | 572 | ||
573 | if (x->aead) | ||
574 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); | ||
513 | if (x->aalg) | 575 | if (x->aalg) |
514 | NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); | 576 | NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); |
515 | if (x->ealg) | 577 | if (x->ealg) |
@@ -1808,6 +1870,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1808 | #undef XMSGSIZE | 1870 | #undef XMSGSIZE |
1809 | 1871 | ||
1810 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | 1872 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { |
1873 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, | ||
1811 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, | 1874 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, |
1812 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, | 1875 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, |
1813 | [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, | 1876 | [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, |
@@ -1972,6 +2035,8 @@ static int xfrm_notify_sa_flush(struct km_event *c) | |||
1972 | static inline size_t xfrm_sa_len(struct xfrm_state *x) | 2035 | static inline size_t xfrm_sa_len(struct xfrm_state *x) |
1973 | { | 2036 | { |
1974 | size_t l = 0; | 2037 | size_t l = 0; |
2038 | if (x->aead) | ||
2039 | l += nla_total_size(aead_len(x->aead)); | ||
1975 | if (x->aalg) | 2040 | if (x->aalg) |
1976 | l += nla_total_size(xfrm_alg_len(x->aalg)); | 2041 | l += nla_total_size(xfrm_alg_len(x->aalg)); |
1977 | if (x->ealg) | 2042 | if (x->ealg) |