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