]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ah_input.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / ah_input.c
CommitLineData
b0d623f7 1/*
eb6b6ca3 2 * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
b0d623f7
A
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.
39037602 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
b0d623f7
A
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.
39037602 25 *
b0d623f7
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
55e303ae
A
29/* $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $ */
30/* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $ */
9bccf70c 31
1c79356b
A
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/*
62 * RFC1826/2402 authentication header.
63 */
64
1c79356b
A
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/malloc.h>
68#include <sys/mbuf.h>
316670eb 69#include <sys/mcache.h>
1c79356b
A
70#include <sys/domain.h>
71#include <sys/protosw.h>
72#include <sys/socket.h>
73#include <sys/errno.h>
74#include <sys/time.h>
75#include <sys/kernel.h>
76#include <sys/syslog.h>
77
78#include <net/if.h>
fe8ab488 79#include <net/if_ipsec.h>
1c79356b 80#include <net/route.h>
1c79356b 81#include <kern/cpu_number.h>
91447636 82#include <kern/locks.h>
1c79356b
A
83
84#include <netinet/in.h>
85#include <netinet/in_systm.h>
86#include <netinet/in_var.h>
87#include <netinet/ip.h>
88#include <netinet/ip_var.h>
89#include <netinet/ip_ecn.h>
9bccf70c 90#include <netinet/in_pcb.h>
9bccf70c 91#include <netinet6/ip6_ecn.h>
1c79356b 92
1c79356b
A
93#include <netinet/ip6.h>
94#include <netinet6/ip6_var.h>
9bccf70c 95#include <netinet6/in6_pcb.h>
1c79356b 96#include <netinet/icmp6.h>
9bccf70c 97#include <netinet6/ip6protosw.h>
1c79356b
A
98
99#include <netinet6/ipsec.h>
9bccf70c 100#include <netinet6/ipsec6.h>
1c79356b 101#include <netinet6/ah.h>
9bccf70c 102#include <netinet6/ah6.h>
1c79356b
A
103#include <netkey/key.h>
104#include <netkey/keydb.h>
9bccf70c 105#if IPSEC_DEBUG
1c79356b 106#include <netkey/key_debug.h>
9bccf70c 107#else
0a7de745 108#define KEYDEBUG(lev, arg)
9bccf70c 109#endif
1c79356b 110
2d21ac55
A
111#include <net/kpi_protocol.h>
112#include <netinet/kpi_ipfilter_var.h>
6d2010ae 113#include <mach/sdt.h>
1c79356b
A
114
115#include <net/net_osdep.h>
116
117#define IPLEN_FLIPPED
118
cb323159
A
119extern lck_mtx_t *sadb_mutex;
120
1c79356b 121#if INET
1c79356b
A
122void
123ah4_input(struct mbuf *m, int off)
124{
125 struct ip *ip;
126 struct ah *ah;
127 u_int32_t spi;
9bccf70c 128 const struct ah_algorithm *algo;
1c79356b
A
129 size_t siz;
130 size_t siz1;
131 u_char *cksum;
132 struct secasvar *sav = NULL;
133 u_int16_t nxt;
f427ee49 134 u_int8_t hlen;
9bccf70c 135 size_t stripsiz = 0;
2d21ac55 136 sa_family_t ifamily;
1c79356b 137
1c79356b
A
138 if (m->m_len < off + sizeof(struct newah)) {
139 m = m_pullup(m, off + sizeof(struct newah));
140 if (!m) {
141 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
0a7de745 142 "dropping the packet for simplicity\n"));
2d21ac55 143 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
144 goto fail;
145 }
146 }
147
316670eb
A
148 /* Expect 32-bit aligned data pointer on strict-align platforms */
149 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
150
1c79356b 151 ip = mtod(m, struct ip *);
316670eb 152 ah = (struct ah *)(void *)(((caddr_t)ip) + off);
1c79356b
A
153 nxt = ah->ah_nxt;
154#ifdef _IP_VHL
f427ee49 155 hlen = (u_int8_t)(IP_VHL_HL(ip->ip_vhl) << 2);
1c79356b 156#else
f427ee49 157 hlen = (u_int8_t)(ip->ip_hl << 2);
1c79356b
A
158#endif
159
160 /* find the sassoc. */
161 spi = ah->ah_spi;
162
163 if ((sav = key_allocsa(AF_INET,
0a7de745
A
164 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
165 IPPROTO_AH, spi)) == 0) {
1c79356b
A
166 ipseclog((LOG_WARNING,
167 "IPv4 AH input: no key association found for spi %u\n",
168 (u_int32_t)ntohl(spi)));
2d21ac55 169 IPSEC_STAT_INCREMENT(ipsecstat.in_nosa);
1c79356b
A
170 goto fail;
171 }
172 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
173 printf("DP ah4_input called to allocate SA:0x%llx\n",
174 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
1c79356b 175 if (sav->state != SADB_SASTATE_MATURE
0a7de745 176 && sav->state != SADB_SASTATE_DYING) {
1c79356b
A
177 ipseclog((LOG_DEBUG,
178 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
179 (u_int32_t)ntohl(spi)));
2d21ac55 180 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
1c79356b
A
181 goto fail;
182 }
9bccf70c
A
183
184 algo = ah_algorithm_lookup(sav->alg_auth);
185 if (!algo) {
1c79356b 186 ipseclog((LOG_DEBUG, "IPv4 AH input: "
9bccf70c 187 "unsupported authentication algorithm for spi %u\n",
1c79356b 188 (u_int32_t)ntohl(spi)));
2d21ac55 189 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
1c79356b
A
190 goto fail;
191 }
192
1c79356b
A
193 siz = (*algo->sumsiz)(sav);
194 siz1 = ((siz + 3) & ~(4 - 1));
195
196 /*
197 * sanity checks for header, 1.
198 */
0a7de745
A
199 {
200 int sizoff;
1c79356b 201
0a7de745 202 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
1c79356b 203
0a7de745
A
204 /*
205 * Here, we do not do "siz1 == siz". This is because the way
206 * RFC240[34] section 2 is written. They do not require truncation
207 * to 96 bits.
208 * For example, Microsoft IPsec stack attaches 160 bits of
209 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
210 * 32 bits of padding is attached.
211 *
212 * There are two downsides to this specification.
213 * They have no real harm, however, they leave us fuzzy feeling.
214 * - if we attach more than 96 bits of authentication data onto AH,
215 * we will never notice about possible modification by rogue
216 * intermediate nodes.
217 * Since extra bits in AH checksum is never used, this constitutes
218 * no real issue, however, it is wacky.
219 * - even if the peer attaches big authentication data, we will never
220 * notice the difference, since longer authentication data will just
221 * work.
222 *
223 * We may need some clarification in the spec.
224 */
225 if (siz1 < siz) {
226 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
94ff46dc 227 "(%u, should be at least %u): %s\n",
0a7de745
A
228 (u_int32_t)siz1, (u_int32_t)siz,
229 ipsec4_logpacketstr(ip, spi)));
230 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
231 goto fail;
232 }
233 if ((ah->ah_len << 2) - sizoff != siz1) {
234 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
94ff46dc 235 "(%d should be %u): %s\n",
0a7de745
A
236 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
237 ipsec4_logpacketstr(ip, spi)));
2d21ac55 238 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
239 goto fail;
240 }
241
0a7de745 242 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
f427ee49
A
243 VERIFY((off + sizeof(struct ah) + sizoff + siz1) <= INT_MAX);
244 m = m_pullup(m, (int)(off + sizeof(struct ah) + sizoff + siz1));
0a7de745
A
245 if (!m) {
246 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
247 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
248 goto fail;
249 }
250 /* Expect 32-bit aligned data ptr on strict-align platforms */
251 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
252
253 ip = mtod(m, struct ip *);
254 ah = (struct ah *)(void *)(((caddr_t)ip) + off);
255 }
1c79356b 256 }
1c79356b
A
257
258 /*
259 * check for sequence number.
260 */
cb323159
A
261 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
262 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
1c79356b 263 ; /*okey*/
0a7de745 264 } else {
2d21ac55 265 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
1c79356b
A
266 ipseclog((LOG_WARNING,
267 "replay packet in IPv4 AH input: %s %s\n",
268 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
269 goto fail;
270 }
271 }
272
273 /*
274 * alright, it seems sane. now we are going to check the
275 * cryptographic checksum.
276 */
277 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT);
278 if (!cksum) {
279 ipseclog((LOG_DEBUG, "IPv4 AH input: "
280 "couldn't alloc temporary region for cksum\n"));
2d21ac55 281 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
282 goto fail;
283 }
0a7de745 284
1c79356b
A
285 /*
286 * some of IP header fields are flipped to the host endian.
287 * convert them back to network endian. VERY stupid.
288 */
f427ee49
A
289 if ((ip->ip_len + hlen) > UINT16_MAX) {
290 ipseclog((LOG_DEBUG, "IPv4 AH input: "
291 "bad length ip header len %u, total len %u\n",
292 ip->ip_len, hlen));
293 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
294 goto fail;
295 }
296
297 ip->ip_len = htons((u_int16_t)(ip->ip_len + hlen));
1c79356b 298 ip->ip_off = htons(ip->ip_off);
9bccf70c
A
299 if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
300 FREE(cksum, M_TEMP);
2d21ac55 301 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
302 goto fail;
303 }
2d21ac55 304 IPSEC_STAT_INCREMENT(ipsecstat.in_ahhist[sav->alg_auth]);
1c79356b
A
305 /*
306 * flip them back.
307 */
1c79356b 308 ip->ip_len = ntohs(ip->ip_len) - hlen;
1c79356b 309 ip->ip_off = ntohs(ip->ip_off);
1c79356b 310
0a7de745
A
311 {
312 caddr_t sumpos = NULL;
1c79356b 313
0a7de745
A
314 if (sav->flags & SADB_X_EXT_OLD) {
315 /* RFC 1826 */
316 sumpos = (caddr_t)(ah + 1);
317 } else {
318 /* RFC 2402 */
319 sumpos = (caddr_t)(((struct newah *)ah) + 1);
320 }
1c79356b 321
0a7de745
A
322 if (bcmp(sumpos, cksum, siz) != 0) {
323 ipseclog((LOG_WARNING,
324 "checksum mismatch in IPv4 AH input: %s %s\n",
325 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
326 FREE(cksum, M_TEMP);
327 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
328 goto fail;
329 }
1c79356b 330 }
1c79356b 331
9bccf70c 332 FREE(cksum, M_TEMP);
1c79356b
A
333
334 m->m_flags |= M_AUTHIPHDR;
335 m->m_flags |= M_AUTHIPDGM;
336
f427ee49 337 if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) {
2d21ac55 338 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthsucc);
1c79356b
A
339 } else {
340 ipseclog((LOG_WARNING,
341 "authentication failed in IPv4 AH input: %s %s\n",
342 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
2d21ac55 343 IPSEC_STAT_INCREMENT(ipsecstat.in_ahauthfail);
1c79356b
A
344 goto fail;
345 }
346
347 /*
348 * update sequence number.
349 */
cb323159
A
350 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
351 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
2d21ac55 352 IPSEC_STAT_INCREMENT(ipsecstat.in_ahreplay);
1c79356b
A
353 goto fail;
354 }
355 }
356
357 /* was it transmitted over the IPsec tunnel SA? */
9bccf70c
A
358 if (sav->flags & SADB_X_EXT_OLD) {
359 /* RFC 1826 */
360 stripsiz = sizeof(struct ah) + siz1;
361 } else {
362 /* RFC 2402 */
363 stripsiz = sizeof(struct newah) + siz1;
364 }
f427ee49 365 if (ipsec4_tunnel_validate(m, (int)(off + stripsiz), nxt, sav, &ifamily)) {
6d2010ae
A
366 ifaddr_t ifa;
367 struct sockaddr_storage addr;
39037602 368 struct sockaddr_in *ipaddr;
6d2010ae 369
1c79356b
A
370 /*
371 * strip off all the headers that precedes AH.
372 * IP xx AH IP' payload -> IP' payload
373 *
374 * XXX more sanity checks
375 * XXX relationship with gif?
376 */
4bd07ac2
A
377 u_int8_t tos, otos;
378 int sum;
379
2d21ac55
A
380 if (ifamily == AF_INET6) {
381 ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
382 "in IPv4 AH input: %s\n", ipsec_logsastr(sav)));
383 goto fail;
384 }
1c79356b 385 tos = ip->ip_tos;
f427ee49 386 m_adj(m, (int)(off + stripsiz));
1c79356b
A
387 if (m->m_len < sizeof(*ip)) {
388 m = m_pullup(m, sizeof(*ip));
389 if (!m) {
2d21ac55 390 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
391 goto fail;
392 }
393 }
394 ip = mtod(m, struct ip *);
4bd07ac2 395 otos = ip->ip_tos;
1c79356b 396 /* ECN consideration. */
3e170ce0
A
397 if (ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos) == 0) {
398 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
399 goto fail;
400 }
4bd07ac2 401
0a7de745
A
402 if (otos != ip->ip_tos) {
403 sum = ~ntohs(ip->ip_sum) & 0xffff;
404 sum += (~otos & 0xffff) + ip->ip_tos;
405 sum = (sum >> 16) + (sum & 0xffff);
406 sum += (sum >> 16); /* add carry */
407 ip->ip_sum = htons(~sum & 0xffff);
408 }
4bd07ac2 409
1c79356b 410 if (!key_checktunnelsanity(sav, AF_INET,
0a7de745 411 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
1c79356b
A
412 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
413 "in IPv4 AH input: %s %s\n",
414 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
2d21ac55 415 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
416 goto fail;
417 }
418
1c79356b
A
419#if 1
420 /*
421 * Should the inner packet be considered authentic?
422 * My current answer is: NO.
423 *
424 * host1 -- gw1 === gw2 -- host2
425 * In this case, gw2 can trust the authenticity of the
426 * outer packet, but NOT inner. Packet may be altered
427 * between host1 and gw1.
428 *
429 * host1 -- gw1 === host2
430 * This case falls into the same scenario as above.
431 *
432 * host1 === host2
433 * This case is the only case when we may be able to leave
434 * M_AUTHIPHDR and M_AUTHIPDGM set.
435 * However, if host1 is wrongly configured, and allows
436 * attacker to inject some packet with src=host1 and
437 * dst=host2, you are in risk.
438 */
439 m->m_flags &= ~M_AUTHIPHDR;
440 m->m_flags &= ~M_AUTHIPDGM;
441#endif
442
443 key_sa_recordxfer(sav, m);
9bccf70c
A
444 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
445 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
2d21ac55 446 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
9bccf70c
A
447 goto fail;
448 }
6d2010ae 449
39037602 450 bzero(&addr, sizeof(addr));
0a7de745 451 ipaddr = (__typeof__(ipaddr)) & addr;
39037602
A
452 ipaddr->sin_family = AF_INET;
453 ipaddr->sin_len = sizeof(*ipaddr);
454 ipaddr->sin_addr = ip->ip_dst;
455
456 // update the receiving interface address based on the inner address
457 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
458 if (ifa) {
459 m->m_pkthdr.rcvif = ifa->ifa_ifp;
460 IFA_REMREF(ifa);
6d2010ae 461 }
0a7de745 462
cb323159
A
463 // Input via IPsec interface
464 lck_mtx_lock(sadb_mutex);
465 ifnet_t ipsec_if = sav->sah->ipsec_if;
466 if (ipsec_if != NULL) {
467 // If an interface is found, add a reference count before dropping the lock
468 ifnet_reference(ipsec_if);
469 }
470 lck_mtx_unlock(sadb_mutex);
471 if (ipsec_if != NULL) {
472 errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
473 ifnet_release(ipsec_if);
474 if (inject_error == 0) {
fe8ab488
A
475 m = NULL;
476 goto done;
477 } else {
478 goto fail;
479 }
480 }
0a7de745
A
481
482 if (proto_input(PF_INET, m) != 0) {
6d2010ae 483 goto fail;
0a7de745 484 }
1c79356b
A
485 nxt = IPPROTO_DONE;
486 } else {
487 /*
488 * strip off AH.
1c79356b 489 */
1c79356b
A
490
491 ip = mtod(m, struct ip *);
9bccf70c
A
492 /*
493 * We do deep-copy since KAME requires that
494 * the packet is placed in a single external mbuf.
495 */
1c79356b
A
496 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
497 m->m_data += stripsiz;
498 m->m_len -= stripsiz;
499 m->m_pkthdr.len -= stripsiz;
1c79356b
A
500
501 if (m->m_len < sizeof(*ip)) {
502 m = m_pullup(m, sizeof(*ip));
503 if (m == NULL) {
2d21ac55 504 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
1c79356b
A
505 goto fail;
506 }
507 }
508 ip = mtod(m, struct ip *);
509#ifdef IPLEN_FLIPPED
f427ee49 510 ip->ip_len = (u_short)(ip->ip_len - stripsiz);
1c79356b
A
511#else
512 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
513#endif
f427ee49 514 ip->ip_p = (u_char)nxt;
1c79356b
A
515 /* forget about IP hdr checksum, the check has already been passed */
516
517 key_sa_recordxfer(sav, m);
9bccf70c 518 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
2d21ac55 519 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
9bccf70c
A
520 goto fail;
521 }
1c79356b 522
6d2010ae 523 DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL,
0a7de745
A
524 struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif,
525 struct ip *, ip, struct ip6_hdr *, NULL);
6d2010ae 526
9bccf70c 527 if (nxt != IPPROTO_DONE) {
cb323159
A
528 // Input via IPsec interface
529 lck_mtx_lock(sadb_mutex);
530 ifnet_t ipsec_if = sav->sah->ipsec_if;
531 if (ipsec_if != NULL) {
532 // If an interface is found, add a reference count before dropping the lock
533 ifnet_reference(ipsec_if);
534 }
535 lck_mtx_unlock(sadb_mutex);
536 if (ipsec_if != NULL) {
fe8ab488
A
537 ip->ip_len = htons(ip->ip_len + hlen);
538 ip->ip_off = htons(ip->ip_off);
539 ip->ip_sum = 0;
540 ip->ip_sum = ip_cksum_hdr_in(m, hlen);
cb323159
A
541 errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
542 ifnet_release(ipsec_if);
543 if (inject_error == 0) {
fe8ab488
A
544 m = NULL;
545 goto done;
546 } else {
547 goto fail;
548 }
549 }
0a7de745 550
9bccf70c
A
551 if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 &&
552 ipsec4_in_reject(m, NULL)) {
2d21ac55 553 IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
9bccf70c
A
554 goto fail;
555 }
f427ee49 556 ip_proto_dispatch_in(m, off, (u_int8_t)nxt, 0);
0a7de745 557 } else {
1c79356b 558 m_freem(m);
0a7de745 559 }
1c79356b
A
560 m = NULL;
561 }
fe8ab488 562done:
1c79356b
A
563 if (sav) {
564 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
565 printf("DP ah4_input call free SA:0x%llx\n",
566 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 567 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 568 }
2d21ac55 569 IPSEC_STAT_INCREMENT(ipsecstat.in_success);
1c79356b
A
570 return;
571
572fail:
573 if (sav) {
574 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
575 printf("DP ah4_input call free SA:0x%llx\n",
576 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 577 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 578 }
0a7de745 579 if (m) {
1c79356b 580 m_freem(m);
0a7de745 581 }
1c79356b
A
582 return;
583}
584#endif /* INET */
585
1c79356b 586int
6d2010ae 587ah6_input(struct mbuf **mp, int *offp, int proto)
1c79356b 588{
6d2010ae 589#pragma unused(proto)
1c79356b
A
590 struct mbuf *m = *mp;
591 int off = *offp;
eb6b6ca3
A
592 struct ip6_hdr *ip6 = NULL;
593 struct ah *ah = NULL;
594 u_int32_t spi = 0;
595 const struct ah_algorithm *algo = NULL;
596 size_t siz = 0;
597 size_t siz1 = 0;
598 u_char *cksum = NULL;
1c79356b 599 struct secasvar *sav = NULL;
eb6b6ca3 600 u_int16_t nxt = IPPROTO_DONE;
9bccf70c 601 size_t stripsiz = 0;
eb6b6ca3 602 sa_family_t ifamily = AF_UNSPEC;
91447636 603
2d21ac55 604 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;});
316670eb 605 ah = (struct ah *)(void *)(mtod(m, caddr_t) + off);
316670eb
A
606 /* Expect 32-bit aligned data pointer on strict-align platforms */
607 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
608
1c79356b
A
609 ip6 = mtod(m, struct ip6_hdr *);
610 nxt = ah->ah_nxt;
611
612 /* find the sassoc. */
613 spi = ah->ah_spi;
614
615 if (ntohs(ip6->ip6_plen) == 0) {
616 ipseclog((LOG_ERR, "IPv6 AH input: "
617 "AH with IPv6 jumbogram is not supported.\n"));
2d21ac55 618 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
619 goto fail;
620 }
621
622 if ((sav = key_allocsa(AF_INET6,
0a7de745
A
623 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
624 IPPROTO_AH, spi)) == 0) {
1c79356b
A
625 ipseclog((LOG_WARNING,
626 "IPv6 AH input: no key association found for spi %u\n",
627 (u_int32_t)ntohl(spi)));
2d21ac55 628 IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa);
1c79356b
A
629 goto fail;
630 }
631 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
632 printf("DP ah6_input called to allocate SA:0x%llx\n",
633 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
1c79356b 634 if (sav->state != SADB_SASTATE_MATURE
0a7de745 635 && sav->state != SADB_SASTATE_DYING) {
1c79356b
A
636 ipseclog((LOG_DEBUG,
637 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
638 (u_int32_t)ntohl(spi)));
2d21ac55 639 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
1c79356b
A
640 goto fail;
641 }
9bccf70c
A
642
643 algo = ah_algorithm_lookup(sav->alg_auth);
644 if (!algo) {
1c79356b 645 ipseclog((LOG_DEBUG, "IPv6 AH input: "
9bccf70c 646 "unsupported authentication algorithm for spi %u\n",
1c79356b 647 (u_int32_t)ntohl(spi)));
2d21ac55 648 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
1c79356b
A
649 goto fail;
650 }
651
1c79356b
A
652 siz = (*algo->sumsiz)(sav);
653 siz1 = ((siz + 3) & ~(4 - 1));
654
655 /*
656 * sanity checks for header, 1.
657 */
0a7de745
A
658 {
659 int sizoff;
1c79356b 660
0a7de745 661 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
1c79356b 662
0a7de745
A
663 /*
664 * Here, we do not do "siz1 == siz". See ah4_input() for complete
665 * description.
666 */
667 if (siz1 < siz) {
668 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
94ff46dc 669 "(%u, should be at least %u): %s\n",
0a7de745
A
670 (u_int32_t)siz1, (u_int32_t)siz,
671 ipsec6_logpacketstr(ip6, spi)));
672 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
673 goto fail;
674 }
675 if ((ah->ah_len << 2) - sizoff != siz1) {
676 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
94ff46dc 677 "(%d should be %u): %s\n",
0a7de745
A
678 (ah->ah_len << 2) - sizoff, (u_int32_t)siz1,
679 ipsec6_logpacketstr(ip6, spi)));
680 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
681 goto fail;
682 }
f427ee49
A
683 VERIFY((sizeof(struct ah) + sizoff + siz1) <= INT_MAX);
684 IP6_EXTHDR_CHECK(m, off, (int)(sizeof(struct ah) + sizoff + siz1),
0a7de745 685 {return IPPROTO_DONE;});
eb6b6ca3
A
686 ip6 = mtod(m, struct ip6_hdr *);
687 ah = (struct ah *)(void *)(mtod(m, caddr_t) + off);
1c79356b 688 }
1c79356b
A
689
690 /*
691 * check for sequence number.
692 */
cb323159
A
693 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
694 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
1c79356b 695 ; /*okey*/
0a7de745 696 } else {
2d21ac55 697 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
1c79356b
A
698 ipseclog((LOG_WARNING,
699 "replay packet in IPv6 AH input: %s %s\n",
700 ipsec6_logpacketstr(ip6, spi),
701 ipsec_logsastr(sav)));
702 goto fail;
703 }
704 }
705
706 /*
707 * alright, it seems sane. now we are going to check the
708 * cryptographic checksum.
709 */
710 cksum = _MALLOC(siz1, M_TEMP, M_NOWAIT);
711 if (!cksum) {
712 ipseclog((LOG_DEBUG, "IPv6 AH input: "
713 "couldn't alloc temporary region for cksum\n"));
2d21ac55 714 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
715 goto fail;
716 }
0a7de745 717
9bccf70c
A
718 if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
719 FREE(cksum, M_TEMP);
2d21ac55 720 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
721 goto fail;
722 }
2d21ac55 723 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahhist[sav->alg_auth]);
1c79356b 724
0a7de745
A
725 {
726 caddr_t sumpos = NULL;
1c79356b 727
0a7de745
A
728 if (sav->flags & SADB_X_EXT_OLD) {
729 /* RFC 1826 */
730 sumpos = (caddr_t)(ah + 1);
731 } else {
732 /* RFC 2402 */
733 sumpos = (caddr_t)(((struct newah *)ah) + 1);
734 }
1c79356b 735
0a7de745
A
736 if (bcmp(sumpos, cksum, siz) != 0) {
737 ipseclog((LOG_WARNING,
738 "checksum mismatch in IPv6 AH input: %s %s\n",
739 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
740 FREE(cksum, M_TEMP);
741 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
742 goto fail;
743 }
1c79356b 744 }
1c79356b 745
9bccf70c 746 FREE(cksum, M_TEMP);
1c79356b
A
747
748 m->m_flags |= M_AUTHIPHDR;
749 m->m_flags |= M_AUTHIPDGM;
750
f427ee49 751 if (m->m_flags & M_AUTHIPHDR && m->m_flags & M_AUTHIPDGM) {
2d21ac55 752 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthsucc);
1c79356b
A
753 } else {
754 ipseclog((LOG_WARNING,
755 "authentication failed in IPv6 AH input: %s %s\n",
756 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
2d21ac55 757 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahauthfail);
1c79356b
A
758 goto fail;
759 }
760
761 /*
762 * update sequence number.
763 */
cb323159
A
764 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
765 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) {
2d21ac55 766 IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
1c79356b
A
767 goto fail;
768 }
769 }
770
771 /* was it transmitted over the IPsec tunnel SA? */
9bccf70c
A
772 if (sav->flags & SADB_X_EXT_OLD) {
773 /* RFC 1826 */
774 stripsiz = sizeof(struct ah) + siz1;
775 } else {
776 /* RFC 2402 */
777 stripsiz = sizeof(struct newah) + siz1;
778 }
f427ee49 779 if (ipsec6_tunnel_validate(m, (int)(off + stripsiz), nxt, sav, &ifamily)) {
6d2010ae
A
780 ifaddr_t ifa;
781 struct sockaddr_storage addr;
39037602 782 struct sockaddr_in6 *ip6addr;
1c79356b
A
783 /*
784 * strip off all the headers that precedes AH.
785 * IP6 xx AH IP6' payload -> IP6' payload
786 *
787 * XXX more sanity checks
788 * XXX relationship with gif?
789 */
0a7de745 790 u_int32_t flowinfo; /*net endian*/
1c79356b 791
3e170ce0
A
792 if (ifamily == AF_INET) {
793 ipseclog((LOG_NOTICE, "ipsec tunnel protocol mismatch "
794 "in IPv6 AH input: %s\n", ipsec_logsastr(sav)));
795 goto fail;
796 }
797
1c79356b 798 flowinfo = ip6->ip6_flow;
f427ee49 799 m_adj(m, (int)(off + stripsiz));
1c79356b
A
800 if (m->m_len < sizeof(*ip6)) {
801 /*
802 * m_pullup is prohibited in KAME IPv6 input processing
803 * but there's no other way!
804 */
805 m = m_pullup(m, sizeof(*ip6));
806 if (!m) {
2d21ac55 807 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
808 goto fail;
809 }
810 }
811 ip6 = mtod(m, struct ip6_hdr *);
812 /* ECN consideration. */
3e170ce0
A
813 if (ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow) == 0) {
814 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
815 goto fail;
816 }
1c79356b 817 if (!key_checktunnelsanity(sav, AF_INET6,
0a7de745 818 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
1c79356b
A
819 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
820 "in IPv6 AH input: %s %s\n",
821 ipsec6_logpacketstr(ip6, spi),
822 ipsec_logsastr(sav)));
2d21ac55 823 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
1c79356b
A
824 goto fail;
825 }
826
1c79356b
A
827 /*
828 * should the inner packet be considered authentic?
829 * see comment in ah4_input().
830 */
831 m->m_flags &= ~M_AUTHIPHDR;
832 m->m_flags &= ~M_AUTHIPDGM;
1c79356b
A
833
834 key_sa_recordxfer(sav, m);
9bccf70c
A
835 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
836 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
2d21ac55 837 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
9bccf70c
A
838 goto fail;
839 }
6d2010ae 840
39037602 841 bzero(&addr, sizeof(addr));
0a7de745 842 ip6addr = (__typeof__(ip6addr)) & addr;
39037602
A
843 ip6addr->sin6_family = AF_INET6;
844 ip6addr->sin6_len = sizeof(*ip6addr);
845 ip6addr->sin6_addr = ip6->ip6_dst;
846
847 // update the receiving interface address based on the inner address
848 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
849 if (ifa) {
850 m->m_pkthdr.rcvif = ifa->ifa_ifp;
851 IFA_REMREF(ifa);
6d2010ae
A
852 }
853
cb323159
A
854 // Input via IPsec interface
855 lck_mtx_lock(sadb_mutex);
856 ifnet_t ipsec_if = sav->sah->ipsec_if;
857 if (ipsec_if != NULL) {
858 // If an interface is found, add a reference count before dropping the lock
859 ifnet_reference(ipsec_if);
860 }
861 lck_mtx_unlock(sadb_mutex);
862 if (ipsec_if != NULL) {
863 errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
864 ifnet_release(ipsec_if);
865 if (inject_error == 0) {
fe8ab488
A
866 m = NULL;
867 nxt = IPPROTO_DONE;
868 goto done;
869 } else {
870 goto fail;
871 }
872 }
0a7de745
A
873
874 if (proto_input(PF_INET6, m) != 0) {
6d2010ae 875 goto fail;
0a7de745 876 }
1c79356b
A
877 nxt = IPPROTO_DONE;
878 } else {
879 /*
880 * strip off AH.
1c79356b 881 */
1c79356b
A
882 char *prvnxtp;
883
884 /*
885 * Copy the value of the next header field of AH to the
886 * next header field of the previous header.
887 * This is necessary because AH will be stripped off below.
888 */
889 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
f427ee49 890 *prvnxtp = (u_int8_t)nxt;
1c79356b 891
1c79356b 892 ip6 = mtod(m, struct ip6_hdr *);
9bccf70c
A
893 /*
894 * We do deep-copy since KAME requires that
895 * the packet is placed in a single mbuf.
896 */
1c79356b
A
897 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
898 m->m_data += stripsiz;
899 m->m_len -= stripsiz;
900 m->m_pkthdr.len -= stripsiz;
1c79356b
A
901 ip6 = mtod(m, struct ip6_hdr *);
902 /* XXX jumbogram */
f427ee49 903 ip6->ip6_plen = htons((u_int16_t)(ntohs(ip6->ip6_plen) - stripsiz));
1c79356b
A
904
905 key_sa_recordxfer(sav, m);
9bccf70c 906 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
2d21ac55 907 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
9bccf70c
A
908 goto fail;
909 }
0a7de745 910
cb323159
A
911 // Input via IPsec interface
912 lck_mtx_lock(sadb_mutex);
913 ifnet_t ipsec_if = sav->sah->ipsec_if;
914 if (ipsec_if != NULL) {
915 // If an interface is found, add a reference count before dropping the lock
916 ifnet_reference(ipsec_if);
917 }
918 lck_mtx_unlock(sadb_mutex);
919 if (ipsec_if != NULL) {
920 errno_t inject_error = ipsec_inject_inbound_packet(ipsec_if, m);
921 ifnet_release(ipsec_if);
922 if (inject_error == 0) {
fe8ab488
A
923 m = NULL;
924 nxt = IPPROTO_DONE;
925 goto done;
926 } else {
927 goto fail;
928 }
929 }
1c79356b
A
930 }
931
fe8ab488 932done:
1c79356b
A
933 *offp = off;
934 *mp = m;
1c79356b
A
935 if (sav) {
936 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
937 printf("DP ah6_input call free SA:0x%llx\n",
938 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 939 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 940 }
2d21ac55 941 IPSEC_STAT_INCREMENT(ipsec6stat.in_success);
1c79356b
A
942 return nxt;
943
944fail:
945 if (sav) {
946 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
39236c6e
A
947 printf("DP ah6_input call free SA:0x%llx\n",
948 (uint64_t)VM_KERNEL_ADDRPERM(sav)));
2d21ac55 949 key_freesav(sav, KEY_SADB_UNLOCKED);
1c79356b 950 }
0a7de745 951 if (m) {
1c79356b 952 m_freem(m);
eb6b6ca3 953 *mp = NULL;
0a7de745 954 }
1c79356b
A
955 return IPPROTO_DONE;
956}
9bccf70c
A
957
958void
39037602 959ah6_ctlinput(int cmd, struct sockaddr *sa, void *d)
9bccf70c
A
960{
961 const struct newah *ahp;
962 struct newah ah;
963 struct secasvar *sav;
964 struct ip6_hdr *ip6;
965 struct mbuf *m;
966 struct ip6ctlparam *ip6cp = NULL;
5ba3f43e 967 int off = 0;
55e303ae 968 struct sockaddr_in6 *sa6_src, *sa6_dst;
9bccf70c
A
969
970 if (sa->sa_family != AF_INET6 ||
0a7de745 971 sa->sa_len != sizeof(struct sockaddr_in6)) {
9bccf70c 972 return;
0a7de745
A
973 }
974 if ((unsigned)cmd >= PRC_NCMDS) {
9bccf70c 975 return;
0a7de745 976 }
9bccf70c
A
977
978 /* if the parameter is from icmp6, decode it. */
979 if (d != NULL) {
980 ip6cp = (struct ip6ctlparam *)d;
981 m = ip6cp->ip6c_m;
982 ip6 = ip6cp->ip6c_ip6;
983 off = ip6cp->ip6c_off;
984 } else {
985 m = NULL;
986 ip6 = NULL;
987 }
988
989 if (ip6) {
990 /*
991 * XXX: We assume that when ip6 is non NULL,
992 * M and OFF are valid.
993 */
994
995 /* check if we can safely examine src and dst ports */
0a7de745 996 if (m->m_pkthdr.len < off + sizeof(ah)) {
9bccf70c 997 return;
0a7de745 998 }
9bccf70c
A
999
1000 if (m->m_len < off + sizeof(ah)) {
1001 /*
1002 * this should be rare case,
1003 * so we compromise on this copy...
1004 */
1005 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1006 ahp = &ah;
0a7de745 1007 } else {
316670eb 1008 ahp = (struct newah *)(void *)(mtod(m, caddr_t) + off);
0a7de745 1009 }
9bccf70c
A
1010
1011 if (cmd == PRC_MSGSIZE) {
1012 int valid = 0;
1013
1014 /*
1015 * Check to see if we have a valid SA corresponding to
1016 * the address in the ICMP message payload.
1017 */
55e303ae 1018 sa6_src = ip6cp->ip6c_src;
316670eb 1019 sa6_dst = (struct sockaddr_in6 *)(void *)sa;
9bccf70c 1020 sav = key_allocsa(AF_INET6,
0a7de745
A
1021 (caddr_t)&sa6_src->sin6_addr,
1022 (caddr_t)&sa6_dst->sin6_addr,
1023 IPPROTO_AH, ahp->ah_spi);
9bccf70c
A
1024 if (sav) {
1025 if (sav->state == SADB_SASTATE_MATURE ||
0a7de745 1026 sav->state == SADB_SASTATE_DYING) {
9bccf70c 1027 valid++;
0a7de745 1028 }
2d21ac55 1029 key_freesav(sav, KEY_SADB_UNLOCKED);
9bccf70c
A
1030 }
1031
1032 /* XXX Further validation? */
1033
1034 /*
1035 * Depending on the value of "valid" and routing table
1036 * size (mtudisc_{hi,lo}wat), we will:
1037 * - recalcurate the new MTU and create the
1038 * corresponding routing entry, or
1039 * - ignore the MTU change notification.
1040 */
1041 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1042 }
1043
1044 /* we normally notify single pcb here */
1045 } else {
1046 /* we normally notify any pcb here */
1047 }
1048}