aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-08-20 00:24:50 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2006-09-20 21:46:18 -0400
commit07d4ee583e21830ec5604d31f65cdc60a6eca19e (patch)
tree32962ef0dd13d0d1f66b143ca5d03a88d8b9f772 /net/ipv6
parente9d41164e2fdd897fe4520c2079ea0000f6e0ec3 (diff)
[IPSEC]: Use HMAC template and hash interface
This patch converts IPsec to use the new HMAC template. The names of existing simple digest algorithms may still be used to refer to their HMAC composites. The same structure can be used by other MACs such as AES-XCBC-MAC. This patch also switches from the digest interface to hash. Signed-off-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/ah6.c35
-rw-r--r--net/ipv6/esp6.c42
2 files changed, 47 insertions, 30 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 9d4831bd4335..00ffa7bc6c9f 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -213,7 +213,10 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
213 ah->spi = x->id.spi; 213 ah->spi = x->id.spi;
214 ah->seq_no = htonl(++x->replay.oseq); 214 ah->seq_no = htonl(++x->replay.oseq);
215 xfrm_aevent_doreplay(x); 215 xfrm_aevent_doreplay(x);
216 ahp->icv(ahp, skb, ah->auth_data); 216 err = ah_mac_digest(ahp, skb, ah->auth_data);
217 if (err)
218 goto error_free_iph;
219 memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
217 220
218 err = 0; 221 err = 0;
219 222
@@ -251,6 +254,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
251 u16 hdr_len; 254 u16 hdr_len;
252 u16 ah_hlen; 255 u16 ah_hlen;
253 int nexthdr; 256 int nexthdr;
257 int err = -EINVAL;
254 258
255 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) 259 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
256 goto out; 260 goto out;
@@ -292,8 +296,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
292 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 296 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
293 memset(ah->auth_data, 0, ahp->icv_trunc_len); 297 memset(ah->auth_data, 0, ahp->icv_trunc_len);
294 skb_push(skb, hdr_len); 298 skb_push(skb, hdr_len);
295 ahp->icv(ahp, skb, ah->auth_data); 299 err = ah_mac_digest(ahp, skb, ah->auth_data);
296 if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { 300 if (err)
301 goto free_out;
302 err = -EINVAL;
303 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
297 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); 304 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
298 x->stats.integrity_failed++; 305 x->stats.integrity_failed++;
299 goto free_out; 306 goto free_out;
@@ -310,7 +317,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
310free_out: 317free_out:
311 kfree(tmp_hdr); 318 kfree(tmp_hdr);
312out: 319out:
313 return -EINVAL; 320 return err;
314} 321}
315 322
316static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 323static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
@@ -338,6 +345,7 @@ static int ah6_init_state(struct xfrm_state *x)
338{ 345{
339 struct ah_data *ahp = NULL; 346 struct ah_data *ahp = NULL;
340 struct xfrm_algo_desc *aalg_desc; 347 struct xfrm_algo_desc *aalg_desc;
348 struct crypto_hash *tfm;
341 349
342 if (!x->aalg) 350 if (!x->aalg)
343 goto error; 351 goto error;
@@ -355,24 +363,27 @@ static int ah6_init_state(struct xfrm_state *x)
355 363
356 ahp->key = x->aalg->alg_key; 364 ahp->key = x->aalg->alg_key;
357 ahp->key_len = (x->aalg->alg_key_len+7)/8; 365 ahp->key_len = (x->aalg->alg_key_len+7)/8;
358 ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); 366 tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
359 if (!ahp->tfm) 367 if (IS_ERR(tfm))
368 goto error;
369
370 ahp->tfm = tfm;
371 if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))
360 goto error; 372 goto error;
361 ahp->icv = ah_hmac_digest;
362 373
363 /* 374 /*
364 * Lookup the algorithm description maintained by xfrm_algo, 375 * Lookup the algorithm description maintained by xfrm_algo,
365 * verify crypto transform properties, and store information 376 * verify crypto transform properties, and store information
366 * we need for AH processing. This lookup cannot fail here 377 * we need for AH processing. This lookup cannot fail here
367 * after a successful crypto_alloc_tfm(). 378 * after a successful crypto_alloc_hash().
368 */ 379 */
369 aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 380 aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
370 BUG_ON(!aalg_desc); 381 BUG_ON(!aalg_desc);
371 382
372 if (aalg_desc->uinfo.auth.icv_fullbits/8 != 383 if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
373 crypto_tfm_alg_digestsize(ahp->tfm)) { 384 crypto_hash_digestsize(tfm)) {
374 printk(KERN_INFO "AH: %s digestsize %u != %hu\n", 385 printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
375 x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), 386 x->aalg->alg_name, crypto_hash_digestsize(tfm),
376 aalg_desc->uinfo.auth.icv_fullbits/8); 387 aalg_desc->uinfo.auth.icv_fullbits/8);
377 goto error; 388 goto error;
378 } 389 }
@@ -396,7 +407,7 @@ static int ah6_init_state(struct xfrm_state *x)
396error: 407error:
397 if (ahp) { 408 if (ahp) {
398 kfree(ahp->work_icv); 409 kfree(ahp->work_icv);
399 crypto_free_tfm(ahp->tfm); 410 crypto_free_hash(ahp->tfm);
400 kfree(ahp); 411 kfree(ahp);
401 } 412 }
402 return -EINVAL; 413 return -EINVAL;
@@ -411,7 +422,7 @@ static void ah6_destroy(struct xfrm_state *x)
411 422
412 kfree(ahp->work_icv); 423 kfree(ahp->work_icv);
413 ahp->work_icv = NULL; 424 ahp->work_icv = NULL;
414 crypto_free_tfm(ahp->tfm); 425 crypto_free_hash(ahp->tfm);
415 ahp->tfm = NULL; 426 ahp->tfm = NULL;
416 kfree(ahp); 427 kfree(ahp);
417} 428}
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 46a7e687948e..2ebfd281e721 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -125,9 +125,9 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
125 } 125 }
126 126
127 if (esp->auth.icv_full_len) { 127 if (esp->auth.icv_full_len) {
128 esp->auth.icv(esp, skb, (u8*)esph-skb->data, 128 err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
129 sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); 129 sizeof(*esph) + esp->conf.ivlen + clen);
130 pskb_put(skb, trailer, alen); 130 memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
131 } 131 }
132 132
133error: 133error:
@@ -162,15 +162,16 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
162 162
163 /* If integrity check is required, do this. */ 163 /* If integrity check is required, do this. */
164 if (esp->auth.icv_full_len) { 164 if (esp->auth.icv_full_len) {
165 u8 sum[esp->auth.icv_full_len]; 165 u8 sum[alen];
166 u8 sum1[alen];
167 166
168 esp->auth.icv(esp, skb, 0, skb->len-alen, sum); 167 ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
168 if (ret)
169 goto out;
169 170
170 if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) 171 if (skb_copy_bits(skb, skb->len - alen, sum, alen))
171 BUG(); 172 BUG();
172 173
173 if (unlikely(memcmp(sum, sum1, alen))) { 174 if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
174 x->stats.integrity_failed++; 175 x->stats.integrity_failed++;
175 ret = -EINVAL; 176 ret = -EINVAL;
176 goto out; 177 goto out;
@@ -279,7 +280,7 @@ static void esp6_destroy(struct xfrm_state *x)
279 esp->conf.tfm = NULL; 280 esp->conf.tfm = NULL;
280 kfree(esp->conf.ivec); 281 kfree(esp->conf.ivec);
281 esp->conf.ivec = NULL; 282 esp->conf.ivec = NULL;
282 crypto_free_tfm(esp->auth.tfm); 283 crypto_free_hash(esp->auth.tfm);
283 esp->auth.tfm = NULL; 284 esp->auth.tfm = NULL;
284 kfree(esp->auth.work_icv); 285 kfree(esp->auth.work_icv);
285 esp->auth.work_icv = NULL; 286 esp->auth.work_icv = NULL;
@@ -308,24 +309,29 @@ static int esp6_init_state(struct xfrm_state *x)
308 309
309 if (x->aalg) { 310 if (x->aalg) {
310 struct xfrm_algo_desc *aalg_desc; 311 struct xfrm_algo_desc *aalg_desc;
312 struct crypto_hash *hash;
311 313
312 esp->auth.key = x->aalg->alg_key; 314 esp->auth.key = x->aalg->alg_key;
313 esp->auth.key_len = (x->aalg->alg_key_len+7)/8; 315 esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
314 esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); 316 hash = crypto_alloc_hash(x->aalg->alg_name, 0,
315 if (esp->auth.tfm == NULL) 317 CRYPTO_ALG_ASYNC);
318 if (IS_ERR(hash))
319 goto error;
320
321 esp->auth.tfm = hash;
322 if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))
316 goto error; 323 goto error;
317 esp->auth.icv = esp_hmac_digest;
318 324
319 aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 325 aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
320 BUG_ON(!aalg_desc); 326 BUG_ON(!aalg_desc);
321 327
322 if (aalg_desc->uinfo.auth.icv_fullbits/8 != 328 if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
323 crypto_tfm_alg_digestsize(esp->auth.tfm)) { 329 crypto_hash_digestsize(hash)) {
324 printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", 330 NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
325 x->aalg->alg_name, 331 x->aalg->alg_name,
326 crypto_tfm_alg_digestsize(esp->auth.tfm), 332 crypto_hash_digestsize(hash),
327 aalg_desc->uinfo.auth.icv_fullbits/8); 333 aalg_desc->uinfo.auth.icv_fullbits/8);
328 goto error; 334 goto error;
329 } 335 }
330 336
331 esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; 337 esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;