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