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/esp_output.c,v 1.1.2.3 2002/04/28 05:40:26 suz Exp $ */ 30/* $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei 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#define _IP_VHL 62 63/* 64 * RFC1827/2406 Encapsulated Security Payload. 65 */ 66 67#include <sys/param.h> 68#include <sys/systm.h> 69#include <sys/malloc.h> 70#include <sys/mbuf.h> 71#include <sys/domain.h> 72#include <sys/protosw.h> 73#include <sys/socket.h> 74#include <sys/socketvar.h> 75#include <sys/errno.h> 76#include <sys/time.h> 77#include <sys/kernel.h> 78#include <sys/syslog.h> 79 80#include <net/if.h> 81#include <net/route.h> 82 83#include <netinet/in.h> 84#include <netinet/in_systm.h> 85#include <netinet/ip.h> 86#include <netinet/in_var.h> 87#include <netinet/udp.h> /* for nat traversal */ 88 89#if INET6 90#include <netinet/ip6.h> 91#include <netinet6/ip6_var.h> 92#include <netinet/icmp6.h> 93#endif 94 95#include <netinet6/ipsec.h> 96#if INET6 97#include <netinet6/ipsec6.h> 98#endif 99#include <netinet6/ah.h> 100#if INET6 101#include <netinet6/ah6.h> 102#endif 103#include <netinet6/esp.h> 104#if INET6 105#include <netinet6/esp6.h> 106#endif 107#include <netkey/key.h> 108#include <netkey/keydb.h> 109 110#include <net/net_osdep.h> 111 112#include <sys/kdebug.h> 113#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1) 114#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3) 115#define DBG_FNC_ESPOUT NETDBG_CODE(DBG_NETIPSEC, (4 << 8)) 116#define DBG_FNC_ENCRYPT NETDBG_CODE(DBG_NETIPSEC, (5 << 8)) 117 118static int esp_output(struct mbuf *, u_char *, struct mbuf *, 119 int, struct secasvar *sav); 120 121extern int esp_udp_encap_port; 122extern u_int32_t natt_now; 123 124extern lck_mtx_t *sadb_mutex; 125 126/* 127 * compute ESP header size. 128 */ 129size_t 130esp_hdrsiz(isr) 131 struct ipsecrequest *isr; 132{ 133 134 /* sanity check */ 135 if (isr == NULL) 136 panic("esp_hdrsiz: NULL was passed.\n"); 137 138 139#if 0 140 lck_mtx_lock(sadb_mutex); 141 { 142 struct secasvar *sav; 143 const struct esp_algorithm *algo; 144 const struct ah_algorithm *aalgo; 145 size_t ivlen; 146 size_t authlen; 147 size_t hdrsiz; 148 size_t maxpad; 149 150 /*%%%% this needs to change - no sav in ipsecrequest any more */ 151 sav = isr->sav; 152 153 if (isr->saidx.proto != IPPROTO_ESP) 154 panic("unsupported mode passed to esp_hdrsiz"); 155 156 if (sav == NULL) 157 goto estimate; 158 if (sav->state != SADB_SASTATE_MATURE 159 && sav->state != SADB_SASTATE_DYING) 160 goto estimate; 161 162 /* we need transport mode ESP. */ 163 algo = esp_algorithm_lookup(sav->alg_enc); 164 if (!algo) 165 goto estimate; 166 ivlen = sav->ivlen; 167 if (ivlen < 0) 168 goto estimate; 169 170 if (algo->padbound) 171 maxpad = algo->padbound; 172 else 173 maxpad = 4; 174 maxpad += 1; /* maximum 'extendsiz' is padbound + 1, see esp_output */ 175 176 if (sav->flags & SADB_X_EXT_OLD) { 177 /* RFC 1827 */ 178 hdrsiz = sizeof(struct esp) + ivlen + maxpad; 179 } else { 180 /* RFC 2406 */ 181 aalgo = ah_algorithm_lookup(sav->alg_auth); 182 if (aalgo && sav->replay && sav->key_auth) 183 authlen = (aalgo->sumsiz)(sav); 184 else 185 authlen = 0; 186 hdrsiz = sizeof(struct newesp) + ivlen + maxpad + authlen; 187 } 188 189 /* 190 * If the security association indicates that NATT is required, 191 * add the size of the NATT encapsulation header: 192 */ 193 if ((sav->flags & SADB_X_EXT_NATT) != 0) hdrsiz += sizeof(struct udphdr) + 4; 194 195 lck_mtx_unlock(sadb_mutex); 196 return hdrsiz; 197 } 198estimate: 199 lck_mtx_unlock(sadb_mutex); 200#endif 201 /* 202 * ASSUMING: 203 * sizeof(struct newesp) > sizeof(struct esp). (8) 204 * esp_max_ivlen() = max ivlen for CBC mode 205 * 17 = (maximum padding length without random padding length) 206 * + (Pad Length field) + (Next Header field). 207 * 64 = maximum ICV we support. 208 * sizeof(struct udphdr) in case NAT traversal is used 209 */ 210 return sizeof(struct newesp) + esp_max_ivlen() + 17 + AH_MAXSUMSIZE + sizeof(struct udphdr); 211} 212 213/* 214 * Modify the packet so that the payload is encrypted. 215 * The mbuf (m) must start with IPv4 or IPv6 header. 216 * On failure, free the given mbuf and return NULL. 217 * 218 * on invocation: 219 * m nexthdrp md 220 * v v v 221 * IP ......... payload 222 * during the encryption: 223 * m nexthdrp mprev md 224 * v v v v 225 * IP ............... esp iv payload pad padlen nxthdr 226 * <--><-><------><---------------> 227 * esplen plen extendsiz 228 * ivlen 229 * <-----> esphlen 230 * <-> hlen 231 * <-----------------> espoff 232 */ 233static int 234esp_output(m, nexthdrp, md, af, sav) 235 struct mbuf *m; 236 u_char *nexthdrp; 237 struct mbuf *md; 238 int af; 239 struct secasvar *sav; 240{ 241 struct mbuf *n; 242 struct mbuf *mprev; 243 struct esp *esp; 244 struct esptail *esptail; 245 const struct esp_algorithm *algo; 246 u_int32_t spi; 247 u_int8_t nxt = 0; 248 size_t plen; /*payload length to be encrypted*/ 249 size_t espoff; 250 int ivlen; 251 int afnumber; 252 size_t extendsiz; 253 int error = 0; 254 struct ipsecstat *stat; 255 struct udphdr *udp = NULL; 256 int udp_encapsulate = (sav->flags & SADB_X_EXT_NATT && af == AF_INET && 257 (esp_udp_encap_port & 0xFFFF) != 0); 258 259 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_START, sav->ivlen,0,0,0,0); 260 switch (af) { 261#if INET 262 case AF_INET: 263 afnumber = 4; 264 stat = &ipsecstat; 265 break; 266#endif 267#if INET6 268 case AF_INET6: 269 afnumber = 6; 270 stat = &ipsec6stat; 271 break; 272#endif 273 default: 274 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af)); 275 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 1,0,0,0,0); 276 return 0; /* no change at all */ 277 } 278 279 /* some sanity check */ 280 if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { 281 switch (af) { 282#if INET 283 case AF_INET: 284 { 285 struct ip *ip; 286 287 ip = mtod(m, struct ip *); 288 ipseclog((LOG_DEBUG, "esp4_output: internal error: " 289 "sav->replay is null: %x->%x, SPI=%u\n", 290 (u_int32_t)ntohl(ip->ip_src.s_addr), 291 (u_int32_t)ntohl(ip->ip_dst.s_addr), 292 (u_int32_t)ntohl(sav->spi))); 293 IPSEC_STAT_INCREMENT(ipsecstat.out_inval); 294 break; 295 } 296#endif /*INET*/ 297#if INET6 298 case AF_INET6: 299 ipseclog((LOG_DEBUG, "esp6_output: internal error: " 300 "sav->replay is null: SPI=%u\n", 301 (u_int32_t)ntohl(sav->spi))); 302 IPSEC_STAT_INCREMENT(ipsec6stat.out_inval); 303 break; 304#endif /*INET6*/ 305 default: 306 panic("esp_output: should not reach here"); 307 } 308 m_freem(m); 309 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 2,0,0,0,0); 310 return EINVAL; 311 } 312 313 algo = esp_algorithm_lookup(sav->alg_enc); 314 if (!algo) { 315 ipseclog((LOG_ERR, "esp_output: unsupported algorithm: " 316 "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); 317 m_freem(m); 318 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 3,0,0,0,0); 319 return EINVAL; 320 } 321 spi = sav->spi; 322 ivlen = sav->ivlen; 323 /* should be okey */ 324 if (ivlen < 0) { 325 panic("invalid ivlen"); 326 } 327 328 { 329 /* 330 * insert ESP header. 331 * XXX inserts ESP header right after IPv4 header. should 332 * chase the header chain. 333 * XXX sequential number 334 */ 335#if INET 336 struct ip *ip = NULL; 337#endif 338#if INET6 339 struct ip6_hdr *ip6 = NULL; 340#endif 341 size_t esplen; /* sizeof(struct esp/newesp) */ 342 size_t esphlen; /* sizeof(struct esp/newesp) + ivlen */ 343 size_t hlen = 0; /* ip header len */ 344 345 if (sav->flags & SADB_X_EXT_OLD) { 346 /* RFC 1827 */ 347 esplen = sizeof(struct esp); 348 } else { 349 /* RFC 2406 */ 350 if (sav->flags & SADB_X_EXT_DERIV) 351 esplen = sizeof(struct esp); 352 else 353 esplen = sizeof(struct newesp); 354 } 355 esphlen = esplen + ivlen; 356 357 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) 358 ; 359 if (mprev == NULL || mprev->m_next != md) { 360 ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n", 361 afnumber)); 362 m_freem(m); 363 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 4,0,0,0,0); 364 return EINVAL; 365 } 366 367 plen = 0; 368 for (n = md; n; n = n->m_next) 369 plen += n->m_len; 370 371 switch (af) { 372#if INET 373 case AF_INET: 374 ip = mtod(m, struct ip *); 375#ifdef _IP_VHL 376 hlen = IP_VHL_HL(ip->ip_vhl) << 2; 377#else 378 hlen = ip->ip_hl << 2; 379#endif 380 break; 381#endif 382#if INET6 383 case AF_INET6: 384 ip6 = mtod(m, struct ip6_hdr *); 385 hlen = sizeof(*ip6); 386 break; 387#endif 388 } 389 390 /* make the packet over-writable */ 391 mprev->m_next = NULL; 392 if ((md = ipsec_copypkt(md)) == NULL) { 393 m_freem(m); 394 error = ENOBUFS; 395 goto fail; 396 } 397 mprev->m_next = md; 398 399 /* 400 * Translate UDP source port back to its original value. 401 * SADB_X_EXT_NATT_MULTIPLEUSERS is only set for transort mode. 402 */ 403 if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0) { 404 /* if not UDP - drop it */ 405 if (ip->ip_p != IPPROTO_UDP) { 406 IPSEC_STAT_INCREMENT(ipsecstat.out_inval); 407 m_freem(m); 408 error = EINVAL; 409 goto fail; 410 } 411 412 udp = mtod(md, struct udphdr *); 413 414 /* if src port not set in sav - find it */ 415 if (sav->natt_encapsulated_src_port == 0) 416 if (key_natt_get_translated_port(sav) == 0) { 417 m_freem(m); 418 error = EINVAL; 419 goto fail; 420 } 421 if (sav->remote_ike_port == htons(udp->uh_dport)) { 422 /* translate UDP port */ 423 udp->uh_dport = sav->natt_encapsulated_src_port; 424 udp->uh_sum = 0; /* don't need checksum with ESP auth */ 425 } else { 426 /* drop the packet - can't translate the port */ 427 IPSEC_STAT_INCREMENT(ipsecstat.out_inval); 428 m_freem(m); 429 error = EINVAL; 430 goto fail; 431 } 432 } 433 434 435 espoff = m->m_pkthdr.len - plen; 436 437 if (udp_encapsulate) { 438 esphlen += sizeof(struct udphdr); 439 espoff += sizeof(struct udphdr); 440 } 441 442 /* 443 * grow the mbuf to accomodate ESP header. 444 * before: IP ... payload 445 * after: IP ... [UDP] ESP IV payload 446 */ 447 if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) { 448 MGET(n, M_DONTWAIT, MT_DATA); 449 if (!n) { 450 m_freem(m); 451 error = ENOBUFS; 452 goto fail; 453 } 454 n->m_len = esphlen; 455 mprev->m_next = n; 456 n->m_next = md; 457 m->m_pkthdr.len += esphlen; 458 if (udp_encapsulate) { 459 udp = mtod(n, struct udphdr *); 460 esp = (struct esp *)(void *)((caddr_t)udp + sizeof(struct udphdr)); 461 } else { 462 esp = mtod(n, struct esp *); 463 } 464 } else { 465 md->m_len += esphlen; 466 md->m_data -= esphlen; 467 m->m_pkthdr.len += esphlen; 468 esp = mtod(md, struct esp *); 469 if (udp_encapsulate) { 470 udp = mtod(md, struct udphdr *); 471 esp = (struct esp *)(void *)((caddr_t)udp + sizeof(struct udphdr)); 472 } else { 473 esp = mtod(md, struct esp *); 474 } 475 } 476 477 switch (af) { 478#if INET 479 case AF_INET: 480 if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len))) 481 ip->ip_len = htons(ntohs(ip->ip_len) + esphlen); 482 else { 483 ipseclog((LOG_ERR, 484 "IPv4 ESP output: size exceeds limit\n")); 485 IPSEC_STAT_INCREMENT(ipsecstat.out_inval); 486 m_freem(m); 487 error = EMSGSIZE; 488 goto fail; 489 } 490 break; 491#endif 492#if INET6 493 case AF_INET6: 494 /* total packet length will be computed in ip6_output() */ 495 break; 496#endif 497 } 498 } 499 500 /* initialize esp header. */ 501 esp->esp_spi = spi; 502 if ((sav->flags & SADB_X_EXT_OLD) == 0) { 503 struct newesp *nesp; 504 nesp = (struct newesp *)esp; 505 if (sav->replay->count == ~0) { 506 if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { 507 /* XXX Is it noisy ? */ 508 ipseclog((LOG_WARNING, 509 "replay counter overflowed. %s\n", 510 ipsec_logsastr(sav))); 511 IPSEC_STAT_INCREMENT(stat->out_inval); 512 m_freem(m); 513 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 5,0,0,0,0); 514 return EINVAL; 515 } 516 } 517 lck_mtx_lock(sadb_mutex); 518 sav->replay->count++; 519 lck_mtx_unlock(sadb_mutex); 520 /* 521 * XXX sequence number must not be cycled, if the SA is 522 * installed by IKE daemon. 523 */ 524 nesp->esp_seq = htonl(sav->replay->count); 525 } 526 527 { 528 /* 529 * find the last mbuf. make some room for ESP trailer. 530 */ 531#if INET 532 struct ip *ip = NULL; 533#endif 534 size_t padbound; 535 u_char *extend; 536 int i; 537 int randpadmax; 538 539 if (algo->padbound) 540 padbound = algo->padbound; 541 else 542 padbound = 4; 543 /* ESP packet, including nxthdr field, must be length of 4n */ 544 if (padbound < 4) 545 padbound = 4; 546 547 extendsiz = padbound - (plen % padbound); 548 if (extendsiz == 1) 549 extendsiz = padbound + 1; 550 551 /* random padding */ 552 switch (af) { 553#if INET 554 case AF_INET: 555 randpadmax = ip4_esp_randpad; 556 break; 557#endif 558#if INET6 559 case AF_INET6: 560 randpadmax = ip6_esp_randpad; 561 break; 562#endif 563 default: 564 randpadmax = -1; 565 break; 566 } 567 if (randpadmax < 0 || plen + extendsiz >= randpadmax) 568 ; 569 else { 570 int pad; 571 572 /* round */ 573 randpadmax = (randpadmax / padbound) * padbound; 574 pad = (randpadmax - plen + extendsiz) / padbound; 575 576 if (pad > 0) 577 pad = (random() % pad) * padbound; 578 else 579 pad = 0; 580 581 /* 582 * make sure we do not pad too much. 583 * MLEN limitation comes from the trailer attachment 584 * code below. 585 * 256 limitation comes from sequential padding. 586 * also, the 1-octet length field in ESP trailer imposes 587 * limitation (but is less strict than sequential padding 588 * as length field do not count the last 2 octets). 589 */ 590 if (extendsiz + pad <= MLEN && extendsiz + pad < 256) 591 extendsiz += pad; 592 } 593 594#if DIAGNOSTIC 595 if (extendsiz > MLEN || extendsiz >= 256) 596 panic("extendsiz too big in esp_output"); 597#endif 598 599 n = m; 600 while (n->m_next) 601 n = n->m_next; 602 603 /* 604 * if M_EXT, the external mbuf data may be shared among 605 * two consequtive TCP packets, and it may be unsafe to use the 606 * trailing space. 607 */ 608 if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) { 609 extend = mtod(n, u_char *) + n->m_len; 610 n->m_len += extendsiz; 611 m->m_pkthdr.len += extendsiz; 612 } else { 613 struct mbuf *nn; 614 615 MGET(nn, M_DONTWAIT, MT_DATA); 616 if (!nn) { 617 ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf", 618 afnumber)); 619 m_freem(m); 620 error = ENOBUFS; 621 goto fail; 622 } 623 extend = mtod(nn, u_char *); 624 nn->m_len = extendsiz; 625 nn->m_next = NULL; 626 n->m_next = nn; 627 n = nn; 628 m->m_pkthdr.len += extendsiz; 629 } 630 switch (sav->flags & SADB_X_EXT_PMASK) { 631 case SADB_X_EXT_PRAND: 632 key_randomfill(extend, extendsiz); 633 break; 634 case SADB_X_EXT_PZERO: 635 bzero(extend, extendsiz); 636 break; 637 case SADB_X_EXT_PSEQ: 638 for (i = 0; i < extendsiz; i++) 639 extend[i] = (i + 1) & 0xff; 640 break; 641 } 642 643 nxt = *nexthdrp; 644 if (udp_encapsulate) { 645 *nexthdrp = IPPROTO_UDP; 646 647 /* Fill out the UDP header */ 648 udp->uh_sport = ntohs((u_short)esp_udp_encap_port); 649 udp->uh_dport = ntohs(sav->remote_ike_port); 650// udp->uh_len set later, after all length tweaks are complete 651 udp->uh_sum = 0; 652 653 /* Update last sent so we know if we need to send keepalive */ 654 sav->natt_last_activity = natt_now; 655 } else { 656 *nexthdrp = IPPROTO_ESP; 657 } 658 659 /* initialize esp trailer. */ 660 esptail = (struct esptail *) 661 (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail)); 662 esptail->esp_nxt = nxt; 663 esptail->esp_padlen = extendsiz - 2; 664 665 /* modify IP header (for ESP header part only) */ 666 switch (af) { 667#if INET 668 case AF_INET: 669 ip = mtod(m, struct ip *); 670 if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len))) 671 ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz); 672 else { 673 ipseclog((LOG_ERR, 674 "IPv4 ESP output: size exceeds limit\n")); 675 IPSEC_STAT_INCREMENT(ipsecstat.out_inval); 676 m_freem(m); 677 error = EMSGSIZE; 678 goto fail; 679 } 680 break; 681#endif 682#if INET6 683 case AF_INET6: 684 /* total packet length will be computed in ip6_output() */ 685 break; 686#endif 687 } 688 } 689 690 /* 691 * pre-compute and cache intermediate key 692 */ 693 error = esp_schedule(algo, sav); 694 if (error) { 695 m_freem(m); 696 IPSEC_STAT_INCREMENT(stat->out_inval); 697 goto fail; 698 } 699 700 /* 701 * encrypt the packet, based on security association 702 * and the algorithm specified. 703 */ 704 if (!algo->encrypt) 705 panic("internal error: no encrypt function"); 706 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_START, 0,0,0,0,0); 707 if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) { 708 /* m is already freed */ 709 ipseclog((LOG_ERR, "packet encryption failure\n")); 710 IPSEC_STAT_INCREMENT(stat->out_inval); 711 error = EINVAL; 712 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 1,error,0,0,0); 713 goto fail; 714 } 715 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 2,0,0,0,0); 716 717 /* 718 * calculate ICV if required. 719 */ 720 if (!sav->replay) 721 goto noantireplay; 722 if (!sav->key_auth) 723 goto noantireplay; 724 if (sav->key_auth == SADB_AALG_NONE) 725 goto noantireplay; 726 727 { 728 const struct ah_algorithm *aalgo; 729 u_char authbuf[AH_MAXSUMSIZE] __attribute__((aligned(4))); 730 u_char *p; 731 size_t siz; 732 #if INET 733 struct ip *ip; 734 #endif 735 736 aalgo = ah_algorithm_lookup(sav->alg_auth); 737 if (!aalgo) 738 goto noantireplay; 739 siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1); 740 if (AH_MAXSUMSIZE < siz) 741 panic("assertion failed for AH_MAXSUMSIZE"); 742 743 if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) { 744 ipseclog((LOG_ERR, "ESP checksum generation failure\n")); 745 m_freem(m); 746 error = EINVAL; 747 IPSEC_STAT_INCREMENT(stat->out_inval); 748 goto fail; 749 } 750 751 n = m; 752 while (n->m_next) 753 n = n->m_next; 754 755 if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */ 756 n->m_len += siz; 757 m->m_pkthdr.len += siz; 758 p = mtod(n, u_char *) + n->m_len - siz; 759 } else { 760 struct mbuf *nn; 761 762 MGET(nn, M_DONTWAIT, MT_DATA); 763 if (!nn) { 764 ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output", 765 afnumber)); 766 m_freem(m); 767 error = ENOBUFS; 768 goto fail; 769 } 770 nn->m_len = siz; 771 nn->m_next = NULL; 772 n->m_next = nn; 773 n = nn; 774 m->m_pkthdr.len += siz; 775 p = mtod(nn, u_char *); 776 } 777 bcopy(authbuf, p, siz); 778 779 /* modify IP header (for ESP header part only) */ 780 switch (af) { 781 #if INET 782 case AF_INET: 783 ip = mtod(m, struct ip *); 784 if (siz < (IP_MAXPACKET - ntohs(ip->ip_len))) 785 ip->ip_len = htons(ntohs(ip->ip_len) + siz); 786 else { 787 ipseclog((LOG_ERR, 788 "IPv4 ESP output: size exceeds limit\n")); 789 IPSEC_STAT_INCREMENT(ipsecstat.out_inval); 790 m_freem(m); 791 error = EMSGSIZE; 792 goto fail; 793 } 794 break; 795 #endif 796 #if INET6 797 case AF_INET6: 798 /* total packet length will be computed in ip6_output() */ 799 break; 800 #endif 801 } 802 } 803 804 if (udp_encapsulate) { 805 struct ip *ip; 806 ip = mtod(m, struct ip *); 807 udp->uh_ulen = htons(ntohs(ip->ip_len) - (IP_VHL_HL(ip->ip_vhl) << 2)); 808 } 809 810 811noantireplay: 812 lck_mtx_lock(sadb_mutex); 813 if (!m) { 814 ipseclog((LOG_ERR, 815 "NULL mbuf after encryption in esp%d_output", afnumber)); 816 } else 817 stat->out_success++; 818 stat->out_esphist[sav->alg_enc]++; 819 lck_mtx_unlock(sadb_mutex); 820 key_sa_recordxfer(sav, m); 821 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 6,0,0,0,0); 822 return 0; 823 824fail: 825#if 1 826 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 7,error,0,0,0); 827 return error; 828#else 829 panic("something bad in esp_output"); 830#endif 831} 832 833#if INET 834int 835esp4_output(m, sav) 836 struct mbuf *m; 837 struct secasvar *sav; 838{ 839 struct ip *ip; 840 if (m->m_len < sizeof(struct ip)) { 841 ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n")); 842 m_freem(m); 843 return EINVAL; 844 } 845 ip = mtod(m, struct ip *); 846 /* XXX assumes that m->m_next points to payload */ 847 return esp_output(m, &ip->ip_p, m->m_next, AF_INET, sav); 848} 849#endif /*INET*/ 850 851#if INET6 852int 853esp6_output(m, nexthdrp, md, sav) 854 struct mbuf *m; 855 u_char *nexthdrp; 856 struct mbuf *md; 857 struct secasvar *sav; 858{ 859 if (m->m_len < sizeof(struct ip6_hdr)) { 860 ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n")); 861 m_freem(m); 862 return EINVAL; 863 } 864 return esp_output(m, nexthdrp, md, AF_INET6, sav); 865} 866#endif /*INET6*/ 867