]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/esp_output.c
xnu-1699.24.23.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_output.c
CommitLineData
b0d623f7
A
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
55e303ae
A
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 $ */
1c79356b
A
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
1c79356b
A
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>
55e303ae 87#include <netinet/udp.h> /* for nat traversal */
1c79356b
A
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>
9bccf70c
A
96#if INET6
97#include <netinet6/ipsec6.h>
98#endif
1c79356b 99#include <netinet6/ah.h>
9bccf70c
A
100#if INET6
101#include <netinet6/ah6.h>
102#endif
1c79356b 103#include <netinet6/esp.h>
9bccf70c
A
104#if INET6
105#include <netinet6/esp6.h>
106#endif
1c79356b
A
107#include <netkey/key.h>
108#include <netkey/keydb.h>
1c79356b
A
109
110#include <net/net_osdep.h>
111
55e303ae
A
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
91447636 118static int esp_output(struct mbuf *, u_char *, struct mbuf *,
2d21ac55 119 int, struct secasvar *sav);
1c79356b 120
55e303ae
A
121extern int esp_udp_encap_port;
122extern u_int32_t natt_now;
123
2d21ac55
A
124extern lck_mtx_t *sadb_mutex;
125
1c79356b
A
126/*
127 * compute ESP header size.
128 */
129size_t
130esp_hdrsiz(isr)
131 struct ipsecrequest *isr;
132{
1c79356b
A
133
134 /* sanity check */
135 if (isr == NULL)
136 panic("esp_hdrsiz: NULL was passed.\n");
137
1c79356b 138
2d21ac55
A
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;
55e303ae 149
2d21ac55
A
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;
1c79356b 172 else
2d21ac55
A
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;
55e303ae 194
2d21ac55
A
195 lck_mtx_unlock(sadb_mutex);
196 return hdrsiz;
197 }
198estimate:
199 lck_mtx_unlock(sadb_mutex);
200#endif
1c79356b
A
201 /*
202 * ASSUMING:
55e303ae 203 * sizeof(struct newesp) > sizeof(struct esp). (8)
9bccf70c 204 * esp_max_ivlen() = max ivlen for CBC mode
55e303ae 205 * 17 = (maximum padding length without random padding length)
1c79356b 206 * + (Pad Length field) + (Next Header field).
b0d623f7 207 * 64 = maximum ICV we support.
55e303ae 208 * sizeof(struct udphdr) in case NAT traversal is used
1c79356b 209 */
b0d623f7 210 return sizeof(struct newesp) + esp_max_ivlen() + 17 + AH_MAXSUMSIZE + sizeof(struct udphdr);
1c79356b
A
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
2d21ac55 234esp_output(m, nexthdrp, md, af, sav)
1c79356b
A
235 struct mbuf *m;
236 u_char *nexthdrp;
237 struct mbuf *md;
1c79356b 238 int af;
2d21ac55 239 struct secasvar *sav;
1c79356b
A
240{
241 struct mbuf *n;
242 struct mbuf *mprev;
243 struct esp *esp;
244 struct esptail *esptail;
9bccf70c 245 const struct esp_algorithm *algo;
1c79356b
A
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;
9bccf70c 254 struct ipsecstat *stat;
55e303ae
A
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);
1c79356b 258
55e303ae 259 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_START, sav->ivlen,0,0,0,0);
1c79356b
A
260 switch (af) {
261#if INET
262 case AF_INET:
263 afnumber = 4;
9bccf70c 264 stat = &ipsecstat;
1c79356b
A
265 break;
266#endif
267#if INET6
268 case AF_INET6:
269 afnumber = 6;
9bccf70c 270 stat = &ipsec6stat;
1c79356b
A
271 break;
272#endif
273 default:
274 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
55e303ae 275 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 1,0,0,0,0);
1c79356b
A
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)));
2d21ac55 293 IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
9bccf70c 294 break;
1c79356b
A
295 }
296#endif /*INET*/
297#if INET6
298 case AF_INET6:
1c79356b
A
299 ipseclog((LOG_DEBUG, "esp6_output: internal error: "
300 "sav->replay is null: SPI=%u\n",
301 (u_int32_t)ntohl(sav->spi)));
2d21ac55 302 IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
9bccf70c 303 break;
1c79356b 304#endif /*INET6*/
9bccf70c
A
305 default:
306 panic("esp_output: should not reach here");
1c79356b 307 }
9bccf70c 308 m_freem(m);
55e303ae 309 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 2,0,0,0,0);
9bccf70c 310 return EINVAL;
1c79356b
A
311 }
312
9bccf70c
A
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);
55e303ae 318 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 3,0,0,0,0);
9bccf70c
A
319 return EINVAL;
320 }
1c79356b
A
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
55e303ae
A
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 */
1c79356b
A
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);
55e303ae 363 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 4,0,0,0,0);
1c79356b
A
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;
2d21ac55
A
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
1c79356b
A
434
435 espoff = m->m_pkthdr.len - plen;
55e303ae
A
436
437 if (udp_encapsulate) {
438 esphlen += sizeof(struct udphdr);
439 espoff += sizeof(struct udphdr);
440 }
1c79356b
A
441
442 /*
443 * grow the mbuf to accomodate ESP header.
444 * before: IP ... payload
55e303ae 445 * after: IP ... [UDP] ESP IV payload
1c79356b 446 */
9bccf70c 447 if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
1c79356b
A
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;
55e303ae
A
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 }
1c79356b
A
464 } else {
465 md->m_len += esphlen;
466 md->m_data -= esphlen;
467 m->m_pkthdr.len += esphlen;
468 esp = mtod(md, struct esp *);
55e303ae
A
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 }
1c79356b
A
475 }
476
1c79356b
A
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"));
2d21ac55 485 IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
1c79356b
A
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)));
2d21ac55 511 IPSEC_STAT_INCREMENT(stat->out_inval);
1c79356b 512 m_freem(m);
55e303ae 513 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 5,0,0,0,0);
1c79356b
A
514 return EINVAL;
515 }
516 }
2d21ac55 517 lck_mtx_lock(sadb_mutex);
1c79356b 518 sav->replay->count++;
2d21ac55 519 lck_mtx_unlock(sadb_mutex);
1c79356b
A
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.
1c79356b
A
530 */
531#if INET
532 struct ip *ip = NULL;
533#endif
534 size_t padbound;
535 u_char *extend;
536 int i;
9bccf70c 537 int randpadmax;
1c79356b
A
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
9bccf70c
A
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 {
2d21ac55 570 int pad;
9bccf70c
A
571
572 /* round */
573 randpadmax = (randpadmax / padbound) * padbound;
2d21ac55 574 pad = (randpadmax - plen + extendsiz) / padbound;
9bccf70c 575
2d21ac55
A
576 if (pad > 0)
577 pad = (random() % pad) * padbound;
9bccf70c 578 else
2d21ac55 579 pad = 0;
9bccf70c
A
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 */
2d21ac55
A
590 if (extendsiz + pad <= MLEN && extendsiz + pad < 256)
591 extendsiz += pad;
9bccf70c
A
592 }
593
594#if DIAGNOSTIC
595 if (extendsiz > MLEN || extendsiz >= 256)
596 panic("extendsiz too big in esp_output");
597#endif
598
1c79356b
A
599 n = m;
600 while (n->m_next)
601 n = n->m_next;
602
603 /*
9bccf70c
A
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.
1c79356b
A
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:
9bccf70c 632 key_randomfill(extend, extendsiz);
1c79356b
A
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 }
55e303ae
A
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 }
1c79356b
A
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"));
2d21ac55 675 IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
1c79356b
A
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
9bccf70c
A
690 /*
691 * pre-compute and cache intermediate key
692 */
693 error = esp_schedule(algo, sav);
694 if (error) {
695 m_freem(m);
2d21ac55 696 IPSEC_STAT_INCREMENT(stat->out_inval);
9bccf70c
A
697 goto fail;
698 }
699
1c79356b
A
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");
55e303ae 706 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_START, 0,0,0,0,0);
1c79356b 707 if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
9bccf70c 708 /* m is already freed */
1c79356b 709 ipseclog((LOG_ERR, "packet encryption failure\n"));
2d21ac55 710 IPSEC_STAT_INCREMENT(stat->out_inval);
1c79356b 711 error = EINVAL;
55e303ae 712 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 1,error,0,0,0);
1c79356b
A
713 goto fail;
714 }
55e303ae 715 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 2,0,0,0,0);
1c79356b
A
716
717 /*
718 * calculate ICV if required.
719 */
720 if (!sav->replay)
721 goto noantireplay;
722 if (!sav->key_auth)
723 goto noantireplay;
9bccf70c 724 if (sav->key_auth == SADB_AALG_NONE)
1c79356b 725 goto noantireplay;
9bccf70c 726
1c79356b 727 {
2d21ac55
A
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"));
1c79356b 745 m_freem(m);
2d21ac55
A
746 error = EINVAL;
747 IPSEC_STAT_INCREMENT(stat->out_inval);
1c79356b
A
748 goto fail;
749 }
2d21ac55
A
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
1c79356b 801 }
1c79356b 802 }
55e303ae
A
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
1c79356b
A
810
811noantireplay:
2d21ac55 812 lck_mtx_lock(sadb_mutex);
1c79356b
A
813 if (!m) {
814 ipseclog((LOG_ERR,
815 "NULL mbuf after encryption in esp%d_output", afnumber));
9bccf70c
A
816 } else
817 stat->out_success++;
818 stat->out_esphist[sav->alg_enc]++;
2d21ac55 819 lck_mtx_unlock(sadb_mutex);
1c79356b 820 key_sa_recordxfer(sav, m);
55e303ae 821 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 6,0,0,0,0);
1c79356b
A
822 return 0;
823
824fail:
825#if 1
55e303ae 826 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 7,error,0,0,0);
1c79356b
A
827 return error;
828#else
829 panic("something bad in esp_output");
830#endif
831}
832
833#if INET
834int
2d21ac55 835esp4_output(m, sav)
1c79356b 836 struct mbuf *m;
2d21ac55 837 struct secasvar *sav;
1c79356b
A
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);
2d21ac55 843 return EINVAL;
1c79356b
A
844 }
845 ip = mtod(m, struct ip *);
846 /* XXX assumes that m->m_next points to payload */
2d21ac55 847 return esp_output(m, &ip->ip_p, m->m_next, AF_INET, sav);
1c79356b
A
848}
849#endif /*INET*/
850
851#if INET6
852int
2d21ac55 853esp6_output(m, nexthdrp, md, sav)
1c79356b
A
854 struct mbuf *m;
855 u_char *nexthdrp;
856 struct mbuf *md;
2d21ac55 857 struct secasvar *sav;
1c79356b
A
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);
2d21ac55 862 return EINVAL;
1c79356b 863 }
2d21ac55 864 return esp_output(m, nexthdrp, md, AF_INET6, sav);
1c79356b
A
865}
866#endif /*INET6*/