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