aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2011-03-07 19:07:51 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-13 23:22:29 -0400
commitd212a4c29096484e5e83b5006e695add126260af (patch)
tree00f5c3bcbc7560591820070364d78e21c241be34 /net/ipv6
parent0dc49e9b28a7253ff05be2794d747f8ea5f1f423 (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.c105
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 */
62static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) 63static 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
81static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp) 85static inline __be32 *esp_tmp_seqhi(void *tmp)
86{
87 return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32));
88}
89
90static 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
87static inline struct aead_givcrypt_request *esp_tmp_givreq( 97static 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);