1/* 2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $ */ 30/* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $ */ 31 32/* 33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the project nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61/* 62 * RFC1826/2402 authentication header. 63 */ 64 65#include <sys/param.h> 66#include <sys/systm.h> 67#include <sys/malloc.h> 68#include <sys/mbuf.h> 69#include <sys/mcache.h> 70#include <sys/domain.h> 71#include <sys/protosw.h> 72#include <sys/socket.h> 73#include <sys/errno.h> 74#include <sys/time.h> 75#include <sys/kernel.h> 76#include <sys/syslog.h> 77 78#include <net/if.h> 79#include <net/if_ipsec.h> 80#include <net/route.h> 81#include <kern/cpu_number.h> 82#include <kern/locks.h> 83 84#include <netinet/in.h> 85#include <netinet/in_systm.h> 86#include <netinet/in_var.h> 87#include <netinet/ip.h> 88#include <netinet/ip_var.h> 89#include <netinet/ip_ecn.h> 90#include <netinet/in_pcb.h> 91#if INET6 92#include <netinet6/ip6_ecn.h> 93#endif 94 95#if INET6 96#include <netinet/ip6.h> 97#include <netinet6/ip6_var.h> 98#include <netinet6/in6_pcb.h> 99#include <netinet/icmp6.h> 100#include <netinet6/ip6protosw.h> 101#endif 102 103#include <netinet6/ipsec.h> 104#if INET6 105#include <netinet6/ipsec6.h> 106#endif 107#include <netinet6/ah.h> 108#if INET6 109#include <netinet6/ah6.h> 110#endif 111#include <netkey/key.h> 112#include <netkey/keydb.h> 113#if IPSEC_DEBUG 114#include <netkey/key_debug.h> 115#else 116#define KEYDEBUG(lev,arg) 117#endif 118 119#include <net/kpi_protocol.h> 120#include <netinet/kpi_ipfilter_var.h> 121#include <mach/sdt.h> 122 123#include <net/net_osdep.h> 124 125#define IPLEN_FLIPPED 126 127#if INET 128void 129ah4_input(struct mbuf *m, int off) 130{ 131 struct ip *ip; 132 struct ah *ah; 133 u_int32_t spi; 134 const struct ah_algorithm *algo; 135 size_t siz; 136 size_t siz1; 137 u_char *cksum; 138 struct secasvar *sav = NULL; 139 u_int16_t nxt; 140 size_t hlen; 141 size_t stripsiz = 0; 142 sa_family_t ifamily; 143 144 if (m->m_len < off + sizeof(struct newah)) { 145 m = m_pullup(m, off + sizeof(struct newah)); 146 if (!m) { 147 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" 148 "dropping the packet for simplicity\n")); 149 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 150 goto fail; 151 } 152 } 153 154 /* Expect 32-bit aligned data pointer on strict-align platforms */ 155 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); 156 157 ip = mtod(m, struct ip *); 158 ah = (struct ah *)(void *)(((caddr_t)ip) + off); 159 nxt = ah->ah_nxt; 160#ifdef _IP_VHL 161 hlen = IP_VHL_HL(ip->ip_vhl) << 2; 162#else 163 hlen = ip->ip_hl << 2; 164#endif 165 166 /* find the sassoc. */ 167 spi = ah->ah_spi; 168 169 if ((sav = key_allocsa(AF_INET, 170 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, 171 IPPROTO_AH, spi)) == 0) { 172 ipseclog((LOG_WARNING, 173 "IPv4 AH input: no key association found for spi %u\n", 174 (u_int32_t)ntohl(spi))); 175 IPSEC_STAT_INCREMENT(ipsecstat.in_nosa); 176 goto fail; 177 } 178 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 179 printf("DP ah4_input called to allocate SA:0x%llx\n", 180 (uint64_t)VM_KERNEL_ADDRPERM(sav))); 181 if (sav->state != SADB_SASTATE_MATURE 182 && sav->state != SADB_SASTATE_DYING) { 183 ipseclog((LOG_DEBUG, 184 "IPv4 AH input: non-mature/dying SA found for spi %u\n", 185 (u_int32_t)ntohl(spi))); 186 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi); 187 goto fail; 188 } 189 190 algo = ah_algorithm_lookup(sav->alg_auth); 191 if (!algo) { 192 ipseclog((LOG_DEBUG, "IPv4 AH input: " 193 "unsupported authentication algorithm for spi %u\n", 194 (u_int32_t)ntohl(spi))); 195 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi); 196 goto fail; 197 } 198 199 siz = (*algo->sumsiz)(sav); 200 siz1 = ((siz + 3) & ~(4 - 1)); 201 202 /* 203 * sanity checks for header, 1. 204 */ 205 { 206 int sizoff; 207 208 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; 209 210 /* 211 * Here, we do not do "siz1 == siz". This is because the way 212 * RFC240[34] section 2 is written. They do not require truncation 213 * to 96 bits. 214 * For example, Microsoft IPsec stack attaches 160 bits of 215 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1, 216 * 32 bits of padding is attached. 217 * 218 * There are two downsides to this specification. 219 * They have no real harm, however, they leave us fuzzy feeling. 220 * - if we attach more than 96 bits of authentication data onto AH, 221 * we will never notice about possible modification by rogue 222 * intermediate nodes. 223 * Since extra bits in AH checksum is never used, this constitutes 224 * no real issue, however, it is wacky. 225 * - even if the peer attaches big authentication data, we will never 226 * notice the difference, since longer authentication data will just 227 * work. 228 * 229 * We may need some clarification in the spec. 230 */ 231 if (siz1 < siz) { 232 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input " 233 "(%lu, should be at least %lu): %s\n", 234 (u_int32_t)siz1, (u_int32_t)siz, 235 ipsec4_logpacketstr(ip, spi))); 236 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 237 goto fail; 238 } 239 if ((ah->ah_len << 2) - sizoff != siz1) { 240 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input " 241 "(%d should be %lu): %s\n", 242 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1, 243 ipsec4_logpacketstr(ip, spi))); 244 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 245 goto fail; 246 } 247 248 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) { 249 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); 250 if (!m) { 251 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); 252 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 253 goto fail; 254 } 255 /* Expect 32-bit aligned data ptr on strict-align platforms */ 256 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); 257 258 ip = mtod(m, struct ip *); 259 ah = (struct ah *)(void *)(((caddr_t)ip) + off); 260 } 261 } 262 263 /* 264 * check for sequence number. 265 */ 266 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { 267 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) 268 ; /*okey*/ 269 else { 270 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay); 271 ipseclog((LOG_WARNING, 272 "replay packet in IPv4 AH input: %s %s\n", 273 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 274 goto fail; 275 } 276 } 277 278 /* 279 * alright, it seems sane. now we are going to check the 280 * cryptographic checksum. 281 */ 282 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT); 283 if (!cksum) { 284 ipseclog((LOG_DEBUG, "IPv4 AH input: " 285 "couldn't alloc temporary region for cksum\n")); 286 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 287 goto fail; 288 } 289 290 /* 291 * some of IP header fields are flipped to the host endian. 292 * convert them back to network endian. VERY stupid. 293 */ 294 ip->ip_len = htons(ip->ip_len + hlen); 295 ip->ip_off = htons(ip->ip_off); 296 if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { 297 FREE(cksum, M_TEMP); 298 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 299 goto fail; 300 } 301 IPSEC_STAT_INCREMENT(ipsecstat.in_ahhist[sav->alg_auth]); 302 /* 303 * flip them back. 304 */ 305 ip->ip_len = ntohs(ip->ip_len) - hlen; 306 ip->ip_off = ntohs(ip->ip_off); 307 308 { 309 caddr_t sumpos = NULL; 310 311 if (sav->flags & SADB_X_EXT_OLD) { 312 /* RFC 1826 */ 313 sumpos = (caddr_t)(ah + 1); 314 } else { 315 /* RFC 2402 */ 316 sumpos = (caddr_t)(((struct newah *)ah) + 1); 317 } 318 319 if (bcmp(sumpos, cksum, siz) != 0) { 320 ipseclog((LOG_WARNING, 321 "checksum mismatch in IPv4 AH input: %s %s\n", 322 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 323 FREE(cksum, M_TEMP); 324 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail); 325 goto fail; 326 } 327 } 328 329 FREE(cksum, M_TEMP); 330 331 m->m_flags |= M_AUTHIPHDR; 332 m->m_flags |= M_AUTHIPDGM; 333 334#if 0 335 /* 336 * looks okey, but we need more sanity check. 337 * XXX should elaborate. 338 */ 339 if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) { 340 struct ip *nip; 341 size_t sizoff; 342 343 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; 344 345 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) { 346 m = m_pullup(m, off + sizeof(struct ah) 347 + sizoff + siz1 + hlen); 348 if (!m) { 349 ipseclog((LOG_DEBUG, 350 "IPv4 AH input: can't pullup\n")); 351 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 352 goto fail; 353 } 354 } 355 356 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1); 357 if (nip->ip_src.s_addr != ip->ip_src.s_addr 358 || nip->ip_dst.s_addr != ip->ip_dst.s_addr) { 359 m->m_flags &= ~M_AUTHIPHDR; 360 m->m_flags &= ~M_AUTHIPDGM; 361 } 362 } 363#if INET6 364 else if (ah->ah_nxt == IPPROTO_IPV6) { 365 m->m_flags &= ~M_AUTHIPHDR; 366 m->m_flags &= ~M_AUTHIPDGM; 367 } 368#endif /*INET6*/ 369#endif /*0*/ 370 371 if (m->m_flags & M_AUTHIPHDR 372 && m->m_flags & M_AUTHIPDGM) { 373#if 0 374 ipseclog((LOG_DEBUG, 375 "IPv4 AH input: authentication succeess\n")); 376#endif 377 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthsucc); 378 } else { 379 ipseclog((LOG_WARNING, 380 "authentication failed in IPv4 AH input: %s %s\n", 381 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 382 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail); 383 goto fail; 384 } 385 386 /* 387 * update sequence number. 388 */ 389 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { 390 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { 391 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay); 392 goto fail; 393 } 394 } 395 396 /* was it transmitted over the IPsec tunnel SA? */ 397 if (sav->flags & SADB_X_EXT_OLD) { 398 /* RFC 1826 */ 399 stripsiz = sizeof(struct ah) + siz1; 400 } else { 401 /* RFC 2402 */ 402 stripsiz = sizeof(struct newah) + siz1; 403 } 404 if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav, &ifamily)) { 405 ifaddr_t ifa; 406 struct sockaddr_storage addr; 407 408 /* 409 * strip off all the headers that precedes AH. 410 * IP xx AH IP' payload -> IP' payload 411 * 412 * XXX more sanity checks 413 * XXX relationship with gif? 414 */ 415 u_int8_t tos; 416 417 if (ifamily == AF_INET6) { 418 ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch " 419 "in IPv4 AH input: %s\n", ipsec_logsastr(sav))); 420 goto fail; 421 } 422 tos = ip->ip_tos; 423 m_adj(m, off + stripsiz); 424 if (m->m_len < sizeof(*ip)) { 425 m = m_pullup(m, sizeof(*ip)); 426 if (!m) { 427 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 428 goto fail; 429 } 430 } 431 ip = mtod(m, struct ip *); 432 /* ECN consideration. */ 433 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); 434 if (!key_checktunnelsanity(sav, AF_INET, 435 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { 436 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " 437 "in IPv4 AH input: %s %s\n", 438 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); 439 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 440 goto fail; 441 } 442 443#if 1 444 /* 445 * Should the inner packet be considered authentic? 446 * My current answer is: NO. 447 * 448 * host1 -- gw1 === gw2 -- host2 449 * In this case, gw2 can trust the authenticity of the 450 * outer packet, but NOT inner. Packet may be altered 451 * between host1 and gw1. 452 * 453 * host1 -- gw1 === host2 454 * This case falls into the same scenario as above. 455 * 456 * host1 === host2 457 * This case is the only case when we may be able to leave 458 * M_AUTHIPHDR and M_AUTHIPDGM set. 459 * However, if host1 is wrongly configured, and allows 460 * attacker to inject some packet with src=host1 and 461 * dst=host2, you are in risk. 462 */ 463 m->m_flags &= ~M_AUTHIPHDR; 464 m->m_flags &= ~M_AUTHIPDGM; 465#endif 466 467 key_sa_recordxfer(sav, m); 468 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || 469 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { 470 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem); 471 goto fail; 472 } 473 474 if (ip_doscopedroute) { 475 struct sockaddr_in *ipaddr; 476 477 bzero(&addr, sizeof(addr)); 478 ipaddr = (__typeof__(ipaddr))&addr; 479 ipaddr->sin_family = AF_INET; 480 ipaddr->sin_len = sizeof(*ipaddr); 481 ipaddr->sin_addr = ip->ip_dst; 482 483 // update the receiving interface address based on the inner address 484 ifa = ifa_ifwithaddr((struct sockaddr *)&addr); 485 if (ifa) { 486 m->m_pkthdr.rcvif = ifa->ifa_ifp; 487 IFA_REMREF(ifa); 488 } 489 } 490 491 // Input via IPSec interface 492 if (sav->sah->ipsec_if != NULL) { 493 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) { 494 m = NULL; 495 goto done; 496 } else { 497 goto fail; 498 } 499 } 500 501 if (proto_input(PF_INET, m) != 0) 502 goto fail; 503 nxt = IPPROTO_DONE; 504 } else { 505 /* 506 * strip off AH. 507 */ 508 509 ip = mtod(m, struct ip *); 510 /* 511 * We do deep-copy since KAME requires that 512 * the packet is placed in a single external mbuf. 513 */ 514 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); 515 m->m_data += stripsiz; 516 m->m_len -= stripsiz; 517 m->m_pkthdr.len -= stripsiz; 518 519 if (m->m_len < sizeof(*ip)) { 520 m = m_pullup(m, sizeof(*ip)); 521 if (m == NULL) { 522 IPSEC_STAT_INCREMENT(ipsecstat.in_inval); 523 goto fail; 524 } 525 } 526 ip = mtod(m, struct ip *); 527#ifdef IPLEN_FLIPPED 528 ip->ip_len = ip->ip_len - stripsiz; 529#else 530 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz); 531#endif 532 ip->ip_p = nxt; 533 /* forget about IP hdr checksum, the check has already been passed */ 534 535 key_sa_recordxfer(sav, m); 536 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { 537 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem); 538 goto fail; 539 } 540 541 DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL, 542 struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif, 543 struct ip *, ip, struct ip6_hdr *, NULL); 544 545 if (nxt != IPPROTO_DONE) { 546 // Input via IPSec interface 547 if (sav->sah->ipsec_if != NULL) { 548 ip->ip_len = htons(ip->ip_len + hlen); 549 ip->ip_off = htons(ip->ip_off); 550 ip->ip_sum = 0; 551 ip->ip_sum = ip_cksum_hdr_in(m, hlen); 552 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) { 553 m = NULL; 554 goto done; 555 } else { 556 goto fail; 557 } 558 } 559 560 if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && 561 ipsec4_in_reject(m, NULL)) { 562 IPSEC_STAT_INCREMENT(ipsecstat.in_polvio); 563 goto fail; 564 } 565 ip_proto_dispatch_in(m, off, nxt, 0); 566 } else 567 m_freem(m); 568 m = NULL; 569 } 570done: 571 if (sav) { 572 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 573 printf("DP ah4_input call free SA:0x%llx\n", 574 (uint64_t)VM_KERNEL_ADDRPERM(sav))); 575 key_freesav(sav, KEY_SADB_UNLOCKED); 576 } 577 IPSEC_STAT_INCREMENT(ipsecstat.in_success); 578 return; 579 580fail: 581 if (sav) { 582 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 583 printf("DP ah4_input call free SA:0x%llx\n", 584 (uint64_t)VM_KERNEL_ADDRPERM(sav))); 585 key_freesav(sav, KEY_SADB_UNLOCKED); 586 } 587 if (m) 588 m_freem(m); 589 return; 590} 591#endif /* INET */ 592 593#if INET6 594int 595ah6_input(struct mbuf **mp, int *offp, int proto) 596{ 597#pragma unused(proto) 598 struct mbuf *m = *mp; 599 int off = *offp; 600 struct ip6_hdr *ip6; 601 struct ah *ah; 602 u_int32_t spi; 603 const struct ah_algorithm *algo; 604 size_t siz; 605 size_t siz1; 606 u_char *cksum; 607 struct secasvar *sav = NULL; 608 u_int16_t nxt; 609 size_t stripsiz = 0; 610 611 612 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;}); 613 ah = (struct ah *)(void *)(mtod(m, caddr_t) + off); 614 /* Expect 32-bit aligned data pointer on strict-align platforms */ 615 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); 616 617 ip6 = mtod(m, struct ip6_hdr *); 618 nxt = ah->ah_nxt; 619 620 /* find the sassoc. */ 621 spi = ah->ah_spi; 622 623 if (ntohs(ip6->ip6_plen) == 0) { 624 ipseclog((LOG_ERR, "IPv6 AH input: " 625 "AH with IPv6 jumbogram is not supported.\n")); 626 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 627 goto fail; 628 } 629 630 if ((sav = key_allocsa(AF_INET6, 631 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, 632 IPPROTO_AH, spi)) == 0) { 633 ipseclog((LOG_WARNING, 634 "IPv6 AH input: no key association found for spi %u\n", 635 (u_int32_t)ntohl(spi))); 636 IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa); 637 goto fail; 638 } 639 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 640 printf("DP ah6_input called to allocate SA:0x%llx\n", 641 (uint64_t)VM_KERNEL_ADDRPERM(sav))); 642 if (sav->state != SADB_SASTATE_MATURE 643 && sav->state != SADB_SASTATE_DYING) { 644 ipseclog((LOG_DEBUG, 645 "IPv6 AH input: non-mature/dying SA found for spi %u; ", 646 (u_int32_t)ntohl(spi))); 647 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi); 648 goto fail; 649 } 650 651 algo = ah_algorithm_lookup(sav->alg_auth); 652 if (!algo) { 653 ipseclog((LOG_DEBUG, "IPv6 AH input: " 654 "unsupported authentication algorithm for spi %u\n", 655 (u_int32_t)ntohl(spi))); 656 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi); 657 goto fail; 658 } 659 660 siz = (*algo->sumsiz)(sav); 661 siz1 = ((siz + 3) & ~(4 - 1)); 662 663 /* 664 * sanity checks for header, 1. 665 */ 666 { 667 int sizoff; 668 669 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; 670 671 /* 672 * Here, we do not do "siz1 == siz". See ah4_input() for complete 673 * description. 674 */ 675 if (siz1 < siz) { 676 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input " 677 "(%lu, should be at least %lu): %s\n", 678 (u_int32_t)siz1, (u_int32_t)siz, 679 ipsec6_logpacketstr(ip6, spi))); 680 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 681 goto fail; 682 } 683 if ((ah->ah_len << 2) - sizoff != siz1) { 684 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input " 685 "(%d should be %lu): %s\n", 686 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1, 687 ipsec6_logpacketstr(ip6, spi))); 688 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 689 goto fail; 690 } 691 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, 692 {return IPPROTO_DONE;}); 693 } 694 695 /* 696 * check for sequence number. 697 */ 698 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { 699 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) 700 ; /*okey*/ 701 else { 702 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay); 703 ipseclog((LOG_WARNING, 704 "replay packet in IPv6 AH input: %s %s\n", 705 ipsec6_logpacketstr(ip6, spi), 706 ipsec_logsastr(sav))); 707 goto fail; 708 } 709 } 710 711 /* 712 * alright, it seems sane. now we are going to check the 713 * cryptographic checksum. 714 */ 715 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT); 716 if (!cksum) { 717 ipseclog((LOG_DEBUG, "IPv6 AH input: " 718 "couldn't alloc temporary region for cksum\n")); 719 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 720 goto fail; 721 } 722 723 if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { 724 FREE(cksum, M_TEMP); 725 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 726 goto fail; 727 } 728 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahhist[sav->alg_auth]); 729 730 { 731 caddr_t sumpos = NULL; 732 733 if (sav->flags & SADB_X_EXT_OLD) { 734 /* RFC 1826 */ 735 sumpos = (caddr_t)(ah + 1); 736 } else { 737 /* RFC 2402 */ 738 sumpos = (caddr_t)(((struct newah *)ah) + 1); 739 } 740 741 if (bcmp(sumpos, cksum, siz) != 0) { 742 ipseclog((LOG_WARNING, 743 "checksum mismatch in IPv6 AH input: %s %s\n", 744 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 745 FREE(cksum, M_TEMP); 746 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail); 747 goto fail; 748 } 749 } 750 751 FREE(cksum, M_TEMP); 752 753 m->m_flags |= M_AUTHIPHDR; 754 m->m_flags |= M_AUTHIPDGM; 755 756#if 0 757 /* 758 * looks okey, but we need more sanity check. 759 * XXX should elaborate. 760 */ 761 if (ah->ah_nxt == IPPROTO_IPV6) { 762 struct ip6_hdr *nip6; 763 size_t sizoff; 764 765 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; 766 767 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1 768 + sizeof(struct ip6_hdr), 769 {return IPPROTO_DONE;}); 770 771 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1); 772 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src) 773 || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) { 774 m->m_flags &= ~M_AUTHIPHDR; 775 m->m_flags &= ~M_AUTHIPDGM; 776 } 777 } else if (ah->ah_nxt == IPPROTO_IPIP) { 778 m->m_flags &= ~M_AUTHIPHDR; 779 m->m_flags &= ~M_AUTHIPDGM; 780 } else if (ah->ah_nxt == IPPROTO_IP) { 781 m->m_flags &= ~M_AUTHIPHDR; 782 m->m_flags &= ~M_AUTHIPDGM; 783 } 784#endif 785 786 if (m->m_flags & M_AUTHIPHDR 787 && m->m_flags & M_AUTHIPDGM) { 788#if 0 789 ipseclog((LOG_DEBUG, 790 "IPv6 AH input: authentication succeess\n")); 791#endif 792 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthsucc); 793 } else { 794 ipseclog((LOG_WARNING, 795 "authentication failed in IPv6 AH input: %s %s\n", 796 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); 797 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail); 798 goto fail; 799 } 800 801 /* 802 * update sequence number. 803 */ 804 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { 805 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { 806 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay); 807 goto fail; 808 } 809 } 810 811 /* was it transmitted over the IPsec tunnel SA? */ 812 if (sav->flags & SADB_X_EXT_OLD) { 813 /* RFC 1826 */ 814 stripsiz = sizeof(struct ah) + siz1; 815 } else { 816 /* RFC 2402 */ 817 stripsiz = sizeof(struct newah) + siz1; 818 } 819 if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) { 820 ifaddr_t ifa; 821 struct sockaddr_storage addr; 822 823 /* 824 * strip off all the headers that precedes AH. 825 * IP6 xx AH IP6' payload -> IP6' payload 826 * 827 * XXX more sanity checks 828 * XXX relationship with gif? 829 */ 830 u_int32_t flowinfo; /*net endian*/ 831 832 flowinfo = ip6->ip6_flow; 833 m_adj(m, off + stripsiz); 834 if (m->m_len < sizeof(*ip6)) { 835 /* 836 * m_pullup is prohibited in KAME IPv6 input processing 837 * but there's no other way! 838 */ 839 m = m_pullup(m, sizeof(*ip6)); 840 if (!m) { 841 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 842 goto fail; 843 } 844 } 845 ip6 = mtod(m, struct ip6_hdr *); 846 /* ECN consideration. */ 847 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); 848 if (!key_checktunnelsanity(sav, AF_INET6, 849 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { 850 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " 851 "in IPv6 AH input: %s %s\n", 852 ipsec6_logpacketstr(ip6, spi), 853 ipsec_logsastr(sav))); 854 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); 855 goto fail; 856 } 857 858#if 1 859 /* 860 * should the inner packet be considered authentic? 861 * see comment in ah4_input(). 862 */ 863 m->m_flags &= ~M_AUTHIPHDR; 864 m->m_flags &= ~M_AUTHIPDGM; 865#endif 866 867 key_sa_recordxfer(sav, m); 868 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || 869 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { 870 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem); 871 goto fail; 872 } 873 874 if (ip6_doscopedroute) { 875 struct sockaddr_in6 *ip6addr; 876 877 bzero(&addr, sizeof(addr)); 878 ip6addr = (__typeof__(ip6addr))&addr; 879 ip6addr->sin6_family = AF_INET6; 880 ip6addr->sin6_len = sizeof(*ip6addr); 881 ip6addr->sin6_addr = ip6->ip6_dst; 882 883 // update the receiving interface address based on the inner address 884 ifa = ifa_ifwithaddr((struct sockaddr *)&addr); 885 if (ifa) { 886 m->m_pkthdr.rcvif = ifa->ifa_ifp; 887 IFA_REMREF(ifa); 888 } 889 } 890 891 // Input via IPSec interface 892 if (sav->sah->ipsec_if != NULL) { 893 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) { 894 m = NULL; 895 nxt = IPPROTO_DONE; 896 goto done; 897 } else { 898 goto fail; 899 } 900 } 901 902 if (proto_input(PF_INET6, m) != 0) 903 goto fail; 904 nxt = IPPROTO_DONE; 905 } else { 906 /* 907 * strip off AH. 908 */ 909 char *prvnxtp; 910 911 /* 912 * Copy the value of the next header field of AH to the 913 * next header field of the previous header. 914 * This is necessary because AH will be stripped off below. 915 */ 916 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ 917 *prvnxtp = nxt; 918 919 ip6 = mtod(m, struct ip6_hdr *); 920 /* 921 * We do deep-copy since KAME requires that 922 * the packet is placed in a single mbuf. 923 */ 924 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); 925 m->m_data += stripsiz; 926 m->m_len -= stripsiz; 927 m->m_pkthdr.len -= stripsiz; 928 ip6 = mtod(m, struct ip6_hdr *); 929 /* XXX jumbogram */ 930 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); 931 932 key_sa_recordxfer(sav, m); 933 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { 934 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem); 935 goto fail; 936 } 937 938 // Input via IPSec interface 939 if (sav->sah->ipsec_if != NULL) { 940 if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) { 941 m = NULL; 942 nxt = IPPROTO_DONE; 943 goto done; 944 } else { 945 goto fail; 946 } 947 } 948 } 949 950done: 951 *offp = off; 952 *mp = m; 953 if (sav) { 954 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 955 printf("DP ah6_input call free SA:0x%llx\n", 956 (uint64_t)VM_KERNEL_ADDRPERM(sav))); 957 key_freesav(sav, KEY_SADB_UNLOCKED); 958 } 959 IPSEC_STAT_INCREMENT(ipsec6stat.in_success); 960 return nxt; 961 962fail: 963 if (sav) { 964 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 965 printf("DP ah6_input call free SA:0x%llx\n", 966 (uint64_t)VM_KERNEL_ADDRPERM(sav))); 967 key_freesav(sav, KEY_SADB_UNLOCKED); 968 } 969 if (m) 970 m_freem(m); 971 return IPPROTO_DONE; 972} 973 974void 975ah6_ctlinput(cmd, sa, d) 976 int cmd; 977 struct sockaddr *sa; 978 void *d; 979{ 980 const struct newah *ahp; 981 struct newah ah; 982 struct secasvar *sav; 983 struct ip6_hdr *ip6; 984 struct mbuf *m; 985 struct ip6ctlparam *ip6cp = NULL; 986 int off; 987 struct sockaddr_in6 *sa6_src, *sa6_dst; 988 989 if (sa->sa_family != AF_INET6 || 990 sa->sa_len != sizeof(struct sockaddr_in6)) 991 return; 992 if ((unsigned)cmd >= PRC_NCMDS) 993 return; 994 995 /* if the parameter is from icmp6, decode it. */ 996 if (d != NULL) { 997 ip6cp = (struct ip6ctlparam *)d; 998 m = ip6cp->ip6c_m; 999 ip6 = ip6cp->ip6c_ip6; 1000 off = ip6cp->ip6c_off; 1001 } else { 1002 m = NULL; 1003 ip6 = NULL; 1004 } 1005 1006 if (ip6) { 1007 /* 1008 * XXX: We assume that when ip6 is non NULL, 1009 * M and OFF are valid. 1010 */ 1011 1012 /* check if we can safely examine src and dst ports */ 1013 if (m->m_pkthdr.len < off + sizeof(ah)) 1014 return; 1015 1016 if (m->m_len < off + sizeof(ah)) { 1017 /* 1018 * this should be rare case, 1019 * so we compromise on this copy... 1020 */ 1021 m_copydata(m, off, sizeof(ah), (caddr_t)&ah); 1022 ahp = &ah; 1023 } else 1024 ahp = (struct newah *)(void *)(mtod(m, caddr_t) + off); 1025 1026 if (cmd == PRC_MSGSIZE) { 1027 int valid = 0; 1028 1029 /* 1030 * Check to see if we have a valid SA corresponding to 1031 * the address in the ICMP message payload. 1032 */ 1033 sa6_src = ip6cp->ip6c_src; 1034 sa6_dst = (struct sockaddr_in6 *)(void *)sa; 1035 sav = key_allocsa(AF_INET6, 1036 (caddr_t)&sa6_src->sin6_addr, 1037 (caddr_t)&sa6_dst->sin6_addr, 1038 IPPROTO_AH, ahp->ah_spi); 1039 if (sav) { 1040 if (sav->state == SADB_SASTATE_MATURE || 1041 sav->state == SADB_SASTATE_DYING) 1042 valid++; 1043 key_freesav(sav, KEY_SADB_UNLOCKED); 1044 } 1045 1046 /* XXX Further validation? */ 1047 1048 /* 1049 * Depending on the value of "valid" and routing table 1050 * size (mtudisc_{hi,lo}wat), we will: 1051 * - recalcurate the new MTU and create the 1052 * corresponding routing entry, or 1053 * - ignore the MTU change notification. 1054 */ 1055 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 1056 } 1057 1058 /* we normally notify single pcb here */ 1059 } else { 1060 /* we normally notify any pcb here */ 1061 } 1062} 1063#endif /* INET6 */ 1064