diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv4/ah4.c | 36 | ||||
| -rw-r--r-- | net/ipv4/esp4.c | 36 | ||||
| -rw-r--r-- | net/ipv6/ah6.c | 35 | ||||
| -rw-r--r-- | net/ipv6/esp6.c | 42 | ||||
| -rw-r--r-- | net/xfrm/xfrm_algo.c | 40 | 
5 files changed, 119 insertions, 70 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 1366bc6ce6a..2b98943e6b0 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -1,3 +1,4 @@ +#include <linux/err.h>  #include <linux/module.h>  #include <net/ip.h>  #include <net/xfrm.h> @@ -97,7 +98,10 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)  	ah->spi = x->id.spi;  	ah->seq_no = htonl(++x->replay.oseq);  	xfrm_aevent_doreplay(x); -	ahp->icv(ahp, skb, ah->auth_data); +	err = ah_mac_digest(ahp, skb, ah->auth_data); +	if (err) +		goto error; +	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);  	top_iph->tos = iph->tos;  	top_iph->ttl = iph->ttl; @@ -119,6 +123,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)  {  	int ah_hlen;  	int ihl; +	int err = -EINVAL;  	struct iphdr *iph;  	struct ip_auth_hdr *ah;  	struct ah_data *ahp; @@ -166,8 +171,11 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)  		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);  		skb_push(skb, ihl); -		ahp->icv(ahp, skb, ah->auth_data); -		if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { +		err = ah_mac_digest(ahp, skb, ah->auth_data); +		if (err) +			goto out; +		err = -EINVAL; +		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {  			x->stats.integrity_failed++;  			goto out;  		} @@ -179,7 +187,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)  	return 0;  out: -	return -EINVAL; +	return err;  }  static void ah4_err(struct sk_buff *skb, u32 info) @@ -204,6 +212,7 @@ static int ah_init_state(struct xfrm_state *x)  {  	struct ah_data *ahp = NULL;  	struct xfrm_algo_desc *aalg_desc; +	struct crypto_hash *tfm;  	if (!x->aalg)  		goto error; @@ -221,24 +230,27 @@ static int ah_init_state(struct xfrm_state *x)  	ahp->key = x->aalg->alg_key;  	ahp->key_len = (x->aalg->alg_key_len+7)/8; -	ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); -	if (!ahp->tfm) +	tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); +	if (IS_ERR(tfm)) +		goto error; + +	ahp->tfm = tfm; +	if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))  		goto error; -	ahp->icv = ah_hmac_digest;  	/*  	 * Lookup the algorithm description maintained by xfrm_algo,  	 * verify crypto transform properties, and store information  	 * we need for AH processing.  This lookup cannot fail here -	 * after a successful crypto_alloc_tfm(). +	 * after a successful crypto_alloc_hash().  	 */  	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);  	BUG_ON(!aalg_desc);  	if (aalg_desc->uinfo.auth.icv_fullbits/8 != -	    crypto_tfm_alg_digestsize(ahp->tfm)) { +	    crypto_hash_digestsize(tfm)) {  		printk(KERN_INFO "AH: %s digestsize %u != %hu\n", -		       x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), +		       x->aalg->alg_name, crypto_hash_digestsize(tfm),  		       aalg_desc->uinfo.auth.icv_fullbits/8);  		goto error;  	} @@ -262,7 +274,7 @@ static int ah_init_state(struct xfrm_state *x)  error:  	if (ahp) {  		kfree(ahp->work_icv); -		crypto_free_tfm(ahp->tfm); +		crypto_free_hash(ahp->tfm);  		kfree(ahp);  	}  	return -EINVAL; @@ -277,7 +289,7 @@ static void ah_destroy(struct xfrm_state *x)  	kfree(ahp->work_icv);  	ahp->work_icv = NULL; -	crypto_free_tfm(ahp->tfm); +	crypto_free_hash(ahp->tfm);  	ahp->tfm = NULL;  	kfree(ahp);  } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 7c63ae49474..b428489f6cc 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -121,9 +121,9 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)  	}  	if (esp->auth.icv_full_len) { -		esp->auth.icv(esp, skb, (u8*)esph-skb->data, -		              sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); -		pskb_put(skb, trailer, alen); +		err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, +				     sizeof(*esph) + esp->conf.ivlen + clen); +		memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);  	}  	ip_send_check(top_iph); @@ -163,15 +163,16 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)  	/* If integrity check is required, do this. */  	if (esp->auth.icv_full_len) { -		u8 sum[esp->auth.icv_full_len]; -		u8 sum1[alen]; -		 -		esp->auth.icv(esp, skb, 0, skb->len-alen, sum); +		u8 sum[alen]; -		if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) +		err = esp_mac_digest(esp, skb, 0, skb->len - alen); +		if (err) +			goto out; + +		if (skb_copy_bits(skb, skb->len - alen, sum, alen))  			BUG(); -		if (unlikely(memcmp(sum, sum1, alen))) { +		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {  			x->stats.integrity_failed++;  			goto out;  		} @@ -307,7 +308,7 @@ static void esp_destroy(struct xfrm_state *x)  	esp->conf.tfm = NULL;  	kfree(esp->conf.ivec);  	esp->conf.ivec = NULL; -	crypto_free_tfm(esp->auth.tfm); +	crypto_free_hash(esp->auth.tfm);  	esp->auth.tfm = NULL;  	kfree(esp->auth.work_icv);  	esp->auth.work_icv = NULL; @@ -333,22 +334,27 @@ static int esp_init_state(struct xfrm_state *x)  	if (x->aalg) {  		struct xfrm_algo_desc *aalg_desc; +		struct crypto_hash *hash;  		esp->auth.key = x->aalg->alg_key;  		esp->auth.key_len = (x->aalg->alg_key_len+7)/8; -		esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); -		if (esp->auth.tfm == NULL) +		hash = crypto_alloc_hash(x->aalg->alg_name, 0, +					 CRYPTO_ALG_ASYNC); +		if (IS_ERR(hash)) +			goto error; + +		esp->auth.tfm = hash; +		if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))  			goto error; -		esp->auth.icv = esp_hmac_digest;  		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);  		BUG_ON(!aalg_desc);  		if (aalg_desc->uinfo.auth.icv_fullbits/8 != -		    crypto_tfm_alg_digestsize(esp->auth.tfm)) { +		    crypto_hash_digestsize(hash)) {  			NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",  				 x->aalg->alg_name, -				 crypto_tfm_alg_digestsize(esp->auth.tfm), +				 crypto_hash_digestsize(hash),  				 aalg_desc->uinfo.auth.icv_fullbits/8);  			goto error;  		} diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 9d4831bd433..00ffa7bc6c9 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)  	ah->spi = x->id.spi;  	ah->seq_no = htonl(++x->replay.oseq);  	xfrm_aevent_doreplay(x); -	ahp->icv(ahp, skb, ah->auth_data); +	err = ah_mac_digest(ahp, skb, ah->auth_data); +	if (err) +		goto error_free_iph; +	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);  	err = 0; @@ -251,6 +254,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)  	u16 hdr_len;  	u16 ah_hlen;  	int nexthdr; +	int err = -EINVAL;  	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))  		goto out; @@ -292,8 +296,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)  		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);  		memset(ah->auth_data, 0, ahp->icv_trunc_len);  		skb_push(skb, hdr_len); -		ahp->icv(ahp, skb, ah->auth_data); -		if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { +		err = ah_mac_digest(ahp, skb, ah->auth_data); +		if (err) +			goto free_out; +		err = -EINVAL; +		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {  			LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");  			x->stats.integrity_failed++;  			goto free_out; @@ -310,7 +317,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)  free_out:  	kfree(tmp_hdr);  out: -	return -EINVAL; +	return err;  }  static 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)  {  	struct ah_data *ahp = NULL;  	struct xfrm_algo_desc *aalg_desc; +	struct crypto_hash *tfm;  	if (!x->aalg)  		goto error; @@ -355,24 +363,27 @@ static int ah6_init_state(struct xfrm_state *x)  	ahp->key = x->aalg->alg_key;  	ahp->key_len = (x->aalg->alg_key_len+7)/8; -	ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); -	if (!ahp->tfm) +	tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); +	if (IS_ERR(tfm)) +		goto error; + +	ahp->tfm = tfm; +	if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))  		goto error; -	ahp->icv = ah_hmac_digest;  	/*  	 * Lookup the algorithm description maintained by xfrm_algo,  	 * verify crypto transform properties, and store information  	 * we need for AH processing.  This lookup cannot fail here -	 * after a successful crypto_alloc_tfm(). +	 * after a successful crypto_alloc_hash().  	 */  	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);  	BUG_ON(!aalg_desc);  	if (aalg_desc->uinfo.auth.icv_fullbits/8 != -	    crypto_tfm_alg_digestsize(ahp->tfm)) { +	    crypto_hash_digestsize(tfm)) {  		printk(KERN_INFO "AH: %s digestsize %u != %hu\n", -		       x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), +		       x->aalg->alg_name, crypto_hash_digestsize(tfm),  		       aalg_desc->uinfo.auth.icv_fullbits/8);  		goto error;  	} @@ -396,7 +407,7 @@ static int ah6_init_state(struct xfrm_state *x)  error:  	if (ahp) {  		kfree(ahp->work_icv); -		crypto_free_tfm(ahp->tfm); +		crypto_free_hash(ahp->tfm);  		kfree(ahp);  	}  	return -EINVAL; @@ -411,7 +422,7 @@ static void ah6_destroy(struct xfrm_state *x)  	kfree(ahp->work_icv);  	ahp->work_icv = NULL; -	crypto_free_tfm(ahp->tfm); +	crypto_free_hash(ahp->tfm);  	ahp->tfm = NULL;  	kfree(ahp);  } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 46a7e687948..2ebfd281e72 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)  	}  	if (esp->auth.icv_full_len) { -		esp->auth.icv(esp, skb, (u8*)esph-skb->data, -			sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); -		pskb_put(skb, trailer, alen); +		err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, +				     sizeof(*esph) + esp->conf.ivlen + clen); +		memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);  	}  error: @@ -162,15 +162,16 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)  	/* If integrity check is required, do this. */          if (esp->auth.icv_full_len) { -		u8 sum[esp->auth.icv_full_len]; -		u8 sum1[alen]; +		u8 sum[alen]; -		esp->auth.icv(esp, skb, 0, skb->len-alen, sum); +		ret = esp_mac_digest(esp, skb, 0, skb->len - alen); +		if (ret) +			goto out; -		if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) +		if (skb_copy_bits(skb, skb->len - alen, sum, alen))  			BUG(); -		if (unlikely(memcmp(sum, sum1, alen))) { +		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {  			x->stats.integrity_failed++;  			ret = -EINVAL;  			goto out; @@ -279,7 +280,7 @@ static void esp6_destroy(struct xfrm_state *x)  	esp->conf.tfm = NULL;  	kfree(esp->conf.ivec);  	esp->conf.ivec = NULL; -	crypto_free_tfm(esp->auth.tfm); +	crypto_free_hash(esp->auth.tfm);  	esp->auth.tfm = NULL;  	kfree(esp->auth.work_icv);  	esp->auth.work_icv = NULL; @@ -308,24 +309,29 @@ static int esp6_init_state(struct xfrm_state *x)  	if (x->aalg) {  		struct xfrm_algo_desc *aalg_desc; +		struct crypto_hash *hash;  		esp->auth.key = x->aalg->alg_key;  		esp->auth.key_len = (x->aalg->alg_key_len+7)/8; -		esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); -		if (esp->auth.tfm == NULL) +		hash = crypto_alloc_hash(x->aalg->alg_name, 0, +					 CRYPTO_ALG_ASYNC); +		if (IS_ERR(hash)) +			goto error; + +		esp->auth.tfm = hash; +		if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))  			goto error; -		esp->auth.icv = esp_hmac_digest;  		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);  		BUG_ON(!aalg_desc);  		if (aalg_desc->uinfo.auth.icv_fullbits/8 != -			crypto_tfm_alg_digestsize(esp->auth.tfm)) { -				printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", -					x->aalg->alg_name, -					crypto_tfm_alg_digestsize(esp->auth.tfm), -					aalg_desc->uinfo.auth.icv_fullbits/8); -				goto error; +		    crypto_hash_digestsize(hash)) { +			NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", +				 x->aalg->alg_name, +				 crypto_hash_digestsize(hash), +				 aalg_desc->uinfo.auth.icv_fullbits/8); +			goto error;  		}  		esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 9b03d8497fb..87918f281bb 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -30,7 +30,8 @@   */  static struct xfrm_algo_desc aalg_list[] = {  { -	.name = "digest_null", +	.name = "hmac(digest_null)", +	.compat = "digest_null",  	.uinfo = {  		.auth = { @@ -47,7 +48,8 @@ static struct xfrm_algo_desc aalg_list[] = {  	}  },  { -	.name = "md5", +	.name = "hmac(md5)", +	.compat = "md5",  	.uinfo = {  		.auth = { @@ -64,7 +66,8 @@ static struct xfrm_algo_desc aalg_list[] = {  	}  },  { -	.name = "sha1", +	.name = "hmac(sha1)", +	.compat = "sha1",  	.uinfo = {  		.auth = { @@ -81,7 +84,8 @@ static struct xfrm_algo_desc aalg_list[] = {  	}  },  { -	.name = "sha256", +	.name = "hmac(sha256)", +	.compat = "sha256",  	.uinfo = {  		.auth = { @@ -98,7 +102,8 @@ static struct xfrm_algo_desc aalg_list[] = {  	}  },  { -	.name = "ripemd160", +	.name = "hmac(ripemd160)", +	.compat = "ripemd160",  	.uinfo = {  		.auth = { @@ -480,11 +485,12 @@ EXPORT_SYMBOL_GPL(xfrm_count_enc_supported);  /* Move to common area: it is shared with AH. */ -void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, -		  int offset, int len, icv_update_fn_t icv_update) +int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, +		 int offset, int len, icv_update_fn_t icv_update)  {  	int start = skb_headlen(skb);  	int i, copy = start - offset; +	int err;  	struct scatterlist sg;  	/* Checksum header. */ @@ -496,10 +502,12 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,  		sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;  		sg.length = copy; -		icv_update(tfm, &sg, 1); +		err = icv_update(desc, &sg, copy); +		if (unlikely(err)) +			return err;  		if ((len -= copy) == 0) -			return; +			return 0;  		offset += copy;  	} @@ -519,10 +527,12 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,  			sg.offset = frag->page_offset + offset-start;  			sg.length = copy; -			icv_update(tfm, &sg, 1); +			err = icv_update(desc, &sg, copy); +			if (unlikely(err)) +				return err;  			if (!(len -= copy)) -				return; +				return 0;  			offset += copy;  		}  		start = end; @@ -540,15 +550,19 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,  			if ((copy = end - offset) > 0) {  				if (copy > len)  					copy = len; -				skb_icv_walk(list, tfm, offset-start, copy, icv_update); +				err = skb_icv_walk(list, desc, offset-start, +						   copy, icv_update); +				if (unlikely(err)) +					return err;  				if ((len -= copy) == 0) -					return; +					return 0;  				offset += copy;  			}  			start = end;  		}  	}  	BUG_ON(len); +	return 0;  }  EXPORT_SYMBOL_GPL(skb_icv_walk);  |