1 /* 2 * Copyright (C)2002 USAGI/WIDE Project 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 * Authors 19 * 20 * Mitsuru KANDA @USAGI : IPv6 Support 21 * Kazunori MIYAZAWA @USAGI : 22 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 23 * 24 * This file is derived from net/ipv4/ah.c. 25 */ 26 27 #include <linux/module.h> 28 #include <net/ip.h> 29 #include <net/ah.h> 30 #include <linux/crypto.h> 31 #include <linux/pfkeyv2.h> 32 #include <linux/string.h> 33 #include <net/icmp.h> 34 #include <net/ipv6.h> 35 #include <net/protocol.h> 36 #include <net/xfrm.h> 37 #include <asm/scatterlist.h> 38 39 static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) 40 { 41 u8 *opt = (u8 *)opthdr; 42 int len = ipv6_optlen(opthdr); 43 int off = 0; 44 int optlen = 0; 45 46 off += 2; 47 len -= 2; 48 49 while (len > 0) { 50 51 switch (opt[off]) { 52 53 case IPV6_TLV_PAD0: 54 optlen = 1; 55 break; 56 default: 57 if (len < 2) 58 goto bad; 59 optlen = opt[off+1]+2; 60 if (len < optlen) 61 goto bad; 62 if (opt[off] & 0x20) 63 memset(&opt[off+2], 0, opt[off+1]); 64 break; 65 } 66 67 off += optlen; 68 len -= optlen; 69 } 70 if (len == 0) 71 return 1; 72 73 bad: 74 return 0; 75 } 76 77 #ifdef CONFIG_IPV6_MIP6 78 /** 79 * ipv6_rearrange_destopt - rearrange IPv6 destination options header 80 * @iph: IPv6 header 81 * @destopt: destionation options header 82 */ 83 static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt) 84 { 85 u8 *opt = (u8 *)destopt; 86 int len = ipv6_optlen(destopt); 87 int off = 0; 88 int optlen = 0; 89 90 off += 2; 91 len -= 2; 92 93 while (len > 0) { 94 95 switch (opt[off]) { 96 97 case IPV6_TLV_PAD0: 98 optlen = 1; 99 break; 100 default: 101 if (len < 2) 102 goto bad; 103 optlen = opt[off+1]+2; 104 if (len < optlen) 105 goto bad; 106 107 /* Rearrange the source address in @iph and the 108 * addresses in home address option for final source. 109 * See 11.3.2 of RFC 3775 for details. 110 */ 111 if (opt[off] == IPV6_TLV_HAO) { 112 struct in6_addr final_addr; 113 struct ipv6_destopt_hao *hao; 114 115 hao = (struct ipv6_destopt_hao *)&opt[off]; 116 if (hao->length != sizeof(hao->addr)) { 117 if (net_ratelimit()) 118 printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length); 119 goto bad; 120 } 121 ipv6_addr_copy(&final_addr, &hao->addr); 122 ipv6_addr_copy(&hao->addr, &iph->saddr); 123 ipv6_addr_copy(&iph->saddr, &final_addr); 124 } 125 break; 126 } 127 128 off += optlen; 129 len -= optlen; 130 } 131 /* Note: ok if len == 0 */ 132 bad: 133 return; 134 } 135 #endif 136 137 /** 138 * ipv6_rearrange_rthdr - rearrange IPv6 routing header 139 * @iph: IPv6 header 140 * @rthdr: routing header 141 * 142 * Rearrange the destination address in @iph and the addresses in @rthdr 143 * so that they appear in the order they will at the final destination. 144 * See Appendix A2 of RFC 2402 for details. 145 */ 146 static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) 147 { 148 int segments, segments_left; 149 struct in6_addr *addrs; 150 struct in6_addr final_addr; 151 152 segments_left = rthdr->segments_left; 153 if (segments_left == 0) 154 return; 155 rthdr->segments_left = 0; 156 157 /* The value of rthdr->hdrlen has been verified either by the system 158 * call if it is locally generated, or by ipv6_rthdr_rcv() for incoming 159 * packets. So we can assume that it is even and that segments is 160 * greater than or equal to segments_left. 161 * 162 * For the same reason we can assume that this option is of type 0. 163 */ 164 segments = rthdr->hdrlen >> 1; 165 166 addrs = ((struct rt0_hdr *)rthdr)->addr; 167 ipv6_addr_copy(&final_addr, addrs + segments - 1); 168 169 addrs += segments - segments_left; 170 memmove(addrs + 1, addrs, (segments_left - 1) * sizeof(*addrs)); 171 172 ipv6_addr_copy(addrs, &iph->daddr); 173 ipv6_addr_copy(&iph->daddr, &final_addr); 174 } 175 176 static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) 177 { 178 union { 179 struct ipv6hdr *iph; 180 struct ipv6_opt_hdr *opth; 181 struct ipv6_rt_hdr *rth; 182 char *raw; 183 } exthdr = { .iph = iph }; 184 char *end = exthdr.raw + len; 185 int nexthdr = iph->nexthdr; 186 187 exthdr.iph++; 188 189 while (exthdr.raw < end) { 190 switch (nexthdr) { 191 case NEXTHDR_DEST: 192 #ifdef CONFIG_IPV6_MIP6 193 if (dir == XFRM_POLICY_OUT) 194 ipv6_rearrange_destopt(iph, exthdr.opth); 195 #endif 196 case NEXTHDR_HOP: 197 if (!zero_out_mutable_opts(exthdr.opth)) { 198 LIMIT_NETDEBUG( 199 KERN_WARNING "overrun %sopts\n", 200 nexthdr == NEXTHDR_HOP ? 201 "hop" : "dest"); 202 return -EINVAL; 203 } 204 break; 205 206 case NEXTHDR_ROUTING: 207 ipv6_rearrange_rthdr(iph, exthdr.rth); 208 break; 209 210 default : 211 return 0; 212 } 213 214 nexthdr = exthdr.opth->nexthdr; 215 exthdr.raw += ipv6_optlen(exthdr.opth); 216 } 217 218 return 0; 219 } 220 221 static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) 222 { 223 int err; 224 int extlen; 225 struct ipv6hdr *top_iph; 226 struct ip_auth_hdr *ah; 227 struct ah_data *ahp; 228 u8 nexthdr; 229 char tmp_base[8]; 230 struct { 231 #ifdef CONFIG_IPV6_MIP6 232 struct in6_addr saddr; 233 #endif 234 struct in6_addr daddr; 235 char hdrs[0]; 236 } *tmp_ext; 237 238 top_iph = (struct ipv6hdr *)skb->data; 239 top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); 240 241 nexthdr = *skb_network_header(skb); 242 *skb_network_header(skb) = IPPROTO_AH; 243 244 /* When there are no extension headers, we only need to save the first 245 * 8 bytes of the base IP header. 246 */ 247 memcpy(tmp_base, top_iph, sizeof(tmp_base)); 248 249 tmp_ext = NULL; 250 extlen = skb_transport_offset(skb) + sizeof(struct ipv6hdr); 251 if (extlen) { 252 extlen += sizeof(*tmp_ext); 253 tmp_ext = kmalloc(extlen, GFP_ATOMIC); 254 if (!tmp_ext) { 255 err = -ENOMEM; 256 goto error; 257 } 258 #ifdef CONFIG_IPV6_MIP6 259 memcpy(tmp_ext, &top_iph->saddr, extlen); 260 #else 261 memcpy(tmp_ext, &top_iph->daddr, extlen); 262 #endif 263 err = ipv6_clear_mutable_options(top_iph, 264 extlen - sizeof(*tmp_ext) + 265 sizeof(*top_iph), 266 XFRM_POLICY_OUT); 267 if (err) 268 goto error_free_iph; 269 } 270 271 ah = (struct ip_auth_hdr *)skb_transport_header(skb); 272 ah->nexthdr = nexthdr; 273 274 top_iph->priority = 0; 275 top_iph->flow_lbl[0] = 0; 276 top_iph->flow_lbl[1] = 0; 277 top_iph->flow_lbl[2] = 0; 278 top_iph->hop_limit = 0; 279 280 ahp = x->data; 281 ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + 282 ahp->icv_trunc_len) >> 2) - 2; 283 284 ah->reserved = 0; 285 ah->spi = x->id.spi; 286 ah->seq_no = htonl(++x->replay.oseq); 287 xfrm_aevent_doreplay(x); 288 err = ah_mac_digest(ahp, skb, ah->auth_data); 289 if (err) 290 goto error_free_iph; 291 memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); 292 293 err = 0; 294 295 memcpy(top_iph, tmp_base, sizeof(tmp_base)); 296 if (tmp_ext) { 297 #ifdef CONFIG_IPV6_MIP6 298 memcpy(&top_iph->saddr, tmp_ext, extlen); 299 #else 300 memcpy(&top_iph->daddr, tmp_ext, extlen); 301 #endif 302 error_free_iph: 303 kfree(tmp_ext); 304 } 305 306 error: 307 return err; 308 } 309 310 static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) 311 { 312 /* 313 * Before process AH 314 * [IPv6][Ext1][Ext2][AH][Dest][Payload] 315 * |<-------------->| hdr_len 316 * 317 * To erase AH: 318 * Keeping copy of cleared headers. After AH processing, 319 * Moving the pointer of skb->network_header by using skb_pull as long 320 * as AH header length. Then copy back the copy as long as hdr_len 321 * If destination header following AH exists, copy it into after [Ext2]. 322 * 323 * |<>|[IPv6][Ext1][Ext2][Dest][Payload] 324 * There is offset of AH before IPv6 header after the process. 325 */ 326 327 struct ipv6_auth_hdr *ah; 328 struct ipv6hdr *ip6h; 329 struct ah_data *ahp; 330 unsigned char *tmp_hdr = NULL; 331 u16 hdr_len; 332 u16 ah_hlen; 333 int nexthdr; 334 int err = -EINVAL; 335 336 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) 337 goto out; 338 339 /* We are going to _remove_ AH header to keep sockets happy, 340 * so... Later this can change. */ 341 if (skb_cloned(skb) && 342 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 343 goto out; 344 345 hdr_len = skb->data - skb_network_header(skb); 346 ah = (struct ipv6_auth_hdr*)skb->data; 347 ahp = x->data; 348 nexthdr = ah->nexthdr; 349 ah_hlen = (ah->hdrlen + 2) << 2; 350 351 if (ah_hlen != XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_full_len) && 352 ah_hlen != XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len)) 353 goto out; 354 355 if (!pskb_may_pull(skb, ah_hlen)) 356 goto out; 357 358 tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC); 359 if (!tmp_hdr) 360 goto out; 361 ip6h = ipv6_hdr(skb); 362 if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN)) 363 goto free_out; 364 ip6h->priority = 0; 365 ip6h->flow_lbl[0] = 0; 366 ip6h->flow_lbl[1] = 0; 367 ip6h->flow_lbl[2] = 0; 368 ip6h->hop_limit = 0; 369 370 { 371 u8 auth_data[MAX_AH_AUTH_LEN]; 372 373 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 374 memset(ah->auth_data, 0, ahp->icv_trunc_len); 375 skb_push(skb, hdr_len); 376 err = ah_mac_digest(ahp, skb, ah->auth_data); 377 if (err) 378 goto free_out; 379 err = -EINVAL; 380 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { 381 LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n"); 382 x->stats.integrity_failed++; 383 goto free_out; 384 } 385 } 386 387 skb->network_header += ah_hlen; 388 memcpy(skb_network_header(skb), tmp_hdr, hdr_len); 389 skb->transport_header = skb->network_header; 390 __skb_pull(skb, ah_hlen + hdr_len); 391 392 kfree(tmp_hdr); 393 394 return nexthdr; 395 396 free_out: 397 kfree(tmp_hdr); 398 out: 399 return err; 400 } 401 402 static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 403 int type, int code, int offset, __be32 info) 404 { 405 struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; 406 struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset); 407 struct xfrm_state *x; 408 409 if (type != ICMPV6_DEST_UNREACH && 410 type != ICMPV6_PKT_TOOBIG) 411 return; 412 413 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); 414 if (!x) 415 return; 416 417 NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/" NIP6_FMT "\n", 418 ntohl(ah->spi), NIP6(iph->daddr)); 419 420 xfrm_state_put(x); 421 } 422 423 static int ah6_init_state(struct xfrm_state *x) 424 { 425 struct ah_data *ahp = NULL; 426 struct xfrm_algo_desc *aalg_desc; 427 struct crypto_hash *tfm; 428 429 if (!x->aalg) 430 goto error; 431 432 /* null auth can use a zero length key */ 433 if (x->aalg->alg_key_len > 512) 434 goto error; 435 436 if (x->encap) 437 goto error; 438 439 ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); 440 if (ahp == NULL) 441 return -ENOMEM; 442 443 ahp->key = x->aalg->alg_key; 444 ahp->key_len = (x->aalg->alg_key_len+7)/8; 445 tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); 446 if (IS_ERR(tfm)) 447 goto error; 448 449 ahp->tfm = tfm; 450 if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len)) 451 goto error; 452 453 /* 454 * Lookup the algorithm description maintained by xfrm_algo, 455 * verify crypto transform properties, and store information 456 * we need for AH processing. This lookup cannot fail here 457 * after a successful crypto_alloc_hash(). 458 */ 459 aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 460 BUG_ON(!aalg_desc); 461 462 if (aalg_desc->uinfo.auth.icv_fullbits/8 != 463 crypto_hash_digestsize(tfm)) { 464 printk(KERN_INFO "AH: %s digestsize %u != %hu\n", 465 x->aalg->alg_name, crypto_hash_digestsize(tfm), 466 aalg_desc->uinfo.auth.icv_fullbits/8); 467 goto error; 468 } 469 470 ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; 471 ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; 472 473 BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); 474 475 ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); 476 if (!ahp->work_icv) 477 goto error; 478 479 x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len); 480 if (x->props.mode == XFRM_MODE_TUNNEL) 481 x->props.header_len += sizeof(struct ipv6hdr); 482 x->data = ahp; 483 484 return 0; 485 486 error: 487 if (ahp) { 488 kfree(ahp->work_icv); 489 crypto_free_hash(ahp->tfm); 490 kfree(ahp); 491 } 492 return -EINVAL; 493 } 494 495 static void ah6_destroy(struct xfrm_state *x) 496 { 497 struct ah_data *ahp = x->data; 498 499 if (!ahp) 500 return; 501 502 kfree(ahp->work_icv); 503 ahp->work_icv = NULL; 504 crypto_free_hash(ahp->tfm); 505 ahp->tfm = NULL; 506 kfree(ahp); 507 } 508 509 static struct xfrm_type ah6_type = 510 { 511 .description = "AH6", 512 .owner = THIS_MODULE, 513 .proto = IPPROTO_AH, 514 .init_state = ah6_init_state, 515 .destructor = ah6_destroy, 516 .input = ah6_input, 517 .output = ah6_output, 518 .hdr_offset = xfrm6_find_1stfragopt, 519 }; 520 521 static struct inet6_protocol ah6_protocol = { 522 .handler = xfrm6_rcv, 523 .err_handler = ah6_err, 524 .flags = INET6_PROTO_NOPOLICY, 525 }; 526 527 static int __init ah6_init(void) 528 { 529 if (xfrm_register_type(&ah6_type, AF_INET6) < 0) { 530 printk(KERN_INFO "ipv6 ah init: can't add xfrm type\n"); 531 return -EAGAIN; 532 } 533 534 if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) { 535 printk(KERN_INFO "ipv6 ah init: can't add protocol\n"); 536 xfrm_unregister_type(&ah6_type, AF_INET6); 537 return -EAGAIN; 538 } 539 540 return 0; 541 } 542 543 static void __exit ah6_fini(void) 544 { 545 if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0) 546 printk(KERN_INFO "ipv6 ah close: can't remove protocol\n"); 547 548 if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0) 549 printk(KERN_INFO "ipv6 ah close: can't remove xfrm type\n"); 550 551 } 552 553 module_init(ah6_init); 554 module_exit(ah6_fini); 555 556 MODULE_LICENSE("GPL"); 557