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