diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2011-03-07 19:07:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-13 23:22:29 -0400 |
commit | d212a4c29096484e5e83b5006e695add126260af (patch) | |
tree | 00f5c3bcbc7560591820070364d78e21c241be34 /net/ipv6 | |
parent | 0dc49e9b28a7253ff05be2794d747f8ea5f1f423 (diff) |
esp6: Add support for IPsec extended sequence numbers
This patch adds IPsec extended sequence numbers support to esp6.
We use the authencesn crypto algorithm to handle esp with separate
encryption/authentication algorithms.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/esp6.c | 105 |
1 files changed, 86 insertions, 19 deletions
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index c7b5d5ee0dee..5aa8ec88f194 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -54,16 +54,20 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu); | |||
54 | /* | 54 | /* |
55 | * Allocate an AEAD request structure with extra space for SG and IV. | 55 | * Allocate an AEAD request structure with extra space for SG and IV. |
56 | * | 56 | * |
57 | * For alignment considerations the IV is placed at the front, followed | 57 | * For alignment considerations the upper 32 bits of the sequence number are |
58 | * by the request and finally the SG list. | 58 | * placed at the front, if present. Followed by the IV, the request and finally |
59 | * the SG list. | ||
59 | * | 60 | * |
60 | * TODO: Use spare space in skb for this where possible. | 61 | * TODO: Use spare space in skb for this where possible. |
61 | */ | 62 | */ |
62 | static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) | 63 | static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqihlen) |
63 | { | 64 | { |
64 | unsigned int len; | 65 | unsigned int len; |
65 | 66 | ||
66 | len = crypto_aead_ivsize(aead); | 67 | len = seqihlen; |
68 | |||
69 | len += crypto_aead_ivsize(aead); | ||
70 | |||
67 | if (len) { | 71 | if (len) { |
68 | len += crypto_aead_alignmask(aead) & | 72 | len += crypto_aead_alignmask(aead) & |
69 | ~(crypto_tfm_ctx_alignment() - 1); | 73 | ~(crypto_tfm_ctx_alignment() - 1); |
@@ -78,10 +82,16 @@ static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) | |||
78 | return kmalloc(len, GFP_ATOMIC); | 82 | return kmalloc(len, GFP_ATOMIC); |
79 | } | 83 | } |
80 | 84 | ||
81 | static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp) | 85 | static inline __be32 *esp_tmp_seqhi(void *tmp) |
86 | { | ||
87 | return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32)); | ||
88 | } | ||
89 | |||
90 | static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen) | ||
82 | { | 91 | { |
83 | return crypto_aead_ivsize(aead) ? | 92 | return crypto_aead_ivsize(aead) ? |
84 | PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp; | 93 | PTR_ALIGN((u8 *)tmp + seqhilen, |
94 | crypto_aead_alignmask(aead) + 1) : tmp + seqhilen; | ||
85 | } | 95 | } |
86 | 96 | ||
87 | static inline struct aead_givcrypt_request *esp_tmp_givreq( | 97 | static inline struct aead_givcrypt_request *esp_tmp_givreq( |
@@ -145,8 +155,12 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
145 | int plen; | 155 | int plen; |
146 | int tfclen; | 156 | int tfclen; |
147 | int nfrags; | 157 | int nfrags; |
158 | int assoclen; | ||
159 | int sglists; | ||
160 | int seqhilen; | ||
148 | u8 *iv; | 161 | u8 *iv; |
149 | u8 *tail; | 162 | u8 *tail; |
163 | __be32 *seqhi; | ||
150 | struct esp_data *esp = x->data; | 164 | struct esp_data *esp = x->data; |
151 | 165 | ||
152 | /* skb is pure payload to encrypt */ | 166 | /* skb is pure payload to encrypt */ |
@@ -175,14 +189,25 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
175 | goto error; | 189 | goto error; |
176 | nfrags = err; | 190 | nfrags = err; |
177 | 191 | ||
178 | tmp = esp_alloc_tmp(aead, nfrags + 1); | 192 | assoclen = sizeof(*esph); |
193 | sglists = 1; | ||
194 | seqhilen = 0; | ||
195 | |||
196 | if (x->props.flags & XFRM_STATE_ESN) { | ||
197 | sglists += 2; | ||
198 | seqhilen += sizeof(__be32); | ||
199 | assoclen += seqhilen; | ||
200 | } | ||
201 | |||
202 | tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); | ||
179 | if (!tmp) | 203 | if (!tmp) |
180 | goto error; | 204 | goto error; |
181 | 205 | ||
182 | iv = esp_tmp_iv(aead, tmp); | 206 | seqhi = esp_tmp_seqhi(tmp); |
207 | iv = esp_tmp_iv(aead, tmp, seqhilen); | ||
183 | req = esp_tmp_givreq(aead, iv); | 208 | req = esp_tmp_givreq(aead, iv); |
184 | asg = esp_givreq_sg(aead, req); | 209 | asg = esp_givreq_sg(aead, req); |
185 | sg = asg + 1; | 210 | sg = asg + sglists; |
186 | 211 | ||
187 | /* Fill padding... */ | 212 | /* Fill padding... */ |
188 | tail = skb_tail_pointer(trailer); | 213 | tail = skb_tail_pointer(trailer); |
@@ -210,11 +235,19 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
210 | skb_to_sgvec(skb, sg, | 235 | skb_to_sgvec(skb, sg, |
211 | esph->enc_data + crypto_aead_ivsize(aead) - skb->data, | 236 | esph->enc_data + crypto_aead_ivsize(aead) - skb->data, |
212 | clen + alen); | 237 | clen + alen); |
213 | sg_init_one(asg, esph, sizeof(*esph)); | 238 | |
239 | if ((x->props.flags & XFRM_STATE_ESN)) { | ||
240 | sg_init_table(asg, 3); | ||
241 | sg_set_buf(asg, &esph->spi, sizeof(__be32)); | ||
242 | *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi); | ||
243 | sg_set_buf(asg + 1, seqhi, seqhilen); | ||
244 | sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); | ||
245 | } else | ||
246 | sg_init_one(asg, esph, sizeof(*esph)); | ||
214 | 247 | ||
215 | aead_givcrypt_set_callback(req, 0, esp_output_done, skb); | 248 | aead_givcrypt_set_callback(req, 0, esp_output_done, skb); |
216 | aead_givcrypt_set_crypt(req, sg, sg, clen, iv); | 249 | aead_givcrypt_set_crypt(req, sg, sg, clen, iv); |
217 | aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); | 250 | aead_givcrypt_set_assoc(req, asg, assoclen); |
218 | aead_givcrypt_set_giv(req, esph->enc_data, | 251 | aead_givcrypt_set_giv(req, esph->enc_data, |
219 | XFRM_SKB_CB(skb)->seq.output.low); | 252 | XFRM_SKB_CB(skb)->seq.output.low); |
220 | 253 | ||
@@ -292,8 +325,12 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
292 | struct sk_buff *trailer; | 325 | struct sk_buff *trailer; |
293 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); | 326 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); |
294 | int nfrags; | 327 | int nfrags; |
328 | int assoclen; | ||
329 | int sglists; | ||
330 | int seqhilen; | ||
295 | int ret = 0; | 331 | int ret = 0; |
296 | void *tmp; | 332 | void *tmp; |
333 | __be32 *seqhi; | ||
297 | u8 *iv; | 334 | u8 *iv; |
298 | struct scatterlist *sg; | 335 | struct scatterlist *sg; |
299 | struct scatterlist *asg; | 336 | struct scatterlist *asg; |
@@ -314,12 +351,24 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
314 | } | 351 | } |
315 | 352 | ||
316 | ret = -ENOMEM; | 353 | ret = -ENOMEM; |
317 | tmp = esp_alloc_tmp(aead, nfrags + 1); | 354 | |
355 | assoclen = sizeof(*esph); | ||
356 | sglists = 1; | ||
357 | seqhilen = 0; | ||
358 | |||
359 | if (x->props.flags & XFRM_STATE_ESN) { | ||
360 | sglists += 2; | ||
361 | seqhilen += sizeof(__be32); | ||
362 | assoclen += seqhilen; | ||
363 | } | ||
364 | |||
365 | tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); | ||
318 | if (!tmp) | 366 | if (!tmp) |
319 | goto out; | 367 | goto out; |
320 | 368 | ||
321 | ESP_SKB_CB(skb)->tmp = tmp; | 369 | ESP_SKB_CB(skb)->tmp = tmp; |
322 | iv = esp_tmp_iv(aead, tmp); | 370 | seqhi = esp_tmp_seqhi(tmp); |
371 | iv = esp_tmp_iv(aead, tmp, seqhilen); | ||
323 | req = esp_tmp_req(aead, iv); | 372 | req = esp_tmp_req(aead, iv); |
324 | asg = esp_req_sg(aead, req); | 373 | asg = esp_req_sg(aead, req); |
325 | sg = asg + 1; | 374 | sg = asg + 1; |
@@ -333,11 +382,19 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
333 | 382 | ||
334 | sg_init_table(sg, nfrags); | 383 | sg_init_table(sg, nfrags); |
335 | skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); | 384 | skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); |
336 | sg_init_one(asg, esph, sizeof(*esph)); | 385 | |
386 | if ((x->props.flags & XFRM_STATE_ESN)) { | ||
387 | sg_init_table(asg, 3); | ||
388 | sg_set_buf(asg, &esph->spi, sizeof(__be32)); | ||
389 | *seqhi = XFRM_SKB_CB(skb)->seq.input.hi; | ||
390 | sg_set_buf(asg + 1, seqhi, seqhilen); | ||
391 | sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); | ||
392 | } else | ||
393 | sg_init_one(asg, esph, sizeof(*esph)); | ||
337 | 394 | ||
338 | aead_request_set_callback(req, 0, esp_input_done, skb); | 395 | aead_request_set_callback(req, 0, esp_input_done, skb); |
339 | aead_request_set_crypt(req, sg, sg, elen, iv); | 396 | aead_request_set_crypt(req, sg, sg, elen, iv); |
340 | aead_request_set_assoc(req, asg, sizeof(*esph)); | 397 | aead_request_set_assoc(req, asg, assoclen); |
341 | 398 | ||
342 | ret = crypto_aead_decrypt(req); | 399 | ret = crypto_aead_decrypt(req); |
343 | if (ret == -EINPROGRESS) | 400 | if (ret == -EINPROGRESS) |
@@ -443,10 +500,20 @@ static int esp_init_authenc(struct xfrm_state *x) | |||
443 | goto error; | 500 | goto error; |
444 | 501 | ||
445 | err = -ENAMETOOLONG; | 502 | err = -ENAMETOOLONG; |
446 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)", | 503 | |
447 | x->aalg ? x->aalg->alg_name : "digest_null", | 504 | if ((x->props.flags & XFRM_STATE_ESN)) { |
448 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | 505 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, |
449 | goto error; | 506 | "authencesn(%s,%s)", |
507 | x->aalg ? x->aalg->alg_name : "digest_null", | ||
508 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | ||
509 | goto error; | ||
510 | } else { | ||
511 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, | ||
512 | "authenc(%s,%s)", | ||
513 | x->aalg ? x->aalg->alg_name : "digest_null", | ||
514 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | ||
515 | goto error; | ||
516 | } | ||
450 | 517 | ||
451 | aead = crypto_alloc_aead(authenc_name, 0, 0); | 518 | aead = crypto_alloc_aead(authenc_name, 0, 0); |
452 | err = PTR_ERR(aead); | 519 | err = PTR_ERR(aead); |