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