]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_output.c
xnu-1504.9.37.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_output.c
1 /*
2 * Copyright (c) 2008 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(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 }
198 estimate:
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 */
233 static int
234 esp_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 *)((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 *)((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];
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
811 noantireplay:
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
824 fail:
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
834 int
835 esp4_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
852 int
853 esp6_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*/