1*42e22086SApple OSS Distributions /*
2*42e22086SApple OSS Distributions * Copyright (c) 2008-2019 Apple Inc. All rights reserved.
3*42e22086SApple OSS Distributions *
4*42e22086SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*42e22086SApple OSS Distributions *
6*42e22086SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*42e22086SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*42e22086SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*42e22086SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*42e22086SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*42e22086SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*42e22086SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*42e22086SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*42e22086SApple OSS Distributions *
15*42e22086SApple OSS Distributions * Please obtain a copy of the License at
16*42e22086SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*42e22086SApple OSS Distributions *
18*42e22086SApple OSS Distributions * The Original Code and all software distributed under the License are
19*42e22086SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*42e22086SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*42e22086SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*42e22086SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*42e22086SApple OSS Distributions * Please see the License for the specific language governing rights and
24*42e22086SApple OSS Distributions * limitations under the License.
25*42e22086SApple OSS Distributions *
26*42e22086SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*42e22086SApple OSS Distributions */
28*42e22086SApple OSS Distributions
29*42e22086SApple OSS Distributions /* $FreeBSD: src/sys/netinet6/ah_output.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $ */
30*42e22086SApple OSS Distributions /* $KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $ */
31*42e22086SApple OSS Distributions
32*42e22086SApple OSS Distributions /*
33*42e22086SApple OSS Distributions * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34*42e22086SApple OSS Distributions * All rights reserved.
35*42e22086SApple OSS Distributions *
36*42e22086SApple OSS Distributions * Redistribution and use in source and binary forms, with or without
37*42e22086SApple OSS Distributions * modification, are permitted provided that the following conditions
38*42e22086SApple OSS Distributions * are met:
39*42e22086SApple OSS Distributions * 1. Redistributions of source code must retain the above copyright
40*42e22086SApple OSS Distributions * notice, this list of conditions and the following disclaimer.
41*42e22086SApple OSS Distributions * 2. Redistributions in binary form must reproduce the above copyright
42*42e22086SApple OSS Distributions * notice, this list of conditions and the following disclaimer in the
43*42e22086SApple OSS Distributions * documentation and/or other materials provided with the distribution.
44*42e22086SApple OSS Distributions * 3. Neither the name of the project nor the names of its contributors
45*42e22086SApple OSS Distributions * may be used to endorse or promote products derived from this software
46*42e22086SApple OSS Distributions * without specific prior written permission.
47*42e22086SApple OSS Distributions *
48*42e22086SApple OSS Distributions * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49*42e22086SApple OSS Distributions * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50*42e22086SApple OSS Distributions * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51*42e22086SApple OSS Distributions * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52*42e22086SApple OSS Distributions * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53*42e22086SApple OSS Distributions * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54*42e22086SApple OSS Distributions * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55*42e22086SApple OSS Distributions * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56*42e22086SApple OSS Distributions * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57*42e22086SApple OSS Distributions * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58*42e22086SApple OSS Distributions * SUCH DAMAGE.
59*42e22086SApple OSS Distributions */
60*42e22086SApple OSS Distributions
61*42e22086SApple OSS Distributions /*
62*42e22086SApple OSS Distributions * RFC1826/2402 authentication header.
63*42e22086SApple OSS Distributions */
64*42e22086SApple OSS Distributions
65*42e22086SApple OSS Distributions #define _IP_VHL
66*42e22086SApple OSS Distributions
67*42e22086SApple OSS Distributions #include <sys/param.h>
68*42e22086SApple OSS Distributions #include <sys/systm.h>
69*42e22086SApple OSS Distributions #include <sys/malloc.h>
70*42e22086SApple OSS Distributions #include <sys/mbuf.h>
71*42e22086SApple OSS Distributions #include <sys/domain.h>
72*42e22086SApple OSS Distributions #include <sys/protosw.h>
73*42e22086SApple OSS Distributions #include <sys/socket.h>
74*42e22086SApple OSS Distributions #include <sys/socketvar.h>
75*42e22086SApple OSS Distributions #include <sys/errno.h>
76*42e22086SApple OSS Distributions #include <sys/time.h>
77*42e22086SApple OSS Distributions #include <sys/kernel.h>
78*42e22086SApple OSS Distributions #include <sys/syslog.h>
79*42e22086SApple OSS Distributions
80*42e22086SApple OSS Distributions #include <net/if.h>
81*42e22086SApple OSS Distributions #include <net/route.h>
82*42e22086SApple OSS Distributions
83*42e22086SApple OSS Distributions #include <netinet/in.h>
84*42e22086SApple OSS Distributions
85*42e22086SApple OSS Distributions #include <netinet/in_systm.h>
86*42e22086SApple OSS Distributions #include <netinet/ip.h>
87*42e22086SApple OSS Distributions #include <netinet/in_var.h>
88*42e22086SApple OSS Distributions
89*42e22086SApple OSS Distributions #include <netinet/ip6.h>
90*42e22086SApple OSS Distributions #include <netinet6/ip6_var.h>
91*42e22086SApple OSS Distributions #include <netinet/icmp6.h>
92*42e22086SApple OSS Distributions
93*42e22086SApple OSS Distributions #include <netinet6/ipsec.h>
94*42e22086SApple OSS Distributions #include <netinet6/ipsec6.h>
95*42e22086SApple OSS Distributions #include <netinet6/ah.h>
96*42e22086SApple OSS Distributions #include <netinet6/ah6.h>
97*42e22086SApple OSS Distributions #include <netkey/key.h>
98*42e22086SApple OSS Distributions #include <netkey/keydb.h>
99*42e22086SApple OSS Distributions
100*42e22086SApple OSS Distributions #include <net/net_osdep.h>
101*42e22086SApple OSS Distributions
102*42e22086SApple OSS Distributions #if INET
103*42e22086SApple OSS Distributions static struct in_addr *ah4_finaldst(struct mbuf *);
104*42e22086SApple OSS Distributions
105*42e22086SApple OSS Distributions static LCK_GRP_DECLARE(sadb_stat_mutex_grp, "sadb_stat");
106*42e22086SApple OSS Distributions static LCK_MTX_DECLARE(sadb_stat_mutex, &sadb_stat_mutex_grp);
107*42e22086SApple OSS Distributions #endif
108*42e22086SApple OSS Distributions
109*42e22086SApple OSS Distributions /*
110*42e22086SApple OSS Distributions * compute AH header size.
111*42e22086SApple OSS Distributions * transport mode only. for tunnel mode, we should implement
112*42e22086SApple OSS Distributions * virtual interface, and control MTU/MSS by the interface MTU.
113*42e22086SApple OSS Distributions */
114*42e22086SApple OSS Distributions size_t
ah_hdrsiz(struct ipsecrequest * isr)115*42e22086SApple OSS Distributions ah_hdrsiz(struct ipsecrequest *isr)
116*42e22086SApple OSS Distributions {
117*42e22086SApple OSS Distributions /* sanity check */
118*42e22086SApple OSS Distributions if (isr == NULL) {
119*42e22086SApple OSS Distributions panic("ah_hdrsiz: NULL was passed.");
120*42e22086SApple OSS Distributions }
121*42e22086SApple OSS Distributions
122*42e22086SApple OSS Distributions if (isr->saidx.proto != IPPROTO_AH) {
123*42e22086SApple OSS Distributions panic("unsupported mode passed to ah_hdrsiz");
124*42e22086SApple OSS Distributions }
125*42e22086SApple OSS Distributions
126*42e22086SApple OSS Distributions #if 0
127*42e22086SApple OSS Distributions {
128*42e22086SApple OSS Distributions lck_mtx_lock(sadb_mutex);
129*42e22086SApple OSS Distributions const struct ah_algorithm *algo;
130*42e22086SApple OSS Distributions size_t hdrsiz;
131*42e22086SApple OSS Distributions
132*42e22086SApple OSS Distributions /*%%%%% this needs to change - no sav in ipsecrequest any more */
133*42e22086SApple OSS Distributions if (isr->sav == NULL) {
134*42e22086SApple OSS Distributions goto estimate;
135*42e22086SApple OSS Distributions }
136*42e22086SApple OSS Distributions if (isr->sav->state != SADB_SASTATE_MATURE
137*42e22086SApple OSS Distributions && isr->sav->state != SADB_SASTATE_DYING) {
138*42e22086SApple OSS Distributions goto estimate;
139*42e22086SApple OSS Distributions }
140*42e22086SApple OSS Distributions
141*42e22086SApple OSS Distributions /* we need transport mode AH. */
142*42e22086SApple OSS Distributions algo = ah_algorithm_lookup(isr->sav->alg_auth);
143*42e22086SApple OSS Distributions if (!algo) {
144*42e22086SApple OSS Distributions goto estimate;
145*42e22086SApple OSS Distributions }
146*42e22086SApple OSS Distributions
147*42e22086SApple OSS Distributions /*
148*42e22086SApple OSS Distributions * XXX
149*42e22086SApple OSS Distributions * right now we don't calcurate the padding size. simply
150*42e22086SApple OSS Distributions * treat the padding size as constant, for simplicity.
151*42e22086SApple OSS Distributions *
152*42e22086SApple OSS Distributions * XXX variable size padding support
153*42e22086SApple OSS Distributions */
154*42e22086SApple OSS Distributions hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1));
155*42e22086SApple OSS Distributions if (isr->sav->flags & SADB_X_EXT_OLD) {
156*42e22086SApple OSS Distributions hdrsiz += sizeof(struct ah);
157*42e22086SApple OSS Distributions } else {
158*42e22086SApple OSS Distributions hdrsiz += sizeof(struct newah);
159*42e22086SApple OSS Distributions }
160*42e22086SApple OSS Distributions
161*42e22086SApple OSS Distributions lck_mtx_unlock(sadb_mutex);
162*42e22086SApple OSS Distributions return hdrsiz;
163*42e22086SApple OSS Distributions }
164*42e22086SApple OSS Distributions
165*42e22086SApple OSS Distributions estimate:
166*42e22086SApple OSS Distributions #endif
167*42e22086SApple OSS Distributions
168*42e22086SApple OSS Distributions //lck_mtx_unlock(sadb_mutex);
169*42e22086SApple OSS Distributions /* ASSUMING:
170*42e22086SApple OSS Distributions * sizeof(struct newah) > sizeof(struct ah).
171*42e22086SApple OSS Distributions * 16 = (16 + 3) & ~(4 - 1).
172*42e22086SApple OSS Distributions */
173*42e22086SApple OSS Distributions return sizeof(struct newah) + 16;
174*42e22086SApple OSS Distributions }
175*42e22086SApple OSS Distributions
176*42e22086SApple OSS Distributions #if INET
177*42e22086SApple OSS Distributions /*
178*42e22086SApple OSS Distributions * Modify the packet so that it includes the authentication data.
179*42e22086SApple OSS Distributions * The mbuf passed must start with IPv4 header.
180*42e22086SApple OSS Distributions *
181*42e22086SApple OSS Distributions * assumes that the first mbuf contains IPv4 header + option only.
182*42e22086SApple OSS Distributions * the function does not modify m.
183*42e22086SApple OSS Distributions */
184*42e22086SApple OSS Distributions int
ah4_output(struct mbuf * m,struct secasvar * sav)185*42e22086SApple OSS Distributions ah4_output(struct mbuf *m, struct secasvar *sav)
186*42e22086SApple OSS Distributions {
187*42e22086SApple OSS Distributions const struct ah_algorithm *algo;
188*42e22086SApple OSS Distributions u_int32_t spi;
189*42e22086SApple OSS Distributions u_char *ahdrpos;
190*42e22086SApple OSS Distributions u_char *ahsumpos = NULL;
191*42e22086SApple OSS Distributions size_t hlen = 0; /*IP header+option in bytes*/
192*42e22086SApple OSS Distributions size_t plen = 0; /*AH payload size in bytes*/
193*42e22086SApple OSS Distributions size_t ahlen = 0; /*plen + sizeof(ah)*/
194*42e22086SApple OSS Distributions struct ip *ip;
195*42e22086SApple OSS Distributions struct in_addr dst = { .s_addr = 0 };
196*42e22086SApple OSS Distributions struct in_addr *finaldst;
197*42e22086SApple OSS Distributions int error;
198*42e22086SApple OSS Distributions
199*42e22086SApple OSS Distributions /* sanity checks */
200*42e22086SApple OSS Distributions if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] == NULL) {
201*42e22086SApple OSS Distributions ip = mtod(m, struct ip *);
202*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG, "ah4_output: internal error: "
203*42e22086SApple OSS Distributions "sav->replay is null: %x->%x, SPI=%u\n",
204*42e22086SApple OSS Distributions (u_int32_t)ntohl(ip->ip_src.s_addr),
205*42e22086SApple OSS Distributions (u_int32_t)ntohl(ip->ip_dst.s_addr),
206*42e22086SApple OSS Distributions (u_int32_t)ntohl(sav->spi)));
207*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
208*42e22086SApple OSS Distributions m_freem(m);
209*42e22086SApple OSS Distributions return EINVAL;
210*42e22086SApple OSS Distributions }
211*42e22086SApple OSS Distributions
212*42e22086SApple OSS Distributions algo = ah_algorithm_lookup(sav->alg_auth);
213*42e22086SApple OSS Distributions if (!algo) {
214*42e22086SApple OSS Distributions ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: "
215*42e22086SApple OSS Distributions "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
216*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
217*42e22086SApple OSS Distributions m_freem(m);
218*42e22086SApple OSS Distributions return EINVAL;
219*42e22086SApple OSS Distributions }
220*42e22086SApple OSS Distributions spi = sav->spi;
221*42e22086SApple OSS Distributions
222*42e22086SApple OSS Distributions /*
223*42e22086SApple OSS Distributions * determine the size to grow.
224*42e22086SApple OSS Distributions */
225*42e22086SApple OSS Distributions if (sav->flags & SADB_X_EXT_OLD) {
226*42e22086SApple OSS Distributions /* RFC 1826 */
227*42e22086SApple OSS Distributions plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
228*42e22086SApple OSS Distributions ahlen = plen + sizeof(struct ah);
229*42e22086SApple OSS Distributions } else {
230*42e22086SApple OSS Distributions /* RFC 2402 */
231*42e22086SApple OSS Distributions plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
232*42e22086SApple OSS Distributions ahlen = plen + sizeof(struct newah);
233*42e22086SApple OSS Distributions }
234*42e22086SApple OSS Distributions
235*42e22086SApple OSS Distributions VERIFY(ahlen <= UINT16_MAX);
236*42e22086SApple OSS Distributions
237*42e22086SApple OSS Distributions /*
238*42e22086SApple OSS Distributions * grow the mbuf to accomodate AH.
239*42e22086SApple OSS Distributions */
240*42e22086SApple OSS Distributions ip = mtod(m, struct ip *);
241*42e22086SApple OSS Distributions #ifdef _IP_VHL
242*42e22086SApple OSS Distributions hlen = IP_VHL_HL(ip->ip_vhl) << 2;
243*42e22086SApple OSS Distributions #else
244*42e22086SApple OSS Distributions hlen = ip->ip_hl << 2;
245*42e22086SApple OSS Distributions #endif
246*42e22086SApple OSS Distributions
247*42e22086SApple OSS Distributions if (m->m_len != hlen) {
248*42e22086SApple OSS Distributions panic("ah4_output: assumption failed (first mbuf length)");
249*42e22086SApple OSS Distributions }
250*42e22086SApple OSS Distributions if (M_LEADINGSPACE(m->m_next) < ahlen) {
251*42e22086SApple OSS Distributions struct mbuf *n;
252*42e22086SApple OSS Distributions MGET(n, M_DONTWAIT, MT_DATA);
253*42e22086SApple OSS Distributions if (!n) {
254*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n",
255*42e22086SApple OSS Distributions __LINE__));
256*42e22086SApple OSS Distributions m_freem(m);
257*42e22086SApple OSS Distributions return ENOBUFS;
258*42e22086SApple OSS Distributions }
259*42e22086SApple OSS Distributions n->m_len = (int32_t)ahlen;
260*42e22086SApple OSS Distributions n->m_next = m->m_next;
261*42e22086SApple OSS Distributions m->m_next = n;
262*42e22086SApple OSS Distributions m->m_pkthdr.len += ahlen;
263*42e22086SApple OSS Distributions ahdrpos = mtod(n, u_char *);
264*42e22086SApple OSS Distributions } else {
265*42e22086SApple OSS Distributions m->m_next->m_len += ahlen;
266*42e22086SApple OSS Distributions m->m_next->m_data -= ahlen;
267*42e22086SApple OSS Distributions m->m_pkthdr.len += ahlen;
268*42e22086SApple OSS Distributions ahdrpos = mtod(m->m_next, u_char *);
269*42e22086SApple OSS Distributions }
270*42e22086SApple OSS Distributions
271*42e22086SApple OSS Distributions ip = mtod(m, struct ip *); /*just to be sure*/
272*42e22086SApple OSS Distributions
273*42e22086SApple OSS Distributions /*
274*42e22086SApple OSS Distributions * initialize AH.
275*42e22086SApple OSS Distributions */
276*42e22086SApple OSS Distributions if (sav->flags & SADB_X_EXT_OLD) {
277*42e22086SApple OSS Distributions struct ah *ahdr;
278*42e22086SApple OSS Distributions
279*42e22086SApple OSS Distributions VERIFY((plen >> 2) <= UINT8_MAX);
280*42e22086SApple OSS Distributions ahdr = (struct ah *)(void *)ahdrpos;
281*42e22086SApple OSS Distributions ahsumpos = (u_char *)(ahdr + 1);
282*42e22086SApple OSS Distributions ahdr->ah_len = (u_int8_t)(plen >> 2);
283*42e22086SApple OSS Distributions ahdr->ah_nxt = ip->ip_p;
284*42e22086SApple OSS Distributions ahdr->ah_reserve = htons(0);
285*42e22086SApple OSS Distributions ahdr->ah_spi = spi;
286*42e22086SApple OSS Distributions bzero(ahdr + 1, plen);
287*42e22086SApple OSS Distributions } else {
288*42e22086SApple OSS Distributions struct newah *ahdr;
289*42e22086SApple OSS Distributions
290*42e22086SApple OSS Distributions VERIFY(((plen >> 2) + 1) <= UINT8_MAX);
291*42e22086SApple OSS Distributions ahdr = (struct newah *)(void *)ahdrpos;
292*42e22086SApple OSS Distributions ahsumpos = (u_char *)(ahdr + 1);
293*42e22086SApple OSS Distributions ahdr->ah_len = (u_int8_t)((plen >> 2) + 1); /* plus one for seq# */
294*42e22086SApple OSS Distributions ahdr->ah_nxt = ip->ip_p;
295*42e22086SApple OSS Distributions ahdr->ah_reserve = htons(0);
296*42e22086SApple OSS Distributions ahdr->ah_spi = spi;
297*42e22086SApple OSS Distributions if (sav->replay[0]->count == ~0) {
298*42e22086SApple OSS Distributions if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
299*42e22086SApple OSS Distributions /* XXX Is it noisy ? */
300*42e22086SApple OSS Distributions ipseclog((LOG_WARNING,
301*42e22086SApple OSS Distributions "replay counter overflowed. %s\n",
302*42e22086SApple OSS Distributions ipsec_logsastr(sav)));
303*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
304*42e22086SApple OSS Distributions m_freem(m);
305*42e22086SApple OSS Distributions return EINVAL;
306*42e22086SApple OSS Distributions }
307*42e22086SApple OSS Distributions }
308*42e22086SApple OSS Distributions lck_mtx_lock(sadb_mutex);
309*42e22086SApple OSS Distributions sav->replay[0]->count++;
310*42e22086SApple OSS Distributions lck_mtx_unlock(sadb_mutex);
311*42e22086SApple OSS Distributions /*
312*42e22086SApple OSS Distributions * XXX sequence number must not be cycled, if the SA is
313*42e22086SApple OSS Distributions * installed by IKE daemon.
314*42e22086SApple OSS Distributions */
315*42e22086SApple OSS Distributions ahdr->ah_seq = htonl(sav->replay[0]->count);
316*42e22086SApple OSS Distributions bzero(ahdr + 1, plen);
317*42e22086SApple OSS Distributions }
318*42e22086SApple OSS Distributions
319*42e22086SApple OSS Distributions /*
320*42e22086SApple OSS Distributions * modify IPv4 header.
321*42e22086SApple OSS Distributions */
322*42e22086SApple OSS Distributions ip->ip_p = IPPROTO_AH;
323*42e22086SApple OSS Distributions if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len))) {
324*42e22086SApple OSS Distributions ip->ip_len = htons(ntohs(ip->ip_len) + (u_int16_t)ahlen);
325*42e22086SApple OSS Distributions } else {
326*42e22086SApple OSS Distributions ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n"));
327*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
328*42e22086SApple OSS Distributions m_freem(m);
329*42e22086SApple OSS Distributions return EMSGSIZE;
330*42e22086SApple OSS Distributions }
331*42e22086SApple OSS Distributions
332*42e22086SApple OSS Distributions /*
333*42e22086SApple OSS Distributions * If there is source routing option, update destination field in
334*42e22086SApple OSS Distributions * the IPv4 header to the final destination.
335*42e22086SApple OSS Distributions * Note that we do not need to update source routing option itself
336*42e22086SApple OSS Distributions * (as done in IPv4 AH processing -- see ip6_output()), since
337*42e22086SApple OSS Distributions * source routing option is not part of the ICV computation.
338*42e22086SApple OSS Distributions */
339*42e22086SApple OSS Distributions finaldst = ah4_finaldst(m);
340*42e22086SApple OSS Distributions if (finaldst) {
341*42e22086SApple OSS Distributions dst.s_addr = ip->ip_dst.s_addr;
342*42e22086SApple OSS Distributions ip->ip_dst.s_addr = finaldst->s_addr;
343*42e22086SApple OSS Distributions }
344*42e22086SApple OSS Distributions
345*42e22086SApple OSS Distributions /*
346*42e22086SApple OSS Distributions * calcurate the checksum, based on security association
347*42e22086SApple OSS Distributions * and the algorithm specified.
348*42e22086SApple OSS Distributions */
349*42e22086SApple OSS Distributions error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
350*42e22086SApple OSS Distributions if (error) {
351*42e22086SApple OSS Distributions ipseclog((LOG_ERR,
352*42e22086SApple OSS Distributions "error after ah4_calccksum, called from ah4_output"));
353*42e22086SApple OSS Distributions m_freem(m);
354*42e22086SApple OSS Distributions m = NULL;
355*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
356*42e22086SApple OSS Distributions return error;
357*42e22086SApple OSS Distributions }
358*42e22086SApple OSS Distributions
359*42e22086SApple OSS Distributions if (finaldst) {
360*42e22086SApple OSS Distributions ip = mtod(m, struct ip *); /*just to make sure*/
361*42e22086SApple OSS Distributions ip->ip_dst.s_addr = dst.s_addr;
362*42e22086SApple OSS Distributions }
363*42e22086SApple OSS Distributions lck_mtx_lock(&sadb_stat_mutex);
364*42e22086SApple OSS Distributions ipsecstat.out_success++;
365*42e22086SApple OSS Distributions ipsecstat.out_ahhist[sav->alg_auth]++;
366*42e22086SApple OSS Distributions lck_mtx_unlock(&sadb_stat_mutex);
367*42e22086SApple OSS Distributions key_sa_recordxfer(sav, m);
368*42e22086SApple OSS Distributions
369*42e22086SApple OSS Distributions return 0;
370*42e22086SApple OSS Distributions }
371*42e22086SApple OSS Distributions #endif
372*42e22086SApple OSS Distributions
373*42e22086SApple OSS Distributions /* Calculate AH length */
374*42e22086SApple OSS Distributions size_t
ah_hdrlen(struct secasvar * sav)375*42e22086SApple OSS Distributions ah_hdrlen(struct secasvar *sav)
376*42e22086SApple OSS Distributions {
377*42e22086SApple OSS Distributions const struct ah_algorithm *algo;
378*42e22086SApple OSS Distributions size_t plen, ahlen;
379*42e22086SApple OSS Distributions
380*42e22086SApple OSS Distributions algo = ah_algorithm_lookup(sav->alg_auth);
381*42e22086SApple OSS Distributions if (!algo) {
382*42e22086SApple OSS Distributions return 0;
383*42e22086SApple OSS Distributions }
384*42e22086SApple OSS Distributions if (sav->flags & SADB_X_EXT_OLD) {
385*42e22086SApple OSS Distributions /* RFC 1826 */
386*42e22086SApple OSS Distributions plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
387*42e22086SApple OSS Distributions ahlen = plen + sizeof(struct ah);
388*42e22086SApple OSS Distributions } else {
389*42e22086SApple OSS Distributions /* RFC 2402 */
390*42e22086SApple OSS Distributions plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
391*42e22086SApple OSS Distributions ahlen = plen + sizeof(struct newah);
392*42e22086SApple OSS Distributions }
393*42e22086SApple OSS Distributions
394*42e22086SApple OSS Distributions return ahlen;
395*42e22086SApple OSS Distributions }
396*42e22086SApple OSS Distributions
397*42e22086SApple OSS Distributions /*
398*42e22086SApple OSS Distributions * Fill in the Authentication Header and calculate checksum.
399*42e22086SApple OSS Distributions */
400*42e22086SApple OSS Distributions int
ah6_output(struct mbuf * m,u_char * nexthdrp,struct mbuf * md,struct secasvar * sav)401*42e22086SApple OSS Distributions ah6_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
402*42e22086SApple OSS Distributions struct secasvar *sav)
403*42e22086SApple OSS Distributions {
404*42e22086SApple OSS Distributions struct mbuf *mprev;
405*42e22086SApple OSS Distributions struct mbuf *mah;
406*42e22086SApple OSS Distributions const struct ah_algorithm *algo;
407*42e22086SApple OSS Distributions u_int32_t spi;
408*42e22086SApple OSS Distributions u_char *ahsumpos = NULL;
409*42e22086SApple OSS Distributions size_t plen; /*AH payload size in bytes*/
410*42e22086SApple OSS Distributions int error = 0;
411*42e22086SApple OSS Distributions size_t ahlen;
412*42e22086SApple OSS Distributions struct ip6_hdr *ip6;
413*42e22086SApple OSS Distributions
414*42e22086SApple OSS Distributions if (m->m_len < sizeof(struct ip6_hdr)) {
415*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n"));
416*42e22086SApple OSS Distributions m_freem(m);
417*42e22086SApple OSS Distributions return EINVAL;
418*42e22086SApple OSS Distributions }
419*42e22086SApple OSS Distributions
420*42e22086SApple OSS Distributions ahlen = ah_hdrlen(sav);
421*42e22086SApple OSS Distributions if (ahlen == 0) {
422*42e22086SApple OSS Distributions return 0;
423*42e22086SApple OSS Distributions }
424*42e22086SApple OSS Distributions
425*42e22086SApple OSS Distributions VERIFY(ahlen <= UINT16_MAX);
426*42e22086SApple OSS Distributions
427*42e22086SApple OSS Distributions for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) {
428*42e22086SApple OSS Distributions ;
429*42e22086SApple OSS Distributions }
430*42e22086SApple OSS Distributions if (!mprev || mprev->m_next != md) {
431*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n"));
432*42e22086SApple OSS Distributions m_freem(m);
433*42e22086SApple OSS Distributions return EINVAL;
434*42e22086SApple OSS Distributions }
435*42e22086SApple OSS Distributions
436*42e22086SApple OSS Distributions MGET(mah, M_DONTWAIT, MT_DATA);
437*42e22086SApple OSS Distributions if (!mah) {
438*42e22086SApple OSS Distributions m_freem(m);
439*42e22086SApple OSS Distributions return ENOBUFS;
440*42e22086SApple OSS Distributions }
441*42e22086SApple OSS Distributions if (ahlen > MLEN) {
442*42e22086SApple OSS Distributions MCLGET(mah, M_DONTWAIT);
443*42e22086SApple OSS Distributions if ((mah->m_flags & M_EXT) == 0) {
444*42e22086SApple OSS Distributions m_free(mah);
445*42e22086SApple OSS Distributions m_freem(m);
446*42e22086SApple OSS Distributions return ENOBUFS;
447*42e22086SApple OSS Distributions }
448*42e22086SApple OSS Distributions }
449*42e22086SApple OSS Distributions mah->m_len = (int32_t)ahlen;
450*42e22086SApple OSS Distributions mah->m_next = md;
451*42e22086SApple OSS Distributions mprev->m_next = mah;
452*42e22086SApple OSS Distributions m->m_pkthdr.len += ahlen;
453*42e22086SApple OSS Distributions
454*42e22086SApple OSS Distributions /* fix plen */
455*42e22086SApple OSS Distributions if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) {
456*42e22086SApple OSS Distributions ipseclog((LOG_ERR,
457*42e22086SApple OSS Distributions "ip6_output: AH with IPv6 jumbogram is not supported\n"));
458*42e22086SApple OSS Distributions m_freem(m);
459*42e22086SApple OSS Distributions return EINVAL;
460*42e22086SApple OSS Distributions }
461*42e22086SApple OSS Distributions
462*42e22086SApple OSS Distributions ip6 = mtod(m, struct ip6_hdr *);
463*42e22086SApple OSS Distributions ip6->ip6_plen = htons((u_int16_t)(m->m_pkthdr.len - sizeof(struct ip6_hdr)));
464*42e22086SApple OSS Distributions
465*42e22086SApple OSS Distributions if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] == NULL) {
466*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG, "ah6_output: internal error: "
467*42e22086SApple OSS Distributions "sav->replay is null: SPI=%u\n",
468*42e22086SApple OSS Distributions (u_int32_t)ntohl(sav->spi)));
469*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
470*42e22086SApple OSS Distributions m_freem(m);
471*42e22086SApple OSS Distributions return EINVAL;
472*42e22086SApple OSS Distributions }
473*42e22086SApple OSS Distributions
474*42e22086SApple OSS Distributions algo = ah_algorithm_lookup(sav->alg_auth);
475*42e22086SApple OSS Distributions if (!algo) {
476*42e22086SApple OSS Distributions ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: "
477*42e22086SApple OSS Distributions "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
478*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
479*42e22086SApple OSS Distributions m_freem(m);
480*42e22086SApple OSS Distributions return EINVAL;
481*42e22086SApple OSS Distributions }
482*42e22086SApple OSS Distributions spi = sav->spi;
483*42e22086SApple OSS Distributions
484*42e22086SApple OSS Distributions /*
485*42e22086SApple OSS Distributions * initialize AH.
486*42e22086SApple OSS Distributions */
487*42e22086SApple OSS Distributions if (sav->flags & SADB_X_EXT_OLD) {
488*42e22086SApple OSS Distributions struct ah *ahdr = mtod(mah, struct ah *);
489*42e22086SApple OSS Distributions
490*42e22086SApple OSS Distributions plen = mah->m_len - sizeof(struct ah);
491*42e22086SApple OSS Distributions VERIFY((plen >> 2) <= UINT8_MAX);
492*42e22086SApple OSS Distributions ahsumpos = (u_char *)(ahdr + 1);
493*42e22086SApple OSS Distributions ahdr->ah_nxt = *nexthdrp;
494*42e22086SApple OSS Distributions *nexthdrp = IPPROTO_AH;
495*42e22086SApple OSS Distributions ahdr->ah_len = (u_int8_t)(plen >> 2);
496*42e22086SApple OSS Distributions ahdr->ah_reserve = htons(0);
497*42e22086SApple OSS Distributions ahdr->ah_spi = spi;
498*42e22086SApple OSS Distributions bzero(ahdr + 1, plen);
499*42e22086SApple OSS Distributions } else {
500*42e22086SApple OSS Distributions struct newah *ahdr = mtod(mah, struct newah *);
501*42e22086SApple OSS Distributions
502*42e22086SApple OSS Distributions plen = mah->m_len - sizeof(struct newah);
503*42e22086SApple OSS Distributions VERIFY(((plen >> 2) + 1) <= UINT8_MAX);
504*42e22086SApple OSS Distributions ahsumpos = (u_char *)(ahdr + 1);
505*42e22086SApple OSS Distributions ahdr->ah_nxt = *nexthdrp;
506*42e22086SApple OSS Distributions *nexthdrp = IPPROTO_AH;
507*42e22086SApple OSS Distributions ahdr->ah_len = (u_int8_t)((plen >> 2) + 1); /* plus one for seq# */
508*42e22086SApple OSS Distributions ahdr->ah_reserve = htons(0);
509*42e22086SApple OSS Distributions ahdr->ah_spi = spi;
510*42e22086SApple OSS Distributions if (sav->replay[0]->count == ~0) {
511*42e22086SApple OSS Distributions if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
512*42e22086SApple OSS Distributions /* XXX Is it noisy ? */
513*42e22086SApple OSS Distributions ipseclog((LOG_WARNING,
514*42e22086SApple OSS Distributions "replay counter overflowed. %s\n",
515*42e22086SApple OSS Distributions ipsec_logsastr(sav)));
516*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
517*42e22086SApple OSS Distributions m_freem(m);
518*42e22086SApple OSS Distributions return EINVAL;
519*42e22086SApple OSS Distributions }
520*42e22086SApple OSS Distributions }
521*42e22086SApple OSS Distributions lck_mtx_lock(sadb_mutex);
522*42e22086SApple OSS Distributions sav->replay[0]->count++;
523*42e22086SApple OSS Distributions lck_mtx_unlock(sadb_mutex);
524*42e22086SApple OSS Distributions /*
525*42e22086SApple OSS Distributions * XXX sequence number must not be cycled, if the SA is
526*42e22086SApple OSS Distributions * installed by IKE daemon.
527*42e22086SApple OSS Distributions */
528*42e22086SApple OSS Distributions ahdr->ah_seq = htonl(sav->replay[0]->count);
529*42e22086SApple OSS Distributions bzero(ahdr + 1, plen);
530*42e22086SApple OSS Distributions }
531*42e22086SApple OSS Distributions
532*42e22086SApple OSS Distributions /*
533*42e22086SApple OSS Distributions * calcurate the checksum, based on security association
534*42e22086SApple OSS Distributions * and the algorithm specified.
535*42e22086SApple OSS Distributions */
536*42e22086SApple OSS Distributions error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
537*42e22086SApple OSS Distributions if (error) {
538*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
539*42e22086SApple OSS Distributions m_freem(m);
540*42e22086SApple OSS Distributions } else {
541*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsec6stat.out_success);
542*42e22086SApple OSS Distributions key_sa_recordxfer(sav, m);
543*42e22086SApple OSS Distributions }
544*42e22086SApple OSS Distributions IPSEC_STAT_INCREMENT(ipsec6stat.out_ahhist[sav->alg_auth]);
545*42e22086SApple OSS Distributions
546*42e22086SApple OSS Distributions return error;
547*42e22086SApple OSS Distributions }
548*42e22086SApple OSS Distributions
549*42e22086SApple OSS Distributions /*
550*42e22086SApple OSS Distributions * Find the final destination if there is loose/strict source routing option.
551*42e22086SApple OSS Distributions * Returns NULL if there's no source routing options.
552*42e22086SApple OSS Distributions * Returns NULL on errors too.
553*42e22086SApple OSS Distributions * Note that this function will return a pointer INTO the given parameter,
554*42e22086SApple OSS Distributions * struct mbuf *m.
555*42e22086SApple OSS Distributions * The mbuf must be pulled up toward, at least, ip option part.
556*42e22086SApple OSS Distributions */
557*42e22086SApple OSS Distributions static struct in_addr *
ah4_finaldst(struct mbuf * m)558*42e22086SApple OSS Distributions ah4_finaldst(struct mbuf *m)
559*42e22086SApple OSS Distributions {
560*42e22086SApple OSS Distributions struct ip *ip;
561*42e22086SApple OSS Distributions int optlen;
562*42e22086SApple OSS Distributions u_char *q;
563*42e22086SApple OSS Distributions int i;
564*42e22086SApple OSS Distributions int hlen;
565*42e22086SApple OSS Distributions
566*42e22086SApple OSS Distributions if (!m) {
567*42e22086SApple OSS Distributions panic("ah4_finaldst: m == NULL");
568*42e22086SApple OSS Distributions }
569*42e22086SApple OSS Distributions ip = mtod(m, struct ip *);
570*42e22086SApple OSS Distributions #ifdef _IP_VHL
571*42e22086SApple OSS Distributions hlen = IP_VHL_HL(ip->ip_vhl) << 2;
572*42e22086SApple OSS Distributions #else
573*42e22086SApple OSS Distributions hlen = ip->ip_hl << 2;
574*42e22086SApple OSS Distributions #endif
575*42e22086SApple OSS Distributions
576*42e22086SApple OSS Distributions if (m->m_len < hlen) {
577*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG,
578*42e22086SApple OSS Distributions "ah4_finaldst: parameter mbuf wrong (not pulled up)\n"));
579*42e22086SApple OSS Distributions return NULL;
580*42e22086SApple OSS Distributions }
581*42e22086SApple OSS Distributions
582*42e22086SApple OSS Distributions if (hlen == sizeof(struct ip)) {
583*42e22086SApple OSS Distributions return NULL;
584*42e22086SApple OSS Distributions }
585*42e22086SApple OSS Distributions
586*42e22086SApple OSS Distributions optlen = hlen - sizeof(struct ip);
587*42e22086SApple OSS Distributions if (optlen < 0) {
588*42e22086SApple OSS Distributions ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n",
589*42e22086SApple OSS Distributions optlen));
590*42e22086SApple OSS Distributions return NULL;
591*42e22086SApple OSS Distributions }
592*42e22086SApple OSS Distributions
593*42e22086SApple OSS Distributions q = (u_char *)(ip + 1);
594*42e22086SApple OSS Distributions i = 0;
595*42e22086SApple OSS Distributions while (i < optlen) {
596*42e22086SApple OSS Distributions if (i + IPOPT_OPTVAL >= optlen) {
597*42e22086SApple OSS Distributions return NULL;
598*42e22086SApple OSS Distributions }
599*42e22086SApple OSS Distributions if (q[i + IPOPT_OPTVAL] == IPOPT_EOL ||
600*42e22086SApple OSS Distributions q[i + IPOPT_OPTVAL] == IPOPT_NOP ||
601*42e22086SApple OSS Distributions i + IPOPT_OLEN < optlen) {
602*42e22086SApple OSS Distributions ;
603*42e22086SApple OSS Distributions } else {
604*42e22086SApple OSS Distributions return NULL;
605*42e22086SApple OSS Distributions }
606*42e22086SApple OSS Distributions
607*42e22086SApple OSS Distributions switch (q[i + IPOPT_OPTVAL]) {
608*42e22086SApple OSS Distributions case IPOPT_EOL:
609*42e22086SApple OSS Distributions i = optlen; /* bye */
610*42e22086SApple OSS Distributions break;
611*42e22086SApple OSS Distributions case IPOPT_NOP:
612*42e22086SApple OSS Distributions i++;
613*42e22086SApple OSS Distributions break;
614*42e22086SApple OSS Distributions case IPOPT_LSRR:
615*42e22086SApple OSS Distributions case IPOPT_SSRR:
616*42e22086SApple OSS Distributions if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) ||
617*42e22086SApple OSS Distributions optlen - i < q[i + IPOPT_OLEN]) {
618*42e22086SApple OSS Distributions ipseclog((LOG_ERR,
619*42e22086SApple OSS Distributions "ip_finaldst: invalid IP option "
620*42e22086SApple OSS Distributions "(code=%02x len=%02x)\n",
621*42e22086SApple OSS Distributions q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
622*42e22086SApple OSS Distributions return NULL;
623*42e22086SApple OSS Distributions }
624*42e22086SApple OSS Distributions i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
625*42e22086SApple OSS Distributions return (struct in_addr *)(void *)(q + i);
626*42e22086SApple OSS Distributions default:
627*42e22086SApple OSS Distributions if (q[i + IPOPT_OLEN] < 2 ||
628*42e22086SApple OSS Distributions optlen - i < q[i + IPOPT_OLEN]) {
629*42e22086SApple OSS Distributions ipseclog((LOG_ERR,
630*42e22086SApple OSS Distributions "ip_finaldst: invalid IP option "
631*42e22086SApple OSS Distributions "(code=%02x len=%02x)\n",
632*42e22086SApple OSS Distributions q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
633*42e22086SApple OSS Distributions return NULL;
634*42e22086SApple OSS Distributions }
635*42e22086SApple OSS Distributions i += q[i + IPOPT_OLEN];
636*42e22086SApple OSS Distributions break;
637*42e22086SApple OSS Distributions }
638*42e22086SApple OSS Distributions }
639*42e22086SApple OSS Distributions return NULL;
640*42e22086SApple OSS Distributions }
641