diff options
Diffstat (limited to 'net/ipv6/esp6.c')
| -rw-r--r-- | net/ipv6/esp6.c | 107 |
1 files changed, 63 insertions, 44 deletions
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index a15a6f320f70..e78680a9985b 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | * This file is derived from net/ipv4/esp.c | 24 | * This file is derived from net/ipv4/esp.c |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <linux/config.h> | 27 | #include <linux/err.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <net/ip.h> | 29 | #include <net/ip.h> |
| 30 | #include <net/xfrm.h> | 30 | #include <net/xfrm.h> |
| @@ -45,7 +45,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 45 | int hdr_len; | 45 | int hdr_len; |
| 46 | struct ipv6hdr *top_iph; | 46 | struct ipv6hdr *top_iph; |
| 47 | struct ipv6_esp_hdr *esph; | 47 | struct ipv6_esp_hdr *esph; |
| 48 | struct crypto_tfm *tfm; | 48 | struct crypto_blkcipher *tfm; |
| 49 | struct blkcipher_desc desc; | ||
| 49 | struct esp_data *esp; | 50 | struct esp_data *esp; |
| 50 | struct sk_buff *trailer; | 51 | struct sk_buff *trailer; |
| 51 | int blksize; | 52 | int blksize; |
| @@ -68,7 +69,9 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 68 | 69 | ||
| 69 | alen = esp->auth.icv_trunc_len; | 70 | alen = esp->auth.icv_trunc_len; |
| 70 | tfm = esp->conf.tfm; | 71 | tfm = esp->conf.tfm; |
| 71 | blksize = ALIGN(crypto_tfm_alg_blocksize(tfm), 4); | 72 | desc.tfm = tfm; |
| 73 | desc.flags = 0; | ||
| 74 | blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); | ||
| 72 | clen = ALIGN(clen + 2, blksize); | 75 | clen = ALIGN(clen + 2, blksize); |
| 73 | if (esp->conf.padlen) | 76 | if (esp->conf.padlen) |
| 74 | clen = ALIGN(clen, esp->conf.padlen); | 77 | clen = ALIGN(clen, esp->conf.padlen); |
| @@ -96,8 +99,13 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 96 | esph->seq_no = htonl(++x->replay.oseq); | 99 | esph->seq_no = htonl(++x->replay.oseq); |
| 97 | xfrm_aevent_doreplay(x); | 100 | xfrm_aevent_doreplay(x); |
| 98 | 101 | ||
| 99 | if (esp->conf.ivlen) | 102 | if (esp->conf.ivlen) { |
| 100 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 103 | if (unlikely(!esp->conf.ivinitted)) { |
| 104 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | ||
| 105 | esp->conf.ivinitted = 1; | ||
| 106 | } | ||
| 107 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); | ||
| 108 | } | ||
| 101 | 109 | ||
| 102 | do { | 110 | do { |
| 103 | struct scatterlist *sg = &esp->sgbuf[0]; | 111 | struct scatterlist *sg = &esp->sgbuf[0]; |
| @@ -108,24 +116,25 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 108 | goto error; | 116 | goto error; |
| 109 | } | 117 | } |
| 110 | skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); | 118 | skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); |
| 111 | crypto_cipher_encrypt(tfm, sg, sg, clen); | 119 | err = crypto_blkcipher_encrypt(&desc, sg, sg, clen); |
| 112 | if (unlikely(sg != &esp->sgbuf[0])) | 120 | if (unlikely(sg != &esp->sgbuf[0])) |
| 113 | kfree(sg); | 121 | kfree(sg); |
| 114 | } while (0); | 122 | } while (0); |
| 115 | 123 | ||
| 124 | if (unlikely(err)) | ||
| 125 | goto error; | ||
| 126 | |||
| 116 | if (esp->conf.ivlen) { | 127 | if (esp->conf.ivlen) { |
| 117 | memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 128 | memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen); |
| 118 | crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 129 | crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen); |
| 119 | } | 130 | } |
| 120 | 131 | ||
| 121 | if (esp->auth.icv_full_len) { | 132 | if (esp->auth.icv_full_len) { |
| 122 | esp->auth.icv(esp, skb, (u8*)esph-skb->data, | 133 | err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, |
| 123 | sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); | 134 | sizeof(*esph) + esp->conf.ivlen + clen); |
| 124 | pskb_put(skb, trailer, alen); | 135 | memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen); |
| 125 | } | 136 | } |
| 126 | 137 | ||
| 127 | err = 0; | ||
| 128 | |||
| 129 | error: | 138 | error: |
| 130 | return err; | 139 | return err; |
| 131 | } | 140 | } |
| @@ -135,8 +144,10 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 135 | struct ipv6hdr *iph; | 144 | struct ipv6hdr *iph; |
| 136 | struct ipv6_esp_hdr *esph; | 145 | struct ipv6_esp_hdr *esph; |
| 137 | struct esp_data *esp = x->data; | 146 | struct esp_data *esp = x->data; |
| 147 | struct crypto_blkcipher *tfm = esp->conf.tfm; | ||
| 148 | struct blkcipher_desc desc = { .tfm = tfm }; | ||
| 138 | struct sk_buff *trailer; | 149 | struct sk_buff *trailer; |
| 139 | int blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4); | 150 | int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4); |
| 140 | int alen = esp->auth.icv_trunc_len; | 151 | int alen = esp->auth.icv_trunc_len; |
| 141 | int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; | 152 | int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen; |
| 142 | 153 | ||
| @@ -156,15 +167,16 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 156 | 167 | ||
| 157 | /* If integrity check is required, do this. */ | 168 | /* If integrity check is required, do this. */ |
| 158 | if (esp->auth.icv_full_len) { | 169 | if (esp->auth.icv_full_len) { |
| 159 | u8 sum[esp->auth.icv_full_len]; | 170 | u8 sum[alen]; |
| 160 | u8 sum1[alen]; | ||
| 161 | 171 | ||
| 162 | esp->auth.icv(esp, skb, 0, skb->len-alen, sum); | 172 | ret = esp_mac_digest(esp, skb, 0, skb->len - alen); |
| 173 | if (ret) | ||
| 174 | goto out; | ||
| 163 | 175 | ||
| 164 | if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) | 176 | if (skb_copy_bits(skb, skb->len - alen, sum, alen)) |
| 165 | BUG(); | 177 | BUG(); |
| 166 | 178 | ||
| 167 | if (unlikely(memcmp(sum, sum1, alen))) { | 179 | if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) { |
| 168 | x->stats.integrity_failed++; | 180 | x->stats.integrity_failed++; |
| 169 | ret = -EINVAL; | 181 | ret = -EINVAL; |
| 170 | goto out; | 182 | goto out; |
| @@ -183,7 +195,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 183 | 195 | ||
| 184 | /* Get ivec. This can be wrong, check against another impls. */ | 196 | /* Get ivec. This can be wrong, check against another impls. */ |
| 185 | if (esp->conf.ivlen) | 197 | if (esp->conf.ivlen) |
| 186 | crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); | 198 | crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen); |
| 187 | 199 | ||
| 188 | { | 200 | { |
| 189 | u8 nexthdr[2]; | 201 | u8 nexthdr[2]; |
| @@ -198,9 +210,11 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 198 | } | 210 | } |
| 199 | } | 211 | } |
| 200 | skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); | 212 | skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen); |
| 201 | crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); | 213 | ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen); |
| 202 | if (unlikely(sg != &esp->sgbuf[0])) | 214 | if (unlikely(sg != &esp->sgbuf[0])) |
| 203 | kfree(sg); | 215 | kfree(sg); |
| 216 | if (unlikely(ret)) | ||
| 217 | goto out; | ||
| 204 | 218 | ||
| 205 | if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) | 219 | if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) |
| 206 | BUG(); | 220 | BUG(); |
| @@ -226,9 +240,9 @@ out: | |||
| 226 | static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) | 240 | static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) |
| 227 | { | 241 | { |
| 228 | struct esp_data *esp = x->data; | 242 | struct esp_data *esp = x->data; |
| 229 | u32 blksize = ALIGN(crypto_tfm_alg_blocksize(esp->conf.tfm), 4); | 243 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
| 230 | 244 | ||
| 231 | if (x->props.mode) { | 245 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
| 232 | mtu = ALIGN(mtu + 2, blksize); | 246 | mtu = ALIGN(mtu + 2, blksize); |
| 233 | } else { | 247 | } else { |
| 234 | /* The worst case. */ | 248 | /* The worst case. */ |
| @@ -267,11 +281,11 @@ static void esp6_destroy(struct xfrm_state *x) | |||
| 267 | if (!esp) | 281 | if (!esp) |
| 268 | return; | 282 | return; |
| 269 | 283 | ||
| 270 | crypto_free_tfm(esp->conf.tfm); | 284 | crypto_free_blkcipher(esp->conf.tfm); |
| 271 | esp->conf.tfm = NULL; | 285 | esp->conf.tfm = NULL; |
| 272 | kfree(esp->conf.ivec); | 286 | kfree(esp->conf.ivec); |
| 273 | esp->conf.ivec = NULL; | 287 | esp->conf.ivec = NULL; |
| 274 | crypto_free_tfm(esp->auth.tfm); | 288 | crypto_free_hash(esp->auth.tfm); |
| 275 | esp->auth.tfm = NULL; | 289 | esp->auth.tfm = NULL; |
| 276 | kfree(esp->auth.work_icv); | 290 | kfree(esp->auth.work_icv); |
| 277 | esp->auth.work_icv = NULL; | 291 | esp->auth.work_icv = NULL; |
| @@ -281,6 +295,7 @@ static void esp6_destroy(struct xfrm_state *x) | |||
| 281 | static int esp6_init_state(struct xfrm_state *x) | 295 | static int esp6_init_state(struct xfrm_state *x) |
| 282 | { | 296 | { |
| 283 | struct esp_data *esp = NULL; | 297 | struct esp_data *esp = NULL; |
| 298 | struct crypto_blkcipher *tfm; | ||
| 284 | 299 | ||
| 285 | /* null auth and encryption can have zero length keys */ | 300 | /* null auth and encryption can have zero length keys */ |
| 286 | if (x->aalg) { | 301 | if (x->aalg) { |
| @@ -299,24 +314,29 @@ static int esp6_init_state(struct xfrm_state *x) | |||
| 299 | 314 | ||
| 300 | if (x->aalg) { | 315 | if (x->aalg) { |
| 301 | struct xfrm_algo_desc *aalg_desc; | 316 | struct xfrm_algo_desc *aalg_desc; |
| 317 | struct crypto_hash *hash; | ||
| 302 | 318 | ||
| 303 | esp->auth.key = x->aalg->alg_key; | 319 | esp->auth.key = x->aalg->alg_key; |
| 304 | esp->auth.key_len = (x->aalg->alg_key_len+7)/8; | 320 | esp->auth.key_len = (x->aalg->alg_key_len+7)/8; |
| 305 | esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); | 321 | hash = crypto_alloc_hash(x->aalg->alg_name, 0, |
| 306 | if (esp->auth.tfm == NULL) | 322 | CRYPTO_ALG_ASYNC); |
| 323 | if (IS_ERR(hash)) | ||
| 324 | goto error; | ||
| 325 | |||
| 326 | esp->auth.tfm = hash; | ||
| 327 | if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len)) | ||
| 307 | goto error; | 328 | goto error; |
| 308 | esp->auth.icv = esp_hmac_digest; | ||
| 309 | 329 | ||
| 310 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); | 330 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); |
| 311 | BUG_ON(!aalg_desc); | 331 | BUG_ON(!aalg_desc); |
| 312 | 332 | ||
| 313 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != | 333 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != |
| 314 | crypto_tfm_alg_digestsize(esp->auth.tfm)) { | 334 | crypto_hash_digestsize(hash)) { |
| 315 | printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", | 335 | NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", |
| 316 | x->aalg->alg_name, | 336 | x->aalg->alg_name, |
| 317 | crypto_tfm_alg_digestsize(esp->auth.tfm), | 337 | crypto_hash_digestsize(hash), |
| 318 | aalg_desc->uinfo.auth.icv_fullbits/8); | 338 | aalg_desc->uinfo.auth.icv_fullbits/8); |
| 319 | goto error; | 339 | goto error; |
| 320 | } | 340 | } |
| 321 | 341 | ||
| 322 | esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; | 342 | esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; |
| @@ -328,24 +348,22 @@ static int esp6_init_state(struct xfrm_state *x) | |||
| 328 | } | 348 | } |
| 329 | esp->conf.key = x->ealg->alg_key; | 349 | esp->conf.key = x->ealg->alg_key; |
| 330 | esp->conf.key_len = (x->ealg->alg_key_len+7)/8; | 350 | esp->conf.key_len = (x->ealg->alg_key_len+7)/8; |
| 331 | if (x->props.ealgo == SADB_EALG_NULL) | 351 | tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC); |
| 332 | esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_ECB); | 352 | if (IS_ERR(tfm)) |
| 333 | else | ||
| 334 | esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC); | ||
| 335 | if (esp->conf.tfm == NULL) | ||
| 336 | goto error; | 353 | goto error; |
| 337 | esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm); | 354 | esp->conf.tfm = tfm; |
| 355 | esp->conf.ivlen = crypto_blkcipher_ivsize(tfm); | ||
| 338 | esp->conf.padlen = 0; | 356 | esp->conf.padlen = 0; |
| 339 | if (esp->conf.ivlen) { | 357 | if (esp->conf.ivlen) { |
| 340 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); | 358 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); |
| 341 | if (unlikely(esp->conf.ivec == NULL)) | 359 | if (unlikely(esp->conf.ivec == NULL)) |
| 342 | goto error; | 360 | goto error; |
| 343 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | 361 | esp->conf.ivinitted = 0; |
| 344 | } | 362 | } |
| 345 | if (crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len)) | 363 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) |
| 346 | goto error; | 364 | goto error; |
| 347 | x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; | 365 | x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; |
| 348 | if (x->props.mode) | 366 | if (x->props.mode == XFRM_MODE_TUNNEL) |
| 349 | x->props.header_len += sizeof(struct ipv6hdr); | 367 | x->props.header_len += sizeof(struct ipv6hdr); |
| 350 | x->data = esp; | 368 | x->data = esp; |
| 351 | return 0; | 369 | return 0; |
| @@ -366,7 +384,8 @@ static struct xfrm_type esp6_type = | |||
| 366 | .destructor = esp6_destroy, | 384 | .destructor = esp6_destroy, |
| 367 | .get_max_size = esp6_get_max_size, | 385 | .get_max_size = esp6_get_max_size, |
| 368 | .input = esp6_input, | 386 | .input = esp6_input, |
| 369 | .output = esp6_output | 387 | .output = esp6_output, |
| 388 | .hdr_offset = xfrm6_find_1stfragopt, | ||
| 370 | }; | 389 | }; |
| 371 | 390 | ||
| 372 | static struct inet6_protocol esp6_protocol = { | 391 | static struct inet6_protocol esp6_protocol = { |
